diff --git a/local/recipes/kde/kf6-kwallet/recipe.toml b/local/recipes/kde/kf6-kwallet/recipe.toml index b7de554000..8db302255b 100644 --- a/local/recipes/kde/kf6-kwallet/recipe.toml +++ b/local/recipes/kde/kf6-kwallet/recipe.toml @@ -26,6 +26,7 @@ dependencies = [ "kf6-kwindowsystem", "kf6-ki18n", "libgcrypt", + "qca", ] script = """ DYNAMIC_INIT diff --git a/local/recipes/libs/libgcrypt/recipe.toml b/local/recipes/libs/libgcrypt/recipe.toml index 1c6568f9b1..9b58e5301a 100644 --- a/local/recipes/libs/libgcrypt/recipe.toml +++ b/local/recipes/libs/libgcrypt/recipe.toml @@ -23,7 +23,7 @@ DYNAMIC_INIT # discovers the sysroot libgpg-error rather than any host copy. export GPGRT_CONFIG="${COOKBOOK_SYSROOT}/usr/bin/gpgrt-config" -cookbook_configure +cookbook_configure --with-pic """ [package] diff --git a/local/recipes/libs/libgpg-error/recipe.toml b/local/recipes/libs/libgpg-error/recipe.toml index 0aa6918933..99c3cdd6d7 100644 --- a/local/recipes/libs/libgpg-error/recipe.toml +++ b/local/recipes/libs/libgpg-error/recipe.toml @@ -45,7 +45,7 @@ typedef struct ## EOF -cookbook_configure --enable-threads=posix +cookbook_configure --enable-threads=posix --with-pic """ [package] diff --git a/local/recipes/libs/qca/recipe.toml b/local/recipes/libs/qca/recipe.toml new file mode 100644 index 0000000000..11a2b2f2ef --- /dev/null +++ b/local/recipes/libs/qca/recipe.toml @@ -0,0 +1,72 @@ +# qca (Qt Cryptographic Architecture, Qt6 build) — Qca-qt6. +# +# Required by kf6-kwallet's ksecretd daemon (the org.freedesktop.secrets Secret +# Service provider): find_package(Qca-qt6 REQUIRED 2.3.1). QCA is a crypto +# abstraction that loads a provider plugin at runtime; we build the gcrypt +# provider (backed by the vendored libgcrypt) so ksecretd has a working +# SymmetricCipher/Hash/PBKDF2 backend on Redox. External-toolkit providers +# (ossl/nss/botan/gnupg/pkcs11/cyrus-sasl) are disabled — those libraries are +# not part of the Redox userland. +# +# Vendored full-fork model: committed source/ tree (offline, reproducible). +# +# upstream: https://download.kde.org/stable/qca/ (2.3.10) +[package] +name = "qca" +version = "2.3.10" + +[source] +path = "source" + +[build] +template = "custom" +dependencies = [ + "qtbase", + "qt5compat", + "libgcrypt", + "libgpg-error", +] +script = """ +DYNAMIC_INIT + +HOST_BUILD="${COOKBOOK_ROOT}/build/qt-host-build" + +for qtdir in plugins mkspecs metatypes modules qml; do + if [ -d "${COOKBOOK_SYSROOT}/usr/${qtdir}" ] && [ ! -e "${COOKBOOK_SYSROOT}/${qtdir}" ]; then + ln -s "usr/${qtdir}" "${COOKBOOK_SYSROOT}/${qtdir}" + fi +done + +rm -f CMakeCache.txt +rm -rf CMakeFiles + +cmake "${COOKBOOK_SOURCE}" \ + -DCMAKE_TOOLCHAIN_FILE="${COOKBOOK_ROOT}/local/recipes/qt/redox-toolchain.cmake" \ + -DQT_HOST_PATH="${HOST_BUILD}" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH="${COOKBOOK_SYSROOT}" \ + -DBUILD_WITH_QT6=ON \ + -DBUILD_TESTS=OFF \ + -DBUILD_TOOLS=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DWITH_gcrypt_PLUGIN=yes \ + -DWITH_ossl_PLUGIN=no \ + -DWITH_nss_PLUGIN=no \ + -DWITH_botan_PLUGIN=no \ + -DWITH_gnupg_PLUGIN=no \ + -DWITH_pkcs11_PLUGIN=no \ + -DWITH_cyrus-sasl_PLUGIN=no \ + -DWITH_logger_PLUGIN=yes \ + -DWITH_softstore_PLUGIN=yes \ + -Wno-dev +cmake --build . -j${COOKBOOK_MAKE_JOBS} +# QCA anchors all its install dirs to the absolute Qt prefix (/usr), so +# --install --prefix is ignored; DESTDIR-stage instead (/usr/... -> STAGE/usr/...). +DESTDIR="${COOKBOOK_STAGE}" cmake --install . + +for lib in "${COOKBOOK_STAGE}/usr/lib/"libqca-qt6.so.* "${COOKBOOK_STAGE}/usr/lib/qca-qt6/crypto/"*.so; do + [ -f "${lib}" ] || continue + patchelf --remove-rpath "${lib}" 2>/dev/null || true +done +""" diff --git a/local/recipes/libs/qca/source/.git-blame-ignore-revs b/local/recipes/libs/qca/source/.git-blame-ignore-revs new file mode 100644 index 0000000000..217c036b70 --- /dev/null +++ b/local/recipes/libs/qca/source/.git-blame-ignore-revs @@ -0,0 +1,4 @@ +# _clang_format added +f62a8ee8f7e81a1b573c335ded3326d8ee985ab4 +# Moved to clang format 13 +27d76c096d384618453680ab4f7c3c24316e3167 diff --git a/local/recipes/libs/qca/source/.gitignore b/local/recipes/libs/qca/source/.gitignore new file mode 100644 index 0000000000..e22024a6b2 --- /dev/null +++ b/local/recipes/libs/qca/source/.gitignore @@ -0,0 +1,7 @@ +/.clang-format +/compile_commands.json +.clangd +.cache +.idea +.vscode +/cmake-build* diff --git a/local/recipes/libs/qca/source/.gitlab-ci.yml b/local/recipes/libs/qca/source/.gitlab-ci.yml new file mode 100644 index 0000000000..7990083faa --- /dev/null +++ b/local/recipes/libs/qca/source/.gitlab-ci.yml @@ -0,0 +1,92 @@ +include: + - project: sysadmin/ci-utilities + file: + - /gitlab-templates/linux.yml + - /gitlab-templates/linux-qt6.yml + - /gitlab-templates/freebsd.yml + - /gitlab-templates/freebsd-qt6.yml + - /gitlab-templates/android-qt6.yml + +build_ubuntu_20_10: + stage: build + image: ubuntu:groovy + tags: + - Linux + only: + - merge_requests + before_script: + - sed -i -e 's/# deb-src/deb-src/g' /etc/apt/sources.list + - sed -i -e 's/archive/old-releases/g' /etc/apt/sources.list + - sed -i -e 's/security.ubuntu/old-releases.ubuntu/g' /etc/apt/sources.list + - echo "91.189.91.124 old-releases.ubuntu.com" >> /etc/hosts + - apt update + - apt install --yes eatmydata + - eatmydata apt build-dep --yes --no-install-recommends qca2 + - eatmydata apt install --yes --no-install-recommends ninja-build libbotan-2-dev libnss3-dev libgcrypt20-dev libpkcs11-helper1-dev gnupg + script: + - mkdir -p build && cd build + - cmake -G Ninja .. -DBUILD_PLUGINS=all + - ninja + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt5/ ctest -V + +build_fedora_34: + stage: build + image: fedora:34 + tags: + - Linux + only: + - merge_requests + before_script: + - dnf -y --setopt=install_weak_deps=False install git gcc-c++ make cmake ninja-build qt6-qtbase-devel qt6-qt5compat-devel botan2-devel cyrus-sasl-devel nss-devel libgcrypt-devel pkcs11-helper-devel gnupg + script: + - mkdir -p build && cd build + - cmake -G Ninja -DBUILD_WITH_QT6=ON .. -DBUILD_PLUGINS=all + - ninja + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt6/ ctest -V + +build_openssl3_botan3: + stage: build + image: debian:unstable + tags: + - Linux + only: + - merge_requests + before_script: + - echo 'deb-src http://deb.debian.org/debian unstable main' >> /etc/apt/sources.list + - apt-get update + - apt-get install --yes eatmydata + - eatmydata apt-get build-dep --yes --no-install-recommends qca2 + - eatmydata apt-get install --yes --no-install-recommends ninja-build libnss3-dev libgcrypt20-dev libpkcs11-helper1-dev gnupg wget libz-dev + script: + - wget https://github.com/randombit/botan/archive/refs/tags/3.0.0.tar.gz + - tar xvfh 3.0.0.tar.gz + - cd botan-3.0.0 + - ./configure.py --prefix="/usr" --with-zlib + - time make -j `nproc` install + - cd .. + - mkdir -p build && cd build + - cmake -G Ninja .. -DBUILD_PLUGINS=all + - ninja + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt5/ bin/qcatool* --debug plugins > features-with-legacy + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt5/ ctest -V + - echo "Now test without the legacy provider" + - ls /usr/lib/x86_64-linux-gnu/ossl-modules/legacy.so + - rm /usr/lib/x86_64-linux-gnu/ossl-modules/legacy.so + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt5/ bin/qcatool* --debug plugins > features-without-legacy + - QT_PLUGIN_PATH=`pwd`/lib/qca-qt5/ ctest -V + - echo "Make sure there is a difference without the legacy provider" + - "! diff -u features-with-legacy features-without-legacy" + +clang_format: + stage: build + image: debian:testing + tags: + - Linux + only: + - merge_requests + before_script: + - apt-get update + - apt-get install --yes --no-install-recommends git clang-format-19 + script: + - find . \( -name "*.cpp" -or -name "*.h" -or -name "*.c" -or -name "*.cc" \) -exec clang-format-19 -i {} \; + - git diff --exit-code diff --git a/local/recipes/libs/qca/source/CMakeLists.txt b/local/recipes/libs/qca/source/CMakeLists.txt new file mode 100644 index 0000000000..cdf9273129 --- /dev/null +++ b/local/recipes/libs/qca/source/CMakeLists.txt @@ -0,0 +1,508 @@ +# Checking for user explicitly defined CMAKE_INSTALL_PREFIX +# It must be done before project(...) +if(NOT CMAKE_INSTALL_PREFIX) + set(QCA_INSTALL_IN_QT_PREFIX ON) + # If CMAKE_INSTALL_PREFIX is set in cmake arguments + unset(CMAKE_INSTALL_PREFIX CACHE) +endif() + +# The cmake min. version should be set before calling project(...) too +cmake_minimum_required(VERSION 3.16) + +project(qca) + +set(QCA_LIB_MAJOR_VERSION "2") +set(QCA_LIB_MINOR_VERSION "3") +set(QCA_LIB_PATCH_VERSION "10") + +set(CMAKE_MACOSX_RPATH OFF) + +option(BUILD_WITH_QT6 "Build with Qt 6" OFF) +option(BUILD_TESTS "Create test" ON) +option(BUILD_TOOLS "Compile mozcerts and qcatool" ON) +set(BUILD_PLUGINS "auto" CACHE STRING "Plugins for building (also possible values: none, all and auto)") +# BUILD_SHARED_LIBS is cmake variable. Need to change default value. +option(BUILD_SHARED_LIBS "Build shared library" ON) +option(DEVELOPER_MODE "Special developer mode" OFF) + +if(QT6) + set(BUILD_WITH_QT6 ON) +endif() + +if(APPLE) + option(OSX_FRAMEWORK "Build a Mac OS X Framework" ON) +else() + set(OSX_FRAMEWORK OFF) +endif() + +find_package(Doxygen) + +string(TOLOWER "${BUILD_PLUGINS}" BUILD_PLUGINS) +if(NOT BUILD_PLUGINS) + set(BUILD_PLUGINS "none") +endif() + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) + +# Do not automatically link Qt executables to qtmain target on Windows. +# QCA exucatables use console mode only. Not need to link against qtmain.lib. +if(BUILD_WITH_QT6) + set(QT_MAJOR_VERSION 6) + message(STATUS "Building Qt 6 version") + find_package(Qt6 COMPONENTS Core Core5Compat REQUIRED) + if(BUILD_TESTS) + find_package(Qt6 COMPONENTS Test REQUIRED) + endif() +else() + set(QT_MAJOR_VERSION 5) + message(STATUS "Building Qt 5 version") + set(Qt5_NO_LINK_QTMAIN ON) + find_package(Qt5 5.14 REQUIRED Core) +endif() + +set(CMAKE_AUTOMOC ON) + +include(QcaMacro) +include(GNUInstallDirs) +if(BUILD_WITH_QT6) + set(QCA_QT_PC_VERSION "Qt6Core") + set(QCA_SUFFIX "qt6") +else() + set(QCA_QT_PC_VERSION "Qt5Core") + set(QCA_SUFFIX "qt5") +endif() + +# QCA can be shared but plugins will be static +# if Qt is static. +if(NOT BUILD_SHARED_LIBS OR QT_IS_STATIC) + set(STATIC_PLUGINS ON) + add_definitions(-DQT_STATICPLUGIN) + set(PLUGIN_TYPE "STATIC") +else() + set(PLUGIN_TYPE "MODULE") +endif() + +set(QCA_SUFFIX "${QCA_SUFFIX}" CACHE STRING "QCA common suffix") +if(QCA_SUFFIX) + set(QCA_LIB_NAME qca-${QCA_SUFFIX}) + set(QCA_TOOL_NAME qcatool-${QCA_SUFFIX}) + set(MOZCERTS_NAME mozcerts-${QCA_SUFFIX}) + set(QCA_PC_NAME qca2-${QCA_SUFFIX}.pc) + set(QCA_CONFIG_NAME_BASE "Qca-${QCA_SUFFIX}") +else() + set(QCA_LIB_NAME qca) + set(QCA_TOOL_NAME qcatool) + set(MOZCERTS_NAME mozcerts) + set(QCA_PC_NAME qca2.pc) + set(QCA_CONFIG_NAME_BASE "Qca") +endif() + +set(QCA_LIB_VERSION_STRING "${QCA_LIB_MAJOR_VERSION}.${QCA_LIB_MINOR_VERSION}.${QCA_LIB_PATCH_VERSION}") + +configure_file("include/QtCrypto/qca_version.h.in" "${CMAKE_BINARY_DIR}/qca_version.h") + +if (WIN32) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-DWIN32_LEAN_AND_MEAN) +elseif (APPLE) + set(CMAKE_DEBUG_POSTFIX "_debug") +endif() + +# C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if (CMAKE_SYSTEM_NAME MATCHES Linux) + add_definitions (-D_DEFAULT_SOURCE) + # on arm -Wcast-align throws many internal qt warning + if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-align") + endif() + + set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -Wundef -Werror-implicit-function-declaration -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common") + set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -Wundef -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -fno-check-new -fno-common") + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override -Wlogical-op" ) + endif() + endif() +endif() + +add_definitions(-DQT_NO_CAST_TO_ASCII + -DQT_NO_CAST_FROM_ASCII + -DQT_NO_URL_CAST_FROM_STRING + -DQT_NO_CAST_FROM_BYTEARRAY + -DQT_NO_SIGNALS_SLOTS_KEYWORDS + -DQT_USE_QSTRINGBUILDER + -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) + +if (NOT WIN32) + # Strict iterators can't be used on Windows, they lead to a link error + # when application code iterates over a QVector for instance, unless + # Qt itself was also built with strict iterators. + # See example at https://bugreports.qt.io/browse/AUTOSUITE-946 + add_definitions(-DQT_STRICT_ITERATORS) +endif() + +include_directories("include/QtCrypto/") +# for generated files +include_directories(${CMAKE_BINARY_DIR}) + +if(NOT DEVELOPER_MODE) + # uninstall target + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + +# Always include srcdir and builddir in include path +# This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY} in about every subdir +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# put the include dirs which are in the source or build tree +# before all other include dirs, so the headers in the sources +# are prefered over the already installed ones +set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON) + +set(qca_INCLUDEDIR "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) +# Use the same path for shared and static library +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" ) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" ) + +if( QCA_INSTALL_IN_QT_PREFIX ) + setup_qt_dirs() + set(QCA_PREFIX_INSTALL_DIR "${QT_PREFIX_DIR}" CACHE PATH "Directory where qca will install") + set(QCA_PLUGINS_INSTALL_DIR "${QT_PLUGINS_DIR}" CACHE PATH "Directory where qca plugins will install") + set(QCA_BINARY_INSTALL_DIR "${QT_BINARY_DIR}" CACHE PATH "Directory where qca plugins will install") + set(QCA_LIBRARY_INSTALL_DIR "${QT_LIBRARY_DIR}" CACHE PATH "Directory where qca library will install") + set(QCA_FEATURE_INSTALL_DIR "${QT_MKSPECS_DIR}/features" CACHE PATH "Directory where qca feature file will install") + if(NOT QCA_SUFFIX) + set(QCA_INCLUDE_INSTALL_DIR "${QT_HEADERS_DIR}" CACHE PATH "Directory where qca public headers will install") + set(QCA_PRIVATE_INCLUDE_INSTALL_DIR "${QT_HEADERS_DIR}" CACHE PATH "Directory where qca headers will install") + else() + set(QCA_INCLUDE_INSTALL_DIR "${QT_HEADERS_DIR}/${QCA_CONFIG_NAME_BASE}" CACHE PATH "Directory where qca public headers will install") + set(QCA_PRIVATE_INCLUDE_INSTALL_DIR "${QT_HEADERS_DIR}/${QCA_CONFIG_NAME_BASE}" CACHE PATH "Directory where qca headers will install") + endif() + set(QCA_DOC_INSTALL_DIR "${QT_DOC_DIR}/html/qca/" CACHE PATH "Directory where qca documentation will install") + set(QCA_MAN_INSTALL_DIR "${QT_DATA_DIR}/man" CACHE PATH "Directory where qca man pages will install") +else() + # Cmake says nothing about LIB_SUFFIX + # de facto it is a standard way to specify lib suffix on many distros + set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) + set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "Directory where lib will install") + + set(QCA_PREFIX_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Directory where qca will install") + set(QCA_PLUGINS_INSTALL_DIR "${LIB_INSTALL_DIR}/${QCA_LIB_NAME}" CACHE PATH "Directory where qca plugins will install") + set(QCA_BINARY_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Directory where qca plugins will install") + set(QCA_LIBRARY_INSTALL_DIR "${LIB_INSTALL_DIR}" CACHE PATH "Directory where qca library will install") + set(QCA_FEATURE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/mkspecs/features" CACHE PATH "Directory where qca feature file will install") + if(NOT QCA_SUFFIX) + set(QCA_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Directory where qca public headers will install") + set(QCA_PRIVATE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Directory where qca headers will install") + else() + set(QCA_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/${QCA_CONFIG_NAME_BASE}" CACHE PATH "Directory where qca public headers will install") + set(QCA_PRIVATE_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/${QCA_CONFIG_NAME_BASE}" CACHE PATH "Directory where qca headers will install") + endif() + set(QCA_DOC_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/doc/${QCA_LIB_NAME}/html" CACHE PATH "Directory where qca documentation will install") + set(QCA_MAN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Directory where qca man pages will install") +endif() + +set(PKGCONFIG_INSTALL_PREFIX "${QCA_LIBRARY_INSTALL_DIR}/pkgconfig" CACHE PATH "Base directory for pkgconfig files") + +normalize_path(QCA_PREFIX_INSTALL_DIR) + +if(OSX_FRAMEWORK) + set(QCA_FULL_INCLUDE_INSTALL_DIR "${QCA_LIBRARY_INSTALL_DIR}/${QCA_LIB_NAME}.framework/Headers") +else() + set(QCA_FULL_INCLUDE_INSTALL_DIR "${QCA_INCLUDE_INSTALL_DIR}/QtCrypto") +endif() + +# check for oportunity to use relative paths +option(USE_RELATIVE_PATHS "Try to make relocatable package") + +foreach(PATH QCA_PLUGINS_INSTALL_DIR + QCA_BINARY_INSTALL_DIR + QCA_LIBRARY_INSTALL_DIR + QCA_FEATURE_INSTALL_DIR + QCA_INCLUDE_INSTALL_DIR + QCA_PRIVATE_INCLUDE_INSTALL_DIR + QCA_DOC_INSTALL_DIR + QCA_MAN_INSTALL_DIR + PKGCONFIG_INSTALL_PREFIX) + + # Normalize path before comparsion + normalize_path(${PATH}) + + # if all paths are subdirs of CMAKE_INSTALL_PREFIX it is possible to use relative paths + string(FIND "${${PATH}}" "${QCA_PREFIX_INSTALL_DIR}/" POS) + if(NOT "${POS}" STREQUAL "0") + set(USE_RELATIVE_PATHS OFF) + endif() +endforeach() + +if(NOT WIN32) + if(OSX_FRAMEWORK) + set(PKGCONFIG_CFLAGS "-F\${libdir} -I\${includedir}") + set(PKGCONFIG_LIBS "-F\${libdir} -framework ${QCA_LIB_NAME}") + else() + set(PKGCONFIG_CFLAGS "-I\${includedir}") + set(PKGCONFIG_LIBS "-L\${libdir} -l${QCA_LIB_NAME}") + endif() + + if(NOT BUILD_WITH_QT6) + # qca2.pc uses absolute paths. So it must be there. Don't rellocate this. + configure_file("qca2.pc.cmake" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig/${QCA_PC_NAME}" @ONLY) + if(NOT DEVELOPER_MODE) + install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/pkgconfig/${QCA_PC_NAME}" DESTINATION ${PKGCONFIG_INSTALL_PREFIX}) + endif() + endif() +endif() + +# strip CMAKE_INSTALL_PREFIX in all paths +if(USE_RELATIVE_PATHS) + message(STATUS "Installed package is relocatable") + file(RELATIVE_PATH CRYPTO_PRF_RELATIVE_PATH "${QCA_FEATURE_INSTALL_DIR}" ${CMAKE_INSTALL_PREFIX}) + set(CRYPTO_PRF_RELATIVE_PATH "$$PWD/${CRYPTO_PRF_RELATIVE_PATH}") + foreach(PATH QCA_PLUGINS_INSTALL_DIR + QCA_BINARY_INSTALL_DIR + QCA_LIBRARY_INSTALL_DIR + QCA_FEATURE_INSTALL_DIR + QCA_INCLUDE_INSTALL_DIR + QCA_PRIVATE_INCLUDE_INSTALL_DIR + QCA_DOC_INSTALL_DIR + QCA_MAN_INSTALL_DIR + PKGCONFIG_INSTALL_PREFIX) + + file(RELATIVE_PATH ${PATH} ${CMAKE_INSTALL_PREFIX} "${${PATH}}") + endforeach() +else() + message(STATUS "Installed package is NOT relocatable") + set(CRYPTO_PRF_RELATIVE_PATH "") +endif() + +if(DEVELOPER_MODE) + add_definitions(-DDEVELOPER_MODE) + +# To prefer plugins from build tree when run qca from build tree + file(WRITE ${CMAKE_BINARY_DIR}/bin/qt.conf +"[Paths] +Plugins=${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME} +") +endif() + +if (APPLE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif() + +message(STATUS "Checking for certstore..") +# fixme add OR mac +if( WIN32 ) + # USE BUILTIN +else() + if ( DEFINED ENV{QC_CERTSTORE_PATH} ) + if(EXISTS $ENV{QC_CERTSTORE_PATH}) + set( qca_CERTSTORE $ENV{QC_CERTSTORE_PATH}) + endif() + else() + set( toTry + "/etc/ssl/certs/ca-certificates.crt" + "/usr/share/ssl/cert.pem" + "/usr/share/ssl/certs/ca-bundle.crt" + "/etc/pki/tls/cert.pem" + "/etc/ssl/ca-bundle.pem" + "/usr/share/curl/curl-ca-bundle.crt" + ) + foreach (_current_try ${toTry}) + if(EXISTS ${_current_try}) + set( qca_CERTSTORE ${_current_try}) + endif() + endforeach (_current_try) + endif() +endif() + +if (qca_CERTSTORE) + message(STATUS "Found system certstore") +else() + message(STATUS "Using built in certstore.") + set( qca_CERTSTORE "${CMAKE_CURRENT_SOURCE_DIR}/certs/rootcerts.pem") + # note that INSTALL_FILES targets are relative to the current installation prefix... + if(NOT DEVELOPER_MODE) + install(FILES "${qca_CERTSTORE}" DESTINATION "${QCA_PREFIX_INSTALL_DIR}/certs") + endif() +endif() +message(STATUS "certstore path: " ${qca_CERTSTORE}) +add_definitions( -DQCA_SYSTEMSTORE_PATH="${qca_CERTSTORE}" ) + + +set( private_HEADERS ${qca_INCLUDEDIR}/QtCrypto/qca_plugin.h ${qca_INCLUDEDIR}/QtCrypto/qca_systemstore.h ) + +set( public_HEADERS + ${qca_INCLUDEDIR}/QtCrypto/qca.h + ${qca_INCLUDEDIR}/QtCrypto/qcaprovider.h + ${qca_INCLUDEDIR}/QtCrypto/QtCrypto + ${qca_INCLUDEDIR}/QtCrypto/qca_support.h + ${qca_INCLUDEDIR}/QtCrypto/qca_tools.h + ${qca_INCLUDEDIR}/QtCrypto/qca_core.h + ${qca_INCLUDEDIR}/QtCrypto/qca_textfilter.h + ${qca_INCLUDEDIR}/QtCrypto/qca_basic.h + ${qca_INCLUDEDIR}/QtCrypto/qca_publickey.h + ${qca_INCLUDEDIR}/QtCrypto/qca_cert.h + ${qca_INCLUDEDIR}/QtCrypto/qca_keystore.h + ${qca_INCLUDEDIR}/QtCrypto/qca_securelayer.h + ${qca_INCLUDEDIR}/QtCrypto/qca_securemessage.h + ${CMAKE_BINARY_DIR}/qca_version.h + ${qca_INCLUDEDIR}/QtCrypto/qpipe.h + ${qca_INCLUDEDIR}/QtCrypto/qca_safetimer.h) + +set( qca_HEADERS ${private_HEADERS} ${public_HEADERS} ) + +include_directories("${qca_INCLUDEDIR}/QtCrypto") + +if(NOT BUILD_WITH_QT6) + configure_file("crypto.prf.cmake" "${CMAKE_BINARY_DIR}/mkspecs/features/crypto.prf" @ONLY) + if(NOT DEVELOPER_MODE) + install(FILES "${CMAKE_BINARY_DIR}/mkspecs/features/crypto.prf" DESTINATION "${QCA_FEATURE_INSTALL_DIR}") + endif() +endif() + +configure_file(man/qcatool.1 "${CMAKE_BINARY_DIR}/share/man/man1/${QCA_TOOL_NAME}.1" COPYONLY) +if(NOT DEVELOPER_MODE) + install(FILES "${CMAKE_BINARY_DIR}/share/man/man1/${QCA_TOOL_NAME}.1" DESTINATION "${QCA_MAN_INSTALL_DIR}/man1") +endif() + +set(QCA_CRYPTO_INSTALL_DIR "${QCA_PLUGINS_INSTALL_DIR}/crypto") + +add_subdirectory(src) +add_subdirectory(plugins) + +include(GenerateExportHeader) +generate_export_header(${QCA_LIB_NAME} BASE_NAME qca) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/qca_export.h DESTINATION ${QCA_FULL_INCLUDE_INSTALL_DIR} +) + +if(STATIC_PLUGINS) + # Generate header with static plugins list + file(WRITE "${CMAKE_BINARY_DIR}/import_plugins.h" "#include \n") + foreach(PLUGIN IN LISTS PLUGINS) + if(WITH_${PLUGIN}_PLUGIN_INTERNAL) + string(REPLACE "-" "_" IMPORT_NAME "qca-${PLUGIN}") + file(APPEND "${CMAKE_BINARY_DIR}/import_plugins.h" "Q_IMPORT_PLUGIN(${IMPORT_NAME})\n") + endif() + endforeach(PLUGIN IN LISTS PLUGINS) +endif() + +if(BUILD_TESTS) + enable_testing() + add_subdirectory(unittest) + add_subdirectory(examples) +endif() +if(BUILD_TOOLS) + add_subdirectory(tools) +endif() + +if(DOXYGEN_FOUND) + configure_file(${CMAKE_SOURCE_DIR}/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY) + add_custom_target(doc + ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/docs/pics + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/docs/pics/qca-arch.eps ${CMAKE_BINARY_DIR}/docs/pics/qca-arch.eps + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/docs/pics/qca-arch.png ${CMAKE_BINARY_DIR}/docs/pics/qca-arch.png + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" VERBATIM) +endif() + +include(CMakePackageConfigHelpers) +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/QcaConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}Config.cmake" + INSTALL_DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} +) +write_basic_config_version_file("${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" VERSION ${QCA_LIB_VERSION_STRING} COMPATIBILITY AnyNewerVersion) + +if(NOT DEVELOPER_MODE) + + # /usr/local is traditional path for installing apps on POSIX-systems. + # I consciously break this. Qt by default looks plugins and features only in + # own directory. So by default install libs in Qt prefix it is a best choice. + # This can be unwanted behaviour for users who don't read INSTALL file or/and + # not read cmake reports. I just try to warn their. + + # In really anybody who do cmake . && make && sudo make install do it for own risk. + + if(QCA_INSTALL_IN_QT_PREFIX) + string(ASCII 27 ESCAPE) + message("") + message("${ESCAPE}[31m") + message("!!!!!!!!!!!!!!!!!!!!!ATTENTION!!!!!!!!!!!!!!!!!!!!!!") + message("!! QCA will be installed in Qt prefix !!") + message("!! If you want to install in /usr/local !!") + message("!! you MUST explicity define CMAKE_INSTALL_PREFIX !!") + message("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + message("${ESCAPE}[0m") + endif() + + message("") + if(USE_RELATIVE_PATHS) + message("QCA prefix is " "${QCA_PREFIX_INSTALL_DIR}") + message("Plugins will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_PLUGINS_INSTALL_DIR}") + message("Binary will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_BINARY_INSTALL_DIR}") + if(OSX_FRAMEWORK) + message("Framework will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_LIBRARY_INSTALL_DIR}") + else() + message("Library will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_LIBRARY_INSTALL_DIR}") + message("Public headers will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_INCLUDE_INSTALL_DIR}") + message("Private headers will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_PRIVATE_INCLUDE_INSTALL_DIR}") + endif() + message("Feature file will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_FEATURE_INSTALL_DIR}") + message("Documentation will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_DOC_INSTALL_DIR}") + message("Man page will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${QCA_MAN_INSTALL_DIR}") + message("Pkg-config file will be installed to " "${QCA_PREFIX_INSTALL_DIR}/${PKGCONFIG_INSTALL_PREFIX}") + else() + message("QCA prefix is " "${QCA_PREFIX_INSTALL_DIR}") + message("Plugins will be installed to " "${QCA_PLUGINS_INSTALL_DIR}") + message("Binary will be installed to " "${QCA_BINARY_INSTALL_DIR}") + if(OSX_FRAMEWORK) + message("Framework will be installed to " "${QCA_LIBRARY_INSTALL_DIR}") + else() + message("Library will be installed to " "${QCA_LIBRARY_INSTALL_DIR}") + message("Public headers will be installed to " "${QCA_INCLUDE_INSTALL_DIR}") + message("Private headers will be installed to " "${QCA_PRIVATE_INCLUDE_INSTALL_DIR}") + endif() + message("Feature file will be installed to " "${QCA_FEATURE_INSTALL_DIR}") + message("Documentation will be installed to " "${QCA_DOC_INSTALL_DIR}") + message("Man page will be installed to " "${QCA_MAN_INSTALL_DIR}") + message("Pkg-config file will be installed to " "${PKGCONFIG_INSTALL_PREFIX}") + endif() + message("") + + if(UNIX AND NOT APPLE) + if(NOT QCA_SUFFIX) + + message("${ESCAPE}[31mYou don't have QCA_SUFFIX set. Please note that the recommended way of") + if(BUILD_WITH_QT6) + message("building Qt6 version of qca for Linux distributions is to set") + message("QCA_SUFFIX to qt6 (-DQCA_SUFFIX=qt6).") + else() + message("building Qt5 version of qca for Linux distributions is to set") + message("QCA_SUFFIX to qt5 (-DQCA_SUFFIX=qt5).") + endif() + message("${ESCAPE}[0m") + endif() + endif() + + install(EXPORT ${QCA_CONFIG_NAME_BASE}Targets DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} FILE ${QCA_CONFIG_NAME_BASE}Targets.cmake) + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/lib/cmake/${QCA_CONFIG_NAME_BASE}/${QCA_CONFIG_NAME_BASE}ConfigVersion.cmake" + DESTINATION ${QCA_LIBRARY_INSTALL_DIR}/cmake/${QCA_CONFIG_NAME_BASE} + ) +endif() diff --git a/local/recipes/libs/qca/source/COPYING b/local/recipes/libs/qca/source/COPYING new file mode 100644 index 0000000000..5ab7695ab8 --- /dev/null +++ b/local/recipes/libs/qca/source/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/Doxyfile.in b/local/recipes/libs/qca/source/Doxyfile.in new file mode 100644 index 0000000000..6100ed6bb7 --- /dev/null +++ b/local/recipes/libs/qca/source/Doxyfile.in @@ -0,0 +1,1291 @@ +# Doxyfile 1.5.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "Qt Cryptographic Architecture" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = apidocs + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = NO + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @CMAKE_SOURCE_DIR@/examples \ + @CMAKE_SOURCE_DIR@ \ + @CMAKE_SOURCE_DIR@/include/QtCrypto \ + @CMAKE_BINARY_DIR@/qca_version.h + +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# See http://www.gnu.org/software/libiconv for the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.h \ + *.doco \ + Mainpage.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = @CMAKE_BINARY_DIR@/import_plugins.h + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = *.moc.* \ + moc* \ + *.all_cpp.* \ + *unload.* \ + */test/* \ + */tests/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples/aes-cmac \ + @CMAKE_SOURCE_DIR@/examples/base64test \ + @CMAKE_SOURCE_DIR@/examples/certtest \ + @CMAKE_SOURCE_DIR@/examples/ciphertest \ + @CMAKE_SOURCE_DIR@/examples/cms \ + @CMAKE_SOURCE_DIR@/examples/cmssigner \ + @CMAKE_SOURCE_DIR@/examples/eventhandlerdemo \ + @CMAKE_SOURCE_DIR@/examples/hashtest \ + @CMAKE_SOURCE_DIR@/examples/hextest \ + @CMAKE_SOURCE_DIR@/examples/keyloader \ + @CMAKE_SOURCE_DIR@/examples/mactest \ + @CMAKE_SOURCE_DIR@/examples/md5crypt \ + @CMAKE_SOURCE_DIR@/examples/providertest \ + @CMAKE_SOURCE_DIR@/examples/publickeyexample \ + @CMAKE_SOURCE_DIR@/examples/randomtest \ + @CMAKE_SOURCE_DIR@/examples/rsatest \ + @CMAKE_SOURCE_DIR@/examples/saslclient \ + @CMAKE_SOURCE_DIR@/examples/saslserver \ + @CMAKE_SOURCE_DIR@/examples/ssltest \ + @CMAKE_SOURCE_DIR@/examples/sslservtest \ + @CMAKE_SOURCE_DIR@/examples/tlssocket + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = @CMAKE_SOURCE_DIR@/docs/pics + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = YES + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +# add DOXYGEN_NO_PROVIDER_API here to disable generation of the +# Provider API documentation with Doxygen. +PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \ + QPIPE_SECURE + + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = QCA_EXPORT QCA_NOEXCEPT + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# be found in the default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = NO + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = NO + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen will always +# show the root nodes and its direct children regardless of this setting. + +DOT_GRAPH_MAX_NODES = 50 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/local/recipes/libs/qca/source/INSTALL b/local/recipes/libs/qca/source/INSTALL new file mode 100644 index 0000000000..24cd3e061f --- /dev/null +++ b/local/recipes/libs/qca/source/INSTALL @@ -0,0 +1,53 @@ +Installing QCA +-------------- + +For Unix/Linux/Mac/Windows: + + cmake . + make + make install + /sbin/ldconfig, if necessary + +Notes +----- + + Use cmake cache entries + + CMAKE_INSTALL_PREFIX - must be defined otherwise QCA will be installed + in Qt prefix (by default: "") + BUILD_TESTS - build unittests (by default: ON) + BUILD_TOOLS - build mozcerts and qcatool (by default: ON) + QCA_SUFFIX - suffix will be used for library, qcatool binary, + qcatool manpage and qca pkg-config file (by default: "") + LIB_SUFFIX - library directory suffix (by default: "") + LIB_INSTALL_DIR - path to library directory + (by default: ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) + BUILD_PLUGINS - list plugins to build (botan;ossl;gnupg for example). + Also possible values is none, auto or all + (by default: "auto") + WITH_${PLUGIN}_PLUGIN - to build particular plugin. Can be no, yes or + auto (WITH_ossl_PLUGIN=auto for example) + DEVELOPER_MODE - mode to enable features for developers. If ON + will be used hardcoded path to 'crypto' + (by default: OFF) + OSX_FRAMEWORK - build an OS X framework (by default: ON) + USE_RELATIVE_PATHS - make relocatable package if possible (by default: OFF) + + Finally install paths can be override with: + + QCA_PREFIX_INSTALL_DIR - qca prefix, just a origin to make other paths + QCA_PLUGINS_INSTALL_DIR - qt plugins path + QCA_BINARY_INSTALL_DIR - qcatool will be installed to + QCA_LIBRARY_INSTALL_DIR - qca library will be installed to + QCA_FEATURE_INSTALL_DIR - path to qt mkspecs dir + QCA_INCLUDE_INSTALL_DIR - path for QtCrypto dir with includes + QCA_PRIVATE_INCLUDE_INSTALL_DIR - for future implementation + QCA_DOC_INSTALL_DIR - for html documentation + QCA_MAN_INSTALL_DIR - for qcatool manpage + PKGCONFIG_INSTALL_PREFIX - path to install pkg config file + +Please report problems to: + http://bugs.kde.org + +Official git repo: + https://invent.kde.org/kde/qca diff --git a/local/recipes/libs/qca/source/Mainpage.dox b/local/recipes/libs/qca/source/Mainpage.dox new file mode 100644 index 0000000000..f9222d993a --- /dev/null +++ b/local/recipes/libs/qca/source/Mainpage.dox @@ -0,0 +1,400 @@ +/** + \mainpage Qt Cryptographic Architecture + + Taking a hint from the similarly-named + Java + Cryptography Architecture, %QCA aims to provide a + straightforward and cross-platform cryptographic API, using Qt + datatypes and conventions. %QCA separates the API from the + implementation, using plugins known as Providers. The advantage + of this model is to allow applications to avoid linking to or + explicitly depending on any particular cryptographic library. + This allows one to easily change or upgrade Provider + implementations without even needing to recompile the + application! + + %QCA should work everywhere %Qt does, including Windows/Unix/MacOSX. This + version of %QCA is for Qt4 or Qt5, and requires no Qt3 compatibility code. + + \section features Features + + This library provides an easy API for the following features: + - Secure byte arrays (QCA::SecureArray) + - Arbitrary precision integers (QCA::BigInteger) + - Random number generation (QCA::Random) + - SSL/TLS (QCA::TLS) + - X509 certificates (QCA::Certificate and QCA::CertificateCollection) + - X509 certificate revocation lists (QCA::CRL) + - Built-in support for operating system certificate root storage (QCA::systemStore) + - Simple Authentication and Security Layer (SASL) (QCA::SASL) + - Cryptographic Message Syntax (e.g., for S/MIME) (QCA::CMS) + - PGP messages (QCA::OpenPGP) + - Unified PGP/CMS API (QCA::SecureMessage) + - Subsystem for managing Smart Cards and PGP keyrings (QCA::KeyStore) + - Simple but flexible logging system (QCA::Logger) + - RSA (QCA::RSAPrivateKey and QCA::RSAPublicKey) + - DSA (QCA::DSAPrivateKey and QCA::DSAPublicKey) + - Diffie-Hellman (QCA::DHPrivateKey and QCA::DHPublicKey) + - Hashing (QCA::Hash) with + - SHA-0 + - SHA-1 + - MD2 + - MD4 + - MD5 + - RIPEMD160 + - SHA-224 + - SHA-256 + - SHA-384 + - SHA-512 + - Whirlpool + - Ciphers (QCA::Cipher) using + - BlowFish + - Triple DES + - DES + - AES (128, 192 and 256 bit) + - CAST5 (also known as CAST-128) + - Message Authentication Code (QCA::MessageAuthenticationCode), using + - HMAC with SHA-1 + - HMAC with MD5 + - HMAC with RIPEMD160 + - HMAC with SHA-224 + - HMAC with SHA-256 + - HMAC with SHA-384 + - HMAC with SHA-512 + - Encoding and decoding of hexadecimal (QCA::Hex) and + Base64 (QCA::Base64) strings. + + Functionality is supplied via plugins. This is useful for avoiding + dependence on a particular crypto library and makes upgrading easier, + as there is no need to recompile your application when adding or + upgrading a crypto plugin. Also, by pushing crypto functionality into + plugins, your application is free of legal issues, such as export + regulation. + + And of course, you get a very simple crypto API for Qt, where you can + do things like: + \code + QString hash = QCA::Hash("sha1").hashToString(blockOfData); + \endcode + + \section using Using QCA + + The application simply includes <QtCrypto> and links to + libqca, which provides the 'wrapper API' and plugin loader. Crypto + functionality is determined during runtime, and plugins are loaded + from the 'crypto' subfolder of the %Qt library paths. There are additional examples available. + + \subsection tute1 Introduction + + Using %QCA is much like using Qt, and if you are familiar with + Qt, then it should feel "natural". There are a few things you + do need to know though, to build reliable applications: + - %QCA needs to be initialized before you use any class that + requires plugin support, or uses secure memory. That is most + of %QCA, so you should assume that you need to perform + initialization. The easiest way to do this is to instantiate + a QCA::Initializer object and ensure it is not deleted (or + allowed to go out of scope) until you have finished using + %QCA. + - Most features/algorithms are provided by plugins/\ref providers. + You should check that the required feature is actually + available (using QCA::isSupported()) before trying to create + it. If you try to create a class and suitable provider support + is not available, you will get back a null object, and when + you try to use one of the methods, your application will + segfault. Also, for features that take algorithm names (e.g. + QCA::Hash, which takes the name of the hashing algorithm such + as "md5" or "sha256"), the name is looked up at run-time, so + if you make a typographical error (e.g. "md56") it will compile + correctly, but segfault at run-time. + + \subsection tute2 Thoughts on security + + %QCA tries to be flexible in what it supports. That does not mean that + every possible combination of features makes sense though. + + We strongly recommend against coming up with your own design made up + of low-level cryptographic primitives (e.g. QCA::Hash, QCA::Cipher and + similar features) and trying to use higher level capabilities. In particular, + we recommend looking at QCA::TLS, QCA::SASL, QCA::CMS and QCA::OpenPGP + as starting points. + + When selecting a particular cryptographic feature, you should make sure + that you understand what sort of threats your application is likely + to be exposed to, and how that threat can be effectively countered. In + addition, you should consider whether you can avoid adding cryptographic + features directly to your application (e.g. for secure transport, you + may be able to tunnel your application over SSH). + + Also, you may need to look beyond %QCA for some security needs (e.g. + for authentication, your situation may be more suited to using + Kerberos than SASL or TLS). + + \subsection intro-design Design + + The architecture of %QCA is shown below: + + \image html qca-arch.png "QCA Architecture" + \image latex qca-arch.eps "QCA Architecture" width=\textwidth + + Application authors normally only need to use the User API. The + provider API is available for plugin authors, but can also + be used by application authors to provide very specific capabilities. + + For more information on the design of %QCA, you might like to review + the \ref architecture description. + + \section availability Availability + + \subsection qca2code Releases + + The latest release packages can be found in the + %QCA 2.x download area. + + See the project web site for + further information about %QCA releases. + + \subsection qca2dev Current development + + The latest version of the code is available from the KDE Git server + (there is no formal release of the current version at this time). + Naturally you will need %Qt properly set up and configured in order + to build and use %QCA. + + The Git code can be browsed + + via the web + + Use + \verbatim + git clone https://invent.kde.org/libraries/qca.git + \endverbatim + to get the latest sources. + */ + +/** \page architecture Architecture + +\note You don't need to understand any of this to use %QCA - it is +documented for those who are curious, and for anyone planning to +extend or modify %QCA. + +The design of %QCA is based on the Bridge design pattern. The intent of +the Bridge pattern is to "Decouple an abstraction from its +implementation so that the two can vary independently." [Gamma et.al, +pg 151]. + +To understand how this decoupling works in the case of %QCA, is is +easiest to look at an example - a cryptographic Hash. The API is +pretty simple (although I've left out some parts that aren't required +for this example): + +\code +class QCA_EXPORT Hash : public Algorithm, public BufferedComputation +{ +public: + Hash(const QString &type, const QString &provider); + virtual void clear(); + virtual void update(const QCA::SecureArray &a); + virtual QCA::SecureArray final(); +} +\endcode + +The implementation for the Hash class is almost as simple: + +\code +Hash::Hash(const QString &type, const QString &provider) +:Algorithm(type, provider) +{ +} + +void Hash::clear() +{ + static_cast(context())->clear(); +} + +void Hash::update(const QCA::SecureArray &a) +{ + static_cast(context())->update(a); +} + +QCA::SecureArray Hash::final() +{ + return static_cast(context())->final(); +} +\endcode + +The reason why it looks so simple is that the various methods in Hash +just call out to equivalent routines in the context() object. The +context comes from a call (getContext()) that is made as part of the +Algorithm constructor. That getContext() call causes %QCA to work +through the list of providers (generally plugins) that it knows about, +looking for a provider that can produce the right kind of context (in +this case, a HashContext). + + The code for a HashContext doesn't need to be linked into %QCA - it can +be varied in its implementation, including being changed at run-time. The +application doesn't need to know how HashContext is implemented, because + it just has to deal with the Hash class interface. In fact, HashContext + may not be implemented, so the application should check (using + QCA::isSupported()) before trying to use features that are implemented +with plugins. + + The code for one implementation (in this case, calling OpenSSL) is shown +below. +\code +class opensslHashContext : public HashContext +{ +public: + opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) : HashContext(p, type) + { + m_algorithm = algorithm; + EVP_DigestInit( &m_context, m_algorithm ); + }; + + ~opensslHashContext() + { + EVP_MD_CTX_cleanup(&m_context); + } + + void clear() + { + EVP_MD_CTX_cleanup(&m_context); + EVP_DigestInit( &m_context, m_algorithm ); + } + + void update(const QCA::SecureArray &a) + { + EVP_DigestUpdate( &m_context, (unsigned char*)a.data(), a.size() ); + } + + QCA::SecureArray final() + { + QCA::SecureArray a( EVP_MD_size( m_algorithm ) ); + EVP_DigestFinal( &m_context, (unsigned char*)a.data(), 0 ); + return a; + } + + Provider::Context *clone() const + { + return new opensslHashContext(*this); + } + +protected: + const EVP_MD *m_algorithm; + EVP_MD_CTX m_context; +}; +\endcode + +This approach (using an Adapter pattern) is very common in %QCA backends, +because the plugins are often based on existing libraries. + + In addition to the various Context objects, each provider also has + a parameterised Factory class that has a createContext() method, as + shown below: +\code + Context *createContext(const QString &type) + { + //OpenSSL_add_all_digests(); + if ( type == "sha1" ) + return new opensslHashContext( EVP_sha1(), this, type); + else if ( type == "sha0" ) + return new opensslHashContext( EVP_sha(), this, type); + else if ( type == "md5" ) + return new opensslHashContext( EVP_md5(), this, type); + else if ( type == "aes128-cfb" ) + return new opensslCipherContext( EVP_aes_128_cfb(), 0, this, type); + else if ( type == "aes128-cbc" ) + return new opensslCipherContext( EVP_aes_128_cbc(), 0, this, type); + else + return 0; + } +\endcode + +The resulting effect is that %QCA can ask the provider to provide an appropriate +Context object without worrying about how it is implemented. + +For features that are implemented with variable algorithms (for example, HashContext can +support a wide range of algorithms - MD5, SHA0, and SHA1 in the example above; and +CipherContext and MACContext can also do this), we need to be able to let applications +determine which algorithms are supported. This is handled through the InfoContext class. +A typical example is shown below: +\code + class opensslInfoContext : public InfoContext + { + Q_OBJECT + public: + opensslInfoContext(Provider *p) : InfoContext(p) + { + } + + Context *clone() const + { + return new opensslInfoContext(*this); + } + + QStringList supportedHashTypes() const + { + QStringList list; + list += "sha1"; + list += "sha0"; + list += "md5"; + return list; + } + + // MAC and Cipher types can go in here + }; +\endcode + +Note that InfoContext is itself a feature, so you have to add it to the createContext() +method for the provider, as shown below: +\code + Context *createContext(const QString &type) + { + if ( type == "sha1" ) + return new opensslHashContext( EVP_sha1(), this, type); + else if ( type == "sha0" ) + return new opensslHashContext( EVP_sha(), this, type); + else if ( type == "md5" ) + return new opensslHashContext( EVP_md5(), this, type); + else if ( type == "info" ) + return new opensslInfoContext( this ); + else + return 0; + } +\endcode + +*/ + +/** \page providers Providers + +%QCA works on the concept of a "provider". There is a limited +internal provider (named "default"), but most of the work is +done in plugin modules. + +The logic to selection of a provider is fairly simple. The user can +specify a provider name - if that name exists, and the provider supports +the requested feature, then the named provider is used. If that +didn't work, then the available plugins are searched (based on a +priority order) for the requested feature. If that doesn't work, +then the default provider is searched for the requested feature. + +So the only way to get the default provider is to either have no other support +whatsoever, or to specify the default provider directly (this goes for the +algorithm constructors as well as setGlobalRNG()). + +You can add your own provider in two ways - as a shared object plugin, +and as a part of the client code. + +The shared object plugin needs to be able to be found using the +built-in scan logic - this normally means you need to install it into +the plugins/crypto subdirectory within the directory that Qt is +installed to. This will make it available for all applications. + +If you have a limited application domain (such as a specialist +algorithm, or a need to be bug-compatible), you may find it easier to +create a client-side provider, and add it using the +QCA::insertProvider call. There is an example of this - see +the AES-CMAC example. +*/ + diff --git a/local/recipes/libs/qca/source/QcaConfig.cmake.in b/local/recipes/libs/qca/source/QcaConfig.cmake.in new file mode 100644 index 0000000000..ce9a8ab2f8 --- /dev/null +++ b/local/recipes/libs/qca/source/QcaConfig.cmake.in @@ -0,0 +1,14 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(Qt@QT_MAJOR_VERSION@Core) + +if (@QT_MAJOR_VERSION@ EQUAL 6 AND NOT @BUILD_SHARED_LIBRARIES@) + find_dependency(Qt@QT_MAJOR_VERSION@Core5Compat) +endif() + +if(NOT TARGET @QCA_LIB_NAME@) + include("${CMAKE_CURRENT_LIST_DIR}/@QCA_CONFIG_NAME_BASE@Targets.cmake") +endif() + +set(Qca_LIBRARY @QCA_LIB_NAME@) diff --git a/local/recipes/libs/qca/source/README b/local/recipes/libs/qca/source/README new file mode 100644 index 0000000000..ae5979f9d8 --- /dev/null +++ b/local/recipes/libs/qca/source/README @@ -0,0 +1,113 @@ +Qt Cryptographic Architecture (QCA) +----------------------------------- + +Description +----------- + + QCA is a library that provides an easy API for a range of cryptographic + features, including SSL/TLS, X.509 certificates, SASL, OpenPGP, smartcards, + and much more. + + Functionality is supplied via plugins. This is useful for avoiding + dependence on a particular crypto library and makes upgrading easier, + as there is no need to recompile your application when adding or + upgrading a crypto plugin. + + In order for QCA to be of much use, you'll want to install some plugins. + + +Install +------- + For installation or compiling instructions, see the INSTALL file. + + +License +------- + This library is licensed under the Lesser GNU General Public License. See + the COPYING file for more information. + + +History +------- + +QCA was originally created to support the security needs of the +Psi XMPP/Jabber client project ( http://psi-im.org/ ). + + +Old Changes list +---------------- + + New in 2.1.0 + - Ported to Qt5 (Qt4 also supported) + - New building system. CMake instead of qmake + - Added CTR symetric cipher support to qca core + - Added no padding encryption algorithm to qca core + - qcatool2 renamed to qcatool + - fixed crash in qcatool when only options provided on command line without any commands + - Use plugins installation path as hard-coded runtime plugins search path + - Added new functiion pluginPaths + - Added functions to get runtime QCA version + - Fixed 'no watch file' warnings in FileWatch + - Added EME_PKCS1v15_SSL Encryption Algorithm + - New implementation of SafeTimer to prevent crashes + - Updated certificates for unittests + - RSA Keys are permutable, can encrypt with private and decrypt with public + - Add unloadProvider() function for symmetry with insertProvider() + - Overloaded "makeKey" to derive a password depending on a time factor + - Remove pointer to deinit() routine from QCoreApplication at deinitialization + - Fix a couple of crashes where all plugins might not be available + - Fix operating on keys with unrelated expired subkeys + - Fixed timers in Synchronizer class + - Dropped randomunittest + - Fixed many unittests + - qca-gnupg: internal refactoring + - qca-gnupg: try both gpg and gpg2 to find gnupg executable + - qca-gnupg: fixed some encodings problem + - qca-ossl: no DSA_* dl groups in FIPS specification + - qca-ossl: added missed signatures to CRLContext + - qca-ossl: fixed certs time zone + - qca-nss: fixed KeyLenght for Cipher + - qca-botan: fixed getting result size for ciphers + + New in 2.0.3 + - Bugfix release, forward and backward compatible with 2.0.x + - Fix compilation when using Qt/Windows SDK + + New in 2.0.2 + - Bugfix release, forward and backward compatible with 2.0.x + - Fix compatibility with Qt 4.5 when QCA::Initializer appears before QApp + - Don't convert to secure memory when Hash::update(QByteArray) is used + - Use configure.exe instead of configwin.bat + + New in 2.0.1 + - Bugfix release, forward and backward compatible with 2.0.x + - Ability to build as a Mac framework (and build this way by default) + - On non-Mac Unix, the pkgconfig file is always qca2.pc, even in debug mode + - Certificates containing wildcards are now matched properly + - DirWatch/FileWatch now work + - Keystore writes now work + - Don't delete objects in their event handler (prevents Qt 4.4 warnings) + - Fix potential hang with TLS in server mode + - Windows version can be configured/installed using paths with spaces + + +Old Developer list +------------------ + +Project Lead/Maintainer (2003-2012): + Justin Karneges + (March 2007 - August 2007 under Barracuda Networks employment) + +Development, Documentation, Unittests (2004-2009): + Brad Hards + +Development (2013-2017) + Ivan Romanov + +Special Thanks: + Portugal Telecom (SAPO division), for sponsorship + Alon Bar-Lev, for smart card and design assistance + Jack Lloyd, for Botan and X.509 mentoring + L. Peter Deutsch, for the public domain MD5 implementation + Steve Reid, for the public domain SHA1 implementation + Jason Kim, for the CMS Signer graphics diff --git a/local/recipes/libs/qca/source/README.clang-format b/local/recipes/libs/qca/source/README.clang-format new file mode 100644 index 0000000000..8488c38dbf --- /dev/null +++ b/local/recipes/libs/qca/source/README.clang-format @@ -0,0 +1,14 @@ +We introduced clang-format mandatory usage in September 2020. +If you want git blame to ignore the revision in which we did the mass change you can do + git config blame.ignoreRevsFile .git-blame-ignore-revs +on your clone + +To get the clang-format warnings locally instead at CI time we recommend you +to copy the hooks/pre-commit to your .git + cp hooks/pre-commit .git/hooks/ + +We are using clang-format 19 on CI. Unfortunately clang-format is not totally +compatible with older versions of itself. If CI gives you trouble but your local +clang-format disagrees, just apply the changes suggested by CI and then commit +with the --no-verify flag. If you get stuck, don't hesitate to ask the reviewer +to help and they will reformat your commits :) diff --git a/local/recipes/libs/qca/source/TODO b/local/recipes/libs/qca/source/TODO new file mode 100644 index 0000000000..ee6b0aa778 --- /dev/null +++ b/local/recipes/libs/qca/source/TODO @@ -0,0 +1,104 @@ +* 2.2.0 +- New plugin qca-gpgme to replace current qca-gnupg. qca-gnupg requires + to have gpg binary which can be any 1.4.x or 2.x. Them behaviour is + different. gpg2 requires gpg-agent to ask user for passphrase. No + correct way to check that key requires passphrase. + +- Add an interface for gnupg to handle keys (create and remove, maybe + something else). + +- Add ECDSA support to qca-ossl plugin + +-- Obsoletes +* 2.0.4 + handle mac universal builds for arches besides x86 and ppc (e.g. x86_64) + use rpath? + cms example: User.pem expired. probably other certs need regen also? + fix publickeyexample. it encrypts with cms, decrypts with raw rsa?? + qcatool: instead of printing full usage at every wrong turn, we might try + to print something closer to the context + publickey: use_asker_fallback should use ErrorPassphrase + cmssigner: convert path separators in field when loading a pkcs11 module + cert: better makeFriendlyName diffing for key usage (consider OIDs) ? + cert unit tests need to test wildcards!! + consider a more readable implementation of qca_securelayer logic using the + object-sessions concept (write the blog first :)) + vs2005: big_io.obj : warning LNK4221: no public symbols found; archive + member will be inaccessible + +* 2.1.0 + CertificateAuthority constructor provider argument should have default value + CertificateAuthority::createCertificate declared but not implemented! + CertificateCollection: ability to remove certs/crls? + pull kwallet's SecureBuffer? + +* possibilities for the future: + abort if feature requested but not found, rather than crashing + examples: bigint, pgp, tls with smartcards (reuse ssltest?), more? + unittests: pgp enc/dec, cms, sasl, tls, filewatch/dirwatch + complete pkits unittests + don't expose windows.h in qpipe.h, find another way to get HANDLE + cert: ability to get a list of all validation errors, rather than just one + the securelayer system doesn't respond to the app if processed data yields + no events (an example of this would be a partially-received encrypted + payload). since securelayer is async, an app could end up waiting for + a response that is never going to come. the current workaround is to wait + some event cycles and then give up (see the saslclient example). the fix + is probably to make the securelayer system always respond to the app once + data has been processed, whether or not the processing yields anything + interesting yet. + find a better way for a provider to automatically promote itself? (see + qca-wingss) + can we ever get SASL::NoAuthzid? + make it possible to change GNUPGHOME and have qca-gnupg respect the change? + see pgpunittest. + why is Logger a QObject? + it seems strange that Logger friends QCA::Global... + operator==,!= for PGPKey? + gss/kerberos interface? + spnego? + make sure it is possible to add new public key types (e.g. ECC). right now + it looks like qca_publickey is hard-coded sometimes (such as canVerify() + returning true only for RSA and DSA public keys, no way to override this + in a plugin...) + if you store a typical self-signed cert into the system store as a way to + trust it, does that make you vulnerable to the cert signing other certs? + make distinction between invalid ca and ca not found + make distinction between depth 0 self-signed and self-signed in chain + use Q_PROPERTY on some things (e.g. TLS::compressionEnabled) ? + signRequest should allow specifying the serial number + qca-ossl: give credit to tim and "openssl" itself, not just eric? + tls: should there be an explicit property for requesting a certificate in + server mode? right now qca-ossl simply always asks for a cert + publickey: ability to compare keys without IO support + provider: separate public and private keys into two classes to enable + delegation easier. the public part should not be implemented by most + providers. + provider: make it possible to support RSA and DSA keys without implementing + a separate class for each. + qcatool: streaming securemessage operations + access to list of known cached certs, similar to how cmssigner works? + securemessage: ability to know which key has performed a decrypt? + emsa3Encode: implement in provider instead of qca? + OCSP + securelayer: ability to specify how much to read, rather than just read all + tls ocsp stapling + tls: pgp, psk auth ? + internally managed intermediate object storage + securemessage: algorithm selection for cms/pgp (and use SecurityLevel?) + tls: renegotiation + Key wrapping - RFC3217 and RFC3394 + quoted-printable TextFilter + keygen on smart cards + keystore: symmetric keys, arbitrary app data + cert: any other fields we don't support but might be used out there + cert: support for arbitrary extensions? + cms: fine-grained control over smime attribs + convertToPublic should return a publickey rather than change itself + providers for: + Mozilla NSS + Windows CryptoAPI + Linux kernel crypto support, if the userspace API ever gets sorted out + Intel Performance Primatives library + Botan: partly implemented + EGD / EGADS: implement for Random support diff --git a/local/recipes/libs/qca/source/certs/README b/local/recipes/libs/qca/source/certs/README new file mode 100644 index 0000000000..e1f2bd1acd --- /dev/null +++ b/local/recipes/libs/qca/source/certs/README @@ -0,0 +1,5 @@ +rootcerts.pem is created by qca/tools/mozcerts + +File: https://hg.mozilla.org/mozilla-central/log/tip/security/nss/lib/ckfw/builtins/certdata.txt +Date: June 24, 2024 + diff --git a/local/recipes/libs/qca/source/certs/rootcerts.pem b/local/recipes/libs/qca/source/certs/rootcerts.pem new file mode 100644 index 0000000000..8afd041b9a --- /dev/null +++ b/local/recipes/libs/qca/source/certs/rootcerts.pem @@ -0,0 +1,4252 @@ +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM +MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD +QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E +jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo +ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI +ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu +Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg +AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 +HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA +uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa +TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg +xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q +CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x +O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs +6GAqm4VKQPNriiTsBhYscw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQD////////////////////zANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp +Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww +HhcNMDcwNzI3MTcxOTM3WhcNMjUwMzMxMTgxOTIyWjBfMQswCQYDVQQGEwJOTDES +MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg +MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B +8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY +tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl +HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj +zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU +JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM +ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv +a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p +K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi +puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT +yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO +owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC +jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy +fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo +Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo +M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM +Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed +2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH +/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl +nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE +O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU +9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 +j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD +QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD +VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZELVRSVVNU +IFJvb3QgQ0EgMyAyMDEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xHtCkoIf7O1UmI4SwMoJ35NuOpNcG+QQd55OaYhs9uFp8vabomGxvQcgdJhl8Ywm +CM2oNcqANtFjbehEeoLDbF7eu+g20sRoNoyfMr2EIuDcwu4QRjltr5M5rofmw7wJ +ySxrZ1vZm3Z1TAvgu8XXvD558l++0ZBX+a72Zl8xv9Ntj6e6SvMjZbu376Ml1wrq +WLbviPr6ebJSWNXwrIyhUXQplapRO5AyA58ccnSQ3j3tYdLl4/1kR+W5t0qp9x+u +loYErC/jpIF3t1oW/9gPP/a3eMykr/pbPBJbqFKJcu+I89VEgYaVI5973bzZNO98 +lDyqwEHC451QGsDkGSL8swIDAQABo4IBBTCCAQEwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUP5DIfccVb/Mkj6nDL0uiDyGyL+cwDgYDVR0PAQH/BAQDAgEGMIG+ +BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv +Q049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLE89RC1UcnVzdCUyMEdt +YkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8v +Y3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDEzLmNybDAN +BgkqhkiG9w0BAQsFAAOCAQEADlkOWOR0SCNEzzQhtZwUGq2aS7eziG1cqRdw8Cqf +jXv5e4X6xznoEAiwNStfzwLS05zICx7uBVSuN5MECX1sj8J0vPgclL4xAUAt8yQg +t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv +m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN +h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln +tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL +BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ +SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n +a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5 +NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT +CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u +Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO +dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI +VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV +9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY +2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY +vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt +bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb +x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+ +l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK +TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj +Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw +DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG +7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk +MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr +gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk +GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS +3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm +Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+ +l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c +JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP +L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa +LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG +mpv0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIQdlP+qExQq5+NMrUdA49X3DANBgkqhkiG9w0BAQwFADBS +MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UE +AxMfR2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IFI0NTAeFw0yMDAzMTgwMDAw +MDBaFw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJv +b3QgUjQ1MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3HnMbQb5bbvg +VgRsf+B1zC0FSehL3FTsW3eVcr9/Yp2FqYokUF9T5dt0b6QpWxMqCa2axS/C93Y7 +oUVGqkPmJP4rsG8ycBlGWnkmL/w9fV9ky1fMYWGo2ZVu45Wgbn9HEhjW7wPJ+4r6 +mr2CFalVd0sRT1nga8Nx8wzYVNWBaD4TuRUuh4o8RCc2YiRu+CwFcjBhvUKRI8Sd +JafZVJoUozGtgHkMp2NsmKOsV0czH2WW4dDSNdr5cfehpiW1QV3fPmDY0fafpfK4 +zBOqj/mybuGDLZPdPoUa3eixXCYBy0mF/PzS1H+FYoZ0+cvsNSKiDDCPO6t561by ++kLz7fkfRYlAKa3qknTqUv1WtCvaou11wm6rzlKQS/be8EmPmkjUiBltRebMjLnd +ZGBgAkD4uc+8WOs9hbnGCtOcB2aPxxg5I0bhPB6jL1Bhkgs9K2zxo0c4V5GrDY/G +nU0E0iZSXOWl/SotFioBaeepfeE2t7Eqxdmxjb25i87Mi6E+C0jNUJU0xNgIWdhr +JvS+9dQiFwBXya6bBDAznwv731aiyW5Udtqxl2InWQ8RiiIbZJY/qPG3JEqNPFN8 +bYN2PbImSHP1RBYBLQkqjhaWUNBzBl27IkiCTApGWj+A/1zy8pqsLAjg1urwEjiB +T6YQ7UarzBacC89kppkChURnRq39TecCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgGG +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKCTFShu7o8IsjXGnmJ5dKexDit7 +MA0GCSqGSIb3DQEBDAUAA4ICAQBFCvjRXKxigdAE17b/V1GJCwzL3iRlN/urnu1m +9OoMGWmJuBmxMFa02fb3vsaul8tF9hGMOjBkTMGfWcBGQggGR2QXeOCVBwbWjKKs +qdk/03tWT/zEhyjftisWI8CfH1vj1kReIk8jBIw1FrV5B4ZcL5fi9ghkptzbqIrj +pHt3DdEpkyggtFOjS05f3sH2dSP8Hzx4T3AxeC+iNVRxBKzIxG3D9pGx/s3uRG6B +9kDFPioBv6tMsQM/DRHkD9Ik4yKIm59fRz1RSeAJN34XITF2t2dxSChLJdcQ6J9h +WRbFPjJOHwzOo8wP5McRByIvOAjdW5frQmxZmpruetCd38XbCUMuCqoZPWvoajB6 +V+a/s2o5qY/j8U9laLa9nyiPoRZaCVA6Mi4dL0QRQqYA5jGY/y2hD+akYFbPedey +Ttew+m4MVyPHzh+lsUxtGUmeDn9wj3E/WCifdd1h4Dq3Obbul9Q1UfuLSWDIPGau +l+6NJllXu3jwelAwCbBgqp9O3Mk+HjrcYpMzsDpUdG8sMUXRaxEyamh29j32ahNe +JJjn6h2az3iCB2D3TRDTgZpFjZ6vm9yAx0OylWikww7oCkcVv1Qz3AHn1aYec9h6 +sr8vreNVMJ7fDkG84BH1oQyoIuHjAKNOcHyS4wTRekKKdZBZ45vRTKJkvXN5m2/y +s8H2PA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICITCCAaegAwIBAgIQdlP+qicdlUZd1vGe5biQCjAKBggqhkjOPQQDAzBSMQsw +CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf +R2xvYmFsU2lnbiBTZWN1cmUgTWFpbCBSb290IEU0NTAeFw0yMDAzMTgwMDAwMDBa +Fw00NTAzMTgwMDAwMDBaMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxT +aWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFNlY3VyZSBNYWlsIFJvb3Qg +RTQ1MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+XmLgUc3iZY/RUlQfxomC5Myfi7A +wKcImsNuj5s+CyLsN1O3b4qwvCc3S22pRjvZH/+loUS7LXO/nkEHXFObUQg6Wrtv +OMcWkXjCShNpHYLfWi8AiJaiLhx0+Z1+ZjeKo0IwQDAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3xNei1/CQAL9VreUTLYe1aaxFJYw +CgYIKoZIzj0EAwMDaAAwZQIwE7C+13EgPuSrnM42En1fTB8qtWlFM1/TLVqy5IjH +3go2QjJ5naZruuH5RCp7isMSAjEAoGYcToedh8ntmUwbCu4tYMM3xx3NtXKw2cbv +vPL/P/BS3QjnqmR5w+RpV5EvpMt8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV +BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk +YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV +BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN +MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF +UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD +VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v +dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj +cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q +yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH +2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX +H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL +zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR +p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz +W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ +SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn +LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 +n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B +u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC +AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L +9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej +rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK +pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 +vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq +OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ +/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 +2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI ++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 +MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo +tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFqjCCA5KgAwIBAgIQVVL4HtsbJCyeu5YYzQIoPjANBgkqhkiG9w0BAQsFADBv +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBS +U0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTg0NloXDTQ1MDIxMzEwNTg0NVow +bzELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBS +ZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJzAlBgNVBAMMHkhBUklDQSBDbGllbnQg +UlNBIFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AIHbV0KQLHQ19Pi4dBlNqwlad0WBc2KwNZ/40LczAIcTtparDlQSMAe8m7dI19EZ +g66O2KnxqQCEsIxenugMj1Rpv/bUCE8mcP4YQWMaszKLQPgHq1cx8MYWdmeatN0v +8tFrxdCShJFxbg8uY+kfU6TdUhPMCYMpgQzFU3VEsQ5nUxjQwx+IS5+UJLQpvLvo +Tv1v0hUdSdyNcPIRGiBRVRG6iG/E91B51qox4oQ9XjLIdypQceULL+m26u+rCjM5 +Dv2PpWdDgo6YaQkJG0DNOGdH6snsl3ES3iT1cjzR90NMJveQsonpRUtVPTEFekHi +lbpDwBfFtoU9GY1kcPNbrM2f0yl1h0uVZ2qm+NHdvJCGiUMpqTdb9V2wJlpTQnaQ +K8+eVmwrVM9cmmXfW4tIYDh8+8ULz3YEYwIzKn31g2fn+sZD/SsP1CYvd6QywSTq +ZJ2/szhxMUTyR7iiZkGh+5t7vMdGanW/WqKM6GpEwbiWtcAyCC17dDVzssrG/q8R +chj258jCz6Uq6nvWWeh8oLJqQAlpDqWW29EAufGIbjbwiLKd8VLyw3y/MIk8Cmn5 +IqRl4ZvgdMaxhZeWLK6Uj1CmORIfvkfygXjTdTaefVogl+JSrpmfxnybZvP+2M/u +vZcGHS2F3D42U5Z7ILroyOGtlmI+EXyzAISep0xxq0o3AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFKDWBz1eJPd7oEQuJFINGaorBJGnMA4GA1Ud +DwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEADUf5CWYxUux57sKo8mg+7ZZF +yzqmmGM/6itNTgPQHILhy9Pl1qtbZyi8nf4MmQqAVafOGyNhDbBX8P7gyr7mkNuD +LL6DjvR5tv7QDUKnWB9p6oH1BaX+RmjrbHjJ4Orn5t4xxdLVLIJjKJ1dqBp+iObn +K/Es1dAFntwtvTdm1ASip62/OsKoO63/jZ0z4LmahKGHH3b0gnTXDvkwSD5biD6q +XGvWLwzojnPCGJGDObZmWtAfYCddTeP2Og1mUJx4e6vzExCuDy+r6GSzGCCdRjVk +JXPqmxBcWDWJsUZIp/Ss1B2eW8yppRoTTyRQqtkbbbFA+53dWHTEwm8UcuzbNZ+4 +VHVFw6bIGig1Oq5l8qmYzq9byTiMMTt/zNyW/eJb1tBZ9Ha6C8tPgxDHQNAdYOkq +5UhYdwxFab4ZcQQk4uMkH0rIwT6Z9ZaYOEgloRWwG9fihBhb9nE1mmh7QMwYXAwk +ndSV9ZmqRuqurL/0FBkk6Izs4/W8BmiKKgwFXwqXdafcfsD913oY3zDROEsfsJhw +v8x8c/BuxDGlpJcdrL/ObCFKvicjZ/MGVoEKkY624QMFMyzaNAhNTlAjrR+lxdR6 +/uoJ7KcoYItGfLXqm91P+edrFcaIz0Pb5SfcBFZub0YV8VYt6FwMc8MjgTggy8kM +ac8sqzuEYDMZUv1pFDM= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICWjCCAeGgAwIBAgIQMWjZ2OFiVx7SGUSI5hB98DAKBggqhkjOPQQDAzBvMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEnMCUGA1UEAwweSEFSSUNBIENsaWVudCBFQ0Mg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDMzNFoXDTQ1MDIxMzExMDMzM1owbzEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJzAlBgNVBAMMHkhBUklDQSBDbGllbnQgRUND +IFJvb3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAcYrZWWlNBcD4L3 +KkD6AsnJPTamowRqwW2VAYhgElRsXKIrbhM6iJUMHCaGNkqJGbcY3jvoqFAfyt9b +v0mAFdvjMOEdWscqigEH/m0sNO8oKJe8wflXhpWLNc+eWtFolaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUUgjSvjKBJf31GpfsTl8au1PNkK0wDgYDVR0P +AQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMEwxRUZPqOa+w3eyGhhLLYh7WOar +lGtEA7AX/9+Cc0RRLP2THQZ7FNKJ7EAM7yEBLgIwL8kuWmwsHdmV4J6wuVxSfPb4 +OMou8dQd8qJJopX4wVheT/5zCu8xsKsjWBOMi947 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw +RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY +BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz +MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u +LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 +v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd +e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw +V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA +AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG +GJTO +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL +BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x +FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx +MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s +THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc +IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU +AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ +GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 +8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH +flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt +J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim +0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN +pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ +UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW +OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB +AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet +8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j +bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM +Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv +TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS +S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr +I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 +b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB +UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P +Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven +sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIQBT9uoAYBcn3tP8OjtqPW7zAKBggqhkjOPQQDAzBQMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xKDAmBgNVBAMTH0Rp +Z2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBQMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xKDAmBgNVBAMTH0RpZ2lDZXJ0IFNNSU1FIEVDQyBQMzg0IFJvb3QgRzUw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQWnVXlttT7+2drGtShqtJ3lT6I5QeftnBm +ICikiOxwNa+zMv83E0qevAED3oTBuMbmZUeJ8hNVv82lHghgf61/6GGSKc8JR14L +HMAfpL/yW7yY75lMzHBrtrrQKB2/vgSjQjBAMB0GA1UdDgQWBBRzemuW20IHi1Jm +wmQyF/7gZ5AurTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNnADBkAjA3RPUygONx6/Rtz3zMkZrDbnHY0iNdkk2CQm1cYZX2kfWn +CPZql+mclC2YcP0ztgkCMAc8L7lYgl4Po2Kok2fwIMNpvwMsO1CnO69BOMlSSJHW +Dvu8YDB8ZD8SHkV/UT70pg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQBfa6BCODRst9XOa5W7ocVTANBgkqhkiG9w0BAQwFADBP +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJzAlBgNVBAMT +HkRpZ2lDZXJ0IFNNSU1FIFJTQTQwOTYgUm9vdCBHNTAeFw0yMTAxMTUwMDAwMDBa +Fw00NjAxMTQyMzU5NTlaME8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2Vy +dCwgSW5jLjEnMCUGA1UEAxMeRGlnaUNlcnQgU01JTUUgUlNBNDA5NiBSb290IEc1 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4Gpb2fj5fey1e+9f3Vw0 +2Npd0ctldashfFsA1IJvRYVBiqkSAnIy8BT1A3W7Y5dJD0CZCxoeVqfS0OGr3eUE +G+MfFBICiPWggAn2J5pQ8LrjouCsahSRtWs4EHqiMeGRG7e58CtbyHcJdrdRxDYK +mVNURCW3CTWGFwVWkz1BtwLXYh+KkhGH6hFt6ggR3LF4SEmS9rRRgHgj2P7hVho6 +kBNWNInV4pWLX96yzPs/OLeF9+qevy6hLi9NfWoRLjag/xEIBJVV4Bs7Z5OplFXq +Mu0GOn/Cf+OtEyfRNEGzMMO/tIj4A4Kk3z6reHegWZNx593rAAR7zEg5KOAeoxVp +yDayoQuX31XW75GcpPYW91EK7gMjkdwE/+DdOPYiAwDCB3EaEsnXRiqUG83Wuxvu +v75NUFiwC80wdin1z+W2ai92sLBpatBtZRg1fpO8chfBVULNL8Ilu/T9HaFkIlRd +4p5yQYRucZbqRQe2XnpKhp1zZHc4A9IPU6VVIMRN/2hvVanq3XHkT9mFo3xOKQKe +CwnyGlPMAKbd0TT2DcEwsZwCZKw17aWwKbHSlTMP0iAzvewjS/IZ+dqYZOQsMR8u +4Y0cBJUoTYxYzUvlc4KGjOyo1nlc+2S73AxMKPYXr+Jo1haGmNv8AdwxuvicDvko +Rkrh/ZYGRXkRaBdlXIsmh1sCAwEAAaNCMEAwHQYDVR0OBBYEFNGj1FcdT1XbdUxc +Qp5jFs60xjsfMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBDAUAA4ICAQAHpwreU7ua63C/sjaQzeSnuPEM5F1aHXhl/Mm4HiMRV3xp +NW0B/1NQvwcOuscBP1gqlHUDqxwLI9wbih43PR1Yj3PZsypv3xCgWwynyrB/uSSi +ATUy5V5GQevYf3PnQumkUSZ3gQqo6w8KUJ1+iiBn/AuOOhHTxYxgGNlLsfzU8bRJ +Tq6H4dH7dqFf8wbPl5YM6Z51gVxTDSL8NuZJbnTbAIWNfCKgjvsQTNRiE1vvS3Im +i/xOio/+lxBTxXiLQmQbX+CJ/bsJf1DgVIUmEWodZflJKdx8Nt/7PffSrO4yjW6m +fTmcRcTKDfU7tHlTpS9Wx1HFikxkXZBDI45rTBd4zOi/9TvkqEjPrZsM3zJK09kS +jiN4DS2vn6+ePAnClwDtOmkccT8539OPxGb17zaUD/PdkraWX5Cm3XOqpiCUlCVq +CQxy5BMjYEyjyhcue2cA29DN6nofOSZXiTB3y07llUVPX/s2XD35ILU6ECVPkzJa +7sGW6OlWBLBJYU3seKidGMH/2OovVu+VK3sEXmfjVUDtOQT5C3n1aoxcD4makMfN +i97bJjWhbs2zQvKiDzsMjpP/FM/895P35EEIbhlSEQ9TGXN4DM/YhYH4rVXIsJ5G +Y6+cUu5cv/DAWzceCSDSPiPGoRVKDjZ+MMV5arwiiNkMUkAf3U4PZyYW0q0XHA== + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtTCCA52gAwIBAgIUXVnIyqsJV/XmtdoplARq/8XUlYcwDQYJKoZIhvcNAQEN +BQAwYjELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmlj +YWRvcmEgRGlnaXRhbDEnMCUGA1UEAwweRElHSVRBTFNJR04gR0xPQkFMIFJPT1Qg +UlNBIENBMB4XDTIxMDEyMTEwNTAzNFoXDTQ2MDExNTEwNTAzNFowYjELMAkGA1UE +BhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRvcmEgRGlnaXRh +bDEnMCUGA1UEAwweRElHSVRBTFNJR04gR0xPQkFMIFJPT1QgUlNBIENBMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyIe2ONMc8N4S+IPHxIriibi0Inp4 ++AxmUWh2NwrVT8JaCLgWXPdyAQk3hIEqVGvXktBs+qinQxI06w7bNw8p/ooxUULo +S5yQqMgsEdP9oCl+zt6U9oLgWLRORSXxIvI90w97VBrcMrbWUU5+QbRXuCzGuQ4u +ylfx1cjTWOel6UIRrtMgJZRp14/Kog3D058HaD8V0mcuU/12gpsLc6kpDZ4RkxQI +mOyeVBJKVqIGFexrbC6SYC6GDa6CH1FN47IH1xAZVyL2qWlEhPPZPaAGv8yIfn/1 +zlulwipqdELqb6b/+Wix0F+9kdJVbzNXTB6d5OKLwYVloOBqnAAAiJLdWAgW8nAx +qBzh3r1OcenWvn61oVrDTfe/m72UpP31qlOTRskmAQRwxKBxus4lZvuRflVw7kkK +TWJ/wlCacvIYZ53pRag0hOj4gfbRWiIeB087s3/dEaVz3L6pGTppqW0bMuKJqqUn +C1p+dOIPZDldfly5wRf8x41eyewk7dLyP3qERTcCvj5rWcTmWxZtwKqeqrVZLixw +VZzMmZaYJFTRjtrKtBG0t3BDH2+QCyCgqHYTZdvbI1p1S6ELMXcK7n1oYRoTjOpR +flxWo1dMXaHrE2W/VBTM8+7c1+w8l/J4Vrjfclxw/M4G3Z/SBzHv51KRns2618AY +RAcxZUkyaRNK648CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW +gBS1Nrw8jBqrLPZZGS2DFNqTJRXWhjAdBgNVHQ4EFgQUtTa8PIwaqyz2WRktgxTa +kyUV1oYwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQAU+zElODH4 +ygiyI3Y4rfjTWfXMtFcl4US+fvwW7K76Jp9PZxZKVvD97ccZATSOkFot1oBc7HHS +gSWCHgBx35rR1R0iu9Gl82IPtOvcJHP+plbNmhTFBDUWMaIH66UA4rb4X3L9P2FJ +jt5+TTjXeh50N2xR3L4ABLg4FPMgwe2bpyP9DUKEHX/yc8PQeGPxn+zXW+nxvmyg +SwOejWnhFNqIEIEjU//aVCsLxrmWlQQYRvN7qJfYW2ik5DgcDkXlmNMJrppe7LN5 +DTly8vSUnQ6eYCLmqPZMhc0HgjpoOc09X+M49LavO2tKn2BRRaJAAuWqDOM+0XjU +onScJroFmihwSj6mC9AdSfC6+K5BEH6kBxK9qM8pPVe7x/FDRwA+rnAYWiB7Ccs6 +OnCA5UxgmMEVwR1K98jwm+FyreddaFgLBLGMvJ+3+26LWwRV++sjVdd4UNoly74n +NrskGnkcUdH+E7v/eCzcpL4v9sVLU8+nTJlecKxZiASuZAS/e6Z6TdPod72hflAV +8+9JMIVNIVeq2yx1l62BAYeisXCdHgZaA2CxP6ZtgizUFLGBpeg9iB20cixYN4qO +OJS4c92p4Lj2d6KzfFjermk6tYulGrvy2HQGnP1icyAhdrF+cJ4Z1OsXYhk4mc02 +K0f+McvfueSsCNPYpuvUnn5LZKRVXSsXyQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICajCCAfCgAwIBAgIUNi2PcoiiKCfkAP8kxi3k6/qdtuEwCgYIKoZIzj0EAwMw +ZDELMAkGA1UEBhMCUFQxKjAoBgNVBAoMIURpZ2l0YWxTaWduIENlcnRpZmljYWRv +cmEgRGlnaXRhbDEpMCcGA1UEAwwgRElHSVRBTFNJR04gR0xPQkFMIFJPT1QgRUNE +U0EgQ0EwHhcNMjEwMTIxMTEwNzUwWhcNNDYwMTE1MTEwNzUwWjBkMQswCQYDVQQG +EwJQVDEqMCgGA1UECgwhRGlnaXRhbFNpZ24gQ2VydGlmaWNhZG9yYSBEaWdpdGFs +MSkwJwYDVQQDDCBESUdJVEFMU0lHTiBHTE9CQUwgUk9PVCBFQ0RTQSBDQTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABG4Lo6szTRzqSuj8BI0UoH3wCCxfg6uT0dJ7utdJ +fY/sElBf1LnL5fD5M2MfyVfsQNgRC5foUhbMKY70BoYeONw9V8Tuqr3IVAQmWicT +UUc9Hx8ajqiVpDPQzEfMbbj8SKNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBTOr0qLGnXi8TjnAvAWrV7qZNV7tDAdBgNVHQ4EFgQUzq9Kixp14vE45wLw +Fq1e6mTVe7QwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMAqIxHGc +RANNjbTHvKiu2TAnNWprFmPX/OdZ4aeJG0wxmiNVRObzQyHVRydvbVcBqgIxAPuy +6uKXf1G1n0jrvG81iahkcKtXds3AxhRgyn/iggBz98w16o4km+UIWccEjHN4/g== + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV +BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw +JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2 +MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg +Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r +CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA +lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG +TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7 +9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7 +8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4 +g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we +GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst ++3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M +0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ +T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw +HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS +YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA +FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd +9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI +UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+ +OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke +gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf +iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV +nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD +2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI// +1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad +TdJ0MN1kURXbg4NR16/9M51NZg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT +AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD +VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx +NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT +HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 +IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl +dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK +ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu +9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O +be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU +MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI +T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz +MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF +SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh +bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z +xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ +spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 +58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR +at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll +5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq +nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK +V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ +pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO +z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn +jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ +WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF +7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli +awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u ++2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 +X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN +SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo +P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI ++pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz +znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 +eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 +YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy +r/6zcCwupvI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw +CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ +VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy +MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ +TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS +b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B +IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ ++kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK +sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA +94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B +43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFmDCCA4CgAwIBAgIEVRpusTANBgkqhkiG9w0BAQsFADBDMQswCQYDVQQGEwJa +QTERMA8GA1UEChMITEFXdHJ1c3QxITAfBgNVBAMTGExBV3RydXN0IFJvb3QgQ0Ey +ICg0MDk2KTAgFw0yMzAyMTQwOTE5MzhaGA8yMDUzMDIxNDA5NDkzOFowQzELMAkG +A1UEBhMCWkExETAPBgNVBAoTCExBV3RydXN0MSEwHwYDVQQDExhMQVd0cnVzdCBS +b290IENBMiAoNDA5NikwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +F8srQ7ps+cmTimUNEkzsJxS3E3ng1NUtGFbx+eoqEBZObETHamVG85qJNdGH+DOJ +L4gJGpIQkZDBa58Obn8mihNdGKxoAQ0QeGVw2I6PhFqXMBjQEQ5KjVIQpYErUSj1 +Y8S27ECzAeWtd73lOO+8jbPdGaB7DY2022r7JTNa+pGvxHFFMPiIKXvLv9W6JwSO +3bIA98pcmTUU6v11BhUIu8pXaPs/+7Q0c2PR1ePIOFppfWp6RAwNik7tkh0Qjzsi +LLbf7cXG8Il5VGVeXxu9j33fubft6+TFB9FnPJU7kf5CelJAgATSOVdL9JJ9/5vv +5Z3JCbKREjimKQg7ruvKzO1N504hAQf8bzLOaYyEUsZ36icwCt6lrzAraB+s1Owh +rSJJds4PwvIHKvlqEoOaOwSuGXr+oYYk+kFeJXxArCe24yk2bzXiV9AZWN//ZPbD +AUl22yu+vLlPFArVG1gh9hwuAHz4lLXLNxoU5DK5FtRg7AWqXzL6aiMSrNQQu9Ki +grRLDotwJ6rWB8FniPqEwwjJioTI0jdygQ+NFkrk1zVRpTgPjIRLlTbA9ded4F2P +q5HuAAi5nVIf7PiZu3lWsUna0uXYYYtbr/CrN8V7Go6Gvn7FexUeYWjoC4eLc0mh +F3N+KXiOyuBBL3VzdKKXOn/3LnQJuExgi0Y2GRAtnQIDAQABo4GRMIGOMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMCsGA1UdEAQkMCKADzIwMjMwMjE0 +MDkxOTM4WoEPMjA1MzAyMTQwOTQ5MzhaMB8GA1UdIwQYMBaAFNfWVmJcPxeB5nNE +KfVRBe8LYDesMB0GA1UdDgQWBBTX1lZiXD8XgeZzRCn1UQXvC2A3rDANBgkqhkiG +9w0BAQsFAAOCAgEASZwp/j3snkV/qz48/iNvNz53p1P/eJ/8SUSAV2acbtp5/81F +rUyTv7VZxukQt+X4jPuHxR6L2LM/ApYKu4qO79e0wIMgOJdZRWT89ncT8gnXocg4 +dAjq+UhM+h8EnLT/7G5WNnKTbJU+LF/eDwurycwVPhaPZvyyELih0bTewGMZzO9T +qnU2IoslH7+byNfBX+ymNwmqe2K89iIt8dZY3Yy7UvQLp3apensajdytmoFiLoYF +kHJHL6HJZ4SwDWywuJsWt9CZFC+cEpsjqI2mQx7p5S3leKcfZJRktneyqFz7Casp +6x5tddH20MWlwx2fHvMaLbLIH+UoCm7zX/3a5iOhdpBcS5gBgizuRy0CGl9/NMVp +tXKtPvPPnm34KegRJyvgWQsbYetKymmlpNXNURuUjnnN3/audF2xLBuGU/7RMAZB +NAdigkz0fseHdA6wIR4JIIDBsxU9Rm3T8QaSP++glYocbncxtut4KQx77oKlT36k +KV6eqi34jsDz/A0GhZtO3PfiCXzQFFEeerMjr/rRYSpltQHZuOMHyiR20vBKvu+G +BIBCFXARaH7Xx7v+506bnJWlHEqkydAJjKrOSNIekpfXEentZsw33PXXG3SbpupC +rF0y4Fj0gUf/0hLifhzcSXaWwx2fS8pcKjdbPYrROJsh2uO/RUPT4Fh3Hyg= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIQbvXTp0GOoFlApzBr0kBlVjAKBggqhkjOPQQDAzBaMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQDEyhT +ZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgRTQ2MB4XDTIxMDMy +MjAwMDAwMFoXDTQ2MDMyMTIzNTk1OVowWjELMAkGA1UEBhMCR0IxGDAWBgNVBAoT +D1NlY3RpZ28gTGltaXRlZDExMC8GA1UEAxMoU2VjdGlnbyBQdWJsaWMgRW1haWwg +UHJvdGVjdGlvbiBSb290IEU0NjB2MBAGByqGSM49AgEGBSuBBAAiA2IABLinUpT1 +PgWwG/YfsdN+ueQFZlSAzmylaH3kU1LbgvrEht9DePfIrRa8P3gyy2vTSdZE5bN+ +n3umxizy4rbTibCaPEvOiUvGxss6SWAPRrxtTnqcyZuFewq2sEfCiOPU0aNCMEAw +HQYDVR0OBBYEFC1OjKfCI7JXqQZrPmsrifPDXkfOMA4GA1UdDwEB/wQEAwIBhjAP +BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCSnRpZY0VYjhsW5H16 +bDZIMB8rcueQMzT9JKLGBoxvOzJXWvj+xkkSU5rZELKZUXICMAUlKjMh/JPmIqLM +cFUoNVaiB8QhhCMaTEyZUJmSFMtK3Fb79dOPaiz1cTr4izsDng== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIQHUSeuQ2DkXSu3fLriLemozANBgkqhkiG9w0BAQwFADBa +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTEwLwYDVQQD +EyhTZWN0aWdvIFB1YmxpYyBFbWFpbCBQcm90ZWN0aW9uIFJvb3QgUjQ2MB4XDTIx +MDMyMjAwMDAwMFoXDTQ2MDMyMTIzNTk1OVowWjELMAkGA1UEBhMCR0IxGDAWBgNV +BAoTD1NlY3RpZ28gTGltaXRlZDExMC8GA1UEAxMoU2VjdGlnbyBQdWJsaWMgRW1h +aWwgUHJvdGVjdGlvbiBSb290IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAJHlG/qqbTcrdccuXxSl2yyXtixGj2nZ7JYt8x1avtMdI+ZoCf9KEXMa +rmefdprS5+y42V8r+SZWUa92nan8F+8yCtAjPLosT0eD7J0FaEJeBuDV6CtoSJey ++vOkcTV9NJsXi39NDdvcTwVMlGK/NfovyKccZtlxX+XmWlXKq/S4dxlFUEVOSqvb +nmbBGbc3QshWpUAS+TPoOEU6xoSjAo4vJLDDQYUHSZzP3NHyJm/tMxwzZypFN9mF +ZSIasbUQUglrA8YfcD2RxH2QPe1m+JD/JeDtkqKLMSmtnBJmeGOdV+z7C96O3IvL +Oql39Lrl7DiMi+YTZqdpWMOCGhrN8Z/YU5JOSX2pRefxQyFatz5AzWOJz9m/x1AL +4bzniJatntQX2l3P4JH9phDUuQOBm2ms+4SogTXrG+tobHxgPsPfybSudB1Ird1u +EYbhKmo2Fq7IzrzbWPxAk0DYjlOXwqwiOOWIMbMuoe/s4EIN6v+TVkoGpJtMAmhk +j1ZQwYEF/cvbxdcV8mu1dsOj+TLOyrVKqRt9Gdx/x2p+ley2uI39lUqcoytti/Fw +5UcrAFzkuZ7U+NlYKdDL4ChibK6cYuLMvDaTQfXv/kZilbBXSnQsR1Ipnd2ioU9C +wpLOLVBSXowKoffYncX4/TaHTlf9aKFfmYMc8LXd6JLTZUBVypaFAgMBAAGjQjBA +MB0GA1UdDgQWBBSn15V360rDJ82TvjdMJoQhFH1dmDAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQwFAAOCAgEANNLxFfOTAdRyi/Cr +CB8TPHO0sKvoeNlsupqvJuwQgOUNUzHd4/qMUSIkMze4GH46+ljoNOWM4KEfCUHS +Nz/Mywk1Qojp/BHXz0KqpHC2ccFTvcV0r8QiJGPPYoJ9yctRwYiQbVtcvvuZqLq2 +hrDpZgvlG2uv6iuGp9+oI0yWP09XQhgVg0Pxhia3KgPOC53opWgejG+9heMbUY/n +Fy8r0NZ4wi3dcojUZZ76mdR+55cKkgGapamEOgwqdD0zGMiH9+ik9YZCOf1rdSn8 +AAasoqUaVI7pUEkXZq9LBC2blIClVKuMVxdEnw/WaGRytEseAcfZm5TZg5mvEgUR +o5gi0vJXyiT5ujgVEki6Yzv8i5V41nIHVszN/J0c0MVkO2M0zwSZircweXq28sbV +2VR6hwt+TveE7BTziBYS8dWuChoJ7oat5av9rsMpeXTDAV8Rm991mcZK95uPbEns +IS+0AlmzLdBykLoLFHR4S8/BX1VyjlQrE876WAzTuyzZqZFh+PjxtnvevKnMkgTM +S2tfc4C2Ie1QT9d2h27O39K3vWKhfVhiaEVStj/eEtvtBGmedoiqAW3ahsdgG8NS +rDfsUHGAciohRQpTRzwZ643SWQTeJbDrHzVvYH3Xtca7CyeN4E1U5c8dJgFuOzXI +IBKJg/DS7Vg7NJ27MfUy/THzVho= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN +MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG +A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC +WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ +6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B +Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa +qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q +4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQDCCAcagAwIBAgIQdvhIHq7wPHAf4D8lVAGD1TAKBggqhkjOPQQDAzBRMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9T +U0wuY29tIENsaWVudCBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzAzMloX +DTQ2MDgxOTE2MzAzMVowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBDbGllbnQgRUNDIFJvb3QgQ0EgMjAy +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABC1Tfp+LPrM2ulDizOvcuiaK04wGP2cP +7/UX5dSumkYqQQEHaedncfHCAzbG8CtSjs8UkmikPnBREmmNeKKCyikUwOSUIrJE +kmBvyASkZ9Wi0PPQ1+qOPA+60kBHkDTufaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAf +BgNVHSMEGDAWgBS3/i1ixYFTzVIaL11goMNd+7IcHDAdBgNVHQ4EFgQUt/4tYsWB +U81SGi9dYKDDXfuyHBwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUC +ME0HES0R+7kmwyHdcuEX/MHPFOpJznGHjtZT3BHNXVSKr9kt9IxR6rxmR+J/lYNg +ZQIxAIwhTE+75bBQ35BiSebMkdv4P11xkQiOT5LJf6Zc6hN+7W3E6MMqb1wR4aXz +alqaTQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFjzCCA3egAwIBAgIQdq/uiJMVRbZQU5uAnKTfmjANBgkqhkiG9w0BAQsFADBR +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD +DB9TU0wuY29tIENsaWVudCBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzEw +N1oXDTQ2MDgxOTE2MzEwNlowUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBD +b3Jwb3JhdGlvbjEoMCYGA1UEAwwfU1NMLmNvbSBDbGllbnQgUlNBIFJvb3QgQ0Eg +MjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALhY20Yw+8k/48jw +ATM04tpIqBjpIG6a1wHh1SmPMLQjauTLYrC+4p8gvT5UoDlox4Y3ZnQGBu90K9rc +n4SpUi+Q0u5+fPulIq1vcEZnlj0p1KO7VnsUBFnBIWNEHrIfElyQh2UNiPYeiCLi +Y1S78zb41n/c2v8pNanGbg5pWz/YvoKHFXBdsMdcEg9jpjjNz3O5ww6JJjcbP2Ic +MmnRm9n/VZAx3rFj3c/FdHf874ghU78AMRomLAAwpV9s4+T2AIrKmIecdAN6i2bs +fv2jjzUlXHils6T7PW2pivBsiIKL/UrQb+TXo7SONEk4vs5F5dIcyl7CNxSLzWZW +Mzed5WvsQ5JkoELadW/AFez5ab00uYp7+hb7Vf5SIOgEBFZWZfU3RJjIikbpt6y4 +6L5ijlQ2W/c7cL9d7i26X95CGYbwf4vrCMvYvuoOQkKgNnNXF+0y6tCN6Acbm5no +xJpiBA5I9zwSuvdYwZqM6cewIzZWNB3LbNq6B4Qd/dGsn+bCie/DuWwYs2mHV1+1 +DDhbpyEkKjunNJGetFTqKE/TwaOL5OYr1fKdv5thACLd1ktEHz9dVv7enHjMmVuq +5L2620NLrUwmTKNNNIpsdDYT22L8m7IFgf+uPwzN9hui9DnnyvVMXPtUdzWAWsAS +oRMBM2c9nYGhqfWFJFiIeOf042hVAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAU8DhClDSpPAB/Uu45pfdLDbxqfSMwHQYDVR0OBBYEFPA4QpQ0 +qTwAf1LuOaX3Sw28an0jMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC +AgEAmU/b8OrWEfoq/cirbeQOc2LSQp8V/nxwUj9kh4IxP0VALuEinwZmKfyW0y2N +tjjH2fMnwVkpoIz2cyQPKCLXTmHdE93bnzJSk/tPzOo4PJhqA6sWryHRQq59RSvq +xM+KWZ+CcHY6+GImyRCXWEAkpC25LymAJ+GJa3LKSQhxN1MF8YDO00IC0vzC0ZQG +7gfi9oPif5/nu1bDW7/dlZMJHiTBzybNraSuwrRp56q17TeU6d3RY4VrmnpKVnbc +GYUo1OTGpNi4lkF30LRZ8UYFh4cCH2m5ghjQQ9km2hpnqNZ1durybQ5C/4gmom6E +/n5iG/DGPe3AHGrHkda4ADdJm7mEBaHNbjHWROpTi7pTmB2hkIrphfgb8pNYw8jc +miZPPiDPT0PzEIx/EGF6NsqqC33Mn0dEWa6llcaZU+MHaz1JELAY/10OhUMUS+dr +00q1smBh3GlJAiNd6JJxw5yfRWd5HtwyhrqqVTxkbzK1EEAV3nJAeOBucLtu6wno +OdmsupJ13UPKugGVrRqBKzrw48UvDBhNEMauwO3+BVJ/GQXLqa81CAw4IuT+VuVT +Pr/k1rPZCMM91TMygSTFqeFlEbgyMzBxGEkdGkXGmhSKWDkobvPLUblJJmR4A8eR +EYOpuZA0tm+qBZ6FKFeZvn8nBkliTaH8CeErRglMFJtWj0U= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICMTCCAbagAwIBAgIMC3MoERh0MBzvbwiEMAoGCCqGSM49BAMDMEsxCzAJBgNV +BAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRSb290 +IFJvb3QgQ0EgRUNDIEcyIDIwMjAwHhcNMjAxMjE1MDgzOTEwWhcNNDAxMjEwMDgz +OTA5WjBLMQswCQYDVQQGEwJERTENMAsGA1UECgwEQXRvczEtMCsGA1UEAwwkQXRv +cyBUcnVzdGVkUm9vdCBSb290IENBIEVDQyBHMiAyMDIwMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEyFyAyk7CKB9XvzjmYSP80KlblhYWwwxeFaWQCf84KLR6HgrWUyrB +u5BAdDfpgeiNL2gBNXxSLtj0WLMRHFvZhxiTkS3sndpsnm2ESPzCiQXrmBMCAWxT +Hg5JY1hHsa/Co2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFsfxHFs +shufvlwfjP2ztvuzDgmHMB0GA1UdDgQWBBRbH8RxbLIbn75cH4z9s7b7sw4JhzAO +BgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaQAwZgIxAOzgmf3d5FTByx/oPijX +FVlKgspTMOzrNqW5yM6TR1bIYabhbZJTlY/241VT8N165wIxALCH1RuzYPyRjYDK +ohtRSzhUy6oee9flRJUWLzxEeC4luuqQ5OxS7lfsA4TzXtsWDQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIMR7opRlU+FpKXsKtAMA0GCSqGSIb3DQEBDAUAMEsxCzAJ +BgNVBAYTAkRFMQ0wCwYDVQQKDARBdG9zMS0wKwYDVQQDDCRBdG9zIFRydXN0ZWRS +b290IFJvb3QgQ0EgUlNBIEcyIDIwMjAwHhcNMjAxMjE1MDg0MTIzWhcNNDAxMjEw +MDg0MTIyWjBLMQswCQYDVQQGEwJERTENMAsGA1UECgwEQXRvczEtMCsGA1UEAwwk +QXRvcyBUcnVzdGVkUm9vdCBSb290IENBIFJTQSBHMiAyMDIwMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAljGFSqoPMv554UOHnPsjt45/DVS9x2KTd+Qc +NQR2owOLIu7EhN2lk25uso4JA+tRFjEXqmkVGA5ndCNe6pp9tTk+PYKpa+H+qRyw +rVpNTHiDQYvP8h1impgEnGPpq2X+SB0kZQdHPrmRLumdm38aNak0sLflcDPvSnJR +tge/YD8qn51U3/PXlElRA1pAqWjdEVlc+HamvFBSEO2s7JXg1INrSdoKT5mD3jKD +SINnlbJ+54GFPc2C98oC7W2IXQiNuDW/KmkwmbtL0UHbRaCTmVGBkDYIqoq26I+z +y+7lRg1ydfVJbOGify+87YSmN+7ewk85Tvae8MnRmzCdSW3h2v8SEIzW5Zl7BbZ9 +sAnHpPiyHDmVOTP0Nc4lYnuwXyDzy234bFIUZESP08ipdgflr3GZLS0EJUh2r8Pn +zEPyB7xKJCQ33fpulAlvTF4BtP5U7COWpV7dhv/pRirx6NzspT2vb6oOD7R1+j4I +uSZFT2aGTLwZuOHVNe6ChMjTqxLnzXMzYnf0F8u9NHYqBc6V5Xh5S56wjfk8WDiR +6l6HOMC3Qv2qTIcjrQQgsX52Qtq7tha6V8iOE/p11QhMrziRqu+P+p9JLlR8Clax +evrETi/Uo/oWitCV5Zem/8P8fA5HWPN/B3sS3Fc/LeOhTVtSTDOHmagJe2x+DvLP +VkKe6wUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQgJfMH +/adv8ZbukRBpzJrvfchoeDAdBgNVHQ4EFgQUICXzB/2nb/GW7pEQacya733IaHgw +DgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBDAUAA4ICAQAkK06Y8h0X7dl2JrYw +M+hpRaFRS1LYejowtuQS6r+fTOAEpPY1xv6hMPdThZKtVAVXX5LlKt42J557E0fJ +anWv/PM35wz1PQFztWlR+L1Z0boL+Lq6ZCdDs3yDlYrnnhOW129KlkFJiw4grRbG +96aHW4gSiYuJyhLSVq8iASFG6auYP6eI3uTLKpp1Gfo5XgkF1wMyGrgXUQjHAEB9 +9L74DFn0aXZu06RYW14mc+RCVQZeeEAP0zif7yZRcHSR8XdiAejZy+uh3zkyHbtr +/XH+68+l5hT9AIATxpoASLCZBemugEj7CT9RFLW552BNTcovgSHuUgxletz1iUlM +MJI0WIAyWbEN/yRhD+cKQtB7vPiOJ0c/cJ0n2bYGPaW7y16Prg5Tx5xqbztMD6NA +cKiaB87UblsHotLiVLa9bzNyY61RmOGPdvFqBzgl/vZizl/bY8Jume8G3LneGRro +VD190nZ12V4+MkinjPKecgz4uFi4FyOlFId1WHoAgQciOWpMlKC1otunLMGw8aOb +wEz3bXDqMZ/xrn0+cyjZod/6k/CbsPDizSUgde/ifTIFyZt27su9MR75lJhLJFhW +SMDeBky9pjRd7RZhY3P7GeL6W9iXddRtnmA5XpSLAizrmc5gKm4bjKdLvP025pgf +ZfJ/8eOPTIBGNli2oWXLzhxEdQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w +LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w +CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 +MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF +Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X +tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 +AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 +KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD +aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu +CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo +9H1/IISpQuQo +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM +MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx +MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 +MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD +QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z +4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv +Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ +kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs +GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln +nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh +3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD +0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy +geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 +ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB +c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI +pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs +o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ +qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw +xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM +rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 +AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR +0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY +o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 +dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE +oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM +BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe +Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw +IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU +cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS +T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK +AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 +nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep +qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA +yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs +hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX +zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv +kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT +f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA +uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih +MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 +wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 +XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 +JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j +ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV +VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx +xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on +AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d +7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj +gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV ++Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo +FGWsJwt0ivKH +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw +WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y +MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD +VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz +dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx +s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw +LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD +pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE +AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR +UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj +/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa +Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C +flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE +hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq +hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg +2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS +Um9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw +TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t +bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa +Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv +cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL +j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU +v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq +hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n +ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV +mkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 +NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk +YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh +suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al +DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj +WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl +P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547 +KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p +UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/ +kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO +Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB +Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U +CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ +KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ +nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+ +QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v +trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a +aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD +j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4 +Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w +lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn +YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc +icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL +BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi +Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 +NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t +U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt +MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE +NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0 +kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C +rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz +hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2 +LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs +n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku +FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5 +kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3 +wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v +wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs +5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ +KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3 ++VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme +APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq +pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT +6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF +sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt +PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d +lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 +v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O +rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 + +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICXjCCAeOgAwIBAgIQUs/kjG2gSvc/gpcMgAmMlTAKBggqhkjOPQQDAzBJMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpELVRy +dXN0IFNCUiBSb290IENBIDEgMjAyMjAeFw0yMjA3MDYxMTMwMDBaFw0zNzA3MDYx +MTI5NTlaMEkxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgxIzAh +BgNVBAMTGkQtVHJ1c3QgU0JSIFJvb3QgQ0EgMSAyMDIyMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEWZM59oxJZijXYQzIq38Moy3foqR8kito1S5+HkDLtGhJfxKhq39X +nxkuYy5b/mZxDDMPud5rxIjDse/sOUDjlqvb5XuuH9z5r0aaakYGL8c3ZIsXYv6W +w6LuhOCwlzm8o4GPMIGMMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPEpox4B +Eh09dVZNx1B8xRmqDxi3MA4GA1UdDwEB/wQEAwIBBjBKBgNVHR8EQzBBMD+gPaA7 +hjlodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Nicl9yb290X2Nh +XzFfMjAyMi5jcmwwCgYIKoZIzj0EAwMDaQAwZgIxAJf53q5Lj5i1HkB/Mn1NVEPa +ic3CqpI80YIec8/6TJIg+2MnxfVzPQk996dhhozzagIxAOcvfLj1JYw7OR82q431 +hqIu4Xpk2mc5Av7+Mz/Zc7ZYWzr8sqTZYHh3zHmnpq5VvQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFrDCCA5SgAwIBAgIQVNWjlR49lbpyG5rQMSFKujANBgkqhkiG9w0BAQ0FADBJ +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSMwIQYDVQQDExpE +LVRydXN0IFNCUiBSb290IENBIDIgMjAyMjAeFw0yMjA3MDcwNzMwMDBaFw0zNzA3 +MDcwNzI5NTlaMEkxCzAJBgNVBAYTAkRFMRUwEwYDVQQKEwxELVRydXN0IEdtYkgx +IzAhBgNVBAMTGkQtVHJ1c3QgU0JSIFJvb3QgQ0EgMiAyMDIyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAryy8jjaM62SvUWrWbjxekTrqmsPKbPuqJ55k +IqlA37koRVrsU2EWKJjCiqR1eFCE3fogSJIHZUE1ZlESdGGdBwaFOTFXeyg/1Zyl +7FrpHEsnn84nBvM39VLYETMWQTof9WN4ZWOGyb/IAQQfbu7i7KwM7oKS4vYaDT85 ++Z1lk634uQXBPfg3gVbDoP4F7OCUFjojFgTapgqThXJtYTuhjUXW43++Fb02hAj2 +C4NrJqqiveCw56rgrmfE04KlDKmk8DN5DVA/8O+QPSS5f9IgbOqX87+c3EfeCWG9 +lHmVWgJ2NWDERyIN93ZjA9PG+4PGXaut7WklKwNbTSUAQeOMhxdSqOAFK0NNFBPK +5z9DIrw3pHXx9r867zIeru5YhpByugSsQEjvXMR4p6mPJ1rLeuxY8sIIWJBtTQOF +eXEVBQ5OPvnfDwX3XxRIViENM5KxrIzlGP6/D+7gBKq9IfJYtlyJCosYCSIaszXG +ZsL1MxWZgOAI+ZYvE4zu2reIxOk3tddq1zqETatwjNNOFFWgohD8ZNpn6PHLM93J +moqPli9Ygdn4mgBDzJD7VXb7huM3ASgMb/TpWU0Vd1FCSsw0uIBDUIHvV6UT26eU +eQ9Lyn4Xfa+jIWTocVVWjwawR+xZD11wWywWQvCGnnXea01ImITiVxi2nIKZZTqL +gHhXDEkCAwEAAaOBjzCBjDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRds4CU +G+WGv2i6FDSk9u5t8t3f5zAOBgNVHQ8BAf8EBAMCAQYwSgYDVR0fBEMwQTA/oD2g +O4Y5aHR0cDovL2NybC5kLXRydXN0Lm5ldC9jcmwvZC10cnVzdF9zYnJfcm9vdF9j +YV8yXzIwMjIuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA0VC5YGFbNSr2X0/V9K9yv +D1HhTbwhS5P0AEQTBxALJRg+SFmW96Hhk5B4Zho9I+siqwGmjgxRM+ZtjDHurKQB +cDlI3sdmLGsNy3Ofh5LpPkcfuO8v7rdWjEiJ8DinFTmy7sA/F6RzAgicvAaKpMK3 +YWH5w9vE0Hp8Yd6xWJH13WVMLwv46z217Yq+dxy6WQISZnHlmCfODj2vUaJF+YL7 +WqWUcPeLhMNMZSWbe+IfMHCzQI467r3052jFnckpR3EOk8i1SE71ZrsHiHFpa3tI +jm/wEcS0yXAUmCC97afqAdpupZsS/j5EMLPw63VSwPTD+ncmpHeCLW/zKB5OlfAw +94n4LKJQW/K+Mn5sVNtyySpa4By2C9hSmlmh47ABJ8WgFlBm3OuubfSbWz2EbVuH +56mJu2644JtTicD/LkAaiUQuGENnOOR8cl/ZoyklQUE9HHcbZKjDVe5jcWZig/R/ +JpmgVDuhEm1wYs7T+bi9IvzUmtS74jgWL7d9OcKwqQPpnM9+GI123F8Ru+tC7FAJ +PlzskDHYGnK6P2kH7pg0wjSk1toT1qmE8gCGwFS6HhGw4rnEB7SR56rmMVZvsUTE +KmK8ybBlnDT8DBpT3yEXu8JtoQrm8bCqRAlQSTh6XXHiMS4ZsN+VQgR9hIjOCiNn +azidFt4G/ihwOKVarvyD7Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICRzCCAc2gAwIBAgIQFSrdFMkY0aRWQIamJa8HXzAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIEVDQyBSb290IDIw +MjEwHhcNMjEwMzE4MTEwODMwWhcNNDYwMzE3MjM1OTU5WjBlMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMS0wKwYD +VQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIEVDQyBSb290IDIwMjEwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAASwGY+ia7XHzQ8wmTcMw2Bb8fEnIFU9wJKLq1ehb3OD +IcJDEwxeiarHBTV5k2KQ1l0TH9F6oLyeEKdmfEYKsFdsv+ZUOTghbBJccczTWl9t +t6eG37Pf7sLniUGWNfYvSrWjQjBAMB0GA1UdDgQWBBQrywEMY8NTEqWoV6/QnIP7 +vZA6SzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQD +AwNoADBlAjEA1rxIkodHA8dwOyW2H65GZ3N0ACdL5KUEogPfXiitbl4DyN1onLa/ +lBBIlS8P/xiLAjABQDOel5dNBfJ0VAzNOf1qawnBJD9hjjiht+jXRBURYv8OYTdH +S0B/Sl+yZ1pzdcI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw +MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx +JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE +AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O +tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP +f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di +z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn +27iQ7t0l +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgIQDH5i9XlzO51Djotj7ZGVuDANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMS0wKwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIFJTQSBSb290 +IDIwMjMwHhcNMjMwMzI4MTIwOTIyWhcNNDgwMzI3MjM1OTU5WjBlMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMS0w +KwYDVQQDDCRUZWxla29tIFNlY3VyaXR5IFNNSU1FIFJTQSBSb290IDIwMjMwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvxQ6LvjLSZ0f/Ckxnsyq/yMPF +keu1xx6R4WaoiItVIIAfUV53l54ZClzHazchfAM2AfSIJdmoLkGq/Ngm4JZAYnmu +V54DOBocsncUPumhctDk4DfRF0btUFx6WMX4K/d1L8+BnlostzqsoFmYBFEM/0nF +UP0e00eFSzNPoje1rwSaJzKdVtU/VWHji2+uUf6X/mkH+mJbJuYUeRWlEziuXze+ +lErWDYAWaaSRsjpJmHWdRhCKXHp/hKXorx7Hq7NaRrWjS/WmIzYARrHbBbYbzp56 +Mlya1XLDnYZNK4TTHrWI2hB4nCLDOyO16xMHvW9T7Jvsm9Nl9QcJ412nmbV+ho7V +Av+3hQnjRxTdlmYYNN4I1d/LGJliCyvsAF1SRNPGlvwyViWRz80ZO5U5PgKHmWO2 +1T40eg8RdYG8fQTKYLQoddcCUd1SAC7H/YnxXPPLpCcSOI+7+4nw5MQ4LL6CoHFh +YpGPSAwvK6mw8csQBOd0vzeQ708qQzWXEsYqcA3eLFVHeWMp9cofagZSHK4tJCKD +Iq/QqjC3Kh//ZSNYZZPIjn1AEDGGeNlVyzww8N5RKgA20idFX9jooSE9fkZWOylF +8R0FCc62QzDcRZAQMEyka4aLPz0vMZFx7ya59r6dsGzfEe5YP0N5hjmA8SYXB5jw +maowLENZFM7t4kAThQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FJrOrCrsAfplcN6XnfHSAIylo2S7MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw +FoAUms6sKuwB+mVw3ped8dIAjKWjZLswDQYJKoZIhvcNAQEMBQADggIBAONQ/fVA +FiIJljoNqe+B5y4y8KHxSV57iA0Ecte+Z6i6He5Qu3JuetG7DHIwRsjV1wISFplO +Ht9alu6Pkb6uhvgQd6XEbkdhwPIm2U9haAVIdQgVpaF71biziXnm7fHzYQCGey4x +/qNc+Hk9tFuIe+Ajuw2hF/rLaA2Yd3EI4m1DdGvENsWUQaQA1lctmYqLIBIVAjIO +0knsgUjFaidS17JzVVOWPJ5PTLWg0E9X0GcoSGS+xri67GTPyHvFaucq5llXttbU +1sBnXNmeKAlAv/OpNTFlYAPLGWyClQMeXz/hvepJceVbtwtHFhsgiW2UmQx+iGwd +DfS3IRpZl6zL6L4XH5V8U5uvUFKqjQsur1rXYPIqaSq57lRwGKq99aE/0t2hYxkA ++KcM66N58nBZo/iiEgPsE//kAoY218HDpLXUpMI3RbaUcD3FveujFR3jNnoVaSpW +NDnPpZo2qsjtebzP9s4EUwvaslAjfLw+Jq3wDkO7JsuuwkDeNx8KoFHNY522T9jG +R3y82LTtnovzEeKotT7srnA+fiK7NUgXYGIUkTCjdj2mUTaLHw3dajEcpe3dlqNu +cg8TTaqnqVx4+QMSGJM3RRKJPfi+yr3ZvgzZGGSnyEE+dYIhOH1l9KDUE0sHeCn5 +nX7Mhz/E2i6I3eML3FpRWunZEk+eAtv3BSVR +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy +MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC +REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG +A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 +cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV +cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA +U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 +Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug +BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy +8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J +co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg +8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 +rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 +mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg ++y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX +gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ +pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm +9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw +M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd +GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ +CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t +xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ +w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK +L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj +X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q +ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm +dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw +CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE +YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB +IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw +CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE +YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB +IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf +e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C +cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O +BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO +PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw +hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG +XSaQpYXFuXqUPoeovQA= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/cmake/modules/COPYING-CMAKE-SCRIPTS b/local/recipes/libs/qca/source/cmake/modules/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000000..4b417765f3 --- /dev/null +++ b/local/recipes/libs/qca/source/cmake/modules/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ +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 copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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/local/recipes/libs/qca/source/cmake/modules/FindPkcs11Helper.cmake b/local/recipes/libs/qca/source/cmake/modules/FindPkcs11Helper.cmake new file mode 100644 index 0000000000..53f0173073 --- /dev/null +++ b/local/recipes/libs/qca/source/cmake/modules/FindPkcs11Helper.cmake @@ -0,0 +1,40 @@ +# - Try to find the pkcs11-helper library +# Once done this will define +# +# PKCS11H_FOUND - system has pkcs11-helper +# PKCS11H_INCLUDE_DIRS - the pkcs11-helper include directories +# PKCS11H_LDFLAGS - Link to these to use pkcs11-helper +# PKCS11H_CFLAGS_OTHER - Compiler switches required for using pkcs11-helper +# +# Copyright (c) 2006, Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +# pkcs11-helper can be found at http://www.opensc-project.org/pkcs11-helper +# + +if(PKCS11H_INCLUDE_DIRS AND PKCS11H_LDFLAGS) + + # in cache already + SET(PKCS11H_FOUND TRUE) + +else() + if(NOT WIN32) + find_package(PkgConfig) + pkg_search_module(PKCS11H libpkcs11-helper-1) + endif() + + if (PKCS11H_FOUND) + if (NOT Pkcs11Helper_FIND_QUIETLY) + message(STATUS "Found pkcs11-helper: ${PKCS11H_LDFLAGS}") + endif() + else() + if (Pkcs11Helper_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find pkcs11-helper") + endif() + endif() + + mark_as_advanced(PKCS11H_INCLUDE_DIRS PKCS11H_LDFLAGS PKCS11H_CFLAGS_OTHER) + +endif() diff --git a/local/recipes/libs/qca/source/cmake/modules/FindSasl2.cmake b/local/recipes/libs/qca/source/cmake/modules/FindSasl2.cmake new file mode 100644 index 0000000000..d9770cdada --- /dev/null +++ b/local/recipes/libs/qca/source/cmake/modules/FindSasl2.cmake @@ -0,0 +1,41 @@ +# - Try to find the sasl2 directory library +# Once done this will define +# +# SASL2_FOUND - system has SASL2 +# SASL2_INCLUDE_DIR - the SASL2 include directory +# SASL2_LIBRARIES - The libraries needed to use SASL2 +# +# Copyright (c) 2006, Laurent Montel, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (SASL2_INCLUDE_DIR) + # Already in cache, be silent + set(SASL2_FIND_QUIETLY TRUE) +endif() + +FIND_PATH(SASL2_INCLUDE_DIR sasl/sasl.h) + +FIND_LIBRARY(SASL2_LIBRARIES NAMES sasl2) + + +if (SASL2_INCLUDE_DIR AND SASL2_LIBRARIES) + set(SASL2_FOUND TRUE) +endif() + + +if (SASL2_FOUND) + if (NOT Sasl2_FIND_QUIETLY) + message(STATUS "Found Sasl2: ${SASL2_LIBRARIES}") + endif() +else() + if (Sasl2_FIND_REQUIRED) + message(FATAL_ERROR "Could not find sasl2 libraries") + endif() +endif() + + +MARK_AS_ADVANCED(SASL2_INCLUDE_DIR SASL2_LIBRARIES) + diff --git a/local/recipes/libs/qca/source/cmake/modules/QcaMacro.cmake b/local/recipes/libs/qca/source/cmake/modules/QcaMacro.cmake new file mode 100644 index 0000000000..94f2562de9 --- /dev/null +++ b/local/recipes/libs/qca/source/cmake/modules/QcaMacro.cmake @@ -0,0 +1,78 @@ + +MACRO(SETUP_QT_DIRS) + if(BUILD_WITH_QT6) + GET_TARGET_PROPERTY(QMAKE_EXECUTABLE Qt6::qmake LOCATION) + else() + GET_TARGET_PROPERTY(QMAKE_EXECUTABLE ${Qt5Core_QMAKE_EXECUTABLE} LOCATION) + endif() + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_LIBS" OUTPUT_VARIABLE QT_LIBRARY_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_PREFIX" OUTPUT_VARIABLE QT_PREFIX_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_PLUGINS" OUTPUT_VARIABLE QT_PLUGINS_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_BINS" OUTPUT_VARIABLE QT_BINARY_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_HEADERS" OUTPUT_VARIABLE QT_HEADERS_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_DOCS" OUTPUT_VARIABLE QT_DOC_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_INSTALL_DATA" OUTPUT_VARIABLE QT_DATA_DIR ) + EXEC_PROGRAM( ${QMAKE_EXECUTABLE} ARGS "-query QT_HOST_DATA" OUTPUT_VARIABLE QT_ARCHDATA_DIR ) + SET( QT_MKSPECS_DIR "${QT_ARCHDATA_DIR}/mkspecs" ) +ENDMACRO(SETUP_QT_DIRS) + +macro(set_enabled_plugin PLUGIN ENABLED) + # To nice looks + if(ENABLED) + set(ENABLED "on") + else() + set(ENABLED "off") + endif() + set(WITH_${PLUGIN}_PLUGIN_INTERNAL ${ENABLED} CACHE INTERNAL "") +endmacro(set_enabled_plugin) + +macro(enable_plugin PLUGIN) + set_enabled_plugin(${PLUGIN} "on") +endmacro(enable_plugin) + +macro(disable_plugin PLUGIN) + set_enabled_plugin(${PLUGIN} "off") +endmacro(disable_plugin) + +# it used to build examples and tools +macro(target_link_qca_libraries TARGET) + # Link with QCA library + target_link_libraries(${TARGET} ${QCA_LIB_NAME}) + + # Statically link with all enabled QCA plugins + if(STATIC_PLUGINS) + target_link_libraries(${TARGET} ${QT_QTCORE_LIB_DEPENDENCIES}) + foreach(PLUGIN IN LISTS PLUGINS) + # Check plugin for enabled + if(WITH_${PLUGIN}_PLUGIN_INTERNAL) + target_link_libraries(${TARGET} qca-${PLUGIN}) + endif() + endforeach(PLUGIN) + endif() +endmacro(target_link_qca_libraries) + +# it used to build unittests +macro(target_link_qca_test_libraries TARGET) + target_link_qca_libraries(${TARGET}) + target_link_libraries(${TARGET} Qt${QT_MAJOR_VERSION}::Test) +endmacro(target_link_qca_test_libraries) + +# it used to build unittests +macro(add_qca_test TARGET DESCRIPTION) + add_test(NAME "${DESCRIPTION}" + WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" + COMMAND "${TARGET}") +endmacro(add_qca_test) + +macro(install_pdb TARGET INSTALL_PATH) + if(MSVC) + install(FILES $ DESTINATION ${INSTALL_PATH} CONFIGURATIONS Debug) + install(FILES $ DESTINATION ${INSTALL_PATH} CONFIGURATIONS RelWithDebInfo) + endif() +endmacro(install_pdb) + +macro(normalize_path PATH) + get_filename_component(${PATH} "${${PATH}}" ABSOLUTE) + # Strip trailing slashes + string(REGEX REPLACE "/+$" "" PATH ${PATH}) +endmacro() diff --git a/local/recipes/libs/qca/source/cmake_uninstall.cmake.in b/local/recipes/libs/qca/source/cmake_uninstall.cmake.in new file mode 100644 index 0000000000..427f03960b --- /dev/null +++ b/local/recipes/libs/qca/source/cmake_uninstall.cmake.in @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 2.6.0) + +cmake_policy(SET CMP0007 OLD) + +if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +endif() + +file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +list(REVERSE files) +foreach (file ${files}) + message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + if (EXISTS "$ENV{DESTDIR}${file}") + execute_process( + COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RESULT_VARIABLE rm_retval + ) + if(NOT ${rm_retval} EQUAL 0) + message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + endif() + else() + message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + endif() +endforeach(file) diff --git a/local/recipes/libs/qca/source/crypto.prf.cmake b/local/recipes/libs/qca/source/crypto.prf.cmake new file mode 100644 index 0000000000..ee15edf419 --- /dev/null +++ b/local/recipes/libs/qca/source/crypto.prf.cmake @@ -0,0 +1,26 @@ +QCA_INCDIR = @CRYPTO_PRF_RELATIVE_PATH@@QCA_INCLUDE_INSTALL_DIR@ +QCA_LIBDIR = @CRYPTO_PRF_RELATIVE_PATH@@QCA_LIBRARY_INSTALL_DIR@ + +CONFIG *= qt + +LINKAGE = + +exists($$QCA_LIBDIR/@QCA_LIB_NAME@.framework) { + QMAKE_CXXFLAGS += -F$$QCA_LIBDIR + LIBS *= -F$$QCA_LIBDIR + INCLUDEPATH += $$QCA_LIBDIR/@QCA_LIB_NAME@.framework/Headers + LINKAGE = -framework @QCA_LIB_NAME@ +} + +# else, link normally +isEmpty(LINKAGE) { + INCLUDEPATH += $$QCA_INCDIR/QtCrypto + LIBS += -L$$QCA_LIBDIR + LINKAGE = -l@QCA_LIB_NAME@ + CONFIG(debug, debug|release) { + windows:LINKAGE = -l@QCA_LIB_NAME@d + mac:LINKAGE = -l@QCA_LIB_NAME@_debug + } +} + +LIBS += $$LINKAGE diff --git a/local/recipes/libs/qca/source/docs/Doxyfile.local b/local/recipes/libs/qca/source/docs/Doxyfile.local new file mode 100644 index 0000000000..59a2af149f --- /dev/null +++ b/local/recipes/libs/qca/source/docs/Doxyfile.local @@ -0,0 +1,3 @@ +### KApiDox Project-specific Overrides File + +FILE_PATTERNS += *.doco diff --git a/local/recipes/libs/qca/source/docs/pics/qca-arch.eps b/local/recipes/libs/qca/source/docs/pics/qca-arch.eps new file mode 100644 index 0000000000..56b949a781 --- /dev/null +++ b/local/recipes/libs/qca/source/docs/pics/qca-arch.eps @@ -0,0 +1,4874 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: inkscape 0.45.1 +%%Pages: 1 +%%Orientation: Portrait +%%BoundingBox: 55 310 561 499 +%%HiResBoundingBox: 55.358892 310.605 560.03076 498.8645 +%%EndComments +%%Page: 1 1 +0 842 translate +0.8 -0.8 scale +0 0 0 setrgbcolor +[] 0 setdash +1 setlinewidth +0 setlinejoin +0 setlinecap +gsave [1 0 0 1 0 0] concat +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +286.70642 429.78156 moveto +455.39757 429.78156 lineto +455.39757 663.10593 lineto +286.70642 663.10593 lineto +286.70642 429.78156 lineto +closepath +stroke +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +503.70898 434.30725 moveto +689.30048 434.30725 lineto +689.30048 463.73053 lineto +503.70898 463.73053 lineto +503.70898 434.30725 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +325.78876 489.8063 moveto +325.78876 491.05435 lineto +325.39031 490.68327 324.96453 490.40592 324.51141 490.22232 curveto +324.06219 490.03873 323.58367 489.94694 323.07587 489.94693 curveto +322.07586 489.94694 321.31024 490.25358 320.77899 490.86685 curveto +320.24774 491.47623 319.98211 492.35904 319.98212 493.51529 curveto +319.98211 494.66764 320.24774 495.55045 320.77899 496.16373 curveto +321.31024 496.7731 322.07586 497.07779 323.07587 497.07779 curveto +323.58367 497.07779 324.06219 496.98599 324.51141 496.8024 curveto +324.96453 496.61881 325.39031 496.34146 325.78876 495.97037 curveto +325.78876 497.2067 lineto +325.37469 497.48795 324.93523 497.69888 324.4704 497.83951 curveto +324.00945 497.98013 323.52117 498.05045 323.00555 498.05045 curveto +321.68133 498.05045 320.63836 497.64615 319.87665 496.83755 curveto +319.11493 496.02506 318.73407 494.91764 318.73407 493.51529 curveto +318.73407 492.10905 319.11493 491.00162 319.87665 490.19302 curveto +320.63836 489.38053 321.68133 488.97428 323.00555 488.97427 curveto +323.52899 488.97428 324.02117 489.0446 324.48212 489.18521 curveto +324.94695 489.32194 325.3825 489.52897 325.78876 489.8063 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +330.12469 492.07388 moveto +329.54657 492.07389 329.08954 492.30045 328.7536 492.75357 curveto +328.41766 493.20279 328.24969 493.81998 328.24969 494.60513 curveto +328.24969 495.39029 328.41571 496.00943 328.74774 496.46255 curveto +329.08368 496.91177 329.54266 497.13638 330.12469 497.13638 curveto +330.69891 497.13638 331.15399 496.90982 331.48993 496.4567 curveto +331.82586 496.00357 331.99383 495.38639 331.99384 494.60513 curveto +331.99383 493.82779 331.82586 493.21256 331.48993 492.75943 curveto +331.15399 492.3024 330.69891 492.07389 330.12469 492.07388 curveto +330.12469 491.15982 moveto +331.06219 491.15983 331.79852 491.46451 332.33368 492.07388 curveto +332.86883 492.68326 333.13641 493.52701 333.13641 494.60513 curveto +333.13641 495.67935 332.86883 496.5231 332.33368 497.13638 curveto +331.79852 497.74576 331.06219 498.05045 330.12469 498.05045 curveto +329.18329 498.05045 328.44501 497.74576 327.90985 497.13638 curveto +327.3786 496.5231 327.11298 495.67935 327.11298 494.60513 curveto +327.11298 493.52701 327.3786 492.68326 327.90985 492.07388 curveto +328.44501 491.46451 329.18329 491.15983 330.12469 491.15982 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +338.7204 492.32584 moveto +338.5993 492.25553 338.46649 492.20475 338.32196 492.17349 curveto +338.18133 492.13834 338.02508 492.12076 337.85321 492.12076 curveto +337.24383 492.12076 336.77508 492.31998 336.44696 492.71841 curveto +336.12274 493.11295 335.96063 493.68131 335.96063 494.42349 curveto +335.96063 497.88052 lineto +334.87665 497.88052 lineto +334.87665 491.31802 lineto +335.96063 491.31802 lineto +335.96063 492.33755 lineto +336.18719 491.93912 336.48211 491.6442 336.8454 491.45279 curveto +337.20868 491.25748 337.65008 491.15983 338.16962 491.15982 curveto +338.24383 491.15983 338.32586 491.16569 338.41571 491.1774 curveto +338.50555 491.18522 338.60516 491.19889 338.71454 491.21841 curveto +338.7204 492.32584 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +345.21844 494.32974 moveto +345.21844 494.85709 lineto +340.26141 494.85709 lineto +340.30829 495.59928 340.53094 496.16568 340.92938 496.5563 curveto +341.33172 496.94302 341.89032 497.13638 342.60516 497.13638 curveto +343.01922 497.13638 343.41961 497.0856 343.80634 496.98404 curveto +344.19695 496.88248 344.58367 496.73013 344.96649 496.52701 curveto +344.96649 497.54654 lineto +344.57977 497.7106 344.18328 497.8356 343.77704 497.92154 curveto +343.37078 498.00748 342.95867 498.05045 342.54071 498.05045 curveto +341.49383 498.05045 340.66376 497.74576 340.05048 497.13638 curveto +339.4411 496.52701 339.13641 495.70279 339.13641 494.66373 curveto +339.13641 493.58951 339.42548 492.73795 340.0036 492.10904 curveto +340.58563 491.47623 341.36883 491.15983 342.35321 491.15982 curveto +343.23602 491.15983 343.93328 491.44498 344.44501 492.01529 curveto +344.96063 492.5817 345.21844 493.35318 345.21844 494.32974 curveto +344.14032 494.01334 moveto +344.1325 493.4235 343.96649 492.95279 343.64227 492.60123 curveto +343.32196 492.24967 342.89617 492.07389 342.36493 492.07388 curveto +341.76336 492.07389 341.28094 492.24381 340.91766 492.58365 curveto +340.55829 492.9235 340.35126 493.40201 340.29657 494.0192 curveto +344.14032 494.01334 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +354.38251 489.93521 moveto +353.52313 489.93522 352.83954 490.25553 352.33173 490.89615 curveto +351.82782 491.53678 351.57586 492.40983 351.57587 493.51529 curveto +351.57586 494.61686 351.82782 495.48795 352.33173 496.12857 curveto +352.83954 496.7692 353.52313 497.08951 354.38251 497.08951 curveto +355.24188 497.08951 355.92156 496.7692 356.42157 496.12857 curveto +356.92547 495.48795 357.17742 494.61686 357.17743 493.51529 curveto +357.17742 492.40983 356.92547 491.53678 356.42157 490.89615 curveto +355.92156 490.25553 355.24188 489.93522 354.38251 489.93521 curveto +356.04071 497.72232 moveto +357.5993 499.4274 lineto +356.16962 499.4274 lineto +354.87469 498.02701 lineto +354.74578 498.03482 354.64617 498.04068 354.57587 498.04459 curveto +354.50946 498.04849 354.445 498.05045 354.38251 498.05045 curveto +353.15204 498.05045 352.16766 497.64029 351.42938 496.81998 curveto +350.69501 495.99576 350.32782 494.8942 350.32782 493.51529 curveto +350.32782 492.13248 350.69501 491.03092 351.42938 490.2106 curveto +352.16766 489.38639 353.15204 488.97428 354.38251 488.97427 curveto +355.60906 488.97428 356.58953 489.38639 357.32391 490.2106 curveto +358.05828 491.03092 358.42547 492.13248 358.42548 493.51529 curveto +358.42547 494.53092 358.22039 495.40006 357.81024 496.12271 curveto +357.40398 496.84537 356.81414 497.37857 356.04071 497.72232 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +366.82782 489.8063 moveto +366.82782 491.05435 lineto +366.42937 490.68327 366.00359 490.40592 365.55048 490.22232 curveto +365.10125 490.03873 364.62274 489.94694 364.11493 489.94693 curveto +363.11493 489.94694 362.3493 490.25358 361.81805 490.86685 curveto +361.2868 491.47623 361.02118 492.35904 361.02118 493.51529 curveto +361.02118 494.66764 361.2868 495.55045 361.81805 496.16373 curveto +362.3493 496.7731 363.11493 497.07779 364.11493 497.07779 curveto +364.62274 497.07779 365.10125 496.98599 365.55048 496.8024 curveto +366.00359 496.61881 366.42937 496.34146 366.82782 495.97037 curveto +366.82782 497.2067 lineto +366.41375 497.48795 365.9743 497.69888 365.50946 497.83951 curveto +365.04852 497.98013 364.56024 498.05045 364.04462 498.05045 curveto +362.72039 498.05045 361.67743 497.64615 360.91571 496.83755 curveto +360.15399 496.02506 359.77313 494.91764 359.77313 493.51529 curveto +359.77313 492.10905 360.15399 491.00162 360.91571 490.19302 curveto +361.67743 489.38053 362.72039 488.97428 364.04462 488.97427 curveto +364.56805 488.97428 365.06024 489.0446 365.52118 489.18521 curveto +365.98602 489.32194 366.42156 489.52897 366.82782 489.8063 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +371.59149 490.29849 moveto +369.98602 494.65201 lineto +373.20282 494.65201 lineto +371.59149 490.29849 lineto +370.92352 489.13248 moveto +372.26532 489.13248 lineto +375.5993 497.88052 lineto +374.36884 497.88052 lineto +373.57196 495.63638 lineto +369.6286 495.63638 lineto +368.83173 497.88052 lineto +367.58368 497.88052 lineto +370.92352 489.13248 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +380.64423 488.76334 moveto +381.72235 488.76334 lineto +381.72235 497.88052 lineto +380.64423 497.88052 lineto +380.64423 488.76334 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +383.97235 491.31802 moveto +385.05048 491.31802 lineto +385.05048 497.88052 lineto +383.97235 497.88052 lineto +383.97235 491.31802 lineto +383.97235 488.76334 moveto +385.05048 488.76334 lineto +385.05048 490.12857 lineto +383.97235 490.12857 lineto +383.97235 488.76334 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +392.01141 494.60513 moveto +392.01141 493.81217 391.84735 493.19108 391.51923 492.74185 curveto +391.195 492.28873 390.74774 492.06217 390.17743 492.06216 curveto +389.60711 492.06217 389.15789 492.28873 388.82977 492.74185 curveto +388.50555 493.19108 388.34344 493.81217 388.34344 494.60513 curveto +388.34344 495.3981 388.50555 496.02115 388.82977 496.47427 curveto +389.15789 496.92349 389.60711 497.1481 390.17743 497.1481 curveto +390.74774 497.1481 391.195 496.92349 391.51923 496.47427 curveto +391.84735 496.02115 392.01141 495.3981 392.01141 494.60513 curveto +388.34344 492.31412 moveto +388.57 491.9235 388.85516 491.63444 389.19891 491.44693 curveto +389.54657 491.25553 389.96063 491.15983 390.4411 491.15982 curveto +391.23797 491.15983 391.88445 491.47623 392.38055 492.10904 curveto +392.88055 492.74186 393.13055 493.57389 393.13055 494.60513 curveto +393.13055 495.63639 392.88055 496.46842 392.38055 497.10123 curveto +391.88445 497.73404 391.23797 498.05045 390.4411 498.05045 curveto +389.96063 498.05045 389.54657 497.9567 389.19891 497.7692 curveto +388.85516 497.57779 388.57 497.28677 388.34344 496.89615 curveto +388.34344 497.88052 lineto +387.25946 497.88052 lineto +387.25946 488.76334 lineto +388.34344 488.76334 lineto +388.34344 492.31412 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +398.7204 492.32584 moveto +398.5993 492.25553 398.46649 492.20475 398.32196 492.17349 curveto +398.18133 492.13834 398.02508 492.12076 397.85321 492.12076 curveto +397.24383 492.12076 396.77508 492.31998 396.44696 492.71841 curveto +396.12274 493.11295 395.96063 493.68131 395.96063 494.42349 curveto +395.96063 497.88052 lineto +394.87665 497.88052 lineto +394.87665 491.31802 lineto +395.96063 491.31802 lineto +395.96063 492.33755 lineto +396.18719 491.93912 396.48211 491.6442 396.8454 491.45279 curveto +397.20868 491.25748 397.65008 491.15983 398.16962 491.15982 curveto +398.24383 491.15983 398.32586 491.16569 398.41571 491.1774 curveto +398.50555 491.18522 398.60516 491.19889 398.71454 491.21841 curveto +398.7204 492.32584 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +402.8454 494.5817 moveto +401.9743 494.5817 401.37079 494.68131 401.03485 494.88052 curveto +400.69891 495.07975 400.53094 495.41959 400.53094 495.90005 curveto +400.53094 496.28287 400.65594 496.58756 400.90594 496.81412 curveto +401.15985 497.03677 401.5036 497.1481 401.93719 497.1481 curveto +402.53485 497.1481 403.01336 496.93717 403.37274 496.51529 curveto +403.73602 496.08951 403.91766 495.52506 403.91766 494.82193 curveto +403.91766 494.5817 lineto +402.8454 494.5817 lineto +404.99579 494.13638 moveto +404.99579 497.88052 lineto +403.91766 497.88052 lineto +403.91766 496.88443 lineto +403.67156 497.28287 403.36492 497.57779 402.99774 497.7692 curveto +402.63055 497.9567 402.18133 498.05045 401.65009 498.05045 curveto +400.97821 498.05045 400.44305 497.86295 400.04462 497.48795 curveto +399.65008 497.10904 399.45282 496.60318 399.45282 495.97037 curveto +399.45282 495.23209 399.69891 494.67545 400.1911 494.30045 curveto +400.68719 493.92545 401.42547 493.73795 402.40594 493.73795 curveto +403.91766 493.73795 lineto +403.91766 493.63248 lineto +403.91766 493.13639 403.7536 492.75358 403.42548 492.48404 curveto +403.10125 492.21061 402.64422 492.07389 402.05438 492.07388 curveto +401.67938 492.07389 401.31415 492.11881 400.95868 492.20865 curveto +400.60321 492.2985 400.26141 492.43326 399.93329 492.61295 curveto +399.93329 491.61685 lineto +400.32782 491.46451 400.71063 491.35123 401.08173 491.27701 curveto +401.45282 491.19889 401.81414 491.15983 402.16571 491.15982 curveto +403.11492 491.15983 403.82391 491.40592 404.29266 491.8981 curveto +404.76141 492.39029 404.99578 493.13639 404.99579 494.13638 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +411.04852 492.32584 moveto +410.92742 492.25553 410.79461 492.20475 410.65009 492.17349 curveto +410.50946 492.13834 410.35321 492.12076 410.18134 492.12076 curveto +409.57196 492.12076 409.10321 492.31998 408.77509 492.71841 curveto +408.45086 493.11295 408.28876 493.68131 408.28876 494.42349 curveto +408.28876 497.88052 lineto +407.20477 497.88052 lineto +407.20477 491.31802 lineto +408.28876 491.31802 lineto +408.28876 492.33755 lineto +408.51532 491.93912 408.81024 491.6442 409.17352 491.45279 curveto +409.5368 491.25748 409.97821 491.15983 410.49774 491.15982 curveto +410.57196 491.15983 410.65399 491.16569 410.74384 491.1774 curveto +410.83367 491.18522 410.93328 491.19889 411.04266 491.21841 curveto +411.04852 492.32584 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +414.92157 498.4899 moveto +414.61688 499.27115 414.32 499.78091 414.03094 500.0192 curveto +413.74188 500.25747 413.35516 500.37661 412.87079 500.37662 curveto +412.00946 500.37662 lineto +412.00946 499.47427 lineto +412.64227 499.47427 lineto +412.93915 499.47427 413.16961 499.40396 413.33368 499.26334 curveto +413.49774 499.12271 413.67938 498.79068 413.8786 498.26724 curveto +414.07196 497.77505 lineto +411.41766 491.31802 lineto +412.56024 491.31802 lineto +414.61102 496.45084 lineto +416.6618 491.31802 lineto +417.80438 491.31802 lineto +414.92157 498.4899 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +349.20282 503.77505 moveto +348.67938 504.6735 348.29071 505.56217 348.0368 506.44107 curveto +347.7829 507.31998 347.65594 508.21061 347.65594 509.11295 curveto +347.65594 510.01529 347.7829 510.90982 348.0368 511.79654 curveto +348.29461 512.67935 348.68329 513.56802 349.20282 514.46255 curveto +348.26532 514.46255 lineto +347.67938 513.54459 347.23993 512.64224 346.94696 511.75552 curveto +346.6579 510.86881 346.51337 509.98795 346.51337 509.11295 curveto +346.51337 508.24186 346.6579 507.3649 346.94696 506.48209 curveto +347.23602 505.59928 347.67547 504.69694 348.26532 503.77505 curveto +349.20282 503.77505 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +351.30048 503.76334 moveto +352.3786 503.76334 lineto +352.3786 512.88052 lineto +351.30048 512.88052 lineto +351.30048 503.76334 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +354.6286 506.31802 moveto +355.70673 506.31802 lineto +355.70673 512.88052 lineto +354.6286 512.88052 lineto +354.6286 506.31802 lineto +354.6286 503.76334 moveto +355.70673 503.76334 lineto +355.70673 505.12857 lineto +354.6286 505.12857 lineto +354.6286 503.76334 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +362.66766 509.60513 moveto +362.66766 508.81217 362.5036 508.19108 362.17548 507.74185 curveto +361.85125 507.28873 361.40399 507.06217 360.83368 507.06216 curveto +360.26336 507.06217 359.81414 507.28873 359.48602 507.74185 curveto +359.1618 508.19108 358.99969 508.81217 358.99969 509.60513 curveto +358.99969 510.3981 359.1618 511.02115 359.48602 511.47427 curveto +359.81414 511.92349 360.26336 512.1481 360.83368 512.1481 curveto +361.40399 512.1481 361.85125 511.92349 362.17548 511.47427 curveto +362.5036 511.02115 362.66766 510.3981 362.66766 509.60513 curveto +358.99969 507.31412 moveto +359.22625 506.9235 359.51141 506.63444 359.85516 506.44693 curveto +360.20282 506.25553 360.61688 506.15983 361.09735 506.15982 curveto +361.89422 506.15983 362.5407 506.47623 363.0368 507.10904 curveto +363.5368 507.74186 363.7868 508.57389 363.7868 509.60513 curveto +363.7868 510.63639 363.5368 511.46842 363.0368 512.10123 curveto +362.5407 512.73404 361.89422 513.05045 361.09735 513.05045 curveto +360.61688 513.05045 360.20282 512.9567 359.85516 512.7692 curveto +359.51141 512.57779 359.22625 512.28677 358.99969 511.89615 curveto +358.99969 512.88052 lineto +357.91571 512.88052 lineto +357.91571 503.76334 lineto +358.99969 503.76334 lineto +358.99969 507.31412 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +366.21844 509.60513 moveto +366.21844 510.3981 366.38055 511.02115 366.70477 511.47427 curveto +367.0329 511.92349 367.48211 512.1481 368.05243 512.1481 curveto +368.62274 512.1481 369.07196 511.92349 369.40009 511.47427 curveto +369.72821 511.02115 369.89227 510.3981 369.89227 509.60513 curveto +369.89227 508.81217 369.72821 508.19108 369.40009 507.74185 curveto +369.07196 507.28873 368.62274 507.06217 368.05243 507.06216 curveto +367.48211 507.06217 367.0329 507.28873 366.70477 507.74185 curveto +366.38055 508.19108 366.21844 508.81217 366.21844 509.60513 curveto +369.89227 511.89615 moveto +369.66571 512.28677 369.3786 512.57779 369.03094 512.7692 curveto +368.68719 512.9567 368.27313 513.05045 367.78876 513.05045 curveto +366.99579 513.05045 366.3493 512.73404 365.8493 512.10123 curveto +365.35321 511.46842 365.10516 510.63639 365.10516 509.60513 curveto +365.10516 508.57389 365.35321 507.74186 365.8493 507.10904 curveto +366.3493 506.47623 366.99579 506.15983 367.78876 506.15982 curveto +368.27313 506.15983 368.68719 506.25553 369.03094 506.44693 curveto +369.3786 506.63444 369.66571 506.9235 369.89227 507.31412 curveto +369.89227 506.31802 lineto +370.9704 506.31802 lineto +370.9704 515.37662 lineto +369.89227 515.37662 lineto +369.89227 511.89615 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +377.91376 506.56998 moveto +377.91376 507.57779 lineto +377.60906 507.40983 377.30242 507.28483 376.99384 507.20279 curveto +376.68914 507.11686 376.38055 507.07389 376.06805 507.07388 curveto +375.36883 507.07389 374.82586 507.29654 374.43915 507.74185 curveto +374.05243 508.18326 373.85907 508.80436 373.85907 509.60513 curveto +373.85907 510.40592 374.05243 511.02896 374.43915 511.47427 curveto +374.82586 511.91568 375.36883 512.13638 376.06805 512.13638 curveto +376.38055 512.13638 376.68914 512.09537 376.99384 512.01334 curveto +377.30242 511.9274 377.60906 511.80045 377.91376 511.63248 curveto +377.91376 512.62857 lineto +377.61297 512.7692 377.30047 512.87466 376.97626 512.94498 curveto +376.65594 513.01529 376.31414 513.05045 375.95087 513.05045 curveto +374.96258 513.05045 374.17743 512.7399 373.5954 512.1188 curveto +373.01337 511.49771 372.72235 510.65982 372.72235 509.60513 curveto +372.72235 508.53482 373.01532 507.69303 373.60126 507.07974 curveto +374.1911 506.46647 374.99774 506.15983 376.02118 506.15982 curveto +376.35321 506.15983 376.67742 506.19498 376.99384 506.26529 curveto +377.31024 506.3317 377.61688 506.43326 377.91376 506.56998 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +382.7829 509.5817 moveto +381.9118 509.5817 381.30829 509.68131 380.97235 509.88052 curveto +380.63641 510.07975 380.46844 510.41959 380.46844 510.90005 curveto +380.46844 511.28287 380.59344 511.58756 380.84344 511.81412 curveto +381.09735 512.03677 381.4411 512.1481 381.87469 512.1481 curveto +382.47235 512.1481 382.95086 511.93717 383.31024 511.51529 curveto +383.67352 511.08951 383.85516 510.52506 383.85516 509.82193 curveto +383.85516 509.5817 lineto +382.7829 509.5817 lineto +384.93329 509.13638 moveto +384.93329 512.88052 lineto +383.85516 512.88052 lineto +383.85516 511.88443 lineto +383.60906 512.28287 383.30242 512.57779 382.93524 512.7692 curveto +382.56805 512.9567 382.11883 513.05045 381.58759 513.05045 curveto +380.91571 513.05045 380.38055 512.86295 379.98212 512.48795 curveto +379.58758 512.10904 379.39032 511.60318 379.39032 510.97037 curveto +379.39032 510.23209 379.63641 509.67545 380.1286 509.30045 curveto +380.62469 508.92545 381.36297 508.73795 382.34344 508.73795 curveto +383.85516 508.73795 lineto +383.85516 508.63248 lineto +383.85516 508.13639 383.6911 507.75358 383.36298 507.48404 curveto +383.03875 507.21061 382.58172 507.07389 381.99188 507.07388 curveto +381.61688 507.07389 381.25165 507.11881 380.89618 507.20865 curveto +380.54071 507.2985 380.19891 507.43326 379.87079 507.61295 curveto +379.87079 506.61685 lineto +380.26532 506.46451 380.64813 506.35123 381.01923 506.27701 curveto +381.39032 506.19889 381.75164 506.15983 382.10321 506.15982 curveto +383.05242 506.15983 383.76141 506.40592 384.23016 506.8981 curveto +384.69891 507.39029 384.93328 508.13639 384.93329 509.13638 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +387.01337 503.77505 moveto +387.95087 503.77505 lineto +388.5368 504.69694 388.9743 505.59928 389.26337 506.48209 curveto +389.55633 507.3649 389.70282 508.24186 389.70282 509.11295 curveto +389.70282 509.98795 389.55633 510.86881 389.26337 511.75552 curveto +388.9743 512.64224 388.5368 513.54459 387.95087 514.46255 curveto +387.01337 514.46255 lineto +387.5329 513.56802 387.91961 512.67935 388.17352 511.79654 curveto +388.43133 510.90982 388.56024 510.01529 388.56024 509.11295 curveto +388.56024 508.21061 388.43133 507.31998 388.17352 506.44107 curveto +387.91961 505.56217 387.5329 504.6735 387.01337 503.77505 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +533.20197 451.07434 moveto +533.20197 448.72473 lineto +531.26837 448.72473 lineto +531.26837 447.75208 lineto +534.37384 447.75208 lineto +534.37384 451.50793 lineto +533.9168 451.83215 533.4129 452.07825 532.86212 452.24622 curveto +532.31133 452.41028 531.72344 452.49231 531.09845 452.49231 curveto +529.73126 452.49231 528.66095 452.09387 527.88751 451.297 curveto +527.11798 450.49622 526.73321 449.38294 526.73322 447.95715 curveto +526.73321 446.52747 527.11798 445.41419 527.88751 444.61731 curveto +528.66095 443.81654 529.73126 443.41615 531.09845 443.41614 curveto +531.66876 443.41615 532.20977 443.48646 532.7215 443.62708 curveto +533.23711 443.76771 533.71172 443.97474 534.14532 444.24817 curveto +534.14532 445.50793 lineto +533.70782 445.13685 533.24297 444.85755 532.75079 444.67004 curveto +532.2586 444.48255 531.74102 444.3888 531.19806 444.38879 curveto +530.12774 444.3888 529.32306 444.68763 528.784 445.28528 curveto +528.24884 445.88294 527.98126 446.77357 527.98126 447.95715 curveto +527.98126 449.13684 528.24884 450.02551 528.784 450.62317 curveto +529.32306 451.22083 530.12774 451.51965 531.19806 451.51965 curveto +531.61602 451.51965 531.98907 451.4845 532.3172 451.41418 curveto +532.64532 451.33997 532.94024 451.22669 533.20197 451.07434 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +541.95001 448.36145 moveto +541.95001 452.32239 lineto +540.87189 452.32239 lineto +540.87189 448.39661 lineto +540.87188 447.77552 540.75079 447.31067 540.50861 447.00208 curveto +540.26641 446.69349 539.90313 446.53919 539.41876 446.53918 curveto +538.83673 446.53919 538.37774 446.72474 538.04181 447.09583 curveto +537.70587 447.46692 537.5379 447.97278 537.5379 448.6134 curveto +537.5379 452.32239 lineto +536.45392 452.32239 lineto +536.45392 445.75989 lineto +537.5379 445.75989 lineto +537.5379 446.77942 lineto +537.79571 446.38489 538.09845 446.08997 538.44611 445.89465 curveto +538.79767 445.69935 539.20196 445.60169 539.659 445.60168 curveto +540.4129 445.60169 540.98321 445.83607 541.36993 446.30481 curveto +541.75665 446.76966 541.95001 447.45521 541.95001 448.36145 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +544.00079 449.73254 moveto +544.00079 445.75989 lineto +545.07892 445.75989 lineto +545.07892 449.69153 lineto +545.07892 450.31262 545.20001 450.77942 545.4422 451.09192 curveto +545.68438 451.40051 546.04767 451.55481 546.53204 451.55481 curveto +547.11407 451.55481 547.57305 451.36926 547.909 450.99817 curveto +548.24884 450.62708 548.41876 450.12122 548.41876 449.48059 curveto +548.41876 445.75989 lineto +549.49689 445.75989 lineto +549.49689 452.32239 lineto +548.41876 452.32239 lineto +548.41876 451.31458 lineto +548.15704 451.71301 547.85235 452.00989 547.5047 452.2052 curveto +547.16095 452.39661 546.76056 452.49231 546.30353 452.49231 curveto +545.54962 452.49231 544.97735 452.25793 544.58673 451.78918 curveto +544.1961 451.32044 544.00079 450.63489 544.00079 449.73254 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +552.95978 444.547 moveto +552.95978 447.83411 lineto +554.44806 447.83411 lineto +554.99884 447.83411 555.42462 447.69153 555.7254 447.40637 curveto +556.02618 447.12122 556.17657 446.71497 556.17657 446.18762 curveto +556.17657 445.66419 556.02618 445.25989 555.7254 444.97473 curveto +555.42462 444.68958 554.99884 444.547 554.44806 444.547 curveto +552.95978 444.547 lineto +551.77618 443.57434 moveto +554.44806 443.57434 lineto +555.42852 443.57435 556.16876 443.79701 556.66876 444.24231 curveto +557.17266 444.68372 557.42461 445.33216 557.42462 446.18762 curveto +557.42461 447.05091 557.17266 447.70325 556.66876 448.14465 curveto +556.16876 448.58606 555.42852 448.80677 554.44806 448.80676 curveto +552.95978 448.80676 lineto +552.95978 452.32239 lineto +551.77618 452.32239 lineto +551.77618 443.57434 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +564.98322 451.07434 moveto +564.98322 448.72473 lineto +563.04962 448.72473 lineto +563.04962 447.75208 lineto +566.15509 447.75208 lineto +566.15509 451.50793 lineto +565.69805 451.83215 565.19415 452.07825 564.64337 452.24622 curveto +564.09258 452.41028 563.50469 452.49231 562.8797 452.49231 curveto +561.51251 452.49231 560.4422 452.09387 559.66876 451.297 curveto +558.89923 450.49622 558.51446 449.38294 558.51447 447.95715 curveto +558.51446 446.52747 558.89923 445.41419 559.66876 444.61731 curveto +560.4422 443.81654 561.51251 443.41615 562.8797 443.41614 curveto +563.45001 443.41615 563.99102 443.48646 564.50275 443.62708 curveto +565.01836 443.76771 565.49297 443.97474 565.92657 444.24817 curveto +565.92657 445.50793 lineto +565.48907 445.13685 565.02422 444.85755 564.53204 444.67004 curveto +564.03985 444.48255 563.52227 444.3888 562.97931 444.38879 curveto +561.90899 444.3888 561.10431 444.68763 560.56525 445.28528 curveto +560.03009 445.88294 559.76251 446.77357 559.76251 447.95715 curveto +559.76251 449.13684 560.03009 450.02551 560.56525 450.62317 curveto +561.10431 451.22083 561.90899 451.51965 562.97931 451.51965 curveto +563.39727 451.51965 563.77032 451.4845 564.09845 451.41418 curveto +564.42657 451.33997 564.72149 451.22669 564.98322 451.07434 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +567.73126 448.55481 moveto +570.88947 448.55481 lineto +570.88947 449.51575 lineto +567.73126 449.51575 lineto +567.73126 448.55481 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +577.32306 449.047 moveto +577.32305 448.25403 577.15899 447.63294 576.83087 447.18372 curveto +576.50665 446.7306 576.05938 446.50403 575.48907 446.50403 curveto +574.91876 446.50403 574.46954 446.7306 574.14142 447.18372 curveto +573.8172 447.63294 573.65509 448.25403 573.65509 449.047 curveto +573.65509 449.83997 573.8172 450.46301 574.14142 450.91614 curveto +574.46954 451.36536 574.91876 451.58997 575.48907 451.58997 curveto +576.05938 451.58997 576.50665 451.36536 576.83087 450.91614 curveto +577.15899 450.46301 577.32305 449.83997 577.32306 449.047 curveto +573.65509 446.75598 moveto +573.88165 446.36536 574.16681 446.0763 574.51056 445.88879 curveto +574.85821 445.69739 575.27227 445.60169 575.75275 445.60168 curveto +576.54962 445.60169 577.1961 445.9181 577.6922 446.5509 curveto +578.19219 447.18372 578.44219 448.01575 578.4422 449.047 curveto +578.44219 450.07825 578.19219 450.91028 577.6922 451.54309 curveto +577.1961 452.1759 576.54962 452.49231 575.75275 452.49231 curveto +575.27227 452.49231 574.85821 452.39856 574.51056 452.21106 curveto +574.16681 452.01965 573.88165 451.72864 573.65509 451.33801 curveto +573.65509 452.32239 lineto +572.57111 452.32239 lineto +572.57111 443.2052 lineto +573.65509 443.2052 lineto +573.65509 446.75598 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +583.21173 449.02356 moveto +582.34063 449.02356 581.73712 449.12317 581.40118 449.32239 curveto +581.06524 449.52161 580.89728 449.86145 580.89728 450.34192 curveto +580.89728 450.72473 581.02228 451.02942 581.27228 451.25598 curveto +581.52618 451.47864 581.86993 451.58997 582.30353 451.58997 curveto +582.90118 451.58997 583.3797 451.37903 583.73907 450.95715 curveto +584.10235 450.53137 584.28399 449.96692 584.284 449.26379 curveto +584.284 449.02356 lineto +583.21173 449.02356 lineto +585.36212 448.57825 moveto +585.36212 452.32239 lineto +584.284 452.32239 lineto +584.284 451.32629 lineto +584.0379 451.72473 583.73126 452.01965 583.36407 452.21106 curveto +582.99688 452.39856 582.54767 452.49231 582.01642 452.49231 curveto +581.34454 452.49231 580.80939 452.30481 580.41095 451.92981 curveto +580.01642 451.5509 579.81915 451.04505 579.81915 450.41223 curveto +579.81915 449.67395 580.06525 449.11731 580.55743 448.74231 curveto +581.05353 448.36731 581.79181 448.17981 582.77228 448.17981 curveto +584.284 448.17981 lineto +584.284 448.07434 lineto +584.28399 447.57825 584.11993 447.19544 583.79181 446.9259 curveto +583.46759 446.65247 583.01056 446.51575 582.42072 446.51575 curveto +582.04571 446.51575 581.68048 446.56067 581.32501 446.65051 curveto +580.96954 446.74036 580.62775 446.87513 580.29962 447.05481 curveto +580.29962 446.05872 lineto +580.69415 445.90638 581.07696 445.7931 581.44806 445.71887 curveto +581.81915 445.64075 582.18048 445.60169 582.53204 445.60168 curveto +583.48126 445.60169 584.19024 445.84778 584.659 446.33997 curveto +585.12774 446.83216 585.36212 447.57825 585.36212 448.57825 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +591.79572 445.95325 moveto +591.79572 446.97278 lineto +591.49102 446.81653 591.17462 446.69935 590.8465 446.62122 curveto +590.51837 446.5431 590.17852 446.50403 589.82697 446.50403 curveto +589.29181 446.50403 588.88946 446.58607 588.61993 446.75012 curveto +588.35431 446.91419 588.22149 447.16028 588.2215 447.4884 curveto +588.22149 447.73841 588.3172 447.93567 588.50861 448.0802 curveto +588.70001 448.22083 589.08478 448.35559 589.6629 448.4845 curveto +590.03204 448.56653 lineto +590.79766 448.73059 591.34063 448.96302 591.66095 449.26379 curveto +591.98516 449.56067 592.14727 449.97669 592.14728 450.51184 curveto +592.14727 451.12122 591.90508 451.60364 591.42072 451.95911 curveto +590.94024 452.31458 590.27813 452.49231 589.43439 452.49231 curveto +589.08282 452.49231 588.71563 452.45715 588.33282 452.38684 curveto +587.95392 452.32043 587.55353 452.21887 587.13165 452.08215 curveto +587.13165 450.96887 lineto +587.53009 451.1759 587.92267 451.33215 588.30939 451.43762 curveto +588.6961 451.53919 589.07892 451.58997 589.45782 451.58997 curveto +589.96563 451.58997 590.35626 451.50403 590.6297 451.33215 curveto +590.90313 451.15637 591.03985 450.91028 591.03986 450.59387 curveto +591.03985 450.30091 590.94024 450.0763 590.74103 449.92004 curveto +590.54571 449.7638 590.11407 449.61341 589.44611 449.46887 curveto +589.07111 449.38098 lineto +588.40314 449.24036 587.92071 449.02552 587.62384 448.73645 curveto +587.32696 448.44349 587.17853 448.0431 587.17853 447.53528 curveto +587.17853 446.9181 587.39728 446.44153 587.83478 446.10559 curveto +588.27228 445.76966 588.89337 445.60169 589.69806 445.60168 curveto +590.09649 445.60169 590.47149 445.63099 590.82306 445.68958 curveto +591.17462 445.74818 591.49884 445.83607 591.79572 445.95325 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +599.48322 448.77161 moveto +599.48322 449.29895 lineto +594.52618 449.29895 lineto +594.57306 450.04114 594.79571 450.60755 595.19415 450.99817 curveto +595.59649 451.38489 596.15509 451.57825 596.86993 451.57825 curveto +597.28399 451.57825 597.68438 451.52747 598.07111 451.4259 curveto +598.46173 451.32434 598.84844 451.172 599.23126 450.96887 curveto +599.23126 451.9884 lineto +598.84454 452.15247 598.44805 452.27747 598.04181 452.3634 curveto +597.63555 452.44934 597.22345 452.49231 596.80548 452.49231 curveto +595.7586 452.49231 594.92853 452.18762 594.31525 451.57825 curveto +593.70587 450.96887 593.40118 450.14466 593.40118 449.10559 curveto +593.40118 448.03138 593.69025 447.17981 594.26837 446.5509 curveto +594.8504 445.9181 595.6336 445.60169 596.61798 445.60168 curveto +597.50079 445.60169 598.19805 445.88685 598.70978 446.45715 curveto +599.2254 447.02356 599.48321 447.79505 599.48322 448.77161 curveto +598.40509 448.4552 moveto +598.39727 447.86536 598.23126 447.39466 597.90704 447.04309 curveto +597.58673 446.69153 597.16095 446.51575 596.6297 446.51575 curveto +596.02813 446.51575 595.54571 446.68567 595.18243 447.02551 curveto +594.82306 447.36536 594.61603 447.84388 594.56134 448.46106 curveto +598.40509 448.4552 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +605.54767 446.75598 moveto +605.54767 443.2052 lineto +606.62579 443.2052 lineto +606.62579 452.32239 lineto +605.54767 452.32239 lineto +605.54767 451.33801 lineto +605.3211 451.72864 605.03399 452.01965 604.68634 452.21106 curveto +604.34259 452.39856 603.92852 452.49231 603.44415 452.49231 curveto +602.65118 452.49231 602.0047 452.1759 601.5047 451.54309 curveto +601.00861 450.91028 600.76056 450.07825 600.76056 449.047 curveto +600.76056 448.01575 601.00861 447.18372 601.5047 446.5509 curveto +602.0047 445.9181 602.65118 445.60169 603.44415 445.60168 curveto +603.92852 445.60169 604.34259 445.69739 604.68634 445.88879 curveto +605.03399 446.0763 605.3211 446.36536 605.54767 446.75598 curveto +601.87384 449.047 moveto +601.87384 449.83997 602.03595 450.46301 602.36017 450.91614 curveto +602.68829 451.36536 603.13751 451.58997 603.70782 451.58997 curveto +604.27813 451.58997 604.72735 451.36536 605.05548 450.91614 curveto +605.3836 450.46301 605.54766 449.83997 605.54767 449.047 curveto +605.54766 448.25403 605.3836 447.63294 605.05548 447.18372 curveto +604.72735 446.7306 604.27813 446.50403 603.70782 446.50403 curveto +603.13751 446.50403 602.68829 446.7306 602.36017 447.18372 curveto +602.03595 447.63294 601.87384 448.25403 601.87384 449.047 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +613.70978 451.33801 moveto +613.70978 454.81848 lineto +612.62579 454.81848 lineto +612.62579 445.75989 lineto +613.70978 445.75989 lineto +613.70978 446.75598 lineto +613.93634 446.36536 614.22149 446.0763 614.56525 445.88879 curveto +614.9129 445.69739 615.32696 445.60169 615.80743 445.60168 curveto +616.6043 445.60169 617.25079 445.9181 617.74689 446.5509 curveto +618.24688 447.18372 618.49688 448.01575 618.49689 449.047 curveto +618.49688 450.07825 618.24688 450.91028 617.74689 451.54309 curveto +617.25079 452.1759 616.6043 452.49231 615.80743 452.49231 curveto +615.32696 452.49231 614.9129 452.39856 614.56525 452.21106 curveto +614.22149 452.01965 613.93634 451.72864 613.70978 451.33801 curveto +617.37775 449.047 moveto +617.37774 448.25403 617.21368 447.63294 616.88556 447.18372 curveto +616.56134 446.7306 616.11407 446.50403 615.54376 446.50403 curveto +614.97345 446.50403 614.52423 446.7306 614.19611 447.18372 curveto +613.87188 447.63294 613.70978 448.25403 613.70978 449.047 curveto +613.70978 449.83997 613.87188 450.46301 614.19611 450.91614 curveto +614.52423 451.36536 614.97345 451.58997 615.54376 451.58997 curveto +616.11407 451.58997 616.56134 451.36536 616.88556 450.91614 curveto +617.21368 450.46301 617.37774 449.83997 617.37775 449.047 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +620.284 443.2052 moveto +621.36212 443.2052 lineto +621.36212 452.32239 lineto +620.284 452.32239 lineto +620.284 443.2052 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +623.50079 449.73254 moveto +623.50079 445.75989 lineto +624.57892 445.75989 lineto +624.57892 449.69153 lineto +624.57892 450.31262 624.70001 450.77942 624.9422 451.09192 curveto +625.18438 451.40051 625.54767 451.55481 626.03204 451.55481 curveto +626.61407 451.55481 627.07305 451.36926 627.409 450.99817 curveto +627.74884 450.62708 627.91876 450.12122 627.91876 449.48059 curveto +627.91876 445.75989 lineto +628.99689 445.75989 lineto +628.99689 452.32239 lineto +627.91876 452.32239 lineto +627.91876 451.31458 lineto +627.65704 451.71301 627.35235 452.00989 627.0047 452.2052 curveto +626.66095 452.39661 626.26056 452.49231 625.80353 452.49231 curveto +625.04962 452.49231 624.47735 452.25793 624.08673 451.78918 curveto +623.6961 451.32044 623.50079 450.63489 623.50079 449.73254 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +635.54767 448.96497 moveto +635.54766 448.18372 635.38555 447.57825 635.06134 447.14856 curveto +634.74102 446.71888 634.28985 446.50403 633.70782 446.50403 curveto +633.1297 446.50403 632.67853 446.71888 632.35431 447.14856 curveto +632.03399 447.57825 631.87384 448.18372 631.87384 448.96497 curveto +631.87384 449.74231 632.03399 450.34583 632.35431 450.77551 curveto +632.67853 451.2052 633.1297 451.42004 633.70782 451.42004 curveto +634.28985 451.42004 634.74102 451.2052 635.06134 450.77551 curveto +635.38555 450.34583 635.54766 449.74231 635.54767 448.96497 curveto +636.62579 451.50793 moveto +636.62579 452.62512 636.37774 453.4552 635.88165 453.99817 curveto +635.38555 454.54504 634.62579 454.81848 633.60236 454.81848 curveto +633.22345 454.81848 632.86603 454.78918 632.53009 454.73059 curveto +632.19415 454.6759 631.86798 454.58996 631.55157 454.47278 curveto +631.55157 453.42395 lineto +631.86798 453.59582 632.18048 453.72278 632.48907 453.80481 curveto +632.79767 453.88684 633.11212 453.92785 633.43243 453.92786 curveto +634.13946 453.92785 634.66876 453.74231 635.02032 453.37122 curveto +635.37188 453.00403 635.54766 452.44739 635.54767 451.70129 curveto +635.54767 451.16809 lineto +635.32501 451.55481 635.03985 451.84387 634.6922 452.03528 curveto +634.34454 452.22668 633.92852 452.32239 633.44415 452.32239 curveto +632.63946 452.32239 631.99103 452.01575 631.49884 451.40247 curveto +631.00665 450.78919 630.76056 449.97669 630.76056 448.96497 curveto +630.76056 447.94935 631.00665 447.13489 631.49884 446.52161 curveto +631.99103 445.90833 632.63946 445.60169 633.44415 445.60168 curveto +633.92852 445.60169 634.34454 445.69739 634.6922 445.88879 curveto +635.03985 446.08021 635.32501 446.36927 635.54767 446.75598 curveto +635.54767 445.75989 lineto +636.62579 445.75989 lineto +636.62579 451.50793 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +638.8465 445.75989 moveto +639.92462 445.75989 lineto +639.92462 452.32239 lineto +638.8465 452.32239 lineto +638.8465 445.75989 lineto +638.8465 443.2052 moveto +639.92462 443.2052 lineto +639.92462 444.57043 lineto +638.8465 444.57043 lineto +638.8465 443.2052 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +647.6297 448.36145 moveto +647.6297 452.32239 lineto +646.55157 452.32239 lineto +646.55157 448.39661 lineto +646.55157 447.77552 646.43048 447.31067 646.18829 447.00208 curveto +645.9461 446.69349 645.58282 446.53919 645.09845 446.53918 curveto +644.51641 446.53919 644.05743 446.72474 643.7215 447.09583 curveto +643.38556 447.46692 643.21759 447.97278 643.21759 448.6134 curveto +643.21759 452.32239 lineto +642.13361 452.32239 lineto +642.13361 445.75989 lineto +643.21759 445.75989 lineto +643.21759 446.77942 lineto +643.4754 446.38489 643.77813 446.08997 644.12579 445.89465 curveto +644.47735 445.69935 644.88165 445.60169 645.33868 445.60168 curveto +646.09259 445.60169 646.6629 445.83607 647.04962 446.30481 curveto +647.43633 446.76966 647.62969 447.45521 647.6297 448.36145 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +0.87437826 setlinewidth +0 setlinejoin +0 setlinecap +newpath +69.640457 429.9487 moveto +238.52138 429.9487 lineto +238.52138 587.29974 lineto +69.640457 587.29974 lineto +69.640457 429.9487 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +119.57101 463.82449 moveto +117.96555 468.17801 lineto +121.18234 468.17801 lineto +119.57101 463.82449 lineto +118.90305 462.65848 moveto +120.24484 462.65848 lineto +123.57883 471.40652 lineto +122.34836 471.40652 lineto +121.55148 469.16238 lineto +117.60812 469.16238 lineto +116.81125 471.40652 lineto +115.5632 471.40652 lineto +118.90305 462.65848 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +125.84641 470.42215 moveto +125.84641 473.90262 lineto +124.76242 473.90262 lineto +124.76242 464.84402 lineto +125.84641 464.84402 lineto +125.84641 465.84012 lineto +126.07297 465.4495 126.35812 465.16044 126.70187 464.97293 curveto +127.04953 464.78153 127.46359 464.68583 127.94406 464.68582 curveto +128.74093 464.68583 129.38741 465.00223 129.88351 465.63504 curveto +130.38351 466.26786 130.63351 467.09989 130.63351 468.13113 curveto +130.63351 469.16239 130.38351 469.99442 129.88351 470.62723 curveto +129.38741 471.26004 128.74093 471.57645 127.94406 471.57645 curveto +127.46359 471.57645 127.04953 471.4827 126.70187 471.2952 curveto +126.35812 471.10379 126.07297 470.81278 125.84641 470.42215 curveto +129.51437 468.13113 moveto +129.51437 467.33817 129.35031 466.71708 129.02219 466.26785 curveto +128.69796 465.81473 128.2507 465.58817 127.68039 465.58817 curveto +127.11007 465.58817 126.66086 465.81473 126.33273 466.26785 curveto +126.00851 466.71708 125.8464 467.33817 125.84641 468.13113 curveto +125.8464 468.92411 126.00851 469.54715 126.33273 470.00027 curveto +126.66086 470.44949 127.11007 470.6741 127.68039 470.6741 curveto +128.2507 470.6741 128.69796 470.44949 129.02219 470.00027 curveto +129.35031 469.54715 129.51437 468.92411 129.51437 468.13113 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +133.46359 470.42215 moveto +133.46359 473.90262 lineto +132.37961 473.90262 lineto +132.37961 464.84402 lineto +133.46359 464.84402 lineto +133.46359 465.84012 lineto +133.69015 465.4495 133.97531 465.16044 134.31906 464.97293 curveto +134.66671 464.78153 135.08078 464.68583 135.56125 464.68582 curveto +136.35812 464.68583 137.0046 465.00223 137.5007 465.63504 curveto +138.0007 466.26786 138.25069 467.09989 138.2507 468.13113 curveto +138.25069 469.16239 138.0007 469.99442 137.5007 470.62723 curveto +137.0046 471.26004 136.35812 471.57645 135.56125 471.57645 curveto +135.08078 471.57645 134.66671 471.4827 134.31906 471.2952 curveto +133.97531 471.10379 133.69015 470.81278 133.46359 470.42215 curveto +137.13156 468.13113 moveto +137.13156 467.33817 136.96749 466.71708 136.63937 466.26785 curveto +136.31515 465.81473 135.86788 465.58817 135.29758 465.58817 curveto +134.72726 465.58817 134.27804 465.81473 133.94992 466.26785 curveto +133.6257 466.71708 133.46359 467.33817 133.46359 468.13113 curveto +133.46359 468.92411 133.6257 469.54715 133.94992 470.00027 curveto +134.27804 470.44949 134.72726 470.6741 135.29758 470.6741 curveto +135.86788 470.6741 136.31515 470.44949 136.63937 470.00027 curveto +136.96749 469.54715 137.13156 468.92411 137.13156 468.13113 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +140.03781 462.28934 moveto +141.11594 462.28934 lineto +141.11594 471.40652 lineto +140.03781 471.40652 lineto +140.03781 462.28934 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +143.36594 464.84402 moveto +144.44406 464.84402 lineto +144.44406 471.40652 lineto +143.36594 471.40652 lineto +143.36594 464.84402 lineto +143.36594 462.28934 moveto +144.44406 462.28934 lineto +144.44406 463.65457 lineto +143.36594 463.65457 lineto +143.36594 462.28934 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +151.41672 465.09598 moveto +151.41672 466.10379 lineto +151.11202 465.93583 150.80538 465.81083 150.4968 465.72879 curveto +150.1921 465.64286 149.88351 465.59989 149.57101 465.59988 curveto +148.87179 465.59989 148.32882 465.82255 147.94211 466.26785 curveto +147.55539 466.70926 147.36203 467.33036 147.36203 468.13113 curveto +147.36203 468.93192 147.55539 469.55496 147.94211 470.00027 curveto +148.32882 470.44168 148.87179 470.66238 149.57101 470.66238 curveto +149.88351 470.66238 150.1921 470.62137 150.4968 470.53934 curveto +150.80538 470.4534 151.11202 470.32645 151.41672 470.15848 curveto +151.41672 471.15457 lineto +151.11593 471.2952 150.80343 471.40067 150.47922 471.47098 curveto +150.1589 471.54129 149.8171 471.57645 149.45383 471.57645 curveto +148.46554 471.57645 147.68039 471.2659 147.09836 470.64481 curveto +146.51633 470.02371 146.22531 469.18582 146.22531 468.13113 curveto +146.22531 467.06083 146.51828 466.21903 147.10422 465.60574 curveto +147.69406 464.99247 148.5007 464.68583 149.52414 464.68582 curveto +149.85617 464.68583 150.18038 464.72098 150.4968 464.79129 curveto +150.8132 464.8577 151.11984 464.95927 151.41672 465.09598 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +156.28586 468.1077 moveto +155.41476 468.1077 154.81125 468.20731 154.47531 468.40652 curveto +154.13937 468.60575 153.9714 468.94559 153.97141 469.42606 curveto +153.9714 469.80887 154.0964 470.11356 154.34641 470.34012 curveto +154.60031 470.56278 154.94406 470.6741 155.37766 470.6741 curveto +155.97531 470.6741 156.45382 470.46317 156.8132 470.04129 curveto +157.17648 469.61551 157.35812 469.05106 157.35812 468.34793 curveto +157.35812 468.1077 lineto +156.28586 468.1077 lineto +158.43625 467.66238 moveto +158.43625 471.40652 lineto +157.35812 471.40652 lineto +157.35812 470.41043 lineto +157.11203 470.80887 156.80538 471.10379 156.4382 471.2952 curveto +156.07101 471.4827 155.62179 471.57645 155.09055 471.57645 curveto +154.41867 471.57645 153.88351 471.38895 153.48508 471.01395 curveto +153.09054 470.63504 152.89328 470.12918 152.89328 469.49637 curveto +152.89328 468.75809 153.13937 468.20145 153.63156 467.82645 curveto +154.12765 467.45145 154.86593 467.26395 155.84641 467.26395 curveto +157.35812 467.26395 lineto +157.35812 467.15848 lineto +157.35812 466.66239 157.19406 466.27958 156.86594 466.01004 curveto +156.54171 465.73661 156.08468 465.59989 155.49484 465.59988 curveto +155.11984 465.59989 154.75461 465.64481 154.39914 465.73465 curveto +154.04367 465.8245 153.70187 465.95926 153.37375 466.13895 curveto +153.37375 465.14285 lineto +153.76828 464.99052 154.15109 464.87723 154.52219 464.80301 curveto +154.89328 464.72489 155.25461 464.68583 155.60617 464.68582 curveto +156.55539 464.68583 157.26437 464.93192 157.73312 465.4241 curveto +158.20187 465.9163 158.43624 466.66239 158.43625 467.66238 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +161.75266 462.98074 moveto +161.75266 464.84402 lineto +163.97336 464.84402 lineto +163.97336 465.68192 lineto +161.75266 465.68192 lineto +161.75266 469.24442 lineto +161.75265 469.77957 161.82492 470.12332 161.96945 470.27567 curveto +162.11789 470.42801 162.41671 470.50418 162.86594 470.50418 curveto +163.97336 470.50418 lineto +163.97336 471.40652 lineto +162.86594 471.40652 lineto +162.0339 471.40652 161.45968 471.25223 161.14328 470.94363 curveto +160.82687 470.63113 160.66867 470.06473 160.66867 469.24442 curveto +160.66867 465.68192 lineto +159.87766 465.68192 lineto +159.87766 464.84402 lineto +160.66867 464.84402 lineto +160.66867 462.98074 lineto +161.75266 462.98074 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +165.39719 464.84402 moveto +166.47531 464.84402 lineto +166.47531 471.40652 lineto +165.39719 471.40652 lineto +165.39719 464.84402 lineto +165.39719 462.28934 moveto +166.47531 462.28934 lineto +166.47531 463.65457 lineto +165.39719 463.65457 lineto +165.39719 462.28934 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +171.26828 465.59988 moveto +170.69015 465.59989 170.23312 465.82645 169.89719 466.27957 curveto +169.56125 466.72879 169.39328 467.34598 169.39328 468.13113 curveto +169.39328 468.91629 169.55929 469.53543 169.89133 469.98856 curveto +170.22726 470.43778 170.68625 470.66238 171.26828 470.66238 curveto +171.84249 470.66238 172.29757 470.43582 172.63351 469.9827 curveto +172.96945 469.52957 173.13742 468.91239 173.13742 468.13113 curveto +173.13742 467.35379 172.96945 466.73856 172.63351 466.28543 curveto +172.29757 465.82841 171.84249 465.59989 171.26828 465.59988 curveto +171.26828 464.68582 moveto +172.20578 464.68583 172.9421 464.99052 173.47726 465.59988 curveto +174.01241 466.20926 174.27999 467.05301 174.28 468.13113 curveto +174.27999 469.20535 174.01241 470.0491 173.47726 470.66238 curveto +172.9421 471.27176 172.20578 471.57645 171.26828 471.57645 curveto +170.32687 471.57645 169.58859 471.27176 169.05344 470.66238 curveto +168.52219 470.0491 168.25656 469.20535 168.25656 468.13113 curveto +168.25656 467.05301 168.52219 466.20926 169.05344 465.59988 curveto +169.58859 464.99052 170.32687 464.68583 171.26828 464.68582 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +181.51633 467.44559 moveto +181.51633 471.40652 lineto +180.4382 471.40652 lineto +180.4382 467.48074 lineto +180.4382 466.85965 180.3171 466.39481 180.07492 466.08621 curveto +179.83273 465.77762 179.46945 465.62333 178.98508 465.62332 curveto +178.40304 465.62333 177.94406 465.80887 177.60812 466.17996 curveto +177.27218 466.55106 177.10422 467.05692 177.10422 467.69754 curveto +177.10422 471.40652 lineto +176.02023 471.40652 lineto +176.02023 464.84402 lineto +177.10422 464.84402 lineto +177.10422 465.86356 lineto +177.36203 465.46903 177.66476 465.17411 178.01242 464.97879 curveto +178.36398 464.78348 178.76828 464.68583 179.22531 464.68582 curveto +179.97921 464.68583 180.54952 464.9202 180.93625 465.38895 curveto +181.32296 465.8538 181.51632 466.53934 181.51633 467.44559 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +0.9484126 setlinewidth +0 setlinejoin +0 setlinecap +newpath +69.672821 587.35339 moveto +238.48438 587.35339 lineto +238.48438 629.87459 lineto +69.672821 629.87459 lineto +69.672821 587.35339 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +100.23355 598.61139 moveto +100.23355 599.85944 lineto +99.835106 599.48835 99.409325 599.21101 98.956207 599.0274 curveto +98.506983 598.84382 98.028467 598.75202 97.52066 598.75201 curveto +96.520656 598.75202 95.755032 599.05866 95.223785 599.67194 curveto +94.692533 600.28132 94.426908 601.16413 94.42691 602.32037 curveto +94.426908 603.47272 94.692533 604.35553 95.223785 604.96881 curveto +95.755032 605.57819 96.520656 605.88287 97.52066 605.88287 curveto +98.028467 605.88287 98.506983 605.79108 98.956207 605.60748 curveto +99.409325 605.42389 99.835106 605.14655 100.23355 604.77545 curveto +100.23355 606.01178 lineto +99.819481 606.29303 99.380029 606.50397 98.915192 606.64459 curveto +98.454248 606.78522 97.965967 606.85553 97.450348 606.85553 curveto +96.126126 606.85553 95.083158 606.45123 94.321442 605.64264 curveto +93.559722 604.83014 93.178863 603.72272 93.178864 602.32037 curveto +93.178863 600.91413 93.559722 599.80671 94.321442 598.99811 curveto +95.083158 598.18562 96.126126 597.77937 97.450348 597.77936 curveto +97.97378 597.77937 98.465967 597.84968 98.92691 597.9903 curveto +99.391747 598.12702 99.827294 598.33405 100.23355 598.61139 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +102.02652 597.56842 moveto +103.10464 597.56842 lineto +103.10464 606.68561 lineto +102.02652 606.68561 lineto +102.02652 597.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +105.35464 600.12311 moveto +106.43277 600.12311 lineto +106.43277 606.68561 lineto +105.35464 606.68561 lineto +105.35464 600.12311 lineto +105.35464 597.56842 moveto +106.43277 597.56842 lineto +106.43277 598.93365 lineto +105.35464 598.93365 lineto +105.35464 597.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +114.29605 603.13483 moveto +114.29605 603.66217 lineto +109.33902 603.66217 lineto +109.38589 604.40436 109.60855 604.97077 110.00699 605.36139 curveto +110.40933 605.74811 110.96792 605.94147 111.68277 605.94147 curveto +112.09683 605.94147 112.49722 605.89069 112.88394 605.78912 curveto +113.27456 605.68756 113.66128 605.53522 114.0441 605.33209 curveto +114.0441 606.35162 lineto +113.65737 606.51569 113.26089 606.64069 112.85464 606.72662 curveto +112.44839 606.81256 112.03628 606.85553 111.61832 606.85553 curveto +110.57144 606.85553 109.74136 606.55084 109.12808 605.94147 curveto +108.51871 605.33209 108.21402 604.50788 108.21402 603.46881 curveto +108.21402 602.3946 108.50308 601.54303 109.08121 600.91412 curveto +109.66324 600.28132 110.44644 599.96491 111.43082 599.9649 curveto +112.31362 599.96491 113.01089 600.25007 113.52261 600.82037 curveto +114.03823 601.38679 114.29604 602.15827 114.29605 603.13483 curveto +113.21793 602.81842 moveto +113.21011 602.22858 113.04409 601.75788 112.71988 601.40631 curveto +112.39956 601.05475 111.97378 600.87897 111.44254 600.87897 curveto +110.84097 600.87897 110.35855 601.04889 109.99527 601.38873 curveto +109.63589 601.72858 109.42886 602.2071 109.37418 602.82428 curveto +113.21793 602.81842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +121.49722 602.72467 moveto +121.49722 606.68561 lineto +120.4191 606.68561 lineto +120.4191 602.75983 lineto +120.41909 602.13874 120.298 601.67389 120.05582 601.3653 curveto +119.81362 601.05671 119.45034 600.90241 118.96597 600.9024 curveto +118.38394 600.90241 117.92495 601.08796 117.58902 601.45905 curveto +117.25308 601.83014 117.08511 602.336 117.08511 602.97662 curveto +117.08511 606.68561 lineto +116.00113 606.68561 lineto +116.00113 600.12311 lineto +117.08511 600.12311 lineto +117.08511 601.14264 lineto +117.34292 600.74811 117.64566 600.45319 117.99332 600.25787 curveto +118.34488 600.06257 118.74917 599.96491 119.20621 599.9649 curveto +119.96011 599.96491 120.53042 600.19929 120.91714 600.66803 curveto +121.30386 601.13288 121.49722 601.81843 121.49722 602.72467 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +124.72574 598.25983 moveto +124.72574 600.12311 lineto +126.94644 600.12311 lineto +126.94644 600.961 lineto +124.72574 600.961 lineto +124.72574 604.5235 lineto +124.72574 605.05866 124.798 605.40241 124.94254 605.55475 curveto +125.09097 605.70709 125.3898 605.78327 125.83902 605.78326 curveto +126.94644 605.78326 lineto +126.94644 606.68561 lineto +125.83902 606.68561 lineto +125.00699 606.68561 124.43277 606.53131 124.11636 606.22272 curveto +123.79996 605.91022 123.64175 605.34381 123.64175 604.5235 curveto +123.64175 600.961 lineto +122.85074 600.961 lineto +122.85074 600.12311 lineto +123.64175 600.12311 lineto +123.64175 598.25983 lineto +124.72574 598.25983 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +127.82535 602.91803 moveto +130.98355 602.91803 lineto +130.98355 603.87897 lineto +127.82535 603.87897 lineto +127.82535 602.91803 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +136.8898 600.31647 moveto +136.8898 601.336 lineto +136.58511 601.17975 136.2687 601.06257 135.94058 600.98444 curveto +135.61245 600.90632 135.27261 600.86725 134.92105 600.86725 curveto +134.38589 600.86725 133.98355 600.94929 133.71402 601.11334 curveto +133.44839 601.27741 133.31558 601.5235 133.31558 601.85162 curveto +133.31558 602.10163 133.41128 602.29889 133.60269 602.44342 curveto +133.7941 602.58405 134.17886 602.71882 134.75699 602.84772 curveto +135.12613 602.92975 lineto +135.89175 603.09381 136.43472 603.32624 136.75504 603.62701 curveto +137.07925 603.92389 137.24136 604.33991 137.24136 604.87506 curveto +137.24136 605.48444 136.99917 605.96686 136.5148 606.32233 curveto +136.03433 606.6778 135.37222 606.85553 134.52847 606.85553 curveto +134.17691 606.85553 133.80972 606.82037 133.42691 606.75006 curveto +133.048 606.68365 132.64761 606.58209 132.22574 606.44537 curveto +132.22574 605.33209 lineto +132.62417 605.53912 133.01675 605.69537 133.40347 605.80084 curveto +133.79019 605.90241 134.173 605.95319 134.55191 605.95319 curveto +135.05972 605.95319 135.45034 605.86725 135.72379 605.69537 curveto +135.99722 605.51959 136.13394 605.2735 136.13394 604.95709 curveto +136.13394 604.66413 136.03433 604.43952 135.83511 604.28326 curveto +135.6398 604.12702 135.20816 603.97663 134.54019 603.83209 curveto +134.16519 603.7442 lineto +133.49722 603.60358 133.0148 603.38874 132.71793 603.09967 curveto +132.42105 602.80671 132.27261 602.40632 132.27261 601.8985 curveto +132.27261 601.28132 132.49136 600.80475 132.92886 600.46881 curveto +133.36636 600.13288 133.98745 599.96491 134.79214 599.9649 curveto +135.19058 599.96491 135.56558 599.99421 135.91714 600.0528 curveto +136.2687 600.1114 136.59292 600.19929 136.8898 600.31647 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +138.96402 600.12311 moveto +140.04214 600.12311 lineto +140.04214 606.68561 lineto +138.96402 606.68561 lineto +138.96402 600.12311 lineto +138.96402 597.56842 moveto +140.04214 597.56842 lineto +140.04214 598.93365 lineto +138.96402 598.93365 lineto +138.96402 597.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +146.6105 601.1192 moveto +146.6105 597.56842 lineto +147.68863 597.56842 lineto +147.68863 606.68561 lineto +146.6105 606.68561 lineto +146.6105 605.70123 lineto +146.38394 606.09186 146.09683 606.38287 145.74918 606.57428 curveto +145.40542 606.76178 144.99136 606.85553 144.50699 606.85553 curveto +143.71402 606.85553 143.06753 606.53912 142.56754 605.90631 curveto +142.07144 605.2735 141.82339 604.44147 141.82339 603.41022 curveto +141.82339 602.37897 142.07144 601.54694 142.56754 600.91412 curveto +143.06753 600.28132 143.71402 599.96491 144.50699 599.9649 curveto +144.99136 599.96491 145.40542 600.06061 145.74918 600.25201 curveto +146.09683 600.43952 146.38394 600.72858 146.6105 601.1192 curveto +142.93668 603.41022 moveto +142.93667 604.20319 143.09878 604.82623 143.423 605.27936 curveto +143.75113 605.72858 144.20034 605.95319 144.77066 605.95319 curveto +145.34097 605.95319 145.79019 605.72858 146.11832 605.27936 curveto +146.44644 604.82623 146.6105 604.20319 146.6105 603.41022 curveto +146.6105 602.61725 146.44644 601.99616 146.11832 601.54694 curveto +145.79019 601.09382 145.34097 600.86725 144.77066 600.86725 curveto +144.20034 600.86725 143.75113 601.09382 143.423 601.54694 curveto +143.09878 601.99616 142.93667 602.61725 142.93668 603.41022 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +155.52261 603.13483 moveto +155.52261 603.66217 lineto +150.56558 603.66217 lineto +150.61246 604.40436 150.83511 604.97077 151.23355 605.36139 curveto +151.63589 605.74811 152.19449 605.94147 152.90933 605.94147 curveto +153.32339 605.94147 153.72378 605.89069 154.1105 605.78912 curveto +154.50112 605.68756 154.88784 605.53522 155.27066 605.33209 curveto +155.27066 606.35162 lineto +154.88394 606.51569 154.48745 606.64069 154.08121 606.72662 curveto +153.67495 606.81256 153.26284 606.85553 152.84488 606.85553 curveto +151.798 606.85553 150.96792 606.55084 150.35464 605.94147 curveto +149.74527 605.33209 149.44058 604.50788 149.44058 603.46881 curveto +149.44058 602.3946 149.72964 601.54303 150.30777 600.91412 curveto +150.8898 600.28132 151.673 599.96491 152.65738 599.9649 curveto +153.54019 599.96491 154.23745 600.25007 154.74918 600.82037 curveto +155.26479 601.38679 155.52261 602.15827 155.52261 603.13483 curveto +154.44449 602.81842 moveto +154.43667 602.22858 154.27065 601.75788 153.94644 601.40631 curveto +153.62612 601.05475 153.20034 600.87897 152.6691 600.87897 curveto +152.06753 600.87897 151.58511 601.04889 151.22183 601.38873 curveto +150.86246 601.72858 150.65542 602.2071 150.60074 602.82428 curveto +154.44449 602.81842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +162.13199 605.70123 moveto +162.13199 609.1817 lineto +161.048 609.1817 lineto +161.048 600.12311 lineto +162.13199 600.12311 lineto +162.13199 601.1192 lineto +162.35855 600.72858 162.6437 600.43952 162.98746 600.25201 curveto +163.33511 600.06061 163.74917 599.96491 164.22964 599.9649 curveto +165.02651 599.96491 165.673 600.28132 166.1691 600.91412 curveto +166.66909 601.54694 166.91909 602.37897 166.9191 603.41022 curveto +166.91909 604.44147 166.66909 605.2735 166.1691 605.90631 curveto +165.673 606.53912 165.02651 606.85553 164.22964 606.85553 curveto +163.74917 606.85553 163.33511 606.76178 162.98746 606.57428 curveto +162.6437 606.38287 162.35855 606.09186 162.13199 605.70123 curveto +165.79996 603.41022 moveto +165.79995 602.61725 165.63589 601.99616 165.30777 601.54694 curveto +164.98355 601.09382 164.53628 600.86725 163.96597 600.86725 curveto +163.39566 600.86725 162.94644 601.09382 162.61832 601.54694 curveto +162.2941 601.99616 162.13199 602.61725 162.13199 603.41022 curveto +162.13199 604.20319 162.2941 604.82623 162.61832 605.27936 curveto +162.94644 605.72858 163.39566 605.95319 163.96597 605.95319 curveto +164.53628 605.95319 164.98355 605.72858 165.30777 605.27936 curveto +165.63589 604.82623 165.79995 604.20319 165.79996 603.41022 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +172.50894 601.13092 moveto +172.38784 601.06061 172.25503 601.00983 172.1105 600.97858 curveto +171.96987 600.94343 171.81362 600.92585 171.64175 600.92584 curveto +171.03238 600.92585 170.56363 601.12507 170.2355 601.5235 curveto +169.91128 601.91803 169.74917 602.48639 169.74918 603.22858 curveto +169.74918 606.68561 lineto +168.66519 606.68561 lineto +168.66519 600.12311 lineto +169.74918 600.12311 lineto +169.74918 601.14264 lineto +169.97574 600.74421 170.27066 600.44929 170.63394 600.25787 curveto +170.99722 600.06257 171.43863 599.96491 171.95816 599.9649 curveto +172.03237 599.96491 172.11441 599.97077 172.20425 599.98248 curveto +172.29409 599.9903 172.3937 600.00397 172.50308 600.0235 curveto +172.50894 601.13092 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +175.93668 600.87897 moveto +175.35855 600.87897 174.90152 601.10554 174.56558 601.55865 curveto +174.22964 602.00788 174.06167 602.62507 174.06168 603.41022 curveto +174.06167 604.19538 174.22769 604.81452 174.55972 605.26764 curveto +174.89566 605.71686 175.35464 605.94147 175.93668 605.94147 curveto +176.51089 605.94147 176.96597 605.71491 177.30191 605.26178 curveto +177.63784 604.80866 177.80581 604.19147 177.80582 603.41022 curveto +177.80581 602.63288 177.63784 602.01764 177.30191 601.56451 curveto +176.96597 601.10749 176.51089 600.87897 175.93668 600.87897 curveto +175.93668 599.9649 moveto +176.87417 599.96491 177.6105 600.2696 178.14566 600.87897 curveto +178.68081 601.48835 178.94839 602.3321 178.94839 603.41022 curveto +178.94839 604.48444 178.68081 605.32819 178.14566 605.94147 curveto +177.6105 606.55084 176.87417 606.85553 175.93668 606.85553 curveto +174.99527 606.85553 174.25699 606.55084 173.72183 605.94147 curveto +173.19058 605.32819 172.92496 604.48444 172.92496 603.41022 curveto +172.92496 602.3321 173.19058 601.48835 173.72183 600.87897 curveto +174.25699 600.2696 174.99527 599.96491 175.93668 599.9649 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +179.95621 600.12311 moveto +181.09879 600.12311 lineto +183.14957 605.63092 lineto +185.20035 600.12311 lineto +186.34293 600.12311 lineto +183.88199 606.68561 lineto +182.41714 606.68561 lineto +179.95621 600.12311 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +187.83121 600.12311 moveto +188.90933 600.12311 lineto +188.90933 606.68561 lineto +187.83121 606.68561 lineto +187.83121 600.12311 lineto +187.83121 597.56842 moveto +188.90933 597.56842 lineto +188.90933 598.93365 lineto +187.83121 598.93365 lineto +187.83121 597.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +195.47769 601.1192 moveto +195.47769 597.56842 lineto +196.55582 597.56842 lineto +196.55582 606.68561 lineto +195.47769 606.68561 lineto +195.47769 605.70123 lineto +195.25112 606.09186 194.96401 606.38287 194.61636 606.57428 curveto +194.27261 606.76178 193.85855 606.85553 193.37418 606.85553 curveto +192.5812 606.85553 191.93472 606.53912 191.43472 605.90631 curveto +190.93863 605.2735 190.69058 604.44147 190.69058 603.41022 curveto +190.69058 602.37897 190.93863 601.54694 191.43472 600.91412 curveto +191.93472 600.28132 192.5812 599.96491 193.37418 599.9649 curveto +193.85855 599.96491 194.27261 600.06061 194.61636 600.25201 curveto +194.96401 600.43952 195.25112 600.72858 195.47769 601.1192 curveto +191.80386 603.41022 moveto +191.80386 604.20319 191.96597 604.82623 192.29019 605.27936 curveto +192.61831 605.72858 193.06753 605.95319 193.63785 605.95319 curveto +194.20816 605.95319 194.65737 605.72858 194.9855 605.27936 curveto +195.31362 604.82623 195.47769 604.20319 195.47769 603.41022 curveto +195.47769 602.61725 195.31362 601.99616 194.9855 601.54694 curveto +194.65737 601.09382 194.20816 600.86725 193.63785 600.86725 curveto +193.06753 600.86725 192.61831 601.09382 192.29019 601.54694 curveto +191.96597 601.99616 191.80386 602.61725 191.80386 603.41022 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +204.3898 603.13483 moveto +204.3898 603.66217 lineto +199.43277 603.66217 lineto +199.47964 604.40436 199.7023 604.97077 200.10074 605.36139 curveto +200.50308 605.74811 201.06167 605.94147 201.77652 605.94147 curveto +202.19058 605.94147 202.59097 605.89069 202.97769 605.78912 curveto +203.36831 605.68756 203.75503 605.53522 204.13785 605.33209 curveto +204.13785 606.35162 lineto +203.75112 606.51569 203.35464 606.64069 202.94839 606.72662 curveto +202.54214 606.81256 202.13003 606.85553 201.71207 606.85553 curveto +200.66519 606.85553 199.83511 606.55084 199.22183 605.94147 curveto +198.61246 605.33209 198.30777 604.50788 198.30777 603.46881 curveto +198.30777 602.3946 198.59683 601.54303 199.17496 600.91412 curveto +199.75699 600.28132 200.54019 599.96491 201.52457 599.9649 curveto +202.40737 599.96491 203.10464 600.25007 203.61636 600.82037 curveto +204.13198 601.38679 204.38979 602.15827 204.3898 603.13483 curveto +203.31168 602.81842 moveto +203.30386 602.22858 203.13784 601.75788 202.81363 601.40631 curveto +202.49331 601.05475 202.06753 600.87897 201.53629 600.87897 curveto +200.93472 600.87897 200.4523 601.04889 200.08902 601.38873 curveto +199.72964 601.72858 199.52261 602.2071 199.46793 602.82428 curveto +203.31168 602.81842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +209.93863 601.13092 moveto +209.81753 601.06061 209.68472 601.00983 209.54019 600.97858 curveto +209.39956 600.94343 209.24331 600.92585 209.07144 600.92584 curveto +208.46206 600.92585 207.99331 601.12507 207.66519 601.5235 curveto +207.34097 601.91803 207.17886 602.48639 207.17886 603.22858 curveto +207.17886 606.68561 lineto +206.09488 606.68561 lineto +206.09488 600.12311 lineto +207.17886 600.12311 lineto +207.17886 601.14264 lineto +207.40542 600.74421 207.70035 600.44929 208.06363 600.25787 curveto +208.42691 600.06257 208.86831 599.96491 209.38785 599.9649 curveto +209.46206 599.96491 209.54409 599.97077 209.63394 599.98248 curveto +209.72378 599.9903 209.82339 600.00397 209.93277 600.0235 curveto +209.93863 601.13092 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +130.15152 612.58014 moveto +129.62808 613.47858 129.23941 614.36726 128.9855 615.24615 curveto +128.7316 616.12507 128.60464 617.01569 128.60464 617.91803 curveto +128.60464 618.82038 128.7316 619.71491 128.9855 620.60162 curveto +129.24331 621.48444 129.63199 622.37311 130.15152 623.26764 curveto +129.21402 623.26764 lineto +128.62808 622.34967 128.18863 621.44733 127.89566 620.56061 curveto +127.6066 619.67389 127.46207 618.79303 127.46207 617.91803 curveto +127.46207 617.04694 127.6066 616.16999 127.89566 615.28717 curveto +128.18472 614.40437 128.62417 613.50202 129.21402 612.58014 curveto +130.15152 612.58014 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +132.24918 615.12311 moveto +133.3273 615.12311 lineto +133.3273 621.68561 lineto +132.24918 621.68561 lineto +132.24918 615.12311 lineto +132.24918 612.56842 moveto +133.3273 612.56842 lineto +133.3273 613.93365 lineto +132.24918 613.93365 lineto +132.24918 612.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +138.89957 612.56842 moveto +138.89957 613.4649 lineto +137.86832 613.4649 lineto +137.48159 613.46491 137.21206 613.54304 137.05972 613.69928 curveto +136.91128 613.85554 136.83706 614.13679 136.83707 614.54303 curveto +136.83707 615.12311 lineto +138.61246 615.12311 lineto +138.61246 615.961 lineto +136.83707 615.961 lineto +136.83707 621.68561 lineto +135.75308 621.68561 lineto +135.75308 615.961 lineto +134.72183 615.961 lineto +134.72183 615.12311 lineto +135.75308 615.12311 lineto +135.75308 614.66608 lineto +135.75308 613.93562 135.923 613.40437 136.26285 613.07233 curveto +136.60269 612.7364 137.14175 612.56843 137.88004 612.56842 curveto +138.89957 612.56842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +143.50504 619.09576 moveto +143.50504 615.12311 lineto +144.58316 615.12311 lineto +144.58316 619.05475 lineto +144.58316 619.67584 144.70425 620.14264 144.94644 620.45514 curveto +145.18863 620.76373 145.55191 620.91803 146.03629 620.91803 curveto +146.61831 620.91803 147.0773 620.73248 147.41324 620.36139 curveto +147.75308 619.9903 147.923 619.48444 147.923 618.84381 curveto +147.923 615.12311 lineto +149.00113 615.12311 lineto +149.00113 621.68561 lineto +147.923 621.68561 lineto +147.923 620.6778 lineto +147.66128 621.07623 147.35659 621.37311 147.00894 621.56842 curveto +146.66519 621.75983 146.2648 621.85553 145.80777 621.85553 curveto +145.05386 621.85553 144.4816 621.62115 144.09097 621.1524 curveto +143.70035 620.68366 143.50503 619.99811 143.50504 619.09576 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +155.41714 615.31647 moveto +155.41714 616.336 lineto +155.11245 616.17975 154.79605 616.06257 154.46793 615.98444 curveto +154.1398 615.90632 153.79995 615.86725 153.44839 615.86725 curveto +152.91324 615.86725 152.51089 615.94929 152.24136 616.11334 curveto +151.97574 616.27741 151.84292 616.5235 151.84293 616.85162 curveto +151.84292 617.10163 151.93863 617.29889 152.13004 617.44342 curveto +152.32144 617.58405 152.7062 617.71882 153.28433 617.84772 curveto +153.65347 617.92975 lineto +154.41909 618.09381 154.96206 618.32624 155.28238 618.62701 curveto +155.60659 618.92389 155.7687 619.33991 155.76871 619.87506 curveto +155.7687 620.48444 155.52651 620.96686 155.04214 621.32233 curveto +154.56167 621.6778 153.89956 621.85553 153.05582 621.85553 curveto +152.70425 621.85553 152.33706 621.82037 151.95425 621.75006 curveto +151.57535 621.68365 151.17496 621.58209 150.75308 621.44537 curveto +150.75308 620.33209 lineto +151.15152 620.53912 151.5441 620.69537 151.93082 620.80084 curveto +152.31753 620.90241 152.70035 620.95319 153.07925 620.95319 curveto +153.58706 620.95319 153.97769 620.86725 154.25113 620.69537 curveto +154.52456 620.51959 154.66128 620.2735 154.66129 619.95709 curveto +154.66128 619.66413 154.56167 619.43952 154.36246 619.28326 curveto +154.16714 619.12702 153.7355 618.97663 153.06754 618.83209 curveto +152.69254 618.7442 lineto +152.02456 618.60358 151.54214 618.38874 151.24527 618.09967 curveto +150.94839 617.80671 150.79996 617.40632 150.79996 616.8985 curveto +150.79996 616.28132 151.01871 615.80475 151.45621 615.46881 curveto +151.89371 615.13288 152.5148 614.96491 153.31949 614.9649 curveto +153.71792 614.96491 154.09292 614.99421 154.44449 615.0528 curveto +154.79605 615.1114 155.12026 615.19929 155.41714 615.31647 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +163.10464 618.13483 moveto +163.10464 618.66217 lineto +158.14761 618.66217 lineto +158.19449 619.40436 158.41714 619.97077 158.81558 620.36139 curveto +159.21792 620.74811 159.77652 620.94147 160.49136 620.94147 curveto +160.90542 620.94147 161.30581 620.89069 161.69254 620.78912 curveto +162.08315 620.68756 162.46987 620.53522 162.85269 620.33209 curveto +162.85269 621.35162 lineto +162.46597 621.51569 162.06948 621.64069 161.66324 621.72662 curveto +161.25698 621.81256 160.84487 621.85553 160.42691 621.85553 curveto +159.38003 621.85553 158.54996 621.55084 157.93668 620.94147 curveto +157.3273 620.33209 157.02261 619.50788 157.02261 618.46881 curveto +157.02261 617.3946 157.31168 616.54303 157.8898 615.91412 curveto +158.47183 615.28132 159.25503 614.96491 160.23941 614.9649 curveto +161.12222 614.96491 161.81948 615.25007 162.33121 615.82037 curveto +162.84683 616.38679 163.10464 617.15827 163.10464 618.13483 curveto +162.02652 617.81842 moveto +162.0187 617.22858 161.85269 616.75788 161.52847 616.40631 curveto +161.20816 616.05475 160.78237 615.87897 160.25113 615.87897 curveto +159.64956 615.87897 159.16714 616.04889 158.80386 616.38873 curveto +158.44449 616.72858 158.23746 617.2071 158.18277 617.82428 curveto +162.02652 617.81842 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +169.1691 616.1192 moveto +169.1691 612.56842 lineto +170.24722 612.56842 lineto +170.24722 621.68561 lineto +169.1691 621.68561 lineto +169.1691 620.70123 lineto +168.94253 621.09186 168.65542 621.38287 168.30777 621.57428 curveto +167.96402 621.76178 167.54995 621.85553 167.06558 621.85553 curveto +166.27261 621.85553 165.62613 621.53912 165.12613 620.90631 curveto +164.63003 620.2735 164.38199 619.44147 164.38199 618.41022 curveto +164.38199 617.37897 164.63003 616.54694 165.12613 615.91412 curveto +165.62613 615.28132 166.27261 614.96491 167.06558 614.9649 curveto +167.54995 614.96491 167.96402 615.06061 168.30777 615.25201 curveto +168.65542 615.43952 168.94253 615.72858 169.1691 616.1192 curveto +165.49527 618.41022 moveto +165.49527 619.20319 165.65738 619.82623 165.9816 620.27936 curveto +166.30972 620.72858 166.75894 620.95319 167.32925 620.95319 curveto +167.89956 620.95319 168.34878 620.72858 168.67691 620.27936 curveto +169.00503 619.82623 169.16909 619.20319 169.1691 618.41022 curveto +169.16909 617.61725 169.00503 616.99616 168.67691 616.54694 curveto +168.34878 616.09382 167.89956 615.86725 167.32925 615.86725 curveto +166.75894 615.86725 166.30972 616.09382 165.9816 616.54694 curveto +165.65738 616.99616 165.49527 617.61725 165.49527 618.41022 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +172.298 612.58014 moveto +173.2355 612.58014 lineto +173.82144 613.50202 174.25894 614.40437 174.548 615.28717 curveto +174.84097 616.16999 174.98745 617.04694 174.98746 617.91803 curveto +174.98745 618.79303 174.84097 619.67389 174.548 620.56061 curveto +174.25894 621.44733 173.82144 622.34967 173.2355 623.26764 curveto +172.298 623.26764 lineto +172.81753 622.37311 173.20425 621.48444 173.45816 620.60162 curveto +173.71597 619.71491 173.84488 618.82038 173.84488 617.91803 curveto +173.84488 617.01569 173.71597 616.12507 173.45816 615.24615 curveto +173.20425 614.36726 172.81753 613.47858 172.298 612.58014 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +1 setlinewidth +0 setlinejoin +0 setlinecap +newpath +501.70806 449.88179 moveto +457.68495 449.88179 457.68495 449.88179 457.68495 449.88179 curveto +stroke +gsave [-1.1 1.347067e-16 -1.347067e-16 -1.1 500.60806 449.88179] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1 -1.347067e-16 1.347067e-16 1.1 458.78495 449.88179] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +503.70898 480.47388 moveto +687.82574 480.47388 lineto +687.82574 509.90476 lineto +503.70898 509.90476 lineto +503.70898 480.47388 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +526.79523 488.32397 moveto +525.93585 488.32398 525.25226 488.64429 524.74445 489.28491 curveto +524.24054 489.92554 523.98858 490.79859 523.98859 491.90405 curveto +523.98858 493.00562 524.24054 493.87671 524.74445 494.51733 curveto +525.25226 495.15796 525.93585 495.47827 526.79523 495.47827 curveto +527.6546 495.47827 528.33428 495.15796 528.83429 494.51733 curveto +529.33819 493.87671 529.59014 493.00562 529.59015 491.90405 curveto +529.59014 490.79859 529.33819 489.92554 528.83429 489.28491 curveto +528.33428 488.64429 527.6546 488.32398 526.79523 488.32397 curveto +526.79523 487.36304 moveto +528.02178 487.36305 529.00225 487.77515 529.73663 488.59937 curveto +530.471 489.41968 530.83819 490.52125 530.8382 491.90405 curveto +530.83819 493.28296 530.471 494.38452 529.73663 495.20874 curveto +529.00225 496.02905 528.02178 496.43921 526.79523 496.43921 curveto +525.56475 496.43921 524.58038 496.02905 523.8421 495.20874 curveto +523.10773 494.38843 522.74054 493.28687 522.74054 491.90405 curveto +522.74054 490.52125 523.10773 489.41968 523.8421 488.59937 curveto +524.58038 487.77515 525.56475 487.36305 526.79523 487.36304 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +533.68585 495.28491 moveto +533.68585 498.76538 lineto +532.60187 498.76538 lineto +532.60187 489.70679 lineto +533.68585 489.70679 lineto +533.68585 490.70288 lineto +533.91241 490.31226 534.19757 490.0232 534.54132 489.83569 curveto +534.88897 489.64429 535.30304 489.54859 535.78351 489.54858 curveto +536.58038 489.54859 537.22686 489.865 537.72296 490.4978 curveto +538.22295 491.13062 538.47295 491.96265 538.47296 492.9939 curveto +538.47295 494.02515 538.22295 494.85718 537.72296 495.48999 curveto +537.22686 496.1228 536.58038 496.43921 535.78351 496.43921 curveto +535.30304 496.43921 534.88897 496.34546 534.54132 496.15796 curveto +534.19757 495.96655 533.91241 495.67554 533.68585 495.28491 curveto +537.35382 492.9939 moveto +537.35381 492.20093 537.18975 491.57984 536.86163 491.13062 curveto +536.53741 490.6775 536.09014 490.45093 535.51984 490.45093 curveto +534.94952 490.45093 534.5003 490.6775 534.17218 491.13062 curveto +533.84796 491.57984 533.68585 492.20093 533.68585 492.9939 curveto +533.68585 493.78687 533.84796 494.40991 534.17218 494.86304 curveto +534.5003 495.31226 534.94952 495.53687 535.51984 495.53687 curveto +536.09014 495.53687 536.53741 495.31226 536.86163 494.86304 curveto +537.18975 494.40991 537.35381 493.78687 537.35382 492.9939 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +545.87335 492.71851 moveto +545.87335 493.24585 lineto +540.91632 493.24585 lineto +540.96319 493.98804 541.18585 494.55445 541.58429 494.94507 curveto +541.98663 495.33179 542.54522 495.52515 543.26007 495.52515 curveto +543.67413 495.52515 544.07452 495.47437 544.46124 495.3728 curveto +544.85186 495.27124 545.23858 495.1189 545.6214 494.91577 curveto +545.6214 495.9353 lineto +545.23467 496.09937 544.83819 496.22437 544.43195 496.3103 curveto +544.02569 496.39624 543.61358 496.43921 543.19562 496.43921 curveto +542.14874 496.43921 541.31866 496.13452 540.70538 495.52515 curveto +540.09601 494.91577 539.79132 494.09155 539.79132 493.05249 curveto +539.79132 491.97828 540.08038 491.12671 540.65851 490.4978 curveto +541.24054 489.865 542.02374 489.54859 543.00812 489.54858 curveto +543.89093 489.54859 544.58819 489.83375 545.09991 490.40405 curveto +545.61553 490.97046 545.87335 491.74195 545.87335 492.71851 curveto +544.79523 492.4021 moveto +544.78741 491.81226 544.62139 491.34156 544.29718 490.98999 curveto +543.97686 490.63843 543.55108 490.46265 543.01984 490.46265 curveto +542.41827 490.46265 541.93585 490.63257 541.57257 490.97241 curveto +541.21319 491.31226 541.00616 491.79078 540.95148 492.40796 curveto +544.79523 492.4021 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +553.07452 492.30835 moveto +553.07452 496.26929 lineto +551.9964 496.26929 lineto +551.9964 492.34351 lineto +551.99639 491.72242 551.8753 491.25757 551.63312 490.94897 curveto +551.39093 490.64039 551.02764 490.48609 550.54327 490.48608 curveto +549.96124 490.48609 549.50226 490.67164 549.16632 491.04272 curveto +548.83038 491.41382 548.66241 491.91968 548.66241 492.5603 curveto +548.66241 496.26929 lineto +547.57843 496.26929 lineto +547.57843 489.70679 lineto +548.66241 489.70679 lineto +548.66241 490.72632 lineto +548.92022 490.33179 549.22296 490.03687 549.57062 489.84155 curveto +549.92218 489.64625 550.32647 489.54859 550.78351 489.54858 curveto +551.53741 489.54859 552.10772 489.78297 552.49445 490.25171 curveto +552.88116 490.71656 553.07452 491.4021 553.07452 492.30835 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +560.52765 487.80835 moveto +560.52765 488.96265 lineto +560.07842 488.74781 559.6546 488.58765 559.25616 488.48218 curveto +558.85772 488.37672 558.47296 488.32398 558.10187 488.32397 curveto +557.45733 488.32398 556.95929 488.44898 556.60773 488.69897 curveto +556.26007 488.94898 556.08624 489.30445 556.08624 489.76538 curveto +556.08624 490.15211 556.20147 490.44507 556.43195 490.64429 curveto +556.66632 490.83961 557.10772 490.99781 557.75616 491.1189 curveto +558.47101 491.26538 lineto +559.35382 491.43335 560.00421 491.73023 560.42218 492.15601 curveto +560.84405 492.57788 561.05499 493.14429 561.05499 493.85522 curveto +561.05499 494.70288 560.76983 495.34546 560.19952 495.78296 curveto +559.63311 496.22046 558.80108 496.43921 557.70343 496.43921 curveto +557.28936 496.43921 556.84796 496.39233 556.37921 496.29858 curveto +555.91437 496.20483 555.43194 496.06616 554.93195 495.88257 curveto +554.93195 494.66382 lineto +555.41241 494.93335 555.88312 495.13648 556.34406 495.27319 curveto +556.80499 495.40991 557.25811 495.47827 557.70343 495.47827 curveto +558.37921 495.47827 558.90069 495.34546 559.26788 495.07983 curveto +559.63507 494.81421 559.81866 494.4353 559.81866 493.94312 curveto +559.81866 493.51343 559.68585 493.17749 559.42023 492.9353 curveto +559.1585 492.69312 558.72686 492.51148 558.12531 492.39038 curveto +557.4046 492.24976 lineto +556.52179 492.07398 555.88312 491.79859 555.48859 491.42358 curveto +555.09405 491.04859 554.89679 490.52711 554.89679 489.85913 curveto +554.89679 489.0857 555.16827 488.47633 555.71124 488.03101 curveto +556.25812 487.5857 557.01007 487.36305 557.9671 487.36304 curveto +558.37725 487.36305 558.79522 487.40016 559.22101 487.47437 curveto +559.64678 487.54859 560.08233 487.65992 560.52765 487.80835 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +568.16827 487.80835 moveto +568.16827 488.96265 lineto +567.71905 488.74781 567.29522 488.58765 566.89679 488.48218 curveto +566.49835 488.37672 566.11358 488.32398 565.74249 488.32397 curveto +565.09796 488.32398 564.59991 488.44898 564.24835 488.69897 curveto +563.90069 488.94898 563.72687 489.30445 563.72687 489.76538 curveto +563.72687 490.15211 563.8421 490.44507 564.07257 490.64429 curveto +564.30694 490.83961 564.74835 490.99781 565.39679 491.1189 curveto +566.11163 491.26538 lineto +566.99444 491.43335 567.64483 491.73023 568.06281 492.15601 curveto +568.48467 492.57788 568.69561 493.14429 568.69562 493.85522 curveto +568.69561 494.70288 568.41045 495.34546 567.84015 495.78296 curveto +567.27374 496.22046 566.44171 496.43921 565.34406 496.43921 curveto +564.92999 496.43921 564.48858 496.39233 564.01984 496.29858 curveto +563.55499 496.20483 563.07257 496.06616 562.57257 495.88257 curveto +562.57257 494.66382 lineto +563.05304 494.93335 563.52374 495.13648 563.98468 495.27319 curveto +564.44561 495.40991 564.89874 495.47827 565.34406 495.47827 curveto +566.01983 495.47827 566.54132 495.34546 566.90851 495.07983 curveto +567.27569 494.81421 567.45928 494.4353 567.45929 493.94312 curveto +567.45928 493.51343 567.32647 493.17749 567.06085 492.9353 curveto +566.79913 492.69312 566.36749 492.51148 565.76593 492.39038 curveto +565.04523 492.24976 lineto +564.16241 492.07398 563.52374 491.79859 563.12921 491.42358 curveto +562.73468 491.04859 562.53741 490.52711 562.53741 489.85913 curveto +562.53741 489.0857 562.8089 488.47633 563.35187 488.03101 curveto +563.89874 487.5857 564.65069 487.36305 565.60773 487.36304 curveto +566.01788 487.36305 566.43585 487.40016 566.86163 487.47437 curveto +567.28741 487.54859 567.72296 487.65992 568.16827 487.80835 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +570.56476 487.52124 moveto +571.74835 487.52124 lineto +571.74835 495.27319 lineto +576.00812 495.27319 lineto +576.00812 496.26929 lineto +570.56476 496.26929 lineto +570.56476 487.52124 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +576.44171 492.50171 moveto +579.59991 492.50171 lineto +579.59991 493.46265 lineto +576.44171 493.46265 lineto +576.44171 492.50171 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +586.03351 492.9939 moveto +586.0335 492.20093 585.86944 491.57984 585.54132 491.13062 curveto +585.2171 490.6775 584.76983 490.45093 584.19952 490.45093 curveto +583.62921 490.45093 583.17999 490.6775 582.85187 491.13062 curveto +582.52765 491.57984 582.36554 492.20093 582.36554 492.9939 curveto +582.36554 493.78687 582.52765 494.40991 582.85187 494.86304 curveto +583.17999 495.31226 583.62921 495.53687 584.19952 495.53687 curveto +584.76983 495.53687 585.2171 495.31226 585.54132 494.86304 curveto +585.86944 494.40991 586.0335 493.78687 586.03351 492.9939 curveto +582.36554 490.70288 moveto +582.5921 490.31226 582.87726 490.0232 583.22101 489.83569 curveto +583.56866 489.64429 583.98272 489.54859 584.4632 489.54858 curveto +585.26007 489.54859 585.90655 489.865 586.40265 490.4978 curveto +586.90264 491.13062 587.15264 491.96265 587.15265 492.9939 curveto +587.15264 494.02515 586.90264 494.85718 586.40265 495.48999 curveto +585.90655 496.1228 585.26007 496.43921 584.4632 496.43921 curveto +583.98272 496.43921 583.56866 496.34546 583.22101 496.15796 curveto +582.87726 495.96655 582.5921 495.67554 582.36554 495.28491 curveto +582.36554 496.26929 lineto +581.28156 496.26929 lineto +581.28156 487.1521 lineto +582.36554 487.1521 lineto +582.36554 490.70288 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +591.92218 492.97046 moveto +591.05108 492.97046 590.44757 493.07007 590.11163 493.26929 curveto +589.77569 493.46851 589.60773 493.80835 589.60773 494.28882 curveto +589.60773 494.67163 589.73273 494.97632 589.98273 495.20288 curveto +590.23663 495.42554 590.58038 495.53687 591.01398 495.53687 curveto +591.61163 495.53687 592.09014 495.32593 592.44952 494.90405 curveto +592.8128 494.47827 592.99444 493.91382 592.99445 493.21069 curveto +592.99445 492.97046 lineto +591.92218 492.97046 lineto +594.07257 492.52515 moveto +594.07257 496.26929 lineto +592.99445 496.26929 lineto +592.99445 495.27319 lineto +592.74835 495.67163 592.44171 495.96655 592.07452 496.15796 curveto +591.70733 496.34546 591.25811 496.43921 590.72687 496.43921 curveto +590.05499 496.43921 589.51983 496.25171 589.1214 495.87671 curveto +588.72687 495.4978 588.5296 494.99194 588.5296 494.35913 curveto +588.5296 493.62085 588.77569 493.06421 589.26788 492.68921 curveto +589.76398 492.31421 590.50226 492.12671 591.48273 492.12671 curveto +592.99445 492.12671 lineto +592.99445 492.02124 lineto +592.99444 491.52515 592.83038 491.14234 592.50226 490.8728 curveto +592.17804 490.59937 591.721 490.46265 591.13116 490.46265 curveto +590.75616 490.46265 590.39093 490.50757 590.03546 490.59741 curveto +589.67999 490.68726 589.33819 490.82203 589.01007 491.00171 curveto +589.01007 490.00562 lineto +589.4046 489.85328 589.78741 489.74 590.15851 489.66577 curveto +590.5296 489.58765 590.89093 489.54859 591.24249 489.54858 curveto +592.19171 489.54859 592.90069 489.79468 593.36945 490.28687 curveto +593.83819 490.77906 594.07256 491.52515 594.07257 492.52515 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +600.50616 489.90015 moveto +600.50616 490.91968 lineto +600.20147 490.76343 599.88507 490.64625 599.55695 490.56812 curveto +599.22882 490.49 598.88897 490.45093 598.53741 490.45093 curveto +598.00226 490.45093 597.59991 490.53296 597.33038 490.69702 curveto +597.06476 490.86109 596.93194 491.10718 596.93195 491.4353 curveto +596.93194 491.68531 597.02765 491.88257 597.21906 492.0271 curveto +597.41046 492.16773 597.79522 492.30249 598.37335 492.4314 curveto +598.74249 492.51343 lineto +599.50811 492.67749 600.05108 492.90992 600.3714 493.21069 curveto +600.69561 493.50757 600.85772 493.92359 600.85773 494.45874 curveto +600.85772 495.06812 600.61553 495.55054 600.13116 495.90601 curveto +599.65069 496.26147 598.98858 496.43921 598.14484 496.43921 curveto +597.79327 496.43921 597.42608 496.40405 597.04327 496.33374 curveto +596.66437 496.26733 596.26398 496.16577 595.8421 496.02905 curveto +595.8421 494.91577 lineto +596.24054 495.1228 596.63312 495.27905 597.01984 495.38452 curveto +597.40655 495.48608 597.78937 495.53687 598.16827 495.53687 curveto +598.67608 495.53687 599.06671 495.45093 599.34015 495.27905 curveto +599.61358 495.10327 599.7503 494.85718 599.75031 494.54077 curveto +599.7503 494.2478 599.65069 494.0232 599.45148 493.86694 curveto +599.25616 493.7107 598.82452 493.56031 598.15656 493.41577 curveto +597.78156 493.32788 lineto +597.11358 493.18726 596.63116 492.97242 596.33429 492.68335 curveto +596.03741 492.39038 595.88898 491.98999 595.88898 491.48218 curveto +595.88898 490.865 596.10773 490.38843 596.54523 490.05249 curveto +596.98273 489.71656 597.60382 489.54859 598.40851 489.54858 curveto +598.80694 489.54859 599.18194 489.57789 599.53351 489.63647 curveto +599.88507 489.69507 600.20928 489.78297 600.50616 489.90015 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +608.19366 492.71851 moveto +608.19366 493.24585 lineto +603.23663 493.24585 lineto +603.28351 493.98804 603.50616 494.55445 603.9046 494.94507 curveto +604.30694 495.33179 604.86554 495.52515 605.58038 495.52515 curveto +605.99444 495.52515 606.39483 495.47437 606.78156 495.3728 curveto +607.17217 495.27124 607.55889 495.1189 607.94171 494.91577 curveto +607.94171 495.9353 lineto +607.55499 496.09937 607.1585 496.22437 606.75226 496.3103 curveto +606.346 496.39624 605.93389 496.43921 605.51593 496.43921 curveto +604.46905 496.43921 603.63897 496.13452 603.0257 495.52515 curveto +602.41632 494.91577 602.11163 494.09155 602.11163 493.05249 curveto +602.11163 491.97828 602.40069 491.12671 602.97882 490.4978 curveto +603.56085 489.865 604.34405 489.54859 605.32843 489.54858 curveto +606.21124 489.54859 606.9085 489.83375 607.42023 490.40405 curveto +607.93585 490.97046 608.19366 491.74195 608.19366 492.71851 curveto +607.11554 492.4021 moveto +607.10772 491.81226 606.94171 491.34156 606.61749 490.98999 curveto +606.29718 490.63843 605.87139 490.46265 605.34015 490.46265 curveto +604.73858 490.46265 604.25616 490.63257 603.89288 490.97241 curveto +603.53351 491.31226 603.32648 491.79078 603.27179 492.40796 curveto +607.11554 492.4021 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +614.25812 490.70288 moveto +614.25812 487.1521 lineto +615.33624 487.1521 lineto +615.33624 496.26929 lineto +614.25812 496.26929 lineto +614.25812 495.28491 lineto +614.03155 495.67554 613.74444 495.96655 613.39679 496.15796 curveto +613.05304 496.34546 612.63897 496.43921 612.1546 496.43921 curveto +611.36163 496.43921 610.71515 496.1228 610.21515 495.48999 curveto +609.71905 494.85718 609.47101 494.02515 609.47101 492.9939 curveto +609.47101 491.96265 609.71905 491.13062 610.21515 490.4978 curveto +610.71515 489.865 611.36163 489.54859 612.1546 489.54858 curveto +612.63897 489.54859 613.05304 489.64429 613.39679 489.83569 curveto +613.74444 490.0232 614.03155 490.31226 614.25812 490.70288 curveto +610.58429 492.9939 moveto +610.58429 493.78687 610.7464 494.40991 611.07062 494.86304 curveto +611.39874 495.31226 611.84796 495.53687 612.41827 495.53687 curveto +612.98858 495.53687 613.4378 495.31226 613.76593 494.86304 curveto +614.09405 494.40991 614.25811 493.78687 614.25812 492.9939 curveto +614.25811 492.20093 614.09405 491.57984 613.76593 491.13062 curveto +613.4378 490.6775 612.98858 490.45093 612.41827 490.45093 curveto +611.84796 490.45093 611.39874 490.6775 611.07062 491.13062 curveto +610.7464 491.57984 610.58429 492.20093 610.58429 492.9939 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +622.42023 495.28491 moveto +622.42023 498.76538 lineto +621.33624 498.76538 lineto +621.33624 489.70679 lineto +622.42023 489.70679 lineto +622.42023 490.70288 lineto +622.64679 490.31226 622.93194 490.0232 623.2757 489.83569 curveto +623.62335 489.64429 624.03741 489.54859 624.51788 489.54858 curveto +625.31475 489.54859 625.96124 489.865 626.45734 490.4978 curveto +626.95733 491.13062 627.20733 491.96265 627.20734 492.9939 curveto +627.20733 494.02515 626.95733 494.85718 626.45734 495.48999 curveto +625.96124 496.1228 625.31475 496.43921 624.51788 496.43921 curveto +624.03741 496.43921 623.62335 496.34546 623.2757 496.15796 curveto +622.93194 495.96655 622.64679 495.67554 622.42023 495.28491 curveto +626.0882 492.9939 moveto +626.08819 492.20093 625.92413 491.57984 625.59601 491.13062 curveto +625.27178 490.6775 624.82452 490.45093 624.25421 490.45093 curveto +623.6839 490.45093 623.23468 490.6775 622.90656 491.13062 curveto +622.58233 491.57984 622.42022 492.20093 622.42023 492.9939 curveto +622.42022 493.78687 622.58233 494.40991 622.90656 494.86304 curveto +623.23468 495.31226 623.6839 495.53687 624.25421 495.53687 curveto +624.82452 495.53687 625.27178 495.31226 625.59601 494.86304 curveto +625.92413 494.40991 626.08819 493.78687 626.0882 492.9939 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +628.99445 487.1521 moveto +630.07257 487.1521 lineto +630.07257 496.26929 lineto +628.99445 496.26929 lineto +628.99445 487.1521 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +632.21124 493.67944 moveto +632.21124 489.70679 lineto +633.28937 489.70679 lineto +633.28937 493.63843 lineto +633.28937 494.25952 633.41046 494.72632 633.65265 495.03882 curveto +633.89483 495.34741 634.25811 495.50171 634.74249 495.50171 curveto +635.32452 495.50171 635.7835 495.31616 636.11945 494.94507 curveto +636.45928 494.57398 636.62921 494.06812 636.62921 493.42749 curveto +636.62921 489.70679 lineto +637.70734 489.70679 lineto +637.70734 496.26929 lineto +636.62921 496.26929 lineto +636.62921 495.26147 lineto +636.36749 495.65991 636.0628 495.95679 635.71515 496.1521 curveto +635.37139 496.34351 634.971 496.43921 634.51398 496.43921 curveto +633.76007 496.43921 633.1878 496.20483 632.79718 495.73608 curveto +632.40655 495.26733 632.21124 494.58179 632.21124 493.67944 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +644.25812 492.91187 moveto +644.25811 492.13062 644.096 491.52515 643.77179 491.09546 curveto +643.45147 490.66578 643.0003 490.45093 642.41827 490.45093 curveto +641.84015 490.45093 641.38897 490.66578 641.06476 491.09546 curveto +640.74444 491.52515 640.58429 492.13062 640.58429 492.91187 curveto +640.58429 493.68921 640.74444 494.29273 641.06476 494.72241 curveto +641.38897 495.1521 641.84015 495.36694 642.41827 495.36694 curveto +643.0003 495.36694 643.45147 495.1521 643.77179 494.72241 curveto +644.096 494.29273 644.25811 493.68921 644.25812 492.91187 curveto +645.33624 495.45483 moveto +645.33624 496.57202 645.08819 497.4021 644.5921 497.94507 curveto +644.096 498.49194 643.33624 498.76538 642.31281 498.76538 curveto +641.9339 498.76538 641.57647 498.73608 641.24054 498.67749 curveto +640.9046 498.6228 640.57843 498.53686 640.26202 498.41968 curveto +640.26202 497.37085 lineto +640.57843 497.54272 640.89093 497.66968 641.19952 497.75171 curveto +641.50811 497.83374 641.82257 497.87475 642.14288 497.87476 curveto +642.84991 497.87475 643.37921 497.68921 643.73077 497.31812 curveto +644.08233 496.95093 644.25811 496.39429 644.25812 495.64819 curveto +644.25812 495.11499 lineto +644.03546 495.50171 643.7503 495.79077 643.40265 495.98218 curveto +643.05499 496.17358 642.63897 496.26929 642.1546 496.26929 curveto +641.34991 496.26929 640.70148 495.96265 640.20929 495.34937 curveto +639.7171 494.73609 639.47101 493.92359 639.47101 492.91187 curveto +639.47101 491.89624 639.7171 491.08179 640.20929 490.46851 curveto +640.70148 489.85523 641.34991 489.54859 642.1546 489.54858 curveto +642.63897 489.54859 643.05499 489.64429 643.40265 489.83569 curveto +643.7503 490.02711 644.03546 490.31617 644.25812 490.70288 curveto +644.25812 489.70679 lineto +645.33624 489.70679 lineto +645.33624 495.45483 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +647.55695 489.70679 moveto +648.63507 489.70679 lineto +648.63507 496.26929 lineto +647.55695 496.26929 lineto +647.55695 489.70679 lineto +647.55695 487.1521 moveto +648.63507 487.1521 lineto +648.63507 488.51733 lineto +647.55695 488.51733 lineto +647.55695 487.1521 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +656.34015 492.30835 moveto +656.34015 496.26929 lineto +655.26202 496.26929 lineto +655.26202 492.34351 lineto +655.26202 491.72242 655.14092 491.25757 654.89874 490.94897 curveto +654.65655 490.64039 654.29327 490.48609 653.8089 490.48608 curveto +653.22686 490.48609 652.76788 490.67164 652.43195 491.04272 curveto +652.09601 491.41382 651.92804 491.91968 651.92804 492.5603 curveto +651.92804 496.26929 lineto +650.84406 496.26929 lineto +650.84406 489.70679 lineto +651.92804 489.70679 lineto +651.92804 490.72632 lineto +652.18585 490.33179 652.48858 490.03687 652.83624 489.84155 curveto +653.1878 489.64625 653.5921 489.54859 654.04913 489.54858 curveto +654.80303 489.54859 655.37335 489.78297 655.76007 490.25171 curveto +656.14678 490.71656 656.34014 491.4021 656.34015 492.30835 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +1 setlinewidth +0 setlinejoin +0 setlinecap +newpath +501.70806 496.03305 moveto +457.68495 496.03305 457.68495 496.03305 457.68495 496.03305 curveto +stroke +gsave [-1.1 1.347067e-16 -1.347067e-16 -1.1 500.60806 496.03305] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1 -1.347067e-16 1.347067e-16 1.1 458.78495 496.03305] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +503.70898 529.39282 moveto +688.56311 529.39282 lineto +688.56311 558.8199 lineto +503.70898 558.8199 lineto +503.70898 529.39282 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +514.17401 535.98425 moveto +514.17401 537.13855 lineto +513.72479 536.92371 513.30096 536.76356 512.90253 536.65808 curveto +512.50408 536.55262 512.11932 536.49989 511.74823 536.49988 curveto +511.1037 536.49989 510.60565 536.62489 510.25409 536.87488 curveto +509.90643 537.12489 509.7326 537.48035 509.7326 537.94128 curveto +509.7326 538.32801 509.84784 538.62098 510.07831 538.82019 curveto +510.31268 539.01551 510.75409 539.17371 511.40253 539.2948 curveto +512.11737 539.44128 lineto +513.00018 539.60926 513.65057 539.90613 514.06854 540.33191 curveto +514.49041 540.75379 514.70135 541.32019 514.70135 542.03113 curveto +514.70135 542.87879 514.41619 543.52136 513.84589 543.95886 curveto +513.27947 544.39636 512.44744 544.61511 511.34979 544.61511 curveto +510.93573 544.61511 510.49432 544.56824 510.02557 544.47449 curveto +509.56073 544.38074 509.07831 544.24207 508.57831 544.05847 curveto +508.57831 542.83972 lineto +509.05878 543.10925 509.52948 543.31238 509.99042 543.4491 curveto +510.45135 543.58582 510.90448 543.65418 511.34979 543.65417 curveto +512.02557 543.65418 512.54705 543.52136 512.91425 543.25574 curveto +513.28143 542.99011 513.46502 542.61121 513.46503 542.11902 curveto +513.46502 541.68933 513.33221 541.3534 513.06659 541.11121 curveto +512.80487 540.86902 512.37323 540.68738 511.77167 540.56628 curveto +511.05096 540.42566 lineto +510.16815 540.24988 509.52948 539.97449 509.13495 539.59949 curveto +508.74042 539.22449 508.54315 538.70301 508.54315 538.03503 curveto +508.54315 537.2616 508.81464 536.65223 509.3576 536.20691 curveto +509.90448 535.76161 510.65643 535.53895 511.61346 535.53894 curveto +512.02362 535.53895 512.44158 535.57606 512.86737 535.65027 curveto +513.29315 535.7245 513.72869 535.83582 514.17401 535.98425 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +521.633 539.14246 moveto +521.90252 538.65809 522.22479 538.30067 522.59979 538.07019 curveto +522.97478 537.83973 523.41619 537.72449 523.92401 537.72449 curveto +524.6076 537.72449 525.13494 537.96473 525.50604 538.44519 curveto +525.87713 538.92176 526.06267 539.60145 526.06268 540.48425 curveto +526.06268 544.44519 lineto +524.9787 544.44519 lineto +524.9787 540.51941 lineto +524.97869 539.89051 524.86736 539.42371 524.64471 539.11902 curveto +524.42205 538.81434 524.08221 538.66199 523.62518 538.66199 curveto +523.06658 538.66199 522.62518 538.84754 522.30096 539.21863 curveto +521.97674 539.58973 521.81463 540.09559 521.81464 540.73621 curveto +521.81464 544.44519 lineto +520.73065 544.44519 lineto +520.73065 540.51941 lineto +520.73065 539.8866 520.61932 539.4198 520.39667 539.11902 curveto +520.17401 538.81434 519.83026 538.66199 519.36542 538.66199 curveto +518.81463 538.66199 518.37713 538.84949 518.05292 539.22449 curveto +517.7287 539.59559 517.56659 540.09949 517.56659 540.73621 curveto +517.56659 544.44519 lineto +516.4826 544.44519 lineto +516.4826 537.88269 lineto +517.56659 537.88269 lineto +517.56659 538.90222 lineto +517.81268 538.49988 518.1076 538.20301 518.45135 538.0116 curveto +518.7951 537.8202 519.2033 537.72449 519.67596 537.72449 curveto +520.15252 537.72449 520.55682 537.84559 520.88885 538.08777 curveto +521.22479 538.32996 521.47283 538.68152 521.633 539.14246 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +531.17792 541.14636 moveto +530.30682 541.14637 529.70331 541.24597 529.36737 541.44519 curveto +529.03143 541.64441 528.86346 541.98426 528.86346 542.46472 curveto +528.86346 542.84754 528.98846 543.15222 529.23846 543.37878 curveto +529.49237 543.60144 529.83612 543.71277 530.26971 543.71277 curveto +530.86737 543.71277 531.34588 543.50183 531.70526 543.07996 curveto +532.06854 542.65418 532.25018 542.08972 532.25018 541.3866 curveto +532.25018 541.14636 lineto +531.17792 541.14636 lineto +533.32831 540.70105 moveto +533.32831 544.44519 lineto +532.25018 544.44519 lineto +532.25018 543.4491 lineto +532.00408 543.84753 531.69744 544.14246 531.33026 544.33386 curveto +530.96307 544.52136 530.51385 544.61511 529.9826 544.61511 curveto +529.31073 544.61511 528.77557 544.42761 528.37714 544.05261 curveto +527.9826 543.67371 527.78534 543.16785 527.78534 542.53503 curveto +527.78534 541.79676 528.03143 541.24012 528.52362 540.86511 curveto +529.01971 540.49012 529.75799 540.30262 530.73846 540.30261 curveto +532.25018 540.30261 lineto +532.25018 540.19714 lineto +532.25018 539.70105 532.08612 539.31824 531.758 539.04871 curveto +531.43377 538.77527 530.97674 538.63856 530.3869 538.63855 curveto +530.0119 538.63856 529.64666 538.68348 529.2912 538.77332 curveto +528.93573 538.86316 528.59393 538.99793 528.26581 539.17761 curveto +528.26581 538.18152 lineto +528.66034 538.02918 529.04315 537.9159 529.41425 537.84167 curveto +529.78534 537.76356 530.14666 537.72449 530.49823 537.72449 curveto +531.44744 537.72449 532.15643 537.97059 532.62518 538.46277 curveto +533.09393 538.95496 533.3283 539.70105 533.32831 540.70105 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +539.38104 538.8905 moveto +539.25994 538.8202 539.12713 538.76941 538.9826 538.73816 curveto +538.84198 538.70301 538.68573 538.68543 538.51385 538.68542 curveto +537.90448 538.68543 537.43573 538.88465 537.1076 539.28308 curveto +536.78338 539.67762 536.62127 540.24598 536.62128 540.98816 curveto +536.62128 544.44519 lineto +535.53729 544.44519 lineto +535.53729 537.88269 lineto +536.62128 537.88269 lineto +536.62128 538.90222 lineto +536.84784 538.50379 537.14276 538.20887 537.50604 538.01746 curveto +537.86932 537.82215 538.31073 537.72449 538.83026 537.72449 curveto +538.90448 537.72449 538.98651 537.73035 539.07635 537.74207 curveto +539.16619 537.74988 539.2658 537.76356 539.37518 537.78308 curveto +539.38104 538.8905 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +541.59003 536.01941 moveto +541.59003 537.88269 lineto +543.81073 537.88269 lineto +543.81073 538.72058 lineto +541.59003 538.72058 lineto +541.59003 542.28308 lineto +541.59002 542.81824 541.66229 543.16199 541.80682 543.31433 curveto +541.95526 543.46668 542.25409 543.54285 542.70331 543.54285 curveto +543.81073 543.54285 lineto +543.81073 544.44519 lineto +542.70331 544.44519 lineto +541.87127 544.44519 541.29706 544.29089 540.98065 543.9823 curveto +540.66424 543.6698 540.50604 543.10339 540.50604 542.28308 curveto +540.50604 538.72058 lineto +539.71503 538.72058 lineto +539.71503 537.88269 lineto +540.50604 537.88269 lineto +540.50604 536.01941 lineto +541.59003 536.01941 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +549.95721 538.13464 moveto +549.95721 539.14246 lineto +549.65252 538.97449 549.34588 538.84949 549.03729 538.76746 curveto +548.7326 538.68152 548.42401 538.63856 548.11151 538.63855 curveto +547.41229 538.63856 546.86932 538.86121 546.4826 539.30652 curveto +546.09588 539.74793 545.90253 540.36902 545.90253 541.1698 curveto +545.90253 541.97058 546.09588 542.59363 546.4826 543.03894 curveto +546.86932 543.48035 547.41229 543.70105 548.11151 543.70105 curveto +548.42401 543.70105 548.7326 543.66003 549.03729 543.578 curveto +549.34588 543.49207 549.65252 543.36511 549.95721 543.19714 curveto +549.95721 544.19324 lineto +549.65643 544.33386 549.34393 544.43933 549.01971 544.50964 curveto +548.6994 544.57996 548.3576 544.61511 547.99432 544.61511 curveto +547.00604 544.61511 546.22088 544.30457 545.63885 543.68347 curveto +545.05682 543.06238 544.76581 542.22449 544.76581 541.1698 curveto +544.76581 540.09949 545.05878 539.2577 545.64471 538.64441 curveto +546.23456 538.03113 547.0412 537.72449 548.06464 537.72449 curveto +548.39666 537.72449 548.72088 537.75965 549.03729 537.82996 curveto +549.35369 537.89637 549.66033 537.99793 549.95721 538.13464 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +554.82635 541.14636 moveto +553.95526 541.14637 553.35174 541.24597 553.01581 541.44519 curveto +552.67987 541.64441 552.5119 541.98426 552.5119 542.46472 curveto +552.5119 542.84754 552.6369 543.15222 552.8869 543.37878 curveto +553.14081 543.60144 553.48456 543.71277 553.91815 543.71277 curveto +554.5158 543.71277 554.99432 543.50183 555.3537 543.07996 curveto +555.71697 542.65418 555.89862 542.08972 555.89862 541.3866 curveto +555.89862 541.14636 lineto +554.82635 541.14636 lineto +556.97675 540.70105 moveto +556.97675 544.44519 lineto +555.89862 544.44519 lineto +555.89862 543.4491 lineto +555.65252 543.84753 555.34588 544.14246 554.9787 544.33386 curveto +554.61151 544.52136 554.16229 544.61511 553.63104 544.61511 curveto +552.95917 544.61511 552.42401 544.42761 552.02557 544.05261 curveto +551.63104 543.67371 551.43378 543.16785 551.43378 542.53503 curveto +551.43378 541.79676 551.67987 541.24012 552.17206 540.86511 curveto +552.66815 540.49012 553.40643 540.30262 554.3869 540.30261 curveto +555.89862 540.30261 lineto +555.89862 540.19714 lineto +555.89862 539.70105 555.73455 539.31824 555.40643 539.04871 curveto +555.08221 538.77527 554.62518 538.63856 554.03534 538.63855 curveto +553.66034 538.63856 553.2951 538.68348 552.93964 538.77332 curveto +552.58417 538.86316 552.24237 538.99793 551.91425 539.17761 curveto +551.91425 538.18152 lineto +552.30878 538.02918 552.69159 537.9159 553.06268 537.84167 curveto +553.43377 537.76356 553.7951 537.72449 554.14667 537.72449 curveto +555.09588 537.72449 555.80487 537.97059 556.27362 538.46277 curveto +556.74236 538.95496 556.97674 539.70105 556.97675 540.70105 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +563.02948 538.8905 moveto +562.90838 538.8202 562.77557 538.76941 562.63104 538.73816 curveto +562.49041 538.70301 562.33416 538.68543 562.16229 538.68542 curveto +561.55291 538.68543 561.08416 538.88465 560.75604 539.28308 curveto +560.43182 539.67762 560.26971 540.24598 560.26971 540.98816 curveto +560.26971 544.44519 lineto +559.18573 544.44519 lineto +559.18573 537.88269 lineto +560.26971 537.88269 lineto +560.26971 538.90222 lineto +560.49627 538.50379 560.7912 538.20887 561.15448 538.01746 curveto +561.51776 537.82215 561.95916 537.72449 562.4787 537.72449 curveto +562.55291 537.72449 562.63494 537.73035 562.72479 537.74207 curveto +562.81463 537.74988 562.91424 537.76356 563.02362 537.78308 curveto +563.02948 538.8905 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +568.27948 538.87878 moveto +568.27948 535.328 lineto +569.3576 535.328 lineto +569.3576 544.44519 lineto +568.27948 544.44519 lineto +568.27948 543.46082 lineto +568.05291 543.85144 567.7658 544.14246 567.41815 544.33386 curveto +567.0744 544.52136 566.66034 544.61511 566.17596 544.61511 curveto +565.38299 544.61511 564.73651 544.29871 564.23651 543.66589 curveto +563.74042 543.03308 563.49237 542.20105 563.49237 541.1698 curveto +563.49237 540.13855 563.74042 539.30652 564.23651 538.67371 curveto +564.73651 538.0409 565.38299 537.72449 566.17596 537.72449 curveto +566.66034 537.72449 567.0744 537.8202 567.41815 538.0116 curveto +567.7658 538.1991 568.05291 538.48817 568.27948 538.87878 curveto +564.60565 541.1698 moveto +564.60565 541.96277 564.76776 542.58582 565.09198 543.03894 curveto +565.4201 543.48816 565.86932 543.71277 566.43964 543.71277 curveto +567.00994 543.71277 567.45916 543.48816 567.78729 543.03894 curveto +568.11541 542.58582 568.27947 541.96277 568.27948 541.1698 curveto +568.27947 540.37684 568.11541 539.75574 567.78729 539.30652 curveto +567.45916 538.8534 567.00994 538.62684 566.43964 538.62683 curveto +565.86932 538.62684 565.4201 538.8534 565.09198 539.30652 curveto +564.76776 539.75574 564.60565 540.37684 564.60565 541.1698 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +577.98846 535.33972 moveto +577.46502 536.23817 577.07635 537.12684 576.82245 538.00574 curveto +576.56854 538.88465 576.44159 539.77527 576.44159 540.67761 curveto +576.44159 541.57996 576.56854 542.47449 576.82245 543.36121 curveto +577.08026 544.24402 577.46893 545.13269 577.98846 546.02722 curveto +577.05096 546.02722 lineto +576.46502 545.10925 576.02557 544.20691 575.7326 543.32019 curveto +575.44354 542.43347 575.29901 541.55262 575.29901 540.67761 curveto +575.29901 539.80652 575.44354 538.92957 575.7326 538.04675 curveto +576.02167 537.16395 576.46112 536.2616 577.05096 535.33972 curveto +577.98846 535.33972 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +581.31659 536.6698 moveto +581.31659 539.95691 lineto +582.80487 539.95691 lineto +583.35565 539.95691 583.78143 539.81434 584.08221 539.52917 curveto +584.38299 539.24402 584.53338 538.83777 584.53339 538.31042 curveto +584.53338 537.78699 584.38299 537.3827 584.08221 537.09753 curveto +583.78143 536.81239 583.35565 536.66981 582.80487 536.6698 curveto +581.31659 536.6698 lineto +580.133 535.69714 moveto +582.80487 535.69714 lineto +583.78533 535.69715 584.52557 535.91981 585.02557 536.36511 curveto +585.52947 536.80653 585.78143 537.45496 585.78143 538.31042 curveto +585.78143 539.17371 585.52947 539.82605 585.02557 540.26746 curveto +584.52557 540.70887 583.78533 540.92957 582.80487 540.92957 curveto +581.31659 540.92957 lineto +581.31659 544.44519 lineto +580.133 544.44519 lineto +580.133 535.69714 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +587.37518 535.69714 moveto +588.55878 535.69714 lineto +588.55878 539.39441 lineto +592.48456 535.69714 lineto +594.008 535.69714 lineto +589.6662 539.77527 lineto +594.31854 544.44519 lineto +592.75995 544.44519 lineto +588.55878 540.2323 lineto +588.55878 544.44519 lineto +587.37518 544.44519 lineto +587.37518 535.69714 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +601.14471 536.37097 moveto +601.14471 537.61902 lineto +600.74627 537.24793 600.32049 536.97059 599.86737 536.78699 curveto +599.41815 536.6034 598.93963 536.5116 598.43182 536.5116 curveto +597.43182 536.5116 596.6662 536.81824 596.13495 537.43152 curveto +595.6037 538.0409 595.33807 538.92371 595.33807 540.07996 curveto +595.33807 541.2323 595.6037 542.11511 596.13495 542.72839 curveto +596.6662 543.33777 597.43182 543.64246 598.43182 543.64246 curveto +598.93963 543.64246 599.41815 543.55066 599.86737 543.36707 curveto +600.32049 543.18347 600.74627 542.90613 601.14471 542.53503 curveto +601.14471 543.77136 lineto +600.73064 544.05261 600.29119 544.26355 599.82635 544.40417 curveto +599.36541 544.5448 598.87713 544.61511 598.36151 544.61511 curveto +597.03729 544.61511 595.99432 544.21082 595.2326 543.40222 curveto +594.47089 542.58972 594.09003 541.4823 594.09003 540.07996 curveto +594.09003 538.67371 594.47089 537.56629 595.2326 536.75769 curveto +595.99432 535.9452 597.03729 535.53895 598.36151 535.53894 curveto +598.88494 535.53895 599.37713 535.60926 599.83807 535.74988 curveto +600.30291 535.88661 600.73846 536.09364 601.14471 536.37097 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +608.2287 535.98425 moveto +608.2287 537.13855 lineto +607.77947 536.92371 607.35565 536.76356 606.95721 536.65808 curveto +606.55877 536.55262 606.17401 536.49989 605.80292 536.49988 curveto +605.15838 536.49989 604.66034 536.62489 604.30878 536.87488 curveto +603.96112 537.12489 603.78729 537.48035 603.78729 537.94128 curveto +603.78729 538.32801 603.90252 538.62098 604.133 538.82019 curveto +604.36737 539.01551 604.80877 539.17371 605.45721 539.2948 curveto +606.17206 539.44128 lineto +607.05487 539.60926 607.70526 539.90613 608.12323 540.33191 curveto +608.5451 540.75379 608.75604 541.32019 608.75604 542.03113 curveto +608.75604 542.87879 608.47088 543.52136 607.90057 543.95886 curveto +607.33416 544.39636 606.50213 544.61511 605.40448 544.61511 curveto +604.99041 544.61511 604.54901 544.56824 604.08026 544.47449 curveto +603.61542 544.38074 603.13299 544.24207 602.633 544.05847 curveto +602.633 542.83972 lineto +603.11346 543.10925 603.58417 543.31238 604.0451 543.4491 curveto +604.50604 543.58582 604.95916 543.65418 605.40448 543.65417 curveto +606.08026 543.65418 606.60174 543.52136 606.96893 543.25574 curveto +607.33612 542.99011 607.51971 542.61121 607.51971 542.11902 curveto +607.51971 541.68933 607.3869 541.3534 607.12128 541.11121 curveto +606.85955 540.86902 606.42791 540.68738 605.82635 540.56628 curveto +605.10565 540.42566 lineto +604.22284 540.24988 603.58417 539.97449 603.18964 539.59949 curveto +602.7951 539.22449 602.59784 538.70301 602.59784 538.03503 curveto +602.59784 537.2616 602.86932 536.65223 603.41229 536.20691 curveto +603.95917 535.76161 604.71112 535.53895 605.66815 535.53894 curveto +606.0783 535.53895 606.49627 535.57606 606.92206 535.65027 curveto +607.34783 535.7245 607.78338 535.83582 608.2287 535.98425 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +610.03339 540.67761 moveto +613.19159 540.67761 lineto +613.19159 541.63855 lineto +610.03339 541.63855 lineto +610.03339 540.67761 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +615.27167 543.4491 moveto +617.20526 543.4491 lineto +617.20526 536.77527 lineto +615.10175 537.19714 lineto +615.10175 536.11902 lineto +617.19354 535.69714 lineto +618.37714 535.69714 lineto +618.37714 543.4491 lineto +620.31073 543.4491 lineto +620.31073 544.44519 lineto +615.27167 544.44519 lineto +615.27167 543.4491 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +622.88885 543.4491 moveto +624.82245 543.4491 lineto +624.82245 536.77527 lineto +622.71893 537.19714 lineto +622.71893 536.11902 lineto +624.81073 535.69714 lineto +625.99432 535.69714 lineto +625.99432 543.4491 lineto +627.92792 543.4491 lineto +627.92792 544.44519 lineto +622.88885 544.44519 lineto +622.88885 543.4491 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +629.9787 535.33972 moveto +630.9162 535.33972 lineto +631.50213 536.2616 631.93963 537.16395 632.2287 538.04675 curveto +632.52166 538.92957 632.66815 539.80652 632.66815 540.67761 curveto +632.66815 541.55262 632.52166 542.43347 632.2287 543.32019 curveto +631.93963 544.20691 631.50213 545.10925 630.9162 546.02722 curveto +629.9787 546.02722 lineto +630.49823 545.13269 630.88495 544.24402 631.13885 543.36121 curveto +631.39667 542.47449 631.52557 541.57996 631.52557 540.67761 curveto +631.52557 539.77527 631.39667 538.88465 631.13885 538.00574 curveto +630.88495 537.12684 630.49823 536.23817 629.9787 535.33972 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +639.6994 543.46082 moveto +639.6994 546.94128 lineto +638.61542 546.94128 lineto +638.61542 537.88269 lineto +639.6994 537.88269 lineto +639.6994 538.87878 lineto +639.92596 538.48817 640.21112 538.1991 640.55487 538.0116 curveto +640.90252 537.8202 641.31659 537.72449 641.79706 537.72449 curveto +642.59393 537.72449 643.24041 538.0409 643.73651 538.67371 curveto +644.2365 539.30652 644.4865 540.13855 644.48651 541.1698 curveto +644.4865 542.20105 644.2365 543.03308 643.73651 543.66589 curveto +643.24041 544.29871 642.59393 544.61511 641.79706 544.61511 curveto +641.31659 544.61511 640.90252 544.52136 640.55487 544.33386 curveto +640.21112 544.14246 639.92596 543.85144 639.6994 543.46082 curveto +643.36737 541.1698 moveto +643.36736 540.37684 643.2033 539.75574 642.87518 539.30652 curveto +642.55096 538.8534 642.10369 538.62684 641.53339 538.62683 curveto +640.96307 538.62684 640.51385 538.8534 640.18573 539.30652 curveto +639.86151 539.75574 639.6994 540.37684 639.6994 541.1698 curveto +639.6994 541.96277 639.86151 542.58582 640.18573 543.03894 curveto +640.51385 543.48816 640.96307 543.71277 641.53339 543.71277 curveto +642.10369 543.71277 642.55096 543.48816 642.87518 543.03894 curveto +643.2033 542.58582 643.36736 541.96277 643.36737 541.1698 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +646.27362 535.328 moveto +647.35175 535.328 lineto +647.35175 544.44519 lineto +646.27362 544.44519 lineto +646.27362 535.328 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +649.49042 541.85535 moveto +649.49042 537.88269 lineto +650.56854 537.88269 lineto +650.56854 541.81433 lineto +650.56854 542.43543 650.68963 542.90222 650.93182 543.21472 curveto +651.17401 543.52332 651.53729 543.67761 652.02167 543.67761 curveto +652.60369 543.67761 653.06268 543.49207 653.39862 543.12097 curveto +653.73846 542.74988 653.90838 542.24402 653.90839 541.60339 curveto +653.90839 537.88269 lineto +654.98651 537.88269 lineto +654.98651 544.44519 lineto +653.90839 544.44519 lineto +653.90839 543.43738 lineto +653.64666 543.83582 653.34198 544.13269 652.99432 544.328 curveto +652.65057 544.51941 652.25018 544.61511 651.79315 544.61511 curveto +651.03924 544.61511 650.46698 544.38074 650.07635 543.91199 curveto +649.68573 543.44324 649.49042 542.75769 649.49042 541.85535 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +661.53729 541.08777 moveto +661.53729 540.30652 661.37518 539.70105 661.05096 539.27136 curveto +660.73065 538.84168 660.27948 538.62684 659.69745 538.62683 curveto +659.11932 538.62684 658.66815 538.84168 658.34393 539.27136 curveto +658.02362 539.70105 657.86346 540.30652 657.86346 541.08777 curveto +657.86346 541.86511 658.02362 542.46863 658.34393 542.89832 curveto +658.66815 543.328 659.11932 543.54285 659.69745 543.54285 curveto +660.27948 543.54285 660.73065 543.328 661.05096 542.89832 curveto +661.37518 542.46863 661.53729 541.86511 661.53729 541.08777 curveto +662.61542 543.63074 moveto +662.61541 544.74792 662.36736 545.578 661.87128 546.12097 curveto +661.37518 546.66784 660.61541 546.94128 659.59198 546.94128 curveto +659.21307 546.94128 658.85565 546.91198 658.51971 546.85339 curveto +658.18377 546.7987 657.8576 546.71277 657.5412 546.59558 curveto +657.5412 545.54675 lineto +657.8576 545.71863 658.1701 545.84558 658.4787 545.92761 curveto +658.78729 546.00964 659.10174 546.05066 659.42206 546.05066 curveto +660.12909 546.05066 660.65838 545.86511 661.00995 545.49402 curveto +661.36151 545.12683 661.53729 544.57019 661.53729 543.8241 curveto +661.53729 543.29089 lineto +661.31463 543.67761 661.02948 543.96668 660.68182 544.15808 curveto +660.33416 544.34949 659.91815 544.44519 659.43378 544.44519 curveto +658.62909 544.44519 657.98065 544.13855 657.48846 543.52527 curveto +656.99628 542.91199 656.75018 542.09949 656.75018 541.08777 curveto +656.75018 540.07215 656.99628 539.2577 657.48846 538.64441 curveto +657.98065 538.03113 658.62909 537.72449 659.43378 537.72449 curveto +659.91815 537.72449 660.33416 537.8202 660.68182 538.0116 curveto +661.02948 538.20301 661.31463 538.49207 661.53729 538.87878 curveto +661.53729 537.88269 lineto +662.61542 537.88269 lineto +662.61542 543.63074 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +664.83612 537.88269 moveto +665.91425 537.88269 lineto +665.91425 544.44519 lineto +664.83612 544.44519 lineto +664.83612 537.88269 lineto +664.83612 535.328 moveto +665.91425 535.328 lineto +665.91425 536.69324 lineto +664.83612 536.69324 lineto +664.83612 535.328 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +673.61932 540.48425 moveto +673.61932 544.44519 lineto +672.5412 544.44519 lineto +672.5412 540.51941 lineto +672.54119 539.89832 672.4201 539.43348 672.17792 539.12488 curveto +671.93573 538.81629 671.57244 538.66199 671.08807 538.66199 curveto +670.50604 538.66199 670.04706 538.84754 669.71112 539.21863 curveto +669.37518 539.58973 669.20721 540.09559 669.20721 540.73621 curveto +669.20721 544.44519 lineto +668.12323 544.44519 lineto +668.12323 537.88269 lineto +669.20721 537.88269 lineto +669.20721 538.90222 lineto +669.46502 538.5077 669.76776 538.21277 670.11542 538.01746 curveto +670.46698 537.82215 670.87127 537.72449 671.32831 537.72449 curveto +672.08221 537.72449 672.65252 537.95887 673.03925 538.42761 curveto +673.42596 538.89246 673.61932 539.57801 673.61932 540.48425 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +514.92169 599.1095 moveto +699.03845 599.1095 lineto +699.03845 628.54038 lineto +514.92169 628.54038 lineto +514.92169 599.1095 lineto +closepath +stroke +gsave +1 1 1 setrgbcolor +newpath +508.84338 592.2049 moveto +692.96014 592.2049 lineto +692.96014 621.63577 lineto +508.84338 621.63577 lineto +508.84338 592.2049 lineto +closepath +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +508.84338 592.2049 moveto +692.96014 592.2049 lineto +692.96014 621.63577 lineto +508.84338 621.63577 lineto +508.84338 592.2049 lineto +closepath +stroke +0 0 0 setrgbcolor +[] 0 setdash +1 setlinewidth +0 setlinejoin +0 setlinecap +newpath +501.70806 542.67659 moveto +457.68495 542.67659 457.68495 542.67659 457.68495 542.67659 curveto +stroke +gsave [-1.1 1.347067e-16 -1.347067e-16 -1.1 500.60806 542.67659] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1 -1.347067e-16 1.347067e-16 1.1 458.78495 542.67659] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave +1 1 1 setrgbcolor +newpath +503.70898 584.23737 moveto +687.82574 584.23737 lineto +687.82574 613.66825 lineto +503.70898 613.66825 lineto +503.70898 584.23737 lineto +closepath +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +2 setlinewidth +0 setlinejoin +0 setlinecap +newpath +503.70898 584.23737 moveto +687.82574 584.23737 lineto +687.82574 613.66825 lineto +503.70898 613.66825 lineto +503.70898 584.23737 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +553.43634 592.08746 moveto +552.57696 592.08747 551.89337 592.40778 551.38556 593.0484 curveto +550.88165 593.68903 550.6297 594.56208 550.6297 595.66754 curveto +550.6297 596.76911 550.88165 597.6402 551.38556 598.28082 curveto +551.89337 598.92145 552.57696 599.24176 553.43634 599.24176 curveto +554.29571 599.24176 554.9754 598.92145 555.4754 598.28082 curveto +555.9793 597.6402 556.23125 596.76911 556.23126 595.66754 curveto +556.23125 594.56208 555.9793 593.68903 555.4754 593.0484 curveto +554.9754 592.40778 554.29571 592.08747 553.43634 592.08746 curveto +553.43634 591.12653 moveto +554.6629 591.12653 555.64336 591.53864 556.37775 592.36285 curveto +557.11211 593.18317 557.4793 594.28473 557.47931 595.66754 curveto +557.4793 597.04645 557.11211 598.14801 556.37775 598.97223 curveto +555.64336 599.79254 554.6629 600.2027 553.43634 600.2027 curveto +552.20587 600.2027 551.22149 599.79254 550.48322 598.97223 curveto +549.74884 598.15192 549.38165 597.05036 549.38165 595.66754 curveto +549.38165 594.28473 549.74884 593.18317 550.48322 592.36285 curveto +551.22149 591.53864 552.20587 591.12653 553.43634 591.12653 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +560.3504 591.60699 moveto +560.3504 593.47028 lineto +562.57111 593.47028 lineto +562.57111 594.30817 lineto +560.3504 594.30817 lineto +560.3504 597.87067 lineto +560.3504 598.40582 560.42267 598.74957 560.5672 598.90192 curveto +560.71563 599.05426 561.01446 599.13043 561.46368 599.13043 curveto +562.57111 599.13043 lineto +562.57111 600.03278 lineto +561.46368 600.03278 lineto +560.63165 600.03278 560.05743 599.87848 559.74103 599.56989 curveto +559.42462 599.25739 559.26642 598.69098 559.26642 597.87067 curveto +559.26642 594.30817 lineto +558.4754 594.30817 lineto +558.4754 593.47028 lineto +559.26642 593.47028 lineto +559.26642 591.60699 lineto +560.3504 591.60699 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +569.45001 596.07184 moveto +569.45001 600.03278 lineto +568.37189 600.03278 lineto +568.37189 596.10699 lineto +568.37188 595.48591 568.25079 595.02106 568.00861 594.71246 curveto +567.76641 594.40388 567.40313 594.24958 566.91876 594.24957 curveto +566.33673 594.24958 565.87774 594.43513 565.54181 594.80621 curveto +565.20587 595.17731 565.0379 595.68317 565.0379 596.32379 curveto +565.0379 600.03278 lineto +563.95392 600.03278 lineto +563.95392 590.91559 lineto +565.0379 590.91559 lineto +565.0379 594.48981 lineto +565.29571 594.09528 565.59845 593.80036 565.94611 593.60504 curveto +566.29767 593.40974 566.70196 593.31208 567.159 593.31207 curveto +567.9129 593.31208 568.48321 593.54645 568.86993 594.0152 curveto +569.25665 594.48005 569.45001 595.16559 569.45001 596.07184 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +577.2254 596.48199 moveto +577.2254 597.00934 lineto +572.26837 597.00934 lineto +572.31524 597.75153 572.5379 598.31793 572.93634 598.70856 curveto +573.33868 599.09528 573.89727 599.28864 574.61212 599.28864 curveto +575.02618 599.28864 575.42657 599.23785 575.81329 599.13629 curveto +576.20391 599.03473 576.59063 598.88239 576.97345 598.67926 curveto +576.97345 599.69879 lineto +576.58672 599.86285 576.19024 599.98785 575.784 600.07379 curveto +575.37774 600.15973 574.96563 600.2027 574.54767 600.2027 curveto +573.50079 600.2027 572.67071 599.89801 572.05743 599.28864 curveto +571.44806 598.67926 571.14337 597.85504 571.14337 596.81598 curveto +571.14337 595.74176 571.43243 594.8902 572.01056 594.26129 curveto +572.59259 593.62849 573.37579 593.31208 574.36017 593.31207 curveto +575.24298 593.31208 575.94024 593.59724 576.45197 594.16754 curveto +576.96758 594.73395 577.2254 595.50544 577.2254 596.48199 curveto +576.14728 596.16559 moveto +576.13946 595.57575 575.97344 595.10505 575.64923 594.75348 curveto +575.32891 594.40192 574.90313 594.22614 574.37189 594.22614 curveto +573.77032 594.22614 573.2879 594.39606 572.92462 594.7359 curveto +572.56524 595.07575 572.35821 595.55426 572.30353 596.17145 curveto +576.14728 596.16559 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +582.77423 594.47809 moveto +582.65313 594.40778 582.52032 594.357 582.37579 594.32574 curveto +582.23516 594.29059 582.07891 594.27302 581.90704 594.27301 curveto +581.29767 594.27302 580.82892 594.47223 580.50079 594.87067 curveto +580.17657 595.2652 580.01446 595.83356 580.01447 596.57574 curveto +580.01447 600.03278 lineto +578.93048 600.03278 lineto +578.93048 593.47028 lineto +580.01447 593.47028 lineto +580.01447 594.48981 lineto +580.24103 594.09138 580.53595 593.79645 580.89923 593.60504 curveto +581.26251 593.40974 581.70391 593.31208 582.22345 593.31207 curveto +582.29766 593.31208 582.3797 593.31794 582.46954 593.32965 curveto +582.55938 593.33747 582.65899 593.35114 582.76837 593.37067 curveto +582.77423 594.47809 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +588.78009 599.0484 moveto +588.78009 602.52887 lineto +587.69611 602.52887 lineto +587.69611 593.47028 lineto +588.78009 593.47028 lineto +588.78009 594.46637 lineto +589.00665 594.07575 589.29181 593.78669 589.63556 593.59918 curveto +589.98321 593.40778 590.39727 593.31208 590.87775 593.31207 curveto +591.67462 593.31208 592.3211 593.62849 592.8172 594.26129 curveto +593.31719 594.89411 593.56719 595.72614 593.5672 596.75739 curveto +593.56719 597.78864 593.31719 598.62067 592.8172 599.25348 curveto +592.3211 599.88629 591.67462 600.2027 590.87775 600.2027 curveto +590.39727 600.2027 589.98321 600.10895 589.63556 599.92145 curveto +589.29181 599.73004 589.00665 599.43903 588.78009 599.0484 curveto +592.44806 596.75739 moveto +592.44805 595.96442 592.28399 595.34333 591.95587 594.8941 curveto +591.63165 594.44098 591.18438 594.21442 590.61407 594.21442 curveto +590.04376 594.21442 589.59454 594.44098 589.26642 594.8941 curveto +588.9422 595.34333 588.78009 595.96442 588.78009 596.75739 curveto +588.78009 597.55036 588.9422 598.1734 589.26642 598.62653 curveto +589.59454 599.07575 590.04376 599.30035 590.61407 599.30035 curveto +591.18438 599.30035 591.63165 599.07575 591.95587 598.62653 curveto +592.28399 598.1734 592.44805 597.55036 592.44806 596.75739 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +595.35431 590.91559 moveto +596.43243 590.91559 lineto +596.43243 600.03278 lineto +595.35431 600.03278 lineto +595.35431 590.91559 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +598.57111 597.44293 moveto +598.57111 593.47028 lineto +599.64923 593.47028 lineto +599.64923 597.40192 lineto +599.64923 598.02301 599.77032 598.48981 600.01251 598.80231 curveto +600.2547 599.1109 600.61798 599.2652 601.10236 599.2652 curveto +601.68438 599.2652 602.14337 599.07965 602.47931 598.70856 curveto +602.81915 598.33747 602.98907 597.83161 602.98907 597.19098 curveto +602.98907 593.47028 lineto +604.0672 593.47028 lineto +604.0672 600.03278 lineto +602.98907 600.03278 lineto +602.98907 599.02496 lineto +602.72735 599.4234 602.42266 599.72028 602.07501 599.91559 curveto +601.73126 600.10699 601.33087 600.2027 600.87384 600.2027 curveto +600.11993 600.2027 599.54767 599.96832 599.15704 599.49957 curveto +598.76642 599.03082 598.5711 598.34528 598.57111 597.44293 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +610.61798 596.67535 moveto +610.61798 595.89411 610.45587 595.28864 610.13165 594.85895 curveto +609.81134 594.42927 609.36016 594.21442 608.77814 594.21442 curveto +608.20001 594.21442 607.74884 594.42927 607.42462 594.85895 curveto +607.10431 595.28864 606.94415 595.89411 606.94415 596.67535 curveto +606.94415 597.4527 607.10431 598.05622 607.42462 598.4859 curveto +607.74884 598.91559 608.20001 599.13043 608.77814 599.13043 curveto +609.36016 599.13043 609.81134 598.91559 610.13165 598.4859 curveto +610.45587 598.05622 610.61798 597.4527 610.61798 596.67535 curveto +611.69611 599.21832 moveto +611.6961 600.33551 611.44805 601.16559 610.95197 601.70856 curveto +610.45587 602.25543 609.6961 602.52887 608.67267 602.52887 curveto +608.29376 602.52887 607.93634 602.49957 607.6004 602.44098 curveto +607.26446 602.38629 606.93829 602.30035 606.62189 602.18317 curveto +606.62189 601.13434 lineto +606.93829 601.30621 607.25079 601.43317 607.55939 601.5152 curveto +607.86798 601.59723 608.18243 601.63824 608.50275 601.63824 curveto +609.20977 601.63824 609.73907 601.4527 610.09064 601.0816 curveto +610.44219 600.71442 610.61798 600.15778 610.61798 599.41168 curveto +610.61798 598.87848 lineto +610.39532 599.2652 610.11016 599.55426 609.76251 599.74567 curveto +609.41485 599.93707 608.99884 600.03278 608.51447 600.03278 curveto +607.70978 600.03278 607.06134 599.72614 606.56915 599.11285 curveto +606.07696 598.49957 605.83087 597.68708 605.83087 596.67535 curveto +605.83087 595.65973 606.07696 594.84528 606.56915 594.23199 curveto +607.06134 593.61872 607.70978 593.31208 608.51447 593.31207 curveto +608.99884 593.31208 609.41485 593.40778 609.76251 593.59918 curveto +610.11016 593.79059 610.39532 594.07966 610.61798 594.46637 curveto +610.61798 593.47028 lineto +611.69611 593.47028 lineto +611.69611 599.21832 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +613.91681 593.47028 moveto +614.99493 593.47028 lineto +614.99493 600.03278 lineto +613.91681 600.03278 lineto +613.91681 593.47028 lineto +613.91681 590.91559 moveto +614.99493 590.91559 lineto +614.99493 592.28082 lineto +613.91681 592.28082 lineto +613.91681 590.91559 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +622.70001 596.07184 moveto +622.70001 600.03278 lineto +621.62189 600.03278 lineto +621.62189 596.10699 lineto +621.62188 595.48591 621.50079 595.02106 621.25861 594.71246 curveto +621.01641 594.40388 620.65313 594.24958 620.16876 594.24957 curveto +619.58673 594.24958 619.12774 594.43513 618.79181 594.80621 curveto +618.45587 595.17731 618.2879 595.68317 618.2879 596.32379 curveto +618.2879 600.03278 lineto +617.20392 600.03278 lineto +617.20392 593.47028 lineto +618.2879 593.47028 lineto +618.2879 594.48981 lineto +618.54571 594.09528 618.84845 593.80036 619.19611 593.60504 curveto +619.54767 593.40974 619.95196 593.31208 620.409 593.31207 curveto +621.1629 593.31208 621.73321 593.54645 622.11993 594.0152 curveto +622.50665 594.48005 622.70001 595.16559 622.70001 596.07184 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +629.04572 593.66364 moveto +629.04572 594.68317 lineto +628.74102 594.52692 628.42462 594.40973 628.0965 594.3316 curveto +627.76837 594.25348 627.42852 594.21442 627.07697 594.21442 curveto +626.54181 594.21442 626.13946 594.29645 625.86993 594.46051 curveto +625.60431 594.62458 625.47149 594.87067 625.4715 595.19879 curveto +625.47149 595.4488 625.5672 595.64606 625.75861 595.79059 curveto +625.95001 595.93122 626.33478 596.06598 626.9129 596.19489 curveto +627.28204 596.27692 lineto +628.04766 596.44098 628.59063 596.6734 628.91095 596.97418 curveto +629.23516 597.27106 629.39727 597.68708 629.39728 598.22223 curveto +629.39727 598.83161 629.15508 599.31403 628.67072 599.66949 curveto +628.19024 600.02496 627.52813 600.2027 626.68439 600.2027 curveto +626.33282 600.2027 625.96563 600.16754 625.58282 600.09723 curveto +625.20392 600.03082 624.80353 599.92926 624.38165 599.79254 curveto +624.38165 598.67926 lineto +624.78009 598.88629 625.17267 599.04254 625.55939 599.14801 curveto +625.9461 599.24957 626.32892 599.30035 626.70782 599.30035 curveto +627.21563 599.30035 627.60626 599.21442 627.8797 599.04254 curveto +628.15313 598.86676 628.28985 598.62067 628.28986 598.30426 curveto +628.28985 598.01129 628.19024 597.78668 627.99103 597.63043 curveto +627.79571 597.47418 627.36407 597.32379 626.69611 597.17926 curveto +626.32111 597.09137 lineto +625.65314 596.95075 625.17071 596.7359 624.87384 596.44684 curveto +624.57696 596.15387 624.42853 595.75348 624.42853 595.24567 curveto +624.42853 594.62848 624.64728 594.15192 625.08478 593.81598 curveto +625.52228 593.48005 626.14337 593.31208 626.94806 593.31207 curveto +627.34649 593.31208 627.72149 593.34138 628.07306 593.39996 curveto +628.42462 593.45856 628.74884 593.54645 629.04572 593.66364 curveto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +1 setlinewidth +0 setlinejoin +0 setlinecap +newpath +501.70806 598.75366 moveto +457.68495 598.75366 457.68495 598.75366 457.68495 598.75366 curveto +stroke +gsave [-1.1 1.347067e-16 -1.347067e-16 -1.1 500.60806 598.75366] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1 -1.347067e-16 1.347067e-16 1.1 458.78495 598.75366] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +0 0 0 setrgbcolor +[] 0 setdash +1.0314479 setlinewidth +0 setlinejoin +0 setlinecap +newpath +286.07811 482.68206 moveto +239.0548 482.68206 239.0548 482.68206 239.0548 482.68206 curveto +stroke +gsave [-1.1345927 1.3894294e-16 -1.3894294e-16 -1.1345927 284.94352 482.68206] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1345927 -1.3894294e-16 1.3894294e-16 1.1345927 240.18939 482.68206] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +0 0 0 setrgbcolor +[] 0 setdash +1.0314479 setlinewidth +0 setlinejoin +0 setlinecap +newpath +286.07811 607.93831 moveto +239.0548 607.93831 239.0548 607.93831 239.0548 607.93831 curveto +stroke +gsave [-1.1345927 1.3894294e-16 -1.3894294e-16 -1.1345927 284.94352 607.93831] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [1.1345927 -1.3894294e-16 1.3894294e-16 1.1345927 240.18939 607.93831] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [0 -1 1 0 0 0] concat +gsave +0 0 1 setrgbcolor +newpath +-635.45868 479.32993 moveto +-631.24774 479.32993 lineto +-631.24774 480.61118 lineto +-635.45868 480.61118 lineto +-635.45868 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-629.67743 479.32993 moveto +-625.46649 479.32993 lineto +-625.46649 480.61118 lineto +-629.67743 480.61118 lineto +-629.67743 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-623.89618 479.32993 moveto +-619.68524 479.32993 lineto +-619.68524 480.61118 lineto +-623.89618 480.61118 lineto +-623.89618 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-618.11493 479.32993 moveto +-613.90399 479.32993 lineto +-613.90399 480.61118 lineto +-618.11493 480.61118 lineto +-618.11493 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-612.33368 479.32993 moveto +-608.12274 479.32993 lineto +-608.12274 480.61118 lineto +-612.33368 480.61118 lineto +-612.33368 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-606.55243 479.32993 moveto +-602.34149 479.32993 lineto +-602.34149 480.61118 lineto +-606.55243 480.61118 lineto +-606.55243 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-600.77118 479.32993 moveto +-596.56024 479.32993 lineto +-596.56024 480.61118 lineto +-600.77118 480.61118 lineto +-600.77118 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-594.98993 479.32993 moveto +-590.77899 479.32993 lineto +-590.77899 480.61118 lineto +-594.98993 480.61118 lineto +-594.98993 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-589.20868 479.32993 moveto +-584.99774 479.32993 lineto +-584.99774 480.61118 lineto +-589.20868 480.61118 lineto +-589.20868 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-581.06024 473.98618 moveto +-581.06024 478.36899 lineto +-579.07587 478.36899 lineto +-578.3415 478.36899 -577.77379 478.17889 -577.37274 477.79868 curveto +-576.97171 477.41847 -576.77119 476.87681 -576.77118 476.17368 curveto +-576.77119 475.47577 -576.97171 474.93671 -577.37274 474.55649 curveto +-577.77379 474.17629 -578.3415 473.98619 -579.07587 473.98618 curveto +-581.06024 473.98618 lineto +-582.63837 472.6893 moveto +-579.07587 472.6893 lineto +-577.76858 472.68931 -576.7816 472.98619 -576.11493 473.57993 curveto +-575.44306 474.16848 -575.10713 475.03306 -575.10712 476.17368 curveto +-575.10713 477.32472 -575.44306 478.19452 -576.11493 478.78305 curveto +-576.7816 479.3716 -577.76858 479.66587 -579.07587 479.66586 curveto +-581.06024 479.66586 lineto +-581.06024 484.35336 lineto +-582.63837 484.35336 lineto +-582.63837 472.6893 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-568.25555 476.94711 moveto +-568.41702 476.85337 -568.5941 476.78566 -568.7868 476.74399 curveto +-568.97431 476.69712 -569.18264 476.67368 -569.4118 476.67368 curveto +-570.22431 476.67368 -570.84931 476.93931 -571.2868 477.47055 curveto +-571.7191 477.9966 -571.93524 478.75441 -571.93524 479.74399 curveto +-571.93524 484.35336 lineto +-573.38055 484.35336 lineto +-573.38055 475.60336 lineto +-571.93524 475.60336 lineto +-571.93524 476.96274 lineto +-571.63316 476.4315 -571.23993 476.03827 -570.75555 475.78305 curveto +-570.27118 475.52264 -569.68264 475.39243 -568.98993 475.39243 curveto +-568.89098 475.39243 -568.7816 475.40025 -568.6618 475.41586 curveto +-568.54202 475.42629 -568.40921 475.44452 -568.26337 475.47055 curveto +-568.25555 476.94711 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-563.68524 476.61118 moveto +-564.45608 476.61118 -565.06545 476.91327 -565.51337 477.51743 curveto +-565.96129 478.11639 -566.18524 478.93931 -566.18524 479.98618 curveto +-566.18524 481.03305 -565.96389 481.85857 -565.52118 482.46274 curveto +-565.07327 483.0617 -564.46129 483.36118 -563.68524 483.36118 curveto +-562.91962 483.36118 -562.31285 483.05909 -561.86493 482.45493 curveto +-561.41702 481.85076 -561.19306 481.02785 -561.19305 479.98618 curveto +-561.19306 478.94972 -561.41702 478.12941 -561.86493 477.52524 curveto +-562.31285 476.91587 -562.91962 476.61118 -563.68524 476.61118 curveto +-563.68524 475.39243 moveto +-562.43525 475.39243 -561.45348 475.79868 -560.73993 476.61118 curveto +-560.0264 477.42368 -559.66963 478.54868 -559.66962 479.98618 curveto +-559.66963 481.41847 -560.0264 482.54347 -560.73993 483.36118 curveto +-561.45348 484.17368 -562.43525 484.57993 -563.68524 484.57993 curveto +-564.94045 484.57993 -565.92483 484.17368 -566.63837 483.36118 curveto +-567.3467 482.54347 -567.70087 481.41847 -567.70087 479.98618 curveto +-567.70087 478.54868 -567.3467 477.42368 -566.63837 476.61118 curveto +-565.92483 475.79868 -564.94045 475.39243 -563.68524 475.39243 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-558.32587 475.60336 moveto +-556.80243 475.60336 lineto +-554.06805 482.94711 lineto +-551.33368 475.60336 lineto +-549.81024 475.60336 lineto +-553.09149 484.35336 lineto +-555.04462 484.35336 lineto +-558.32587 475.60336 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-547.82587 475.60336 moveto +-546.38837 475.60336 lineto +-546.38837 484.35336 lineto +-547.82587 484.35336 lineto +-547.82587 475.60336 lineto +-547.82587 472.19711 moveto +-546.38837 472.19711 lineto +-546.38837 474.01743 lineto +-547.82587 474.01743 lineto +-547.82587 472.19711 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-537.63055 476.93149 moveto +-537.63055 472.19711 lineto +-536.19305 472.19711 lineto +-536.19305 484.35336 lineto +-537.63055 484.35336 lineto +-537.63055 483.04086 lineto +-537.93264 483.5617 -538.31546 483.94972 -538.77899 484.20493 curveto +-539.23733 484.45493 -539.78941 484.57993 -540.43524 484.57993 curveto +-541.49254 484.57993 -542.35452 484.15805 -543.02118 483.3143 curveto +-543.68264 482.47055 -544.01337 481.36118 -544.01337 479.98618 curveto +-544.01337 478.61118 -543.68264 477.50181 -543.02118 476.65805 curveto +-542.35452 475.81431 -541.49254 475.39243 -540.43524 475.39243 curveto +-539.78941 475.39243 -539.23733 475.52004 -538.77899 475.77524 curveto +-538.31546 476.02525 -537.93264 476.41066 -537.63055 476.93149 curveto +-542.52899 479.98618 moveto +-542.52899 481.04347 -542.31285 481.8742 -541.88055 482.47836 curveto +-541.44306 483.07732 -540.8441 483.3768 -540.08368 483.3768 curveto +-539.32327 483.3768 -538.72431 483.07732 -538.2868 482.47836 curveto +-537.84931 481.8742 -537.63056 481.04347 -537.63055 479.98618 curveto +-537.63056 478.92889 -537.84931 478.10077 -538.2868 477.5018 curveto +-538.72431 476.89764 -539.32327 476.59556 -540.08368 476.59555 curveto +-540.8441 476.59556 -541.44306 476.89764 -541.88055 477.5018 curveto +-542.31285 478.10077 -542.52899 478.92889 -542.52899 479.98618 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-525.74774 479.61899 moveto +-525.74774 480.32211 lineto +-532.35712 480.32211 lineto +-532.29462 481.3117 -531.99774 482.06691 -531.46649 482.58774 curveto +-530.93004 483.10336 -530.18525 483.36118 -529.23212 483.36118 curveto +-528.68004 483.36118 -528.14619 483.29347 -527.63055 483.15805 curveto +-527.10973 483.02264 -526.5941 482.81951 -526.08368 482.54868 curveto +-526.08368 483.90805 lineto +-526.59931 484.1268 -527.12796 484.29347 -527.66962 484.40805 curveto +-528.21129 484.52263 -528.76077 484.57993 -529.31805 484.57993 curveto +-530.71389 484.57993 -531.82066 484.17368 -532.63837 483.36118 curveto +-533.45087 482.54868 -533.85712 481.44972 -533.85712 480.0643 curveto +-533.85712 478.63201 -533.4717 477.4966 -532.70087 476.65805 curveto +-531.92483 475.81431 -530.88056 475.39243 -529.56805 475.39243 curveto +-528.39098 475.39243 -527.46129 475.77264 -526.77899 476.53305 curveto +-526.0915 477.28827 -525.74775 478.31691 -525.74774 479.61899 curveto +-527.18524 479.19711 moveto +-527.19567 478.41066 -527.41702 477.78306 -527.8493 477.3143 curveto +-528.27639 476.84556 -528.8441 476.61118 -529.55243 476.61118 curveto +-530.35452 476.61118 -530.99775 476.83775 -531.48212 477.29086 curveto +-531.96129 477.74399 -532.23733 478.38201 -532.31024 479.20493 curveto +-527.18524 479.19711 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-518.3493 476.94711 moveto +-518.51077 476.85337 -518.68785 476.78566 -518.88055 476.74399 curveto +-519.06806 476.69712 -519.27639 476.67368 -519.50555 476.67368 curveto +-520.31806 476.67368 -520.94306 476.93931 -521.38055 477.47055 curveto +-521.81285 477.9966 -522.02899 478.75441 -522.02899 479.74399 curveto +-522.02899 484.35336 lineto +-523.4743 484.35336 lineto +-523.4743 475.60336 lineto +-522.02899 475.60336 lineto +-522.02899 476.96274 lineto +-521.72691 476.4315 -521.33368 476.03827 -520.8493 475.78305 curveto +-520.36493 475.52264 -519.77639 475.39243 -519.08368 475.39243 curveto +-518.98473 475.39243 -518.87535 475.40025 -518.75555 475.41586 curveto +-518.63577 475.42629 -518.50296 475.44452 -518.35712 475.47055 curveto +-518.3493 476.94711 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-507.77118 474.24399 moveto +-509.9118 480.04868 lineto +-505.62274 480.04868 lineto +-507.77118 474.24399 lineto +-508.6618 472.6893 moveto +-506.87274 472.6893 lineto +-502.42743 484.35336 lineto +-504.06805 484.35336 lineto +-505.13055 481.36118 lineto +-510.38837 481.36118 lineto +-511.45087 484.35336 lineto +-513.11493 484.35336 lineto +-508.6618 472.6893 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-499.15399 473.98618 moveto +-499.15399 478.36899 lineto +-497.16962 478.36899 lineto +-496.43525 478.36899 -495.86754 478.17889 -495.46649 477.79868 curveto +-495.06546 477.41847 -494.86494 476.87681 -494.86493 476.17368 curveto +-494.86494 475.47577 -495.06546 474.93671 -495.46649 474.55649 curveto +-495.86754 474.17629 -496.43525 473.98619 -497.16962 473.98618 curveto +-499.15399 473.98618 lineto +-500.73212 472.6893 moveto +-497.16962 472.6893 lineto +-495.86233 472.68931 -494.87535 472.98619 -494.20868 473.57993 curveto +-493.53681 474.16848 -493.20088 475.03306 -493.20087 476.17368 curveto +-493.20088 477.32472 -493.53681 478.19452 -494.20868 478.78305 curveto +-494.87535 479.3716 -495.86233 479.66587 -497.16962 479.66586 curveto +-499.15399 479.66586 lineto +-499.15399 484.35336 lineto +-500.73212 484.35336 lineto +-500.73212 472.6893 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-491.07587 472.6893 moveto +-489.49774 472.6893 lineto +-489.49774 484.35336 lineto +-491.07587 484.35336 lineto +-491.07587 472.6893 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-487.14618 479.32993 moveto +-482.93524 479.32993 lineto +-482.93524 480.61118 lineto +-487.14618 480.61118 lineto +-487.14618 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-481.36493 479.32993 moveto +-477.15399 479.32993 lineto +-477.15399 480.61118 lineto +-481.36493 480.61118 lineto +-481.36493 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-475.58368 479.32993 moveto +-471.37274 479.32993 lineto +-471.37274 480.61118 lineto +-475.58368 480.61118 lineto +-475.58368 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-469.80243 479.32993 moveto +-465.59149 479.32993 lineto +-465.59149 480.61118 lineto +-469.80243 480.61118 lineto +-469.80243 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-464.02118 479.32993 moveto +-459.81024 479.32993 lineto +-459.81024 480.61118 lineto +-464.02118 480.61118 lineto +-464.02118 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-458.23993 479.32993 moveto +-454.02899 479.32993 lineto +-454.02899 480.61118 lineto +-458.23993 480.61118 lineto +-458.23993 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-452.45868 479.32993 moveto +-448.24774 479.32993 lineto +-448.24774 480.61118 lineto +-452.45868 480.61118 lineto +-452.45868 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-446.67743 479.32993 moveto +-442.46649 479.32993 lineto +-442.46649 480.61118 lineto +-446.67743 480.61118 lineto +-446.67743 479.32993 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +-440.89618 479.32993 moveto +-436.68524 479.32993 lineto +-436.68524 480.61118 lineto +-440.89618 480.61118 lineto +-440.89618 479.32993 lineto +fill +grestore +grestore +gsave [0 1 -1 0 0 0] concat +gsave +0 0 1 setrgbcolor +newpath +561.92816 -268.25806 moveto +561.92816 -263.87524 lineto +563.91254 -263.87524 lineto +564.64691 -263.87524 565.21461 -264.06534 565.61566 -264.44556 curveto +566.0167 -264.82576 566.21722 -265.36742 566.21722 -266.07056 curveto +566.21722 -266.76846 566.0167 -267.30753 565.61566 -267.68774 curveto +565.21461 -268.06794 564.64691 -268.25805 563.91254 -268.25806 curveto +561.92816 -268.25806 lineto +560.35004 -269.55493 moveto +563.91254 -269.55493 lineto +565.21982 -269.55492 566.2068 -269.25805 566.87347 -268.66431 curveto +567.54534 -268.07575 567.88128 -267.21117 567.88129 -266.07056 curveto +567.88128 -264.91951 567.54534 -264.04972 566.87347 -263.46118 curveto +566.2068 -262.87263 565.21982 -262.57836 563.91254 -262.57837 curveto +561.92816 -262.57837 lineto +561.92816 -257.89087 lineto +560.35004 -257.89087 lineto +560.35004 -269.55493 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +574.73285 -265.29712 moveto +574.57138 -265.39086 574.3943 -265.45857 574.2016 -265.50024 curveto +574.01409 -265.54711 573.80576 -265.57055 573.5766 -265.57056 curveto +572.76409 -265.57055 572.1391 -265.30492 571.7016 -264.77368 curveto +571.2693 -264.24763 571.05316 -263.48982 571.05316 -262.50024 curveto +571.05316 -257.89087 lineto +569.60785 -257.89087 lineto +569.60785 -266.64087 lineto +571.05316 -266.64087 lineto +571.05316 -265.28149 lineto +571.35524 -265.81274 571.74847 -266.20596 572.23285 -266.46118 curveto +572.71722 -266.72159 573.30576 -266.8518 573.99847 -266.85181 curveto +574.09743 -266.8518 574.2068 -266.84399 574.3266 -266.82837 curveto +574.44638 -266.81794 574.5792 -266.79971 574.72504 -266.77368 curveto +574.73285 -265.29712 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +579.30316 -265.63306 moveto +578.53232 -265.63305 577.92295 -265.33097 577.47504 -264.72681 curveto +577.02712 -264.12784 576.80316 -263.30493 576.80316 -262.25806 curveto +576.80316 -261.21118 577.02451 -260.38566 577.46722 -259.78149 curveto +577.91514 -259.18253 578.52712 -258.88306 579.30316 -258.88306 curveto +580.06878 -258.88306 580.67555 -259.18514 581.12347 -259.78931 curveto +581.57138 -260.39347 581.79534 -261.21639 581.79535 -262.25806 curveto +581.79534 -263.29451 581.57138 -264.11482 581.12347 -264.71899 curveto +580.67555 -265.32836 580.06878 -265.63305 579.30316 -265.63306 curveto +579.30316 -266.85181 moveto +580.55316 -266.8518 581.53493 -266.44555 582.24847 -265.63306 curveto +582.96201 -264.82055 583.31878 -263.69555 583.31879 -262.25806 curveto +583.31878 -260.82576 582.96201 -259.70076 582.24847 -258.88306 curveto +581.53493 -258.07056 580.55316 -257.66431 579.30316 -257.66431 curveto +578.04795 -257.66431 577.06358 -258.07056 576.35004 -258.88306 curveto +575.6417 -259.70076 575.28754 -260.82576 575.28754 -262.25806 curveto +575.28754 -263.69555 575.6417 -264.82055 576.35004 -265.63306 curveto +577.06358 -266.44555 578.04795 -266.8518 579.30316 -266.85181 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +584.66254 -266.64087 moveto +586.18597 -266.64087 lineto +588.92035 -259.29712 lineto +591.65472 -266.64087 lineto +593.17816 -266.64087 lineto +589.89691 -257.89087 lineto +587.94379 -257.89087 lineto +584.66254 -266.64087 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +595.16254 -266.64087 moveto +596.60004 -266.64087 lineto +596.60004 -257.89087 lineto +595.16254 -257.89087 lineto +595.16254 -266.64087 lineto +595.16254 -270.04712 moveto +596.60004 -270.04712 lineto +596.60004 -268.22681 lineto +595.16254 -268.22681 lineto +595.16254 -270.04712 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +605.35785 -265.31274 moveto +605.35785 -270.04712 lineto +606.79535 -270.04712 lineto +606.79535 -257.89087 lineto +605.35785 -257.89087 lineto +605.35785 -259.20337 lineto +605.05576 -258.68254 604.67295 -258.29451 604.20941 -258.03931 curveto +603.75107 -257.78931 603.19899 -257.66431 602.55316 -257.66431 curveto +601.49587 -257.66431 600.63389 -258.08618 599.96722 -258.92993 curveto +599.30576 -259.77368 598.97504 -260.88305 598.97504 -262.25806 curveto +598.97504 -263.63305 599.30576 -264.74242 599.96722 -265.58618 curveto +600.63389 -266.42992 601.49587 -266.8518 602.55316 -266.85181 curveto +603.19899 -266.8518 603.75107 -266.72419 604.20941 -266.46899 curveto +604.67295 -266.21899 605.05576 -265.83357 605.35785 -265.31274 curveto +600.45941 -262.25806 moveto +600.45941 -261.20076 600.67555 -260.37003 601.10785 -259.76587 curveto +601.54535 -259.16691 602.1443 -258.86743 602.90472 -258.86743 curveto +603.66514 -258.86743 604.26409 -259.16691 604.7016 -259.76587 curveto +605.13909 -260.37003 605.35784 -261.20076 605.35785 -262.25806 curveto +605.35784 -263.31534 605.13909 -264.14347 604.7016 -264.74243 curveto +604.26409 -265.34659 603.66514 -265.64867 602.90472 -265.64868 curveto +602.1443 -265.64867 601.54535 -265.34659 601.10785 -264.74243 curveto +600.67555 -264.14347 600.45941 -263.31534 600.45941 -262.25806 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +617.24066 -262.62524 moveto +617.24066 -261.92212 lineto +610.63129 -261.92212 lineto +610.69378 -260.93253 610.99066 -260.17733 611.52191 -259.65649 curveto +612.05837 -259.14087 612.80316 -258.88306 613.75629 -258.88306 curveto +614.30836 -258.88306 614.84222 -258.95076 615.35785 -259.08618 curveto +615.87867 -259.2216 616.3943 -259.42472 616.90472 -259.69556 curveto +616.90472 -258.33618 lineto +616.38909 -258.11743 615.86045 -257.95076 615.31879 -257.83618 curveto +614.77711 -257.7216 614.22763 -257.66431 613.67035 -257.66431 curveto +612.27451 -257.66431 611.16774 -258.07056 610.35004 -258.88306 curveto +609.53754 -259.69555 609.13129 -260.79451 609.13129 -262.17993 curveto +609.13129 -263.61222 609.5167 -264.74763 610.28754 -265.58618 curveto +611.06358 -266.42992 612.10785 -266.8518 613.42035 -266.85181 curveto +614.59743 -266.8518 615.52711 -266.47159 616.20941 -265.71118 curveto +616.8969 -264.95597 617.24065 -263.92732 617.24066 -262.62524 curveto +615.80316 -263.04712 moveto +615.79274 -263.83357 615.57138 -264.46118 615.1391 -264.92993 curveto +614.71201 -265.39867 614.1443 -265.63305 613.43597 -265.63306 curveto +612.63389 -265.63305 611.99066 -265.40649 611.50629 -264.95337 curveto +611.02712 -264.50024 610.75108 -263.86222 610.67816 -263.03931 curveto +615.80316 -263.04712 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +624.6391 -265.29712 moveto +624.47763 -265.39086 624.30055 -265.45857 624.10785 -265.50024 curveto +623.92034 -265.54711 623.71201 -265.57055 623.48285 -265.57056 curveto +622.67034 -265.57055 622.04535 -265.30492 621.60785 -264.77368 curveto +621.17555 -264.24763 620.95941 -263.48982 620.95941 -262.50024 curveto +620.95941 -257.89087 lineto +619.5141 -257.89087 lineto +619.5141 -266.64087 lineto +620.95941 -266.64087 lineto +620.95941 -265.28149 lineto +621.26149 -265.81274 621.65472 -266.20596 622.1391 -266.46118 curveto +622.62347 -266.72159 623.21201 -266.8518 623.90472 -266.85181 curveto +624.00368 -266.8518 624.11305 -266.84399 624.23285 -266.82837 curveto +624.35263 -266.81794 624.48545 -266.79971 624.63129 -266.77368 curveto +624.6391 -265.29712 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +635.21722 -268.00024 moveto +633.0766 -262.19556 lineto +637.36566 -262.19556 lineto +635.21722 -268.00024 lineto +634.3266 -269.55493 moveto +636.11566 -269.55493 lineto +640.56097 -257.89087 lineto +638.92035 -257.89087 lineto +637.85785 -260.88306 lineto +632.60004 -260.88306 lineto +631.53754 -257.89087 lineto +629.87347 -257.89087 lineto +634.3266 -269.55493 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +643.83441 -268.25806 moveto +643.83441 -263.87524 lineto +645.81879 -263.87524 lineto +646.55316 -263.87524 647.12086 -264.06534 647.52191 -264.44556 curveto +647.92295 -264.82576 648.12347 -265.36742 648.12347 -266.07056 curveto +648.12347 -266.76846 647.92295 -267.30753 647.52191 -267.68774 curveto +647.12086 -268.06794 646.55316 -268.25805 645.81879 -268.25806 curveto +643.83441 -268.25806 lineto +642.25629 -269.55493 moveto +645.81879 -269.55493 lineto +647.12607 -269.55492 648.11305 -269.25805 648.77972 -268.66431 curveto +649.45159 -268.07575 649.78753 -267.21117 649.78754 -266.07056 curveto +649.78753 -264.91951 649.45159 -264.04972 648.77972 -263.46118 curveto +648.11305 -262.87263 647.12607 -262.57836 645.81879 -262.57837 curveto +643.83441 -262.57837 lineto +643.83441 -257.89087 lineto +642.25629 -257.89087 lineto +642.25629 -269.55493 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +651.91254 -269.55493 moveto +653.49066 -269.55493 lineto +653.49066 -257.89087 lineto +651.91254 -257.89087 lineto +651.91254 -269.55493 lineto +fill +grestore +grestore +gsave [0 1 -1 0 0 0] concat +gsave +0 1 0 setrgbcolor +newpath +444.54819 -268.81378 moveto +446.13412 -268.81378 lineto +446.13412 -261.72784 lineto +446.13412 -260.47784 446.36068 -259.5768 446.81381 -259.02472 curveto +447.26693 -258.47784 448.00131 -258.20441 449.01694 -258.20441 curveto +450.02735 -258.20441 450.75912 -258.47784 451.21225 -259.02472 curveto +451.66537 -259.5768 451.89193 -260.47784 451.89194 -261.72784 curveto +451.89194 -268.81378 lineto +453.47787 -268.81378 lineto +453.47787 -261.53253 lineto +453.47786 -260.0117 453.10026 -258.86326 452.34506 -258.08722 curveto +451.59505 -257.31118 450.48568 -256.92316 449.01694 -256.92316 curveto +447.54297 -256.92316 446.42839 -257.31118 445.67319 -258.08722 curveto +444.92319 -258.86326 444.54819 -260.0117 444.54819 -261.53253 curveto +444.54819 -268.81378 lineto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +461.96225 -265.64191 moveto +461.96225 -264.28253 lineto +461.55599 -264.49086 461.13412 -264.64711 460.69662 -264.75128 curveto +460.25912 -264.85544 459.80599 -264.90752 459.33725 -264.90753 curveto +458.6237 -264.90752 458.08725 -264.79815 457.72787 -264.57941 curveto +457.37371 -264.36065 457.19662 -264.03252 457.19662 -263.59503 curveto +457.19662 -263.26169 457.32423 -262.99867 457.57944 -262.80597 curveto +457.83464 -262.61846 458.34766 -262.43878 459.1185 -262.26691 curveto +459.61069 -262.15753 lineto +460.63151 -261.93878 461.35547 -261.62888 461.78256 -261.22784 curveto +462.21485 -260.83201 462.43099 -260.27732 462.431 -259.56378 curveto +462.43099 -258.75128 462.10808 -258.10805 461.46225 -257.63409 curveto +460.82162 -257.16014 459.93881 -256.92316 458.81381 -256.92316 curveto +458.34506 -256.92316 457.85548 -256.97003 457.34506 -257.06378 curveto +456.83985 -257.15232 456.306 -257.28774 455.7435 -257.47003 curveto +455.7435 -258.95441 lineto +456.27475 -258.67836 456.79819 -258.47003 457.31381 -258.32941 curveto +457.82943 -258.19399 458.33985 -258.12628 458.84506 -258.12628 curveto +459.52214 -258.12628 460.04297 -258.24086 460.40756 -258.47003 curveto +460.77214 -258.70441 460.95443 -259.03253 460.95444 -259.45441 curveto +460.95443 -259.84503 460.82162 -260.14451 460.556 -260.35284 curveto +460.29558 -260.56117 459.72006 -260.76169 458.82944 -260.95441 curveto +458.32944 -261.07159 lineto +457.43881 -261.25909 456.79558 -261.54555 456.39975 -261.93097 curveto +456.00392 -262.32159 455.806 -262.85544 455.806 -263.53253 curveto +455.806 -264.35544 456.09767 -264.99086 456.681 -265.43878 curveto +457.26433 -265.88669 458.09245 -266.11065 459.16537 -266.11066 curveto +459.69662 -266.11065 460.19662 -266.07159 460.66537 -265.99347 curveto +461.13412 -265.91534 461.56641 -265.79815 461.96225 -265.64191 curveto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +472.21225 -261.88409 moveto +472.21225 -261.18097 lineto +465.60287 -261.18097 lineto +465.66537 -260.19138 465.96225 -259.43618 466.4935 -258.91534 curveto +467.02995 -258.39972 467.77475 -258.14191 468.72787 -258.14191 curveto +469.27995 -258.14191 469.81381 -258.20961 470.32944 -258.34503 curveto +470.85026 -258.48045 471.36589 -258.68357 471.87631 -258.95441 curveto +471.87631 -257.59503 lineto +471.36068 -257.37628 470.83203 -257.20962 470.29037 -257.09503 curveto +469.7487 -256.98045 469.19922 -256.92316 468.64194 -256.92316 curveto +467.2461 -256.92316 466.13933 -257.32941 465.32162 -258.14191 curveto +464.50912 -258.9544 464.10287 -260.05336 464.10287 -261.43878 curveto +464.10287 -262.87107 464.48829 -264.00648 465.25912 -264.84503 curveto +466.03516 -265.68877 467.07943 -266.11065 468.39194 -266.11066 curveto +469.56901 -266.11065 470.4987 -265.73044 471.181 -264.97003 curveto +471.86849 -264.21482 472.21224 -263.18617 472.21225 -261.88409 curveto +470.77475 -262.30597 moveto +470.76433 -263.09242 470.54297 -263.72003 470.11069 -264.18878 curveto +469.6836 -264.65752 469.11589 -264.8919 468.40756 -264.89191 curveto +467.60547 -264.8919 466.96225 -264.66534 466.47787 -264.21222 curveto +465.99871 -263.75909 465.72266 -263.12107 465.64975 -262.29816 curveto +470.77475 -262.30597 lineto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +479.61069 -264.55597 moveto +479.44922 -264.64971 479.27214 -264.71742 479.07944 -264.75909 curveto +478.89193 -264.80596 478.6836 -264.8294 478.45444 -264.82941 curveto +477.64193 -264.8294 477.01693 -264.56377 476.57944 -264.03253 curveto +476.14714 -263.50648 475.931 -262.74867 475.931 -261.75909 curveto +475.931 -257.14972 lineto +474.48569 -257.14972 lineto +474.48569 -265.89972 lineto +475.931 -265.89972 lineto +475.931 -264.54034 lineto +476.23308 -265.07159 476.62631 -265.46482 477.11069 -265.72003 curveto +477.59506 -265.98044 478.1836 -266.11065 478.87631 -266.11066 curveto +478.97526 -266.11065 479.08464 -266.10284 479.20444 -266.08722 curveto +479.32422 -266.07679 479.45703 -266.05856 479.60287 -266.03253 curveto +479.61069 -264.55597 lineto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +490.18881 -267.25909 moveto +488.04819 -261.45441 lineto +492.33725 -261.45441 lineto +490.18881 -267.25909 lineto +489.29819 -268.81378 moveto +491.08725 -268.81378 lineto +495.53256 -257.14972 lineto +493.89194 -257.14972 lineto +492.82944 -260.14191 lineto +487.57162 -260.14191 lineto +486.50912 -257.14972 lineto +484.84506 -257.14972 lineto +489.29819 -268.81378 lineto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +498.806 -267.51691 moveto +498.806 -263.13409 lineto +500.79037 -263.13409 lineto +501.52474 -263.13409 502.09245 -263.32419 502.4935 -263.70441 curveto +502.89453 -264.08461 503.09505 -264.62627 503.09506 -265.32941 curveto +503.09505 -266.02731 502.89453 -266.56638 502.4935 -266.94659 curveto +502.09245 -267.32679 501.52474 -267.5169 500.79037 -267.51691 curveto +498.806 -267.51691 lineto +497.22787 -268.81378 moveto +500.79037 -268.81378 lineto +502.09766 -268.81377 503.08464 -268.5169 503.75131 -267.92316 curveto +504.42318 -267.3346 504.75912 -266.47002 504.75912 -265.32941 curveto +504.75912 -264.17836 504.42318 -263.30857 503.75131 -262.72003 curveto +503.08464 -262.13149 502.09766 -261.83721 500.79037 -261.83722 curveto +498.806 -261.83722 lineto +498.806 -257.14972 lineto +497.22787 -257.14972 lineto +497.22787 -268.81378 lineto +fill +grestore +gsave +0 1 0 setrgbcolor +newpath +506.88412 -268.81378 moveto +508.46225 -268.81378 lineto +508.46225 -257.14972 lineto +506.88412 -257.14972 lineto +506.88412 -268.81378 lineto +fill +grestore +grestore +gsave +1 1 1 setrgbcolor +newpath +311.65579 618.66467 moveto +421.35918 618.66467 lineto +421.35918 648.54013 lineto +311.65579 648.54013 lineto +311.65579 618.66467 lineto +closepath +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +1.5554247 setlinewidth +0 setlinejoin +0 setlinecap +newpath +311.65579 618.66467 moveto +421.35918 618.66467 lineto +421.35918 648.54013 lineto +311.65579 648.54013 lineto +311.65579 618.66467 lineto +closepath +stroke +gsave +0 0 0 setrgbcolor +newpath +318.39755 627.07782 moveto +319.58115 627.07782 lineto +319.58115 635.82587 lineto +318.39755 635.82587 lineto +318.39755 627.07782 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +327.34482 631.86493 moveto +327.34482 635.82587 lineto +326.26669 635.82587 lineto +326.26669 631.90009 lineto +326.26669 631.279 326.14559 630.81415 325.90341 630.50555 curveto +325.66122 630.19697 325.29794 630.04267 324.81357 630.04266 curveto +324.23153 630.04267 323.77255 630.22822 323.43661 630.5993 curveto +323.10068 630.9704 322.93271 631.47626 322.93271 632.11688 curveto +322.93271 635.82587 lineto +321.84872 635.82587 lineto +321.84872 629.26337 lineto +322.93271 629.26337 lineto +322.93271 630.2829 lineto +323.19052 629.88837 323.49325 629.59345 323.84091 629.39813 curveto +324.19247 629.20283 324.59677 629.10517 325.0538 629.10516 curveto +325.8077 629.10517 326.37802 629.33955 326.76474 629.80829 curveto +327.15145 630.27314 327.34481 630.95868 327.34482 631.86493 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +330.57333 627.40009 moveto +330.57333 629.26337 lineto +332.79404 629.26337 lineto +332.79404 630.10126 lineto +330.57333 630.10126 lineto +330.57333 633.66376 lineto +330.57333 634.19892 330.6456 634.54266 330.79013 634.69501 curveto +330.93857 634.84735 331.23739 634.92352 331.68661 634.92352 curveto +332.79404 634.92352 lineto +332.79404 635.82587 lineto +331.68661 635.82587 lineto +330.85458 635.82587 330.28036 635.67157 329.96396 635.36298 curveto +329.64755 635.05048 329.48935 634.48407 329.48935 633.66376 curveto +329.48935 630.10126 lineto +328.69833 630.10126 lineto +328.69833 629.26337 lineto +329.48935 629.26337 lineto +329.48935 627.40009 lineto +330.57333 627.40009 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +339.83115 632.27509 moveto +339.83115 632.80243 lineto +334.87411 632.80243 lineto +334.92099 633.54462 335.14364 634.11102 335.54208 634.50165 curveto +335.94442 634.88837 336.50302 635.08173 337.21786 635.08173 curveto +337.63192 635.08173 338.03231 635.03095 338.41904 634.92938 curveto +338.80966 634.82782 339.19637 634.67548 339.57919 634.47235 curveto +339.57919 635.49188 lineto +339.19247 635.65594 338.79598 635.78094 338.38974 635.86688 curveto +337.98349 635.95282 337.57138 635.99579 337.15341 635.99579 curveto +336.10653 635.99579 335.27646 635.6911 334.66318 635.08173 curveto +334.0538 634.47235 333.74911 633.64813 333.74911 632.60907 curveto +333.74911 631.53486 334.03818 630.68329 334.6163 630.05438 curveto +335.19833 629.42158 335.98153 629.10517 336.96591 629.10516 curveto +337.84872 629.10517 338.54598 629.39033 339.05771 629.96063 curveto +339.57333 630.52704 339.83114 631.29853 339.83115 632.27509 curveto +338.75302 631.95868 moveto +338.7452 631.36884 338.57919 630.89814 338.25497 630.54657 curveto +337.93466 630.19501 337.50888 630.01923 336.97763 630.01923 curveto +336.37606 630.01923 335.89364 630.18915 335.53036 630.52899 curveto +335.17099 630.86884 334.96396 631.34736 334.90927 631.96454 curveto +338.75302 631.95868 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +345.37997 630.27118 moveto +345.25888 630.20087 345.12606 630.15009 344.98154 630.11884 curveto +344.84091 630.08368 344.68466 630.06611 344.51279 630.0661 curveto +343.90341 630.06611 343.43466 630.26533 343.10654 630.66376 curveto +342.78232 631.05829 342.62021 631.62665 342.62021 632.36884 curveto +342.62021 635.82587 lineto +341.53622 635.82587 lineto +341.53622 629.26337 lineto +342.62021 629.26337 lineto +342.62021 630.2829 lineto +342.84677 629.88447 343.14169 629.58954 343.50497 629.39813 curveto +343.86825 629.20283 344.30966 629.10517 344.82919 629.10516 curveto +344.90341 629.10517 344.98544 629.11103 345.07529 629.12274 curveto +345.16513 629.13056 345.26474 629.14423 345.37411 629.16376 curveto +345.37997 630.27118 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +351.76669 631.86493 moveto +351.76669 635.82587 lineto +350.68857 635.82587 lineto +350.68857 631.90009 lineto +350.68856 631.279 350.56747 630.81415 350.32529 630.50555 curveto +350.08309 630.19697 349.71981 630.04267 349.23544 630.04266 curveto +348.65341 630.04267 348.19442 630.22822 347.85849 630.5993 curveto +347.52255 630.9704 347.35458 631.47626 347.35458 632.11688 curveto +347.35458 635.82587 lineto +346.2706 635.82587 lineto +346.2706 629.26337 lineto +347.35458 629.26337 lineto +347.35458 630.2829 lineto +347.61239 629.88837 347.91513 629.59345 348.26279 629.39813 curveto +348.61435 629.20283 349.01864 629.10517 349.47568 629.10516 curveto +350.22958 629.10517 350.79989 629.33955 351.18661 629.80829 curveto +351.57333 630.27314 351.76669 630.95868 351.76669 631.86493 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +356.91122 632.52704 moveto +356.04013 632.52704 355.43661 632.62665 355.10068 632.82587 curveto +354.76474 633.02509 354.59677 633.36493 354.59677 633.8454 curveto +354.59677 634.22821 354.72177 634.5329 354.97177 634.75946 curveto +355.22568 634.98212 355.56942 635.09345 356.00302 635.09344 curveto +356.60067 635.09345 357.07919 634.88251 357.43857 634.46063 curveto +357.80184 634.03485 357.98348 633.4704 357.98349 632.76727 curveto +357.98349 632.52704 lineto +356.91122 632.52704 lineto +359.06161 632.08173 moveto +359.06161 635.82587 lineto +357.98349 635.82587 lineto +357.98349 634.82977 lineto +357.73739 635.22821 357.43075 635.52313 357.06357 635.71454 curveto +356.69638 635.90204 356.24716 635.99579 355.71591 635.99579 curveto +355.04403 635.99579 354.50888 635.80829 354.11044 635.43329 curveto +353.71591 635.05438 353.51865 634.54852 353.51865 633.91571 curveto +353.51865 633.17743 353.76474 632.62079 354.25693 632.24579 curveto +354.75302 631.87079 355.4913 631.68329 356.47177 631.68329 curveto +357.98349 631.68329 lineto +357.98349 631.57782 lineto +357.98348 631.08173 357.81942 630.69892 357.4913 630.42938 curveto +357.16708 630.15595 356.71005 630.01923 356.12021 630.01923 curveto +355.74521 630.01923 355.37997 630.06415 355.02451 630.15399 curveto +354.66903 630.24384 354.32724 630.37861 353.99911 630.55829 curveto +353.99911 629.56219 lineto +354.39364 629.40986 354.77646 629.29658 355.14755 629.22235 curveto +355.51864 629.14423 355.87997 629.10517 356.23154 629.10516 curveto +357.18075 629.10517 357.88973 629.35126 358.35849 629.84344 curveto +358.82723 630.33564 359.06161 631.08173 359.06161 632.08173 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +361.31161 626.70868 moveto +362.38974 626.70868 lineto +362.38974 635.82587 lineto +361.31161 635.82587 lineto +361.31161 626.70868 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +369.69052 628.05048 moveto +369.69052 631.33759 lineto +371.1788 631.33759 lineto +371.72958 631.33759 372.15536 631.19501 372.45615 630.90985 curveto +372.75692 630.6247 372.90731 630.21845 372.90732 629.6911 curveto +372.90731 629.16767 372.75692 628.76337 372.45615 628.47821 curveto +372.15536 628.19306 371.72958 628.05048 371.1788 628.05048 curveto +369.69052 628.05048 lineto +368.50693 627.07782 moveto +371.1788 627.07782 lineto +372.15927 627.07783 372.8995 627.30048 373.39951 627.74579 curveto +373.90341 628.1872 374.15536 628.83564 374.15536 629.6911 curveto +374.15536 630.55439 373.90341 631.20673 373.39951 631.64813 curveto +372.8995 632.08954 372.15927 632.31025 371.1788 632.31024 curveto +369.69052 632.31024 lineto +369.69052 635.82587 lineto +368.50693 635.82587 lineto +368.50693 627.07782 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +379.29404 630.27118 moveto +379.17294 630.20087 379.04013 630.15009 378.8956 630.11884 curveto +378.75497 630.08368 378.59872 630.06611 378.42685 630.0661 curveto +377.81747 630.06611 377.34872 630.26533 377.0206 630.66376 curveto +376.69638 631.05829 376.53427 631.62665 376.53427 632.36884 curveto +376.53427 635.82587 lineto +375.45029 635.82587 lineto +375.45029 629.26337 lineto +376.53427 629.26337 lineto +376.53427 630.2829 lineto +376.76083 629.88447 377.05575 629.58954 377.41904 629.39813 curveto +377.78231 629.20283 378.22372 629.10517 378.74326 629.10516 curveto +378.81747 629.10517 378.8995 629.11103 378.98935 629.12274 curveto +379.07919 629.13056 379.1788 629.14423 379.28818 629.16376 curveto +379.29404 630.27118 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +382.72177 630.01923 moveto +382.14364 630.01923 381.68661 630.24579 381.35068 630.69891 curveto +381.01474 631.14814 380.84677 631.76532 380.84677 632.55048 curveto +380.84677 633.33563 381.01278 633.95477 381.34482 634.4079 curveto +381.68075 634.85712 382.13974 635.08173 382.72177 635.08173 curveto +383.29599 635.08173 383.75106 634.85516 384.08701 634.40204 curveto +384.42294 633.94892 384.59091 633.33173 384.59091 632.55048 curveto +384.59091 631.77314 384.42294 631.1579 384.08701 630.70477 curveto +383.75106 630.24775 383.29599 630.01923 382.72177 630.01923 curveto +382.72177 629.10516 moveto +383.65927 629.10517 384.39559 629.40986 384.93076 630.01923 curveto +385.46591 630.62861 385.73348 631.47236 385.73349 632.55048 curveto +385.73348 633.6247 385.46591 634.46845 384.93076 635.08173 curveto +384.39559 635.6911 383.65927 635.99579 382.72177 635.99579 curveto +381.78036 635.99579 381.04208 635.6911 380.50693 635.08173 curveto +379.97568 634.46845 379.71005 633.6247 379.71005 632.55048 curveto +379.71005 631.47236 379.97568 630.62861 380.50693 630.01923 curveto +381.04208 629.40986 381.78036 629.10517 382.72177 629.10516 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +386.7413 629.26337 moveto +387.88388 629.26337 lineto +389.93466 634.77118 lineto +391.98544 629.26337 lineto +393.12802 629.26337 lineto +390.66708 635.82587 lineto +389.20224 635.82587 lineto +386.7413 629.26337 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +394.6163 629.26337 moveto +395.69443 629.26337 lineto +395.69443 635.82587 lineto +394.6163 635.82587 lineto +394.6163 629.26337 lineto +394.6163 626.70868 moveto +395.69443 626.70868 lineto +395.69443 628.07391 lineto +394.6163 628.07391 lineto +394.6163 626.70868 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +402.26279 630.25946 moveto +402.26279 626.70868 lineto +403.34091 626.70868 lineto +403.34091 635.82587 lineto +402.26279 635.82587 lineto +402.26279 634.84149 lineto +402.03622 635.23212 401.74911 635.52313 401.40146 635.71454 curveto +401.0577 635.90204 400.64364 635.99579 400.15927 635.99579 curveto +399.3663 635.99579 398.71982 635.67938 398.21982 635.04657 curveto +397.72372 634.41376 397.47568 633.58173 397.47568 632.55048 curveto +397.47568 631.51923 397.72372 630.6872 398.21982 630.05438 curveto +398.71982 629.42158 399.3663 629.10517 400.15927 629.10516 curveto +400.64364 629.10517 401.0577 629.20087 401.40146 629.39227 curveto +401.74911 629.57978 402.03622 629.86884 402.26279 630.25946 curveto +398.58896 632.55048 moveto +398.58896 633.34345 398.75107 633.96649 399.07529 634.41962 curveto +399.40341 634.86884 399.85263 635.09345 400.42294 635.09344 curveto +400.99325 635.09345 401.44247 634.86884 401.7706 634.41962 curveto +402.09872 633.96649 402.26278 633.34345 402.26279 632.55048 curveto +402.26278 631.75751 402.09872 631.13642 401.7706 630.68719 curveto +401.44247 630.23408 400.99325 630.00751 400.42294 630.00751 curveto +399.85263 630.00751 399.40341 630.23408 399.07529 630.68719 curveto +398.75107 631.13642 398.58896 631.75751 398.58896 632.55048 curveto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +411.1749 632.27509 moveto +411.1749 632.80243 lineto +406.21786 632.80243 lineto +406.26474 633.54462 406.48739 634.11102 406.88583 634.50165 curveto +407.28817 634.88837 407.84677 635.08173 408.56161 635.08173 curveto +408.97567 635.08173 409.37606 635.03095 409.76279 634.92938 curveto +410.15341 634.82782 410.54012 634.67548 410.92294 634.47235 curveto +410.92294 635.49188 lineto +410.53622 635.65594 410.13973 635.78094 409.73349 635.86688 curveto +409.32724 635.95282 408.91513 635.99579 408.49716 635.99579 curveto +407.45028 635.99579 406.62021 635.6911 406.00693 635.08173 curveto +405.39755 634.47235 405.09286 633.64813 405.09286 632.60907 curveto +405.09286 631.53486 405.38193 630.68329 405.96005 630.05438 curveto +406.54208 629.42158 407.32528 629.10517 408.30966 629.10516 curveto +409.19247 629.10517 409.88973 629.39033 410.40146 629.96063 curveto +410.91708 630.52704 411.17489 631.29853 411.1749 632.27509 curveto +410.09677 631.95868 moveto +410.08895 631.36884 409.92294 630.89814 409.59872 630.54657 curveto +409.27841 630.19501 408.85263 630.01923 408.32138 630.01923 curveto +407.71981 630.01923 407.23739 630.18915 406.87411 630.52899 curveto +406.51474 630.86884 406.30771 631.34736 406.25302 631.96454 curveto +410.09677 631.95868 lineto +fill +grestore +gsave +0 0 0 setrgbcolor +newpath +416.72372 630.27118 moveto +416.60263 630.20087 416.46981 630.15009 416.32529 630.11884 curveto +416.18466 630.08368 416.02841 630.06611 415.85654 630.0661 curveto +415.24716 630.06611 414.77841 630.26533 414.45029 630.66376 curveto +414.12607 631.05829 413.96396 631.62665 413.96396 632.36884 curveto +413.96396 635.82587 lineto +412.87997 635.82587 lineto +412.87997 629.26337 lineto +413.96396 629.26337 lineto +413.96396 630.2829 lineto +414.19052 629.88447 414.48544 629.58954 414.84872 629.39813 curveto +415.212 629.20283 415.65341 629.10517 416.17294 629.10516 curveto +416.24716 629.10517 416.32919 629.11103 416.41904 629.12274 curveto +416.50888 629.13056 416.60849 629.14423 416.71786 629.16376 curveto +416.72372 630.27118 lineto +fill +grestore +0 0 0 setrgbcolor +[] 0 setdash +0.87666082 setlinewidth +0 setlinejoin +0 setlinecap +newpath +366.87805 584.8962 moveto +366.87805 618.38061 366.87805 618.38061 366.87805 618.38061 curveto +stroke +gsave [5.9046043e-17 0.96432691 -0.96432691 5.9046043e-17 366.87805 585.86053] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave [-5.9046043e-17 -0.96432691 0.96432691 -5.9046043e-17 366.87805 617.41628] concat +gsave +0 0 0 setrgbcolor +newpath +8.7185878 4.0337352 moveto +-2.2072895 0.016013256 lineto +8.7185884 -4.0017078 lineto +6.97309 -1.6296469 6.9831476 1.6157441 8.7185878 4.0337352 curveto +closepath +eofill +grestore +grestore +gsave +0 0 1 setrgbcolor +newpath +338.6001 596.77057 moveto +338.6001 599.50983 lineto +339.84033 599.50983 lineto +340.29931 599.50983 340.65413 599.39102 340.90479 599.15338 curveto +341.15543 598.91576 341.28076 598.57721 341.28076 598.13776 curveto +341.28076 597.70156 341.15543 597.36465 340.90479 597.12701 curveto +340.65413 596.88939 340.29931 596.77058 339.84033 596.77057 curveto +338.6001 596.77057 lineto +337.61377 595.96002 moveto +339.84033 595.96002 lineto +340.65739 595.96003 341.27425 596.14558 341.69092 596.51666 curveto +342.11083 596.88451 342.3208 597.42487 342.3208 598.13776 curveto +342.3208 598.85716 342.11083 599.40078 341.69092 599.76862 curveto +341.27425 600.13646 340.65739 600.32038 339.84033 600.32037 curveto +338.6001 600.32037 lineto +338.6001 603.25006 lineto +337.61377 603.25006 lineto +337.61377 595.96002 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +346.60303 598.62115 moveto +346.50211 598.56257 346.39143 598.52025 346.271 598.4942 curveto +346.1538 598.46491 346.0236 598.45026 345.88037 598.45026 curveto +345.37256 598.45026 344.98193 598.61628 344.7085 598.9483 curveto +344.43831 599.27708 344.30322 599.75072 344.30322 600.3692 curveto +344.30322 603.25006 lineto +343.3999 603.25006 lineto +343.3999 597.78131 lineto +344.30322 597.78131 lineto +344.30322 598.63092 lineto +344.49202 598.29889 344.73779 598.05313 345.04053 597.89362 curveto +345.34326 597.73086 345.7111 597.64948 346.14404 597.64948 curveto +346.20589 597.64948 346.27425 597.65436 346.34912 597.66412 curveto +346.42399 597.67064 346.50699 597.68203 346.59814 597.6983 curveto +346.60303 598.62115 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +349.45947 598.41119 moveto +348.9777 598.4112 348.59684 598.6 348.31689 598.9776 curveto +348.03694 599.35195 347.89697 599.86628 347.89697 600.52057 curveto +347.89697 601.17487 348.03532 601.69082 348.31201 602.06842 curveto +348.59196 602.44277 348.97444 602.62994 349.45947 602.62994 curveto +349.93798 602.62994 350.31722 602.44114 350.59717 602.06354 curveto +350.87711 601.68593 351.01709 601.17161 351.01709 600.52057 curveto +351.01709 599.87279 350.87711 599.36009 350.59717 598.98248 curveto +350.31722 598.60163 349.93798 598.4112 349.45947 598.41119 curveto +349.45947 597.64948 moveto +350.24072 597.64948 350.85432 597.90339 351.30029 598.41119 curveto +351.74625 598.91901 351.96923 599.62213 351.96924 600.52057 curveto +351.96923 601.41575 351.74625 602.11888 351.30029 602.62994 curveto +350.85432 603.13776 350.24072 603.39166 349.45947 603.39166 curveto +348.67497 603.39166 348.05973 603.13776 347.61377 602.62994 curveto +347.17106 602.11888 346.94971 601.41575 346.94971 600.52057 curveto +346.94971 599.62213 347.17106 598.91901 347.61377 598.41119 curveto +348.05973 597.90339 348.67497 597.64948 349.45947 597.64948 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +352.80908 597.78131 moveto +353.76123 597.78131 lineto +355.47021 602.37115 lineto +357.1792 597.78131 lineto +358.13135 597.78131 lineto +356.08057 603.25006 lineto +354.85986 603.25006 lineto +352.80908 597.78131 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +359.37158 597.78131 moveto +360.27002 597.78131 lineto +360.27002 603.25006 lineto +359.37158 603.25006 lineto +359.37158 597.78131 lineto +359.37158 595.6524 moveto +360.27002 595.6524 lineto +360.27002 596.7901 lineto +359.37158 596.7901 lineto +359.37158 595.6524 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +365.74365 598.61139 moveto +365.74365 595.6524 lineto +366.64209 595.6524 lineto +366.64209 603.25006 lineto +365.74365 603.25006 lineto +365.74365 602.42975 lineto +365.55485 602.75527 365.31559 602.99778 365.02588 603.15729 curveto +364.73942 603.31354 364.39437 603.39166 363.99072 603.39166 curveto +363.32991 603.39166 362.79118 603.12799 362.37451 602.60065 curveto +361.9611 602.0733 361.75439 601.37995 361.75439 600.52057 curveto +361.75439 599.6612 361.9611 598.96784 362.37451 598.44049 curveto +362.79118 597.91315 363.32991 597.64948 363.99072 597.64948 curveto +364.39437 597.64948 364.73942 597.72923 365.02588 597.88873 curveto +365.31559 598.04499 365.55485 598.28587 365.74365 598.61139 curveto +362.68213 600.52057 moveto +362.68213 601.18138 362.81722 601.70058 363.0874 602.07819 curveto +363.36084 602.45254 363.73519 602.63971 364.21045 602.63971 curveto +364.68571 602.63971 365.06005 602.45254 365.3335 602.07819 curveto +365.60693 601.70058 365.74365 601.18138 365.74365 600.52057 curveto +365.74365 599.85976 365.60693 599.34219 365.3335 598.96783 curveto +365.06005 598.59023 364.68571 598.40143 364.21045 598.40143 curveto +363.73519 598.40143 363.36084 598.59023 363.0874 598.96783 curveto +362.81722 599.34219 362.68213 599.85976 362.68213 600.52057 curveto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +373.17041 600.29108 moveto +373.17041 600.73053 lineto +369.03955 600.73053 lineto +369.07861 601.34902 369.26416 601.82103 369.59619 602.14655 curveto +369.93148 602.46881 370.39697 602.62994 370.99268 602.62994 curveto +371.33772 602.62994 371.67138 602.58763 371.99365 602.50299 curveto +372.31917 602.41836 372.64143 602.2914 372.96045 602.12213 curveto +372.96045 602.97174 lineto +372.63818 603.10846 372.30778 603.21263 371.96924 603.28424 curveto +371.63069 603.35586 371.28727 603.39166 370.93896 603.39166 curveto +370.06657 603.39166 369.37484 603.13776 368.86377 602.62994 curveto +368.35596 602.12213 368.10205 601.43528 368.10205 600.5694 curveto +368.10205 599.67422 368.34294 598.96458 368.82471 598.44049 curveto +369.30973 597.91315 369.9624 597.64948 370.78271 597.64948 curveto +371.51839 597.64948 372.09944 597.88711 372.52588 598.36237 curveto +372.95556 598.83438 373.1704 599.47728 373.17041 600.29108 curveto +372.27197 600.0274 moveto +372.26546 599.53587 372.12711 599.14362 371.85693 598.85065 curveto +371.59 598.55768 371.23519 598.4112 370.79248 598.41119 curveto +370.29118 598.4112 369.88916 598.5528 369.58643 598.836 curveto +369.28694 599.11921 369.11442 599.51797 369.06885 600.03229 curveto +372.27197 600.0274 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +377.79443 598.62115 moveto +377.69352 598.56257 377.58284 598.52025 377.4624 598.4942 curveto +377.34521 598.46491 377.215 598.45026 377.07178 598.45026 curveto +376.56396 598.45026 376.17334 598.61628 375.8999 598.9483 curveto +375.62972 599.27708 375.49463 599.75072 375.49463 600.3692 curveto +375.49463 603.25006 lineto +374.59131 603.25006 lineto +374.59131 597.78131 lineto +375.49463 597.78131 lineto +375.49463 598.63092 lineto +375.68343 598.29889 375.9292 598.05313 376.23193 597.89362 curveto +376.53467 597.73086 376.9025 597.64948 377.33545 597.64948 curveto +377.39729 597.64948 377.46565 597.65436 377.54053 597.66412 curveto +377.61539 597.67064 377.6984 597.68203 377.78955 597.6983 curveto +377.79443 598.62115 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +384.40576 596.9317 moveto +383.06787 600.55963 lineto +385.74854 600.55963 lineto +384.40576 596.9317 lineto +383.84912 595.96002 moveto +384.96729 595.96002 lineto +387.74561 603.25006 lineto +386.72021 603.25006 lineto +386.05615 601.37994 lineto +382.77002 601.37994 lineto +382.10596 603.25006 lineto +381.06592 603.25006 lineto +383.84912 595.96002 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +389.7915 596.77057 moveto +389.7915 599.50983 lineto +391.03174 599.50983 lineto +391.49072 599.50983 391.84554 599.39102 392.09619 599.15338 curveto +392.34684 598.91576 392.47216 598.57721 392.47217 598.13776 curveto +392.47216 597.70156 392.34684 597.36465 392.09619 597.12701 curveto +391.84554 596.88939 391.49072 596.77058 391.03174 596.77057 curveto +389.7915 596.77057 lineto +388.80518 595.96002 moveto +391.03174 595.96002 lineto +391.84879 595.96003 392.46565 596.14558 392.88232 596.51666 curveto +393.30224 596.88451 393.5122 597.42487 393.51221 598.13776 curveto +393.5122 598.85716 393.30224 599.40078 392.88232 599.76862 curveto +392.46565 600.13646 391.84879 600.32038 391.03174 600.32037 curveto +389.7915 600.32037 lineto +389.7915 603.25006 lineto +388.80518 603.25006 lineto +388.80518 595.96002 lineto +fill +grestore +gsave +0 0 1 setrgbcolor +newpath +394.84033 595.96002 moveto +395.82666 595.96002 lineto +395.82666 603.25006 lineto +394.84033 603.25006 lineto +394.84033 595.96002 lineto +fill +grestore +grestore +showpage +%%EOF diff --git a/local/recipes/libs/qca/source/docs/pics/qca-arch.png b/local/recipes/libs/qca/source/docs/pics/qca-arch.png new file mode 100644 index 0000000000..21d876a517 Binary files /dev/null and b/local/recipes/libs/qca/source/docs/pics/qca-arch.png differ diff --git a/local/recipes/libs/qca/source/docs/pics/qca-arch.svg b/local/recipes/libs/qca/source/docs/pics/qca-arch.svg new file mode 100644 index 0000000000..9dd195f663 --- /dev/null +++ b/local/recipes/libs/qca/source/docs/pics/qca-arch.svg @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Core QCA library(libqca) + GnuPG-based plugin + + Application + + Client-side provider(if used) + + + OpenSSL-based plugin + + + Smartcard (PKCS-11) plugin + + + + + Other plugins + + + + ---------Provider API--------- + Provider API + User API + + Internal Provider + + Provider API + + diff --git a/local/recipes/libs/qca/source/examples/CMakeLists.txt b/local/recipes/libs/qca/source/examples/CMakeLists.txt new file mode 100644 index 0000000000..6ce6ef3b07 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/CMakeLists.txt @@ -0,0 +1,27 @@ +find_package(Qt${QT_MAJOR_VERSION} REQUIRED Network) +if(NOT BUILD_WITH_QT6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") +endif() +add_subdirectory(aes-cmac) +add_subdirectory(base64test) +add_subdirectory(certtest) +add_subdirectory(ciphertest) +add_subdirectory(cms) +# this is not meant to be added, because it introduces +# a dependency on QtGui. +# add_subdirectory(cmssigner) +add_subdirectory(eventhandlerdemo) +add_subdirectory(hashtest) +add_subdirectory(hextest) +add_subdirectory(keyloader) +add_subdirectory(mactest) +add_subdirectory(md5crypt) +add_subdirectory(providertest) +add_subdirectory(publickeyexample) +add_subdirectory(randomtest) +add_subdirectory(rsatest) +add_subdirectory(saslclient) +add_subdirectory(saslserver) +add_subdirectory(ssltest) +add_subdirectory(sslservtest) +add_subdirectory(tlssocket) diff --git a/local/recipes/libs/qca/source/examples/aes-cmac/CMakeLists.txt b/local/recipes/libs/qca/source/examples/aes-cmac/CMakeLists.txt new file mode 100644 index 0000000000..9dcdb2e314 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/aes-cmac/CMakeLists.txt @@ -0,0 +1,5 @@ +set(aes-cmac_bin_SRCS aes-cmac.cpp) + +add_executable(aes-cmac ${aes-cmac_bin_SRCS}) + +target_link_qca_libraries(aes-cmac) diff --git a/local/recipes/libs/qca/source/examples/aes-cmac/aes-cmac.cpp b/local/recipes/libs/qca/source/examples/aes-cmac/aes-cmac.cpp new file mode 100644 index 0000000000..2ac161a5fd --- /dev/null +++ b/local/recipes/libs/qca/source/examples/aes-cmac/aes-cmac.cpp @@ -0,0 +1,306 @@ +/* + Copyright (C) 2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class AESCMACContext : public QCA::MACContext +{ + Q_OBJECT +public: + AESCMACContext(QCA::Provider *p) + : QCA::MACContext(p, QStringLiteral("cmac(aes)")) + { + } + + // Helper to left shift an arbitrary length array + // This is heavily based on the example in the I-D. + QCA::SecureArray leftShift(const QCA::SecureArray &array) + { + // We create an output of the same size as the input + QCA::SecureArray out(array.size()); + // We handle one byte at a time - this is the high bit + // from the previous byte. + int overflow = 0; + + // work through each byte. + for (int i = array.size() - 1; i >= 0; --i) { + // do the left shift on this byte. + out[i] = array[i] << 1; + // make the low bit on this byte be the high bit + // from the previous byte. + out[i] |= overflow; + // save the high bit for next time + overflow = (array[i] & 0x80) ? 1 : 0; + } + return out; + } + + // Helper to XOR two arrays - must be same length + QCA::SecureArray xorArray(const QCA::SecureArray &array1, const QCA::SecureArray &array2) + { + if (array1.size() != array2.size()) + // empty array + return QCA::SecureArray(); + + QCA::SecureArray result(array1.size()); + + for (int i = 0; i < array1.size(); ++i) + result[i] = array1[i] ^ array2[i]; + + return result; + } + + void setup(const QCA::SymmetricKey &key) override + { + // We might not have a real key, since this can get called + // from the constructor. + if (key.size() == 0) + return; + + m_key = key; + // Generate the subkeys + QCA::SecureArray const_Zero(16); + QCA::SecureArray const_Rb(16); + const_Rb[15] = (char)0x87; + + m_X = const_Zero; + m_residual = QCA::SecureArray(); + + // Figure 2.2, step 1. + QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, key); + QCA::SecureArray L = aesObj.process(const_Zero); + + // Figure 2.2, step 2 + if (0 == (L[0] & 0x80)) + m_k1 = leftShift(L); + else + m_k1 = xorArray(leftShift(L), const_Rb); + + // Figure 2.2, step 3 + if (0 == (m_k1[0] & 0x80)) + m_k2 = leftShift(m_k1); + else + m_k2 = xorArray(leftShift(m_k1), const_Rb); + } + + QCA::Provider::Context *clone() const override + { + return new AESCMACContext(*this); + } + + void clear() + { + setup(m_key); + } + + QCA::KeyLength keyLength() const override + { + return QCA::KeyLength(16, 16, 1); + } + + // This is a bit different to the way the I-D does it, + // to allow for multiple update() calls. + void update(const QCA::MemoryRegion &a) override + { + QCA::SecureArray bytesToProcess = m_residual + a; + int blockNum; + // note that we don't want to do the last full block here, because + // it needs special treatment in final(). + for (blockNum = 0; blockNum < ((bytesToProcess.size() - 1) / 16); ++blockNum) { + // copy a block of data + QCA::SecureArray thisBlock(16); + for (int yalv = 0; yalv < 16; ++yalv) + thisBlock[yalv] = bytesToProcess[blockNum * 16 + yalv]; + + m_Y = xorArray(m_X, thisBlock); + + QCA::Cipher aesObj( + QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key); + m_X = aesObj.process(m_Y); + } + // This can be between 1 and 16 + int numBytesLeft = bytesToProcess.size() - 16 * blockNum; + // we copy the left over part + m_residual.resize(numBytesLeft); + for (int yalv = 0; yalv < numBytesLeft; ++yalv) + m_residual[yalv] = bytesToProcess[blockNum * 16 + yalv]; + } + + void final(QCA::MemoryRegion *out) override + { + QCA::SecureArray lastBlock; + int numBytesLeft = m_residual.size(); + + if (numBytesLeft != 16) { + // no full block, so we have to pad. + m_residual.resize(16); + m_residual[numBytesLeft] = (char)0x80; + lastBlock = xorArray(m_residual, m_k2); + } else { + // this is a full block - no padding + lastBlock = xorArray(m_residual, m_k1); + } + m_Y = xorArray(m_X, lastBlock); + QCA::Cipher aesObj(QStringLiteral("aes128"), QCA::Cipher::ECB, QCA::Cipher::DefaultPadding, QCA::Encode, m_key); + *out = aesObj.process(m_Y); + } + +protected: + // first subkey + QCA::SecureArray m_k1; + // second subkey + QCA::SecureArray m_k2; + // main key + QCA::SecureArray m_key; + + // state + QCA::SecureArray m_X; + QCA::SecureArray m_Y; + + // partial block that we can't do yet + QCA::SecureArray m_residual; +}; + +class ClientSideProvider : public QCA::Provider +{ +public: + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("exampleClientSideProvider"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("cmac(aes)"); + // you can add more features in here, if you have some. + return list; + } + + Provider::Context *createContext(const QString &type) override + { + if (type == QLatin1String("cmac(aes)")) + return new AESCMACContext(this); + // else if (type == some other feature) + // return some other context. + else + return nullptr; + } +}; + +// AES CMAC is a Message Authentication Code based on a block cipher +// instead of the more normal keyed hash. +// See RFC 4493 "The AES-CMAC Algorithm" +class AES_CMAC : public QCA::MessageAuthenticationCode +{ +public: + AES_CMAC(const QCA::SymmetricKey &key = QCA::SymmetricKey(), const QString &provider = QString()) + : QCA::MessageAuthenticationCode(QStringLiteral("cmac(aes)"), key, provider) + { + } +}; + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + qDebug() << "This example shows AES CMAC"; + + QCoreApplication app(argc, argv); + + if (!QCA::isSupported("aes128-ecb")) { + qDebug() << "AES not supported!"; + } + + if (QCA::insertProvider(new ClientSideProvider, 0)) + qDebug() << "Inserted our provider"; + else + qDebug() << "our provider could not be added"; + + // We should check AES CMAC is supported before using it. + if (!QCA::isSupported("cmac(aes)")) { + qDebug() << "AES CMAC not supported!"; + } else { + // create the required object + AES_CMAC cmacObject; + + // create the key + QCA::SymmetricKey key(QCA::hexToArray(QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c"))); + + // set the MAC to use the key + cmacObject.setup(key); + + QCA::SecureArray message = + QCA::hexToArray(QStringLiteral("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710")); + QCA::SecureArray message1(message); + message1.resize(0); + qDebug(); + qDebug() << "Message1: " << QCA::arrayToHex(message1.toByteArray()); + qDebug() << "Expecting: bb1d6929e95937287fa37d129b756746"; + qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message1).toByteArray()); + + cmacObject.clear(); + QCA::SecureArray message2(message); + message2.resize(16); + qDebug(); + qDebug() << "Message2: " << QCA::arrayToHex(message2.toByteArray()); + qDebug() << "Expecting: 070a16b46b4d4144f79bdd9dd04a287c"; + qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message2).toByteArray()); + + cmacObject.clear(); + QCA::SecureArray message3(message); + message3.resize(40); + qDebug(); + qDebug() << "Message3: " << QCA::arrayToHex(message3.toByteArray()); + qDebug() << "Expecting: dfa66747de9ae63030ca32611497c827"; + qDebug() << "AES-CMAC " << QCA::arrayToHex(cmacObject.process(message3).toByteArray()); + + cmacObject.clear(); + QCA::SecureArray message4(message); + message4.resize(64); + qDebug(); + qDebug() << "Message4: " << QCA::arrayToHex(message4.toByteArray()); + qDebug() << "Expecting: 51f0bebf7e3b9d92fc49741779363cfe"; + qDebug() << "AES-CMAC: " << QCA::arrayToHex(cmacObject.process(message4).toByteArray()); + } + + return 0; +} + +#include "aes-cmac.moc" diff --git a/local/recipes/libs/qca/source/examples/base64test/CMakeLists.txt b/local/recipes/libs/qca/source/examples/base64test/CMakeLists.txt new file mode 100644 index 0000000000..f07551a284 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/base64test/CMakeLists.txt @@ -0,0 +1,5 @@ +set(base64test_bin_SRCS base64test.cpp) + +add_executable(base64test ${base64test_bin_SRCS}) + +target_link_qca_libraries(base64test) diff --git a/local/recipes/libs/qca/source/examples/base64test/base64test.cpp b/local/recipes/libs/qca/source/examples/base64test/base64test.cpp new file mode 100644 index 0000000000..9ceb9270c6 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/base64test/base64test.cpp @@ -0,0 +1,70 @@ +/* + Copyright (C) 2004-2005 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + QCoreApplication(argc, argv); + + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + // we use the first argument as the data to encode + // if an argument is provided. Use "hello" if no argument + QByteArray arg; // empty array + arg.append((argc >= 2) ? argv[1] : "hello"); + + // create our object, which does encoding by default + // QCA::Base64 encoder(QCA::Encode); is equivalent + QCA::Base64 encoder; + + // This does the actual conversion (encoding). + // You might prefer to use encoder.encode(); and have + // it return a QCA::SecureArray, depending on your needs + QString encoded = encoder.arrayToString(arg); + + std::cout << arg.data() << " in base64 encoding is "; + std::cout << encoded.toLatin1().data() << std::endl; + + // This time, we'll create an object to decode base64. We + // could also have reused the existing object, calling + // clear(); and setup(QCA::Decode); on it. + QCA::Base64 decoder(QCA::Decode); + + // This time, we convert a QString into a QString + QString decoded = decoder.decodeString(encoded); + + std::cout << encoded.toLatin1().data() << " decoded from base64 is "; + std::cout << decoded.toLatin1().data() << std::endl; + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/certtest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/certtest/CMakeLists.txt new file mode 100644 index 0000000000..83bfeb7719 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/certtest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(certtest_bin_SRCS certtest.cpp) + +add_executable(certtest ${certtest_bin_SRCS}) + +target_link_qca_libraries(certtest) diff --git a/local/recipes/libs/qca/source/examples/certtest/certtest.cpp b/local/recipes/libs/qca/source/examples/certtest/certtest.cpp new file mode 100644 index 0000000000..238bb86a15 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/certtest/certtest.cpp @@ -0,0 +1,173 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2005 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +// dump out information about some part of the certificate +// we use this same approach for information about the subject +// of the certificate, and also about the issuer of the certificate +static void dumpCertificateInfo(const QCA::CertificateInfo &info) +{ + std::cout << " Organization: " << std::endl; + + // Note that a single certificate can apply to more than one + // organisation. QCA::Certificate is a multimap, so when you + // ask for the values associated with a parameter, it returns + // a list. + QList orgInfoList = info.values(QCA::Organization); + + // foreach() interates over each value in the list, and we dump + // out each value. Note that is uncommon for a certificate to + // actually contain multiple values for a single parameter. + QString organization; + foreach (organization, orgInfoList) { + std::cout << " " << qPrintable(organization) << std::endl; + } + + std::cout << " Country: " << std::endl; + // As above, however this shows a more compact way to represent + // the iteration and output. + foreach (QString country, info.values(QCA::Country)) { // clazy:exclude=container-anti-pattern + std::cout << " " << qPrintable(country) << std::endl; + } +} + +// This is just a convenience routine +static void dumpSubjectInfo(const QCA::CertificateInfo &subject) +{ + std::cout << "Subject: " << std::endl; + + dumpCertificateInfo(subject); +} + +// This is just a convenience routine +static void dumpIssuerInfo(const QCA::CertificateInfo &issuer) +{ + std::cout << "Issuer: " << std::endl; + + dumpCertificateInfo(issuer); +} + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // We need to ensure that we have certificate handling support + if (!QCA::isSupported("cert")) { + std::cout << "Sorry, no PKI certificate support" << std::endl; + return 1; + } + + // We are going to work with a number of certificates, and a + // QList is a great template class for that + QList certlist; + + // We do two different cases - if we provide an argument, it is taken + // as a filename to read the keys from. If there is no argument, we just + // read from the system store certificates. + if (argc >= 2) { + // we are going to read the certificates in using a single call + // which requires a CertificateCollection. + QCA::CertificateCollection filecerts; + // The conversion can be tested (although you don't have to) to find out if it + // worked. + QCA::ConvertResult importResult; + // This imports all the PEM encoded certificates from the file specified as the argument + // Note that you pass in a pointer to the result argument. + filecerts = QCA::CertificateCollection::fromFlatTextFile(QFile::decodeName(argv[1]), &importResult); + if (QCA::ConvertGood == importResult) { + std::cout << "Import succeeded" << std::endl; + // this turns the CertificateCollection into a QList of Certificate objects + certlist = filecerts.certificates(); + } + } else { + // we have no arguments, so just use the system certificates + if (!QCA::haveSystemStore()) { + std::cout << "System certificates not available" << std::endl; + return 2; + } + + // Similar to above, except we just want the system certificates + QCA::CertificateCollection systemcerts = QCA::systemStore(); + + // this turns the CertificateCollection into a QList of Certificate objects + certlist = systemcerts.certificates(); + } + + std::cout << "Number of certificates: " << certlist.count() << std::endl; + + QCA::Certificate cert; + foreach (cert, certlist) { + std::cout << "Serial Number:"; + // the serial number of the certificate is a QCA::BigInteger, but we can + // just convert it to a string, and then output it. + std::cout << qPrintable(cert.serialNumber().toString()) << std::endl; + + // The subject information shows properties of who the certificate + // applies to. See the convenience routines above. + dumpSubjectInfo(cert.subjectInfo()); + + // The issuer information shows properties of who the certificate + // was signed by. See the convenience routines above. + dumpIssuerInfo(cert.issuerInfo()); + + // Test if the certificate can be used as a certificate authority + if (cert.isCA()) { + std::cout << "Is certificate authority" << std::endl; + } else { + std::cout << "Is not a certificate authority" << std::endl; + } + + // Test if the certificate is self-signed. + if (cert.isSelfSigned()) { + std::cout << "Self signed" << std::endl; + } else { + std::cout << "Is not self-signed!!!" << std::endl; + } + + // Certificate are only valid between specific dates. We can get the dates + // (as a QDateTime) using a couple of calls + std::cout << "Valid from " << qPrintable(cert.notValidBefore().toString()); + std::cout << ", until " << qPrintable(cert.notValidAfter().toString()); + std::cout << std::endl; + + // You can get the certificate in PEM encoding with a simple toPEM() call + std::cout << "PEM:" << std::endl; + std::cout << qPrintable(cert.toPEM()); + std::cout << std::endl << std::endl; + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/ciphertest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/ciphertest/CMakeLists.txt new file mode 100644 index 0000000000..9197188d5f --- /dev/null +++ b/local/recipes/libs/qca/source/examples/ciphertest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(ciphertest_bin_SRCS ciphertest.cpp) + +add_executable(ciphertest ${ciphertest_bin_SRCS}) + +target_link_qca_libraries(ciphertest) diff --git a/local/recipes/libs/qca/source/examples/ciphertest/ciphertest.cpp b/local/recipes/libs/qca/source/examples/ciphertest/ciphertest.cpp new file mode 100644 index 0000000000..67dd6e156b --- /dev/null +++ b/local/recipes/libs/qca/source/examples/ciphertest/ciphertest.cpp @@ -0,0 +1,130 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2005-2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // we use the first argument if provided, or + // use "hello" if no arguments + QCA::SecureArray arg = (argc >= 2) ? argv[1] : "hello"; + + // AES128 testing + if (!QCA::isSupported("aes128-cbc-pkcs7")) + printf("AES128-CBC not supported!\n"); + else { + // Create a random key - you'd probably use one from another + // source in a real application + QCA::SymmetricKey key(16); + + // Create a random initialisation vector - you need this + // value to decrypt the resulting cipher text, but it + // need not be kept secret (unlike the key). + QCA::InitializationVector iv(16); + + // create a 128 bit AES cipher object using Cipher Block Chaining (CBC) mode + QCA::Cipher cipher(QStringLiteral("aes128"), + QCA::Cipher::CBC, + // use Default padding, which is equivalent to PKCS7 for CBC + QCA::Cipher::DefaultPadding, + // this object will encrypt + QCA::Encode, + key, + iv); + + // we use the cipher object to encrypt the argument we passed in + // the result of that is returned - note that if there is less than + // 16 bytes (1 block), then nothing will be returned - it is buffered + // update() can be called as many times as required. + QCA::SecureArray u = cipher.update(arg); + + // We need to check if that update() call worked. + if (!cipher.ok()) { + printf("Update failed\n"); + } + // output the results of that stage + printf("AES128 encryption of %s is [%s]\n", arg.data(), qPrintable(QCA::arrayToHex(u.toByteArray()))); + + // Because we are using PKCS7 padding, we need to output the final (padded) block + // Note that we should always call final() even with no padding, to clean up + QCA::SecureArray f = cipher.final(); + + // Check if the final() call worked + if (!cipher.ok()) { + printf("Final failed\n"); + } + // and output the resulting block. The ciphertext is the results of update() + // and the result of final() + printf("Final block for AES128 encryption is [0x%s]\n", qPrintable(QCA::arrayToHex(f.toByteArray()))); + + // re-use the Cipher t decrypt. We need to use the same key and + // initialisation vector as in the encryption. + cipher.setup(QCA::Decode, key, iv); + + // Build a single cipher text array. You could also call update() with + // each block as you receive it, if that is more useful. + QCA::SecureArray cipherText = u.append(f); + + // take that cipher text, and decrypt it + QCA::SecureArray plainText = cipher.update(cipherText); + + // check if the update() call worked + if (!cipher.ok()) { + printf("Update failed\n"); + } + + // output results + printf("Decryption using AES128 of [0x%s] is %s\n", + qPrintable(QCA::arrayToHex(cipherText.toByteArray())), + plainText.data()); + + // Again we need to call final(), to get the last block (with its padding removed) + plainText = cipher.final(); + + // check if the final() call worked + if (!cipher.ok()) { + printf("Final failed\n"); + } + + // output results + printf("Final decryption block using AES128 is %s\n", plainText.data()); + // instead of update() and final(), you can do the whole thing + // in one step, using process() + printf("One step decryption using AES128: %s\n", QCA::SecureArray(cipher.process(cipherText)).data()); + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/cms/CMakeLists.txt b/local/recipes/libs/qca/source/examples/cms/CMakeLists.txt new file mode 100644 index 0000000000..7384422719 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cms/CMakeLists.txt @@ -0,0 +1,5 @@ +set(cmsexample_bin_SRCS cmsexample.cpp) + +add_executable(cmsexample ${cmsexample_bin_SRCS}) + +target_link_qca_libraries(cmsexample) diff --git a/local/recipes/libs/qca/source/examples/cms/User.pem b/local/recipes/libs/qca/source/examples/cms/User.pem new file mode 100644 index 0000000000..3e724697a7 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cms/User.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEYjCCA0qgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4MzIzOFoXDTA2MDgxNjA4MzIzOFoweDELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMSAwHgYDVQQDExdJbnNl +Y3VyZSBVc2VyIFRlc3QgQ2VydDElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVz +dC5pbnNlY3VyZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArCM8+V7VH46Y ++bMtgOaqFc8vCSBpSeL5hnHN3uwEH8/OqwKaO9hMP15lFpzEJOIPMVtOSLCg4dJy ++eS3azL3/B+4qDVqbCgKSXDMKhBDKKw0TvfhN4tgfmvy0rpgMHYApfyRdewnvKgV +YkI+sDwupmZJo87kuvPM2JzbV/DNAyMCAwEAAaOCAYIwggF+MAsGA1UdDwQEAwIE +8DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFIiefvcp +cZ17KA82Gq5tANOd4arbMIGZBgNVHSMEgZEwgY6AFL9TQ4J40J7DgOUbZ8oFAN+5 +SIOloXOkcTBvMQswCQYDVQQGEwJkZTEgMB4GA1UEChMXSW5zZWN1cmVUZXN0Q2Vy +dGlmaWNhdGUxFzAVBgNVBAMTDkZvciBUZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkB +FhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlggEAMCEGA1UdEQQaMBiBFmluc2VjdXJl +QHRlc3QuaW5zZWN1cmUwIQYDVR0SBBowGIEWaW5zZWN1cmVAdGVzdC5pbnNlY3Vy +ZTARBglghkgBhvhCAQEEBAMCBaAwPAYJYIZIAYb4QgENBC8WLVRoaXMgY2VydGlm +aWNhdGUgd2FzIGlzc3VlZCBmb3IgdGVzdGluZyBvbmx5ITANBgkqhkiG9w0BAQQF +AAOCAQEAeRBEcR/xp4pLH3VbQmTbZEGjVEBDxNAapsdIDrKB1ecA3JMhZDjweKc4 +MG5M+FQ5hcCT8kSi+6bL15BJRyyMB4727NRSC1i/2VkZmUGhhk3AR9UjsvrCC00D +gPuHdQPrIxl9+CK26ypATizb5VapzmoBc2B/dWeVh+KJbEkgTudfFj98Dqn8kiUn +bqbC3OMPa1uiez8oer8h6OAyOinmx0atjTqS5SOLI+2+p1lpMHMhodn4jgmd8Pms +KQ0jMyA0ZQ1tozQXOw9VpRYegsm8LMq0emdfybxpwGbrCIIk7BXjBIDrhYbnb3GK +blykzt4bqOeDtJuTgyBOS3Ldxqgfzg== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/examples/cms/Userkey.pem b/local/recipes/libs/qca/source/examples/cms/Userkey.pem new file mode 100644 index 0000000000..81731a284c --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cms/Userkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCsIzz5XtUfjpj5sy2A5qoVzy8JIGlJ4vmGcc3e7AQfz86rApo7 +2Ew/XmUWnMQk4g8xW05IsKDh0nL55LdrMvf8H7ioNWpsKApJcMwqEEMorDRO9+E3 +i2B+a/LSumAwdgCl/JF17Ce8qBViQj6wPC6mZkmjzuS688zYnNtX8M0DIwIDAQAB +AoGAUmPrY1BIofoWri1csj21Wwr3cF7bBkplNDx0VSaSMse8G437VHmKxSnhKJmQ +KDcrHmydY51m469e6MzYHa8fkfwFiqRhBE7rSw9n0K1sqzU6fJYXgpxdV+GOQcKw +v+Lu+o6ej4BGQ7woJZXOiC3GDiWu3rC91UNC9eC74yCGuAECQQDhd36m/M9Bjw+C +pNi55oFGdOCaiL+OT9I3Gt2+7MIo4d2YGvhl8Nr3PC6bEq1DzoWiaE+qxE3JFZdp +J2+F0fCjAkEAw3LsfrqVZH5HW57csAapmhA+oiCTP3cDDObQ3pKNi3sfYKq8u+aK +93XAbw3+sPaWlQbVnQF+2fNxOZB9TqFLgQJALVw+Fdhs1hKzGySRGa1/Oq6O9Wgn +qbjzYPS9wgid812lmFFswg2X7/+inL5AL5EgH5F+3atKvvbiFFzDuheHowJAHwiS +cJTjv68lWXDiDbkhGOtXZprRhpQ5EcVciNqwSuNj2g+CJDu4+Q3jXj7Un/indEY/ +iMyB/c1fvwooO2H1AQJAEmlUKcfUMdMKbsnqcBfUcge3POdb06pXDpZ/+X0g2OBE +1fTIQgPgP6y+Ucp/WCW6l2pEJtt26KI5kEp31WSbHA== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/examples/cms/cmsexample.cpp b/local/recipes/libs/qca/source/examples/cms/cmsexample.cpp new file mode 100644 index 0000000000..345d1c7710 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cms/cmsexample.cpp @@ -0,0 +1,204 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2005-2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // We need to ensure that we have certificate handling support + if (!QCA::isSupported("cert")) { + qWarning() << "Sorry, no PKI certificate support"; + return 1; + } + + // Read in a public key cert + // you could also build this using the fromPEMFile() method + QCA::Certificate pubCert(QStringLiteral("User.pem")); + if (pubCert.isNull()) { + qWarning() << "Sorry, could not import public key certificate"; + return 1; + } + // We are building the certificate into a SecureMessageKey object, via a + // CertificateChain + QCA::SecureMessageKey secMsgKey; + QCA::CertificateChain chain; + chain += pubCert; + secMsgKey.setX509CertificateChain(chain); + + // build up a SecureMessage object, based on our public key certificate + if (!QCA::isSupported("cms")) { + qWarning() << "Sorry, no CMS support"; + return 1; + } + QCA::CMS cms; + QCA::SecureMessage msg(&cms); + msg.setRecipient(secMsgKey); + + // Some plain text - we use the first command line argument if provided + QByteArray plainText = (argc >= 2) ? argv[1] : "What do ya want for nuthin'"; + + // Now use the SecureMessage object to encrypt the plain text. + msg.startEncrypt(); + msg.update(plainText); + msg.end(); + // I think it is reasonable to wait for 1 second for this + msg.waitForFinished(1000); + + // check to see if it worked + if (!msg.success()) { + qWarning() << "Error encrypting: " << msg.errorCode(); + return 1; + } + + // get the result + QByteArray cipherText = msg.read(); + QCA::Base64 enc; + qDebug() << "'" << plainText.data() << "' encrypts to (in base 64): "; + qDebug() << enc.arrayToString(cipherText); + qDebug() << "Message uses" << msg.hashName() << "hashing algorithm"; + qDebug(); + + // Show we can decrypt it with the private key + + // Read in a private key + QCA::PrivateKey privKey; + QCA::ConvertResult convRes; + QCA::SecureArray passPhrase = "start"; + privKey = QCA::PrivateKey::fromPEMFile(QStringLiteral("Userkey.pem"), passPhrase, &convRes); + if (convRes != QCA::ConvertGood) { + qWarning() << "Sorry, could not import Private Key"; + return 1; + } + + QCA::SecureMessageKey secMsgKey2; + // needed? + secMsgKey2.setX509CertificateChain(chain); + secMsgKey2.setX509PrivateKey(privKey); + QCA::SecureMessageKeyList privKeyList; + privKeyList += secMsgKey2; + + // build up a SecureMessage object, based on the private key + // you could re-use the existing QCA::CMS object (cms), but + // this example simulates encryption and one end, and decryption + // at the other + QCA::CMS anotherCms; + anotherCms.setPrivateKeys(privKeyList); + + QCA::SecureMessage msg2(&anotherCms); + + msg2.startDecrypt(); + msg2.update(cipherText); + msg2.end(); + + // I think it is reasonable to wait for 1 second for this + msg2.waitForFinished(1000); + + // check to see if it worked + if (!msg2.success()) { + qWarning() << "Error encrypting: " << msg2.errorCode(); + return 1; + } + + QCA::SecureArray plainTextResult = msg2.read(); + + qDebug() << enc.arrayToString(cipherText) << " (in base 64) decrypts to: " << plainTextResult.data(); + + if (msg2.wasSigned()) { + qDebug() << "Message was signed at " << msg2.signer().timestamp(); + } else { + qDebug() << "Message was not signed"; + } + + qDebug() << "Message used" << msg2.hashName() << "hashing algorithm"; + + qDebug(); + + // Now we want to try a signature + QByteArray text("Got your message"); + + // Re-use the CMS and SecureMessageKeyList objects from the decrypt... + QCA::SecureMessage signing(&anotherCms); + signing.setSigners(privKeyList); + + signing.startSign(QCA::SecureMessage::Detached); + signing.update(text); + signing.end(); + + // I think it is reasonable to wait for 1 second for this + signing.waitForFinished(1000); + + // check to see if it worked + if (!signing.success()) { + qWarning() << "Error signing: " << signing.errorCode(); + return 1; + } + + // get the result + QByteArray signature = signing.signature(); + + qDebug() << "'" << text.data() << "', signature (converted to base 64), is: "; + qDebug() << enc.arrayToString(signature); + qDebug() << "Message uses" << signing.hashName() << "hashing algorithm"; + qDebug(); + + // Now we go back to the first CMS, and re-use that. + QCA::SecureMessage verifying(&cms); + + // You have to pass the signature to startVerify(), + // and the message to update() + verifying.startVerify(signature); + verifying.update(text); + verifying.end(); + + verifying.waitForFinished(1000); + + // check to see if it worked + if (!verifying.success()) { + qWarning() << "Error verifying: " << verifying.errorCode(); + return 1; + } + + QCA::SecureMessageSignature sign; + sign = verifying.signer(); + // todo: dump some data out about the signer + + if (verifying.verifySuccess()) { + qDebug() << "Message verified"; + } else { + qDebug() << "Message failed to verify:" << verifying.errorCode(); + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/cmssigner/TODO b/local/recipes/libs/qca/source/examples/cmssigner/TODO new file mode 100644 index 0000000000..671976c2dc --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/TODO @@ -0,0 +1,18 @@ +app icon (may need different sizes of this?) (a pen?) +store icons + system + user + application + smart card + pgp keyring +unknown store/entry icon (can use the same icon for both i think) +animation rather than text for keystore busy? +animation for signing in progress (maybe just use an endless QProgressBar?) +integrated logger window? also allow setting the log level +prompter should not call entrylist unless necessary. right now it starts + async mode on all stores, even if there is no prompting or anything going + on. qcatool has this problem also +report all 3 kinds of diagnostic text somewhere + plugin: plugin dialog invoked from file menu ? also show provider versions + keystore: invoked from keyselectdlg ? + secmessage: "details" button on error dialog? diff --git a/local/recipes/libs/qca/source/examples/cmssigner/certitem.cpp b/local/recipes/libs/qca/source/examples/cmssigner/certitem.cpp new file mode 100644 index 0000000000..c43171458a --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/certitem.cpp @@ -0,0 +1,697 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "certitem.h" + +#include "prompter.h" +#include +#include +#include +#include + +typedef QMap CertItemIconset; + +//---------------------------------------------------------------------------- +// MyPrompter +//---------------------------------------------------------------------------- +class MyPrompter : public Prompter +{ + Q_OBJECT +private: + QMap known; + QMap maybe; + +public: + MyPrompter(QObject *parent = 0) + : Prompter(parent) + { + } + + void fileSuccess(const QString &fileName) + { + if (maybe.contains(fileName)) { + known[fileName] = maybe[fileName]; + maybe.remove(fileName); + } + } + + void fileFailed(const QString &fileName) + { + maybe.remove(fileName); + known.remove(fileName); + } + +protected: + virtual QCA::SecureArray knownPassword(const QCA::Event &event) + { + if (event.source() == QCA::Event::Data && !event.fileName().isEmpty()) + return known.value(event.fileName()); + else + return QCA::SecureArray(); + } + + virtual void userSubmitted(const QCA::SecureArray &password, const QCA::Event &event) + { + if (event.source() == QCA::Event::Data && !event.fileName().isEmpty()) + maybe[event.fileName()] = password; + } +}; + +//---------------------------------------------------------------------------- +// CertItem +//---------------------------------------------------------------------------- +static QString escape(const QString &in) +{ + QString out; + for (int n = 0; n < in.length(); ++n) { + if (in[n] == '\\') + out += "\\\\"; + else if (in[n] == ':') + out += "\\c"; + else if (in[n] == '\n') + out += "\\n"; + else + out += in[n]; + } + return out; +} + +static QString unescape(const QString &in) +{ + QString out; + for (int n = 0; n < in.length(); ++n) { + if (in[n] == '\\') { + if (n + 1 < in.length()) { + ++n; + if (in[n] == '\\') + out += '\\'; + else if (in[n] == 'c') + out += ':'; + else if (in[n] == 'n') + out += '\n'; + } + } else + out += in[n]; + } + return out; +} + +class CertItem::Private : public QSharedData +{ +public: + QString name; + QCA::CertificateChain chain; + bool havePrivate; + StorageType storageType; + bool usable; + + QString fileName; + QCA::KeyStoreEntry keyStoreEntry; + QString keyStoreEntryString; + + Private() + : havePrivate(false) + , storageType(File) + , usable(false) + { + } + + QString toString() const + { + QStringList parts; + + parts += name; + parts += QString::number(chain.count()); + foreach (const QCA::Certificate &cert, chain) + parts += QCA::Base64().arrayToString(cert.toDER()); + + if (havePrivate) { + if (storageType == File) { + parts += "privateFile"; + parts += fileName; + } else // KeyStoreEntry + { + parts += "privateEntry"; + if (!keyStoreEntry.isNull()) + parts += keyStoreEntry.toString(); + else + parts += keyStoreEntryString; + } + } + + for (int n = 0; n < parts.count(); ++n) + parts[n] = escape(parts[n]); + return parts.join(":"); + } + + bool fromString(const QString &in) + { + const QStringList parts = in.split(':'); + for (int n = 0; n < parts.count(); ++n) + parts[n] = unescape(parts[n]); + + if (parts.count() < 3) + return false; + + name = parts[0]; + int chainCount = parts[1].toInt(); + if (chainCount < 1 || chainCount > parts.count() - 2) + return false; + chain.clear(); + for (int n = 0; n < chainCount; ++n) { + QCA::Certificate cert = QCA::Certificate::fromDER(QCA::Base64().stringToArray(parts[n + 2]).toByteArray()); + if (cert.isNull()) + return false; + chain += cert; + } + int at = chain.count() + 2; + + if (at < parts.count()) { + havePrivate = true; + usable = false; + + if (parts[at] == "privateFile") { + storageType = File; + fileName = parts[at + 1]; + if (QFile::exists(fileName)) + usable = true; + } else if (parts[at] == "privateEntry") { + storageType = KeyStore; + keyStoreEntryString = parts[at + 1]; + keyStoreEntry = QCA::KeyStoreEntry(keyStoreEntryString); + if (!keyStoreEntry.isNull()) + usable = true; + } else + return false; + } + + return true; + } +}; + +CertItem::CertItem() +{ +} + +CertItem::CertItem(const CertItem &from) + : d(from.d) +{ +} + +CertItem::~CertItem() +{ +} + +CertItem &CertItem::operator=(const CertItem &from) +{ + d = from.d; + return *this; +} + +QString CertItem::name() const +{ + return d->name; +} + +QCA::CertificateChain CertItem::certificateChain() const +{ + return d->chain; +} + +bool CertItem::havePrivate() const +{ + return d->havePrivate; +} + +CertItem::StorageType CertItem::storageType() const +{ + return d->storageType; +} + +bool CertItem::isUsable() const +{ + return d->usable; +} + +//---------------------------------------------------------------------------- +// CertItemStore +//---------------------------------------------------------------------------- +static MyPrompter *g_prompter = 0; +static int g_prompter_refs = 0; + +class CertItemStorePrivate : public QObject +{ + Q_OBJECT +public: + CertItemStore *q; + MyPrompter *prompter; + QList list; + QList idList; + CertItemIconset iconset; + int next_id; + int next_req_id; + + class LoaderItem + { + public: + int req_id; + QCA::KeyLoader *keyLoader; + QString fileName; + }; + + QList loaders; + + CertItemStorePrivate(CertItemStore *_q) + : QObject(_q) + , q(_q) + , next_id(0) + , next_req_id(0) + { + if (!g_prompter) { + g_prompter = new MyPrompter; + g_prompter_refs = 1; + } else + ++g_prompter_refs; + + prompter = g_prompter; + } + + ~CertItemStorePrivate() + { + foreach (const LoaderItem &i, loaders) + delete i.keyLoader; + + --g_prompter_refs; + if (g_prompter_refs == 0) { + delete g_prompter; + g_prompter = 0; + } + } + + QString getUniqueName(const QString &name) + { + int num = 1; + while (1) { + QString tryname; + if (num == 1) + tryname = name; + else + tryname = name + QString(" (%1)").arg(num); + + bool found = false; + foreach (const CertItem &i, list) { + if (i.name() == tryname) { + found = true; + break; + } + } + if (!found) + return tryname; + + ++num; + } + } + + static QString convertErrorToString(QCA::ConvertResult r) + { + QString str; + switch (r) { + case QCA::ConvertGood: + break; + case QCA::ErrorPassphrase: + str = tr("Incorrect passphrase."); + case QCA::ErrorFile: + str = tr("Unable to open or read file."); + case QCA::ErrorDecode: + default: + str = tr("Unable to decode format."); + } + return str; + } + +public Q_SLOTS: + void loader_finished() + { + QCA::KeyLoader *keyLoader = (QCA::KeyLoader *)sender(); + int at = -1; + for (int n = 0; n < loaders.count(); ++n) { + if (loaders[n].keyLoader == keyLoader) { + at = n; + break; + } + } + Q_ASSERT(at != -1); + + int req_id = loaders[at].req_id; + QString fileName = loaders[at].fileName; + loaders.removeAt(at); + + QCA::ConvertResult r = keyLoader->convertResult(); + if (r != QCA::ConvertGood) { + delete keyLoader; + prompter->fileFailed(fileName); + QMessageBox::information( + 0, + tr("Error"), + tr("Error importing certificate and private key.\nReason: %1").arg(convertErrorToString(r))); + emit q->addFailed(req_id); + return; + } + + prompter->fileSuccess(fileName); + + QCA::KeyBundle kb = keyLoader->keyBundle(); + delete keyLoader; + + QCA::CertificateChain chain = kb.certificateChain(); + QCA::Certificate cert = chain.primary(); + + QString name = getUniqueName(cert.commonName()); + + CertItem i; + i.d = new CertItem::Private; + i.d->name = name; + i.d->chain = chain; + i.d->havePrivate = true; + i.d->storageType = CertItem::File; + i.d->usable = true; + i.d->fileName = fileName; + + int id = next_id++; + + q->beginInsertRows(QModelIndex(), list.size(), list.size()); + list += i; + idList += id; + q->endInsertRows(); + + emit q->addSuccess(req_id, id); + } +}; + +CertItemStore::CertItemStore(QObject *parent) + : QAbstractListModel(parent) +{ + d = new CertItemStorePrivate(this); +} + +CertItemStore::~CertItemStore() +{ + delete d; +} + +int CertItemStore::idFromRow(int row) const +{ + return d->idList[row]; +} + +int CertItemStore::rowFromId(int id) const +{ + for (int n = 0; n < d->idList.count(); ++n) { + if (d->idList[n] == id) + return n; + } + return -1; +} + +CertItem CertItemStore::itemFromId(int id) const +{ + return d->list[rowFromId(id)]; +} + +CertItem CertItemStore::itemFromRow(int row) const +{ + return d->list[row]; +} + +QList CertItemStore::items() const +{ + return d->list; +} + +QStringList CertItemStore::save() const +{ + QStringList out; + foreach (const CertItem &i, d->list) + out += i.d->toString(); + return out; +} + +bool CertItemStore::load(const QStringList &in) +{ + QList addList; + QList addIdList; + foreach (const QString &s, in) { + CertItem i; + i.d = new CertItem::Private; + if (i.d->fromString(s)) { + addList += i; + addIdList += d->next_id++; + } + } + + if (addList.isEmpty()) + return true; + + beginInsertRows(QModelIndex(), d->list.size(), d->list.size() + addList.count() - 1); + d->list += addList; + d->idList += addIdList; + endInsertRows(); + + return true; +} + +int CertItemStore::addFromFile(const QString &fileName) +{ + CertItemStorePrivate::LoaderItem i; + i.req_id = d->next_req_id++; + i.keyLoader = new QCA::KeyLoader(d); + i.fileName = fileName; + connect(i.keyLoader, SIGNAL(finished()), d, SLOT(loader_finished())); + d->loaders += i; + i.keyLoader->loadKeyBundleFromFile(fileName); + return i.req_id; +} + +int CertItemStore::addFromKeyStore(const QCA::KeyStoreEntry &entry) +{ + QCA::KeyBundle kb = entry.keyBundle(); + + QCA::CertificateChain chain = kb.certificateChain(); + QCA::Certificate cert = chain.primary(); + + QString name = d->getUniqueName(entry.name()); + + CertItem i; + i.d = new CertItem::Private; + i.d->name = name; + i.d->chain = chain; + i.d->havePrivate = true; + i.d->storageType = CertItem::KeyStore; + i.d->usable = true; + i.d->keyStoreEntry = entry; + + int id = d->next_id++; + + beginInsertRows(QModelIndex(), d->list.size(), d->list.size()); + d->list += i; + d->idList += id; + endInsertRows(); + + int req_id = d->next_req_id++; + QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id)); + return req_id; +} + +int CertItemStore::addUser(const QCA::CertificateChain &chain) +{ + QCA::Certificate cert = chain.primary(); + + QString name = d->getUniqueName(cert.commonName()); + + CertItem i; + i.d = new CertItem::Private; + i.d->name = name; + i.d->chain = chain; + + int id = d->next_id++; + + beginInsertRows(QModelIndex(), d->list.size(), d->list.size()); + d->list += i; + d->idList += id; + endInsertRows(); + + int req_id = d->next_req_id++; + QMetaObject::invokeMethod(this, "addSuccess", Qt::QueuedConnection, Q_ARG(int, req_id), Q_ARG(int, id)); + return req_id; +} + +void CertItemStore::updateChain(int id, const QCA::CertificateChain &chain) +{ + int at = rowFromId(id); + d->list[at].d->chain = chain; +} + +void CertItemStore::removeItem(int id) +{ + int at = rowFromId(id); + + beginRemoveRows(QModelIndex(), at, at); + d->list.removeAt(at); + d->idList.removeAt(at); + endRemoveRows(); +} + +void CertItemStore::setIcon(IconType type, const QPixmap &icon) +{ + d->iconset[type] = icon; +} + +int CertItemStore::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return d->list.count(); +} + +QVariant CertItemStore::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + int at = index.row(); + QList &list = d->list; + + if (at >= list.count()) + return QVariant(); + + if (role == Qt::DisplayRole) { + QString str = list[at].name(); + if (list[at].havePrivate() && !list[at].isUsable()) + str += QString(" ") + tr("(not usable)"); + return str; + } else if (role == Qt::EditRole) + return list[at].name(); + else if (role == Qt::DecorationRole) { + if (list[at].havePrivate()) + return d->iconset[CertItemStore::IconKeyBundle]; + else + return d->iconset[CertItemStore::IconCert]; + } else + return QVariant(); +} + +Qt::ItemFlags CertItemStore::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; +} + +bool CertItemStore::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid() && role == Qt::EditRole) { + QString str = value.toString(); + d->list[index.row()].d->name = str; + emit dataChanged(index, index); + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +// CertItemPrivateLoader +//---------------------------------------------------------------------------- +class CertItemPrivateLoaderPrivate : public QObject +{ + Q_OBJECT +public: + CertItemPrivateLoader *q; + CertItemStore *store; + QCA::KeyLoader *loader; + QString fileName; + QCA::PrivateKey key; + + CertItemPrivateLoaderPrivate(CertItemPrivateLoader *_q) + : QObject(_q) + , q(_q) + { + } + +public Q_SLOTS: + void loader_finished() + { + QCA::ConvertResult r = loader->convertResult(); + if (r != QCA::ConvertGood) { + delete loader; + loader = 0; + store->d->prompter->fileFailed(fileName); + QMessageBox::information( + 0, + tr("Error"), + tr("Error accessing private key.\nReason: %1").arg(CertItemStorePrivate::convertErrorToString(r))); + emit q->finished(); + return; + } + + store->d->prompter->fileSuccess(fileName); + + key = loader->keyBundle().privateKey(); + delete loader; + loader = 0; + emit q->finished(); + } +}; + +CertItemPrivateLoader::CertItemPrivateLoader(CertItemStore *store, QObject *parent) + : QObject(parent) +{ + d = new CertItemPrivateLoaderPrivate(this); + d->store = store; +} + +CertItemPrivateLoader::~CertItemPrivateLoader() +{ + delete d; +} + +void CertItemPrivateLoader::start(int id) +{ + CertItem i = d->store->itemFromId(id); + + if (i.storageType() == CertItem::KeyStore) { + d->key = i.d->keyStoreEntry.keyBundle().privateKey(); + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + return; + } + + d->key = QCA::PrivateKey(); + d->fileName = i.d->fileName; + d->loader = new QCA::KeyLoader(d); + connect(d->loader, SIGNAL(finished()), d, SLOT(loader_finished())); + d->loader->loadKeyBundleFromFile(d->fileName); +} + +QCA::PrivateKey CertItemPrivateLoader::privateKey() const +{ + return d->key; +} + +#include "certitem.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/certitem.h b/local/recipes/libs/qca/source/examples/cmssigner/certitem.h new file mode 100644 index 0000000000..65c5c2b626 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/certitem.h @@ -0,0 +1,145 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef CERTITEM_H +#define CERTITEM_H + +#include +#include + +class QString; +class QStringList; + +namespace QCA { +class PrivateKey; +class CertificateChain; +class KeyStoreEntry; +} + +class CertItemStore; +class CertItemStorePrivate; +class CertItemPrivateLoaderPrivate; + +class CertItem +{ +public: + enum StorageType + { + File, + KeyStore + }; + + CertItem(); + CertItem(const CertItem &from); + ~CertItem(); + CertItem &operator=(const CertItem &from); + + QString name() const; + QCA::CertificateChain certificateChain() const; + bool havePrivate() const; + StorageType storageType() const; // private key storage type + bool isUsable() const; // file/provider present + +private: + class Private; + QSharedDataPointer d; + + friend class CertItemStore; + friend class CertItemStorePrivate; + friend class CertItemPrivateLoader; + friend class CertItemPrivateLoaderPrivate; +}; + +class CertItemStore : public QAbstractListModel +{ + Q_OBJECT +public: + enum IconType + { + IconCert, + IconCrl, + IconKeyBundle, + IconPgpPub, + IconPgpSec + }; + + CertItemStore(QObject *parent = nullptr); + ~CertItemStore(); + + int idFromRow(int row) const; + int rowFromId(int id) const; + CertItem itemFromId(int id) const; + CertItem itemFromRow(int row) const; + + QList items() const; + + QStringList save() const; + bool load(const QStringList &in); + + // returns a reqId + int addFromFile(const QString &fileName); + int addFromKeyStore(const QCA::KeyStoreEntry &entry); + int addUser(const QCA::CertificateChain &chain); + + void updateChain(int id, const QCA::CertificateChain &chain); + + void removeItem(int id); + + void setIcon(IconType type, const QPixmap &icon); + + // reimplemented + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + +Q_SIGNALS: + void addSuccess(int reqId, int id); + void addFailed(int reqId); + +private: + friend class CertItemStorePrivate; + CertItemStorePrivate *d; + + friend class CertItemPrivateLoader; + friend class CertItemPrivateLoaderPrivate; +}; + +class CertItemPrivateLoader : public QObject +{ + Q_OBJECT +public: + explicit CertItemPrivateLoader(CertItemStore *store, QObject *parent = nullptr); + ~CertItemPrivateLoader(); + + void start(int id); + + QCA::PrivateKey privateKey() const; + +Q_SIGNALS: + void finished(); + +private: + friend class CertItemPrivateLoaderPrivate; + CertItemPrivateLoaderPrivate *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/examples/cmssigner/certview.ui b/local/recipes/libs/qca/source/examples/cmssigner/certview.ui new file mode 100644 index 0000000000..c8f4b768f4 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/certview.ui @@ -0,0 +1,85 @@ + + CertView + + + + 0 + 0 + 400 + 300 + + + + View Certificate + + + + 9 + + + 6 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 9 + + + 6 + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + cb_chain + buttonBox + + + + + buttonBox + rejected() + CertView + reject() + + + 284 + 278 + + + 291 + 299 + + + + + diff --git a/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.cpp b/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.cpp new file mode 100644 index 0000000000..7143e3c3f1 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.cpp @@ -0,0 +1,185 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "certviewdlg.h" + +#include "ui_certview.h" +#include +#include +#include + +// from qcatool +class InfoType +{ +public: + QCA::CertificateInfoType type; + QString varname; + QString shortname; + QString name; + QString desc; + + InfoType() + { + } + + InfoType(QCA::CertificateInfoType _type, + const QString &_varname, + const QString &_shortname, + const QString &_name, + const QString &_desc) + : type(_type) + , varname(_varname) + , shortname(_shortname) + , name(_name) + , desc(_desc) + { + } +}; + +static QList makeInfoTypeList(bool legacyEmail = false) +{ + QList out; + out += InfoType( + QCA::CommonName, "CommonName", "CN", CertViewDlg::tr("Common Name (CN)"), "Full name, domain, anything"); + out += InfoType(QCA::Email, "Email", "", CertViewDlg::tr("Email Address"), ""); + if (legacyEmail) + out += InfoType(QCA::EmailLegacy, "EmailLegacy", "", CertViewDlg::tr("PKCS#9 Email Address"), ""); + out += InfoType(QCA::Organization, "Organization", "O", CertViewDlg::tr("Organization (O)"), "Company, group, etc"); + out += InfoType(QCA::OrganizationalUnit, + "OrganizationalUnit", + "OU", + CertViewDlg::tr("Organizational Unit (OU)"), + "Division/branch of organization"); + out += InfoType(QCA::Locality, "Locality", "", CertViewDlg::tr("Locality (L)"), "City, shire, part of a state"); + out += InfoType(QCA::State, "State", "", CertViewDlg::tr("State (ST)"), "State within the country"); + out += InfoType(QCA::Country, "Country", "C", CertViewDlg::tr("Country Code (C)"), "2-letter code"); + out += InfoType(QCA::IncorporationLocality, + "IncorporationLocality", + "", + CertViewDlg::tr("Incorporation Locality"), + "For EV certificates"); + out += InfoType(QCA::IncorporationState, + "IncorporationState", + "", + CertViewDlg::tr("Incorporation State"), + "For EV certificates"); + out += InfoType(QCA::IncorporationCountry, + "IncorporationCountry", + "", + CertViewDlg::tr("Incorporation Country"), + "For EV certificates"); + out += InfoType(QCA::URI, "URI", "", CertViewDlg::tr("URI"), ""); + out += InfoType(QCA::DNS, "DNS", "", CertViewDlg::tr("Domain Name"), "Domain (dnsName)"); + out += InfoType(QCA::IPAddress, "IPAddress", "", CertViewDlg::tr("IP Adddress"), ""); + out += InfoType(QCA::XMPP, "XMPP", "", CertViewDlg::tr("XMPP Address (JID)"), "From RFC 3920 (id-on-xmppAddr)"); + return out; +} + +static QString try_print_info(const QString &name, const QStringList &values) +{ + QString out; + if (!values.isEmpty()) { + QString value = values.join(", "); + out = QString(" ") + CertViewDlg::tr("%1: %2").arg(name, value) + '\n'; + } + return out; +} + +static QString print_info(const QString &title, const QCA::CertificateInfo &info) +{ + QString out; + QList list = makeInfoTypeList(); + out += title + '\n'; + foreach (const InfoType &t, list) + out += try_print_info(t.name, info.values(t.type)); + return out; +} + +static QString cert_info_string(const QCA::Certificate &cert) +{ + QString out; + out += CertViewDlg::tr("Serial Number: %1").arg(cert.serialNumber().toString()) + '\n'; + out += print_info(CertViewDlg::tr("Subject"), cert.subjectInfo()); + out += print_info(CertViewDlg::tr("Issuer"), cert.issuerInfo()); + out += CertViewDlg::tr("Validity") + '\n'; + out += QString(" ") + CertViewDlg::tr("Not before: %1").arg(cert.notValidBefore().toString()) + '\n'; + out += QString(" ") + CertViewDlg::tr("Not after: %1").arg(cert.notValidAfter().toString()) + '\n'; + return out; +} + +class CertViewDlg::Private : public QObject +{ + Q_OBJECT +public: + CertViewDlg *q; + Ui_CertView ui; + QCA::CertificateChain chain; + + Private(CertViewDlg *_q) + : QObject(_q) + , q(_q) + { + ui.setupUi(q); + connect(ui.cb_chain, SIGNAL(activated(int)), SLOT(cb_activated(int))); + ui.lb_info->setTextInteractionFlags(Qt::TextSelectableByMouse); + } + + void update() + { + QStringList names = QCA::makeFriendlyNames(chain); + ui.cb_chain->clear(); + foreach (const QString &s, names) + ui.cb_chain->insertItem(ui.cb_chain->count(), s); + updateInfo(); + } + + void updateInfo() + { + int x = ui.cb_chain->currentIndex(); + if (x == -1) { + ui.lb_info->setText(""); + return; + } + + ui.lb_info->setText(cert_info_string(chain[x])); + } + +private Q_SLOTS: + void cb_activated(int) + { + updateInfo(); + } +}; + +CertViewDlg::CertViewDlg(const QCA::CertificateChain &chain, QWidget *parent) + : QDialog(parent) +{ + d = new Private(this); + d->chain = chain; + d->update(); +} + +CertViewDlg::~CertViewDlg() +{ + delete d; +} + +#include "certviewdlg.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.h b/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.h new file mode 100644 index 0000000000..e38417f2f4 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/certviewdlg.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef CERTVIEWDLG_H +#define CERTVIEWDLG_H + +#include + +namespace QCA { +class CertificateChain; +} + +class CertViewDlg : public QDialog +{ + Q_OBJECT +public: + explicit CertViewDlg(const QCA::CertificateChain &chain, QWidget *parent = 0); + ~CertViewDlg(); + +private: + class Private; + Private *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/examples/cmssigner/cmssigner.qrc b/local/recipes/libs/qca/source/examples/cmssigner/cmssigner.qrc new file mode 100644 index 0000000000..46da0bae45 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/cmssigner.qrc @@ -0,0 +1,9 @@ + + + icons/cert16.png + icons/crl16.png + icons/keybundle16.png + icons/keypair16.png + icons/publickey16.png + + diff --git a/local/recipes/libs/qca/source/examples/cmssigner/icons/cert16.png b/local/recipes/libs/qca/source/examples/cmssigner/icons/cert16.png new file mode 100644 index 0000000000..2fdf9e3d79 Binary files /dev/null and b/local/recipes/libs/qca/source/examples/cmssigner/icons/cert16.png differ diff --git a/local/recipes/libs/qca/source/examples/cmssigner/icons/crl16.png b/local/recipes/libs/qca/source/examples/cmssigner/icons/crl16.png new file mode 100644 index 0000000000..ec9b6f3298 Binary files /dev/null and b/local/recipes/libs/qca/source/examples/cmssigner/icons/crl16.png differ diff --git a/local/recipes/libs/qca/source/examples/cmssigner/icons/keybundle16.png b/local/recipes/libs/qca/source/examples/cmssigner/icons/keybundle16.png new file mode 100644 index 0000000000..3212226e36 Binary files /dev/null and b/local/recipes/libs/qca/source/examples/cmssigner/icons/keybundle16.png differ diff --git a/local/recipes/libs/qca/source/examples/cmssigner/icons/keypair16.png b/local/recipes/libs/qca/source/examples/cmssigner/icons/keypair16.png new file mode 100644 index 0000000000..fea3d44515 Binary files /dev/null and b/local/recipes/libs/qca/source/examples/cmssigner/icons/keypair16.png differ diff --git a/local/recipes/libs/qca/source/examples/cmssigner/icons/publickey16.png b/local/recipes/libs/qca/source/examples/cmssigner/icons/publickey16.png new file mode 100644 index 0000000000..63d09cdb1e Binary files /dev/null and b/local/recipes/libs/qca/source/examples/cmssigner/icons/publickey16.png differ diff --git a/local/recipes/libs/qca/source/examples/cmssigner/keyselect.ui b/local/recipes/libs/qca/source/examples/cmssigner/keyselect.ui new file mode 100644 index 0000000000..143088c225 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/keyselect.ui @@ -0,0 +1,96 @@ + + KeySelect + + + + 0 + 0 + 363 + 233 + + + + Storage Device Browser + + + + 9 + + + 6 + + + + + Select an identity from a storage device below: + + + + + + + + + + 0 + + + 6 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + lv_stores + buttonBox + + + + + buttonBox + accepted() + KeySelect + accept() + + + 227 + 211 + + + 157 + 232 + + + + + buttonBox + rejected() + KeySelect + reject() + + + 295 + 217 + + + 286 + 232 + + + + + diff --git a/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.cpp b/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.cpp new file mode 100644 index 0000000000..89faaafda2 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.cpp @@ -0,0 +1,414 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "keyselectdlg.h" + +#include "ui_keyselect.h" +#include +#include +#include +#include +#include +#include + +#define ONLY_SHOW_KEYBUNDLE + +typedef QMap KeyStoreIconset; + +class KeyStoreItemShared +{ +public: + KeyStoreIconset iconset; + QString notAvailableString; +}; + +class KeyStoreItem : public QStandardItem +{ +public: + enum Type + { + Store = UserType, + Entry + }; + + enum Role + { + NameRole = Qt::UserRole, + SubTypeRole, + AvailabilityRole, + PositionRole + }; + + QPixmap entryTypeToIcon(QCA::KeyStoreEntry::Type type) const + { + QPixmap out; + if (!_shared) + return out; + const KeyStoreIconset &iconset = _shared->iconset; + switch (type) { + case QCA::KeyStoreEntry::TypeKeyBundle: + out = iconset[KeySelectDlg::IconKeyBundle]; + break; + case QCA::KeyStoreEntry::TypeCertificate: + out = iconset[KeySelectDlg::IconCert]; + break; + case QCA::KeyStoreEntry::TypeCRL: + out = iconset[KeySelectDlg::IconCrl]; + break; + case QCA::KeyStoreEntry::TypePGPSecretKey: + out = iconset[KeySelectDlg::IconPgpSec]; + break; + case QCA::KeyStoreEntry::TypePGPPublicKey: + out = iconset[KeySelectDlg::IconPgpPub]; + break; + default: + break; + } + return out; + } + + Type _type; + KeyStoreItemShared *_shared; + + QCA::KeyStore *keyStore; + QCA::KeyStoreEntry keyStoreEntry; + + KeyStoreItem(Type type, KeyStoreItemShared *shared) + : _type(type) + , _shared(shared) + { + setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + + void setStore(const QString &name, QCA::KeyStore::Type type) + { + setData(name, NameRole); + setData((int)type, SubTypeRole); + } + + void setEntry(const QString &name, QCA::KeyStoreEntry::Type type, bool available, int pos) + { + setData(name, NameRole); + setData((int)type, SubTypeRole); + setData(available, AvailabilityRole); + setData(pos, PositionRole); + } + + virtual QVariant data(int role) const + { + if (role == Qt::DisplayRole) { + if (_type == Store) { + return data(NameRole).toString(); + } else if (_type == Entry) { + QString str = data(NameRole).toString(); + if (_shared && !data(AvailabilityRole).toBool()) + str += QString(" ") + _shared->notAvailableString; + return str; + } else + return QStandardItem::data(role); + } else if (role == Qt::DecorationRole) { + if (_type == Entry) { + QCA::KeyStoreEntry::Type type = (QCA::KeyStoreEntry::Type)data(SubTypeRole).toInt(); + return entryTypeToIcon(type); + } else + return QStandardItem::data(role); + } else + return QStandardItem::data(role); + } + + virtual int type() const + { + return _type; + } + + virtual QStandardItem *clone() const + { + return new KeyStoreItem(*this); + } +}; + +class KeyStoreModel : public QStandardItemModel +{ + Q_OBJECT +public: + KeyStoreItemShared shared; + + QCA::KeyStoreManager ksm; + + KeyStoreModel(QObject *parent = 0) + : QStandardItemModel(parent) + , ksm(this) + { + shared.notAvailableString = tr("(not available)"); + + // make sure keystores are started + QCA::KeyStoreManager::start(); + + connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &))); + QStringList list = ksm.keyStores(); + foreach (const QString &s, list) + ks_available(s); + + setSortRole(KeyStoreItem::PositionRole); + } + + KeyStoreItem *itemFromStore(QCA::KeyStore *ks) const + { + for (int n = 0; n < rowCount(); ++n) { + KeyStoreItem *i = (KeyStoreItem *)item(n); + if (i->keyStore == ks) + return i; + } + return 0; + } + +private Q_SLOTS: + void ks_available(const QString &keyStoreId) + { + QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm); + +#ifdef ONLY_SHOW_KEYBUNDLE + // only list stores containing keybundles (non-pgp identities) + if (!ks->holdsIdentities() || ks->type() == QCA::KeyStore::PGPKeyring) + return; +#endif + + connect(ks, SIGNAL(updated()), SLOT(ks_updated())); + connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable())); + + KeyStoreItem *store_item = new KeyStoreItem(KeyStoreItem::Store, &shared); + store_item->setStore(ks->name(), ks->type()); + store_item->keyStore = ks; + ks->startAsynchronousMode(); + appendRow(store_item); + } + + void ks_updated() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + KeyStoreItem *store_item = itemFromStore(ks); + Q_ASSERT(store_item); + + QList newEntries = ks->entryList(); + +#ifdef ONLY_SHOW_KEYBUNDLE + // ignore entries that are not keybundles + for (int n = 0; n < newEntries.count(); ++n) { + if (newEntries[n].type() != QCA::KeyStoreEntry::TypeKeyBundle) { + newEntries.removeAt(n); + --n; // adjust position + } + } +#endif + + // update the store item itself + store_item->setStore(ks->name(), ks->type()); + + // handle removed child entries + for (int n = 0; n < store_item->rowCount(); ++n) { + KeyStoreItem *i = (KeyStoreItem *)store_item->child(n); + + // is the existing entry in the new list? + bool found = false; + foreach (const QCA::KeyStoreEntry &ne, newEntries) { + if (ne.id() == i->keyStoreEntry.id()) { + found = true; + break; + } + } + + // if not, remove it + if (!found) { + store_item->removeRow(n); + --n; // adjust position + } + } + + // handle added/updated child entries + for (int n = 0; n < newEntries.count(); ++n) { + const QCA::KeyStoreEntry &ne = newEntries[n]; + + // was this entry in the original list? + KeyStoreItem *entry_item = 0; + for (int k = 0; k < store_item->rowCount(); ++k) { + KeyStoreItem *i = (KeyStoreItem *)store_item->child(k); + if (i->keyStoreEntry.id() == ne.id()) { + entry_item = i; + break; + } + } + + // if not, add it + if (!entry_item) { + entry_item = new KeyStoreItem(KeyStoreItem::Entry, &shared); + entry_item->keyStoreEntry = ne; + entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n); + store_item->appendRow(entry_item); + } + // if so, update it + else { + entry_item->keyStoreEntry = ne; + entry_item->setEntry(newEntries[n].name(), newEntries[n].type(), newEntries[n].isAvailable(), n); + } + } + + store_item->sortChildren(0); + } + + void ks_unavailable() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + KeyStoreItem *store_item = itemFromStore(ks); + Q_ASSERT(store_item); + + store_item->removeRows(0, store_item->rowCount()); + removeRow(store_item->row()); + delete ks; + } +}; + +class KeySelectDlg::Private : public QObject +{ + Q_OBJECT +public: + KeySelectDlg *q; + Ui_KeySelect ui; + KeyStoreModel *model; + QCA::KeyStoreEntry cur_entry; + QAction *actionView; + + Private(KeySelectDlg *_q) + : QObject(_q) + , q(_q) + { + ui.setupUi(q); + + model = new KeyStoreModel(this); + connect(&model->ksm, SIGNAL(busyStarted()), SLOT(ksm_busyStarted())); + connect(&model->ksm, SIGNAL(busyFinished()), SLOT(ksm_busyFinished())); + if (model->ksm.isBusy()) + ksm_busyStarted(); + + ui.lv_stores->header()->hide(); + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui.lv_stores->setModel(model); + ui.lv_stores->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.lv_stores->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(stores_selectionChanged(const QItemSelection &, const QItemSelection &))); + connect(ui.lv_stores, + SIGNAL(customContextMenuRequested(const QPoint &)), + SLOT(stores_customContextMenuRequested(const QPoint &))); + + actionView = new QAction(tr("&View"), this); + connect(actionView, SIGNAL(triggered()), SLOT(view())); + actionView->setEnabled(false); + } + +private Q_SLOTS: + void ksm_busyStarted() + { + ui.lb_busy->setText(tr("Looking for devices...")); + } + + void ksm_busyFinished() + { + ui.lb_busy->setText(""); + } + + void stores_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) + { + Q_UNUSED(deselected); + + KeyStoreItem *i = 0; + if (!selected.indexes().isEmpty()) { + QModelIndex index = selected.indexes().first(); + i = (KeyStoreItem *)model->itemFromIndex(index); + } + + bool viewable = false; + bool choosable = false; + if (i && i->type() == KeyStoreItem::Entry) { + QCA::KeyStoreEntry entry = i->keyStoreEntry; + if (entry.type() == QCA::KeyStoreEntry::TypeKeyBundle) { + viewable = true; + choosable = true; + cur_entry = entry; + } + } + + if (!choosable) + cur_entry = QCA::KeyStoreEntry(); + + actionView->setEnabled(viewable); + + QPushButton *ok = ui.buttonBox->button(QDialogButtonBox::Ok); + if (choosable && !ok->isEnabled()) + ok->setEnabled(true); + else if (!choosable && ok->isEnabled()) + ok->setEnabled(false); + } + + void stores_customContextMenuRequested(const QPoint &pos) + { + QItemSelection selection = ui.lv_stores->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + + QModelIndex index = selection.indexes().first(); + KeyStoreItem *i = (KeyStoreItem *)model->itemFromIndex(index); + if (i && i->type() == KeyStoreItem::Entry) { + QMenu menu(q); + menu.addAction(actionView); + menu.exec(ui.lv_stores->viewport()->mapToGlobal(pos)); + } + } + + void view() + { + emit q->viewCertificate(cur_entry.keyBundle().certificateChain()); + } +}; + +KeySelectDlg::KeySelectDlg(QWidget *parent) + : QDialog(parent) +{ + d = new Private(this); +} + +KeySelectDlg::~KeySelectDlg() +{ + delete d; +} + +void KeySelectDlg::setIcon(IconType type, const QPixmap &icon) +{ + d->model->shared.iconset[type] = icon; +} + +void KeySelectDlg::accept() +{ + QCA::KeyStoreEntry entry = d->cur_entry; + QDialog::accept(); + emit selected(entry); +} + +#include "keyselectdlg.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.h b/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.h new file mode 100644 index 0000000000..d23647367e --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/keyselectdlg.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef KEYSELECTDLG_H +#define KEYSELECTDLG_H + +#include + +class QPixmap; + +namespace QCA { +class CertificateChain; +class KeyStoreEntry; +} + +class KeySelectDlg : public QDialog +{ + Q_OBJECT +public: + enum IconType + { + IconCert, + IconCrl, + IconKeyBundle, + IconPgpPub, + IconPgpSec + }; + + KeySelectDlg(QWidget *parent = 0); + ~KeySelectDlg(); + + void setIcon(IconType type, const QPixmap &icon); + +Q_SIGNALS: + void selected(const QCA::KeyStoreEntry &entry); + void viewCertificate(const QCA::CertificateChain &chain); + +protected slots: + virtual void accept(); + +private: + class Private; + friend class Private; + Private *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/examples/cmssigner/main.cpp b/local/recipes/libs/qca/source/examples/cmssigner/main.cpp new file mode 100644 index 0000000000..e424e14a70 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/main.cpp @@ -0,0 +1,951 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include "certitem.h" +#include "certviewdlg.h" +#include "keyselectdlg.h" +#include "pkcs11configdlg/pkcs11configdlg.h" +#include "ui_mainwin.h" + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +#define VERSION "1.0.0" + +class Icons +{ +public: + QPixmap cert, crl, keybundle, pgppub, pgpsec; +}; + +Icons *g_icons = 0; + +//---------------------------------------------------------------------------- +// Operation +//---------------------------------------------------------------------------- +class Operation : public QObject +{ + Q_OBJECT +public: + Operation(QObject *parent = 0) + : QObject(parent) + { + } + +Q_SIGNALS: + void error(const QString &str); +}; + +static QString validityToString(QCA::Validity v) +{ + QString s; + switch (v) { + case QCA::ValidityGood: + s = Operation::tr("Validated"); + break; + case QCA::ErrorRejected: + s = Operation::tr("Root CA is marked to reject the specified purpose"); + break; + case QCA::ErrorUntrusted: + s = Operation::tr("Certificate not trusted for the required purpose"); + break; + case QCA::ErrorSignatureFailed: + s = Operation::tr("Invalid signature"); + break; + case QCA::ErrorInvalidCA: + s = Operation::tr("Invalid CA certificate"); + break; + case QCA::ErrorInvalidPurpose: + s = Operation::tr("Invalid certificate purpose"); + break; + case QCA::ErrorSelfSigned: + s = Operation::tr("Certificate is self-signed"); + break; + case QCA::ErrorRevoked: + s = Operation::tr("Certificate has been revoked"); + break; + case QCA::ErrorPathLengthExceeded: + s = Operation::tr("Maximum certificate chain length exceeded"); + break; + case QCA::ErrorExpired: + s = Operation::tr("Certificate has expired"); + break; + case QCA::ErrorExpiredCA: + s = Operation::tr("CA has expired"); + break; + case QCA::ErrorValidityUnknown: + default: + s = Operation::tr("General certificate validation error"); + break; + } + return s; +} + +static QString smErrorToString(QCA::SecureMessage::Error e) +{ + QString s; + switch (e) { + case QCA::SecureMessage::ErrorPassphrase: + s = Operation::tr("Invalid passphrase."); + break; + case QCA::SecureMessage::ErrorFormat: + s = Operation::tr("Bad input format."); + break; + case QCA::SecureMessage::ErrorSignerExpired: + s = Operation::tr("Signer key is expired."); + break; + case QCA::SecureMessage::ErrorSignerInvalid: + s = Operation::tr("Signer key is invalid."); + break; + case QCA::SecureMessage::ErrorEncryptExpired: + s = Operation::tr("Encrypting key is expired."); + break; + case QCA::SecureMessage::ErrorEncryptUntrusted: + s = Operation::tr("Encrypting key is untrusted."); + break; + case QCA::SecureMessage::ErrorEncryptInvalid: + s = Operation::tr("Encrypting key is invalid."); + break; + case QCA::SecureMessage::ErrorNeedCard: + s = Operation::tr("Card was needed but not found."); + break; + case QCA::SecureMessage::ErrorCertKeyMismatch: + s = Operation::tr("Certificate and private key don't match."); + break; + case QCA::SecureMessage::ErrorUnknown: + default: + s = Operation::tr("General error."); + break; + } + return s; +} + +static QString smsIdentityToString(const QCA::SecureMessageSignature &sig) +{ + QString s; + switch (sig.identityResult()) { + case QCA::SecureMessageSignature::Valid: + break; + case QCA::SecureMessageSignature::InvalidSignature: + s = Operation::tr("Invalid signature"); + break; + case QCA::SecureMessageSignature::InvalidKey: + s = Operation::tr("Invalid key: %1").arg(validityToString(sig.keyValidity())); + break; + case QCA::SecureMessageSignature::NoKey: + s = Operation::tr("Key not found"); + break; + default: // this should not really be possible + s = Operation::tr("Unknown"); + break; + } + return s; +} + +class SignOperation : public Operation +{ + Q_OBJECT +private: + QByteArray in; + CertItemStore *store; + int id; + QCA::CMS *cms; + CertItemPrivateLoader *loader; + QCA::SecureMessage *msg; + int pending; + +public: + SignOperation(const QByteArray &_in, CertItemStore *_store, int _id, QCA::CMS *_cms, QObject *parent = 0) + : Operation(parent) + , in(_in) + , store(_store) + , id(_id) + , cms(_cms) + , msg(0) + { + loader = new CertItemPrivateLoader(store, this); + connect(loader, SIGNAL(finished()), SLOT(loader_finished())); + loader->start(id); + } + +Q_SIGNALS: + void loadError(); + void finished(const QString &sig); + +private Q_SLOTS: + void loader_finished() + { + QCA::PrivateKey privateKey = loader->privateKey(); + delete loader; + loader = 0; + + if (privateKey.isNull()) { + emit loadError(); + return; + } + + CertItem item = store->itemFromId(id); + + QCA::SecureMessageKey signer; + signer.setX509CertificateChain(item.certificateChain()); + signer.setX509PrivateKey(privateKey); + + msg = new QCA::SecureMessage(cms); + connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int))); + connect(msg, SIGNAL(finished()), SLOT(msg_finished())); + msg->setFormat(QCA::SecureMessage::Ascii); + msg->setSigner(signer); + msg->startSign(QCA::SecureMessage::Detached); + + pending = 0; + update(); + } + + void update() + { + QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks + in = in.mid(buf.size()); + pending += buf.size(); + msg->update(buf); + } + + void msg_bytesWritten(int x) + { + pending -= x; + + if (in.isEmpty() && pending == 0) + msg->end(); + else + update(); + } + + void msg_finished() + { + if (!msg->success()) { + QString str = smErrorToString(msg->errorCode()); + delete msg; + msg = 0; + emit error(tr("Error during sign operation.\nReason: %1").arg(str)); + return; + } + + QByteArray result = msg->signature(); + delete msg; + msg = 0; + emit finished(QString::fromLatin1(result)); + } +}; + +class VerifyOperation : public Operation +{ + Q_OBJECT +private: + QByteArray in, sig; + QCA::CMS *cms; + QCA::SecureMessage *msg; + int pending; + +public: + QCA::SecureMessageSignature signer; + + VerifyOperation(const QByteArray &_in, const QByteArray &_sig, QCA::CMS *_cms, QObject *parent = 0) + : Operation(parent) + , in(_in) + , sig(_sig) + , cms(_cms) + , msg(0) + { + msg = new QCA::SecureMessage(cms); + connect(msg, SIGNAL(bytesWritten(int)), SLOT(msg_bytesWritten(int))); + connect(msg, SIGNAL(finished()), SLOT(msg_finished())); + msg->setFormat(QCA::SecureMessage::Ascii); + msg->startVerify(sig); + + pending = 0; + update(); + } + +Q_SIGNALS: + void finished(); + +private Q_SLOTS: + void update() + { + QByteArray buf = in.mid(0, 16384 - pending); // 16k chunks + in = in.mid(buf.size()); + pending += buf.size(); + msg->update(buf); + } + + void msg_bytesWritten(int x) + { + pending -= x; + + if (in.isEmpty() && pending == 0) + msg->end(); + else + update(); + } + + void msg_finished() + { + if (!msg->success()) { + QString str = smErrorToString(msg->errorCode()); + delete msg; + msg = 0; + emit error(tr("Error during verify operation.\nReason: %1").arg(str)); + return; + } + + signer = msg->signer(); + delete msg; + msg = 0; + + if (signer.identityResult() != QCA::SecureMessageSignature::Valid) { + QString str = smsIdentityToString(signer); + emit error(tr("Verification failed!\nReason: %1").arg(str)); + return; + } + + emit finished(); + } +}; + +//---------------------------------------------------------------------------- +// MainWin +//---------------------------------------------------------------------------- +static QString get_fingerprint(const QCA::Certificate &cert) +{ + QString hex = QCA::Hash("sha1").hashToString(cert.toDER()); + QString out; + for (int n = 0; n < hex.count(); ++n) { + if (n != 0 && n % 2 == 0) + out += ':'; + out += hex[n]; + } + return out; +} + +class MainWin : public QMainWindow +{ + Q_OBJECT +private: + Ui_MainWin ui; + CertItemStore *users, *roots; + QCA::CMS *cms; + Operation *op; + QAction *actionView, *actionRename, *actionRemove; + QCA::Certificate self_signed_verify_cert; + int auto_import_req_id; + +public: + MainWin(QWidget *parent = 0) + : QMainWindow(parent) + , op(0) + , auto_import_req_id(-1) + { + ui.setupUi(this); + + g_icons = new Icons; + g_icons->cert = QPixmap(":/gfx/icons/cert16.png"); + g_icons->crl = QPixmap(":/gfx/icons/crl16.png"); + g_icons->keybundle = QPixmap(":/gfx/icons/keybundle16.png"); + g_icons->pgppub = QPixmap(":/gfx/icons/publickey16.png"); + g_icons->pgpsec = QPixmap(":/gfx/icons/keypair16.png"); + if (g_icons->cert.isNull() || g_icons->crl.isNull() || g_icons->keybundle.isNull() || + g_icons->pgppub.isNull() || g_icons->pgpsec.isNull()) + printf("Warning: not all icons loaded\n"); + + users = new CertItemStore(this); + roots = new CertItemStore(this); + + setIcons(users); + setIcons(roots); + + connect(users, SIGNAL(addSuccess(int, int)), SLOT(users_addSuccess(int, int))); + connect(users, SIGNAL(addFailed(int)), SLOT(users_addFailed(int))); + + actionView = new QAction(tr("&View"), this); + actionRename = new QAction(tr("Re&name"), this); + actionRemove = new QAction(tr("Rem&ove"), this); + + connect(ui.actionLoadIdentityFile, SIGNAL(triggered()), SLOT(load_file())); + connect(ui.actionLoadIdentityEntry, SIGNAL(triggered()), SLOT(load_device())); + connect(ui.actionLoadAuthority, SIGNAL(triggered()), SLOT(load_root())); + connect(ui.actionConfigurePkcs11, SIGNAL(triggered()), SLOT(mod_config())); + connect(ui.actionQuit, SIGNAL(triggered()), SLOT(close())); + connect(ui.actionAbout, SIGNAL(triggered()), SLOT(about())); + connect(ui.pb_sign, SIGNAL(clicked()), SLOT(do_sign())); + connect(ui.pb_verify, SIGNAL(clicked()), SLOT(do_verify())); + + connect(actionView, SIGNAL(triggered()), SLOT(item_view())); + connect(actionRename, SIGNAL(triggered()), SLOT(item_rename())); + connect(actionRemove, SIGNAL(triggered()), SLOT(item_remove())); + + ui.pb_sign->setEnabled(false); + + ui.lv_users->setModel(users); + connect(ui.lv_users->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(users_selectionChanged(const QItemSelection &, const QItemSelection &))); + + ui.lv_users->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.lv_users, + SIGNAL(customContextMenuRequested(const QPoint &)), + SLOT(users_customContextMenuRequested(const QPoint &))); + + ui.lv_authorities->setModel(roots); + + ui.lv_authorities->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.lv_authorities, + SIGNAL(customContextMenuRequested(const QPoint &)), + SLOT(roots_customContextMenuRequested(const QPoint &))); + + cms = new QCA::CMS(this); + + QStringList ulist, rlist; + { + QSettings settings("Affinix", "CMS Signer"); + ulist = settings.value("users").toStringList(); + rlist = settings.value("roots").toStringList(); + } + + users->load(ulist); + roots->load(rlist); + } + + ~MainWin() + { + QStringList ulist = users->save(); + QStringList rlist = roots->save(); + + QSettings settings("Affinix", "CMS Signer"); + settings.setValue("users", ulist); + settings.setValue("roots", rlist); + + delete g_icons; + g_icons = 0; + } + + void setIcons(CertItemStore *store) + { + store->setIcon(CertItemStore::IconCert, g_icons->cert); + store->setIcon(CertItemStore::IconCrl, g_icons->crl); + store->setIcon(CertItemStore::IconKeyBundle, g_icons->keybundle); + store->setIcon(CertItemStore::IconPgpPub, g_icons->pgppub); + store->setIcon(CertItemStore::IconPgpSec, g_icons->pgpsec); + } + + QCA::CertificateCollection allCerts() + { + QCA::CertificateCollection col; + + // system store + col += QCA::systemStore(); + + // additional roots configured in application + foreach (const CertItem &i, roots->items()) + col.addCertificate(i.certificateChain().primary()); + + // user chains + foreach (const CertItem &i, users->items()) { + foreach (const QCA::Certificate &cert, i.certificateChain()) + col.addCertificate(cert); + } + + return col; + } + + QCA::CertificateChain complete(const QCA::CertificateChain &chain) + { + return chain.complete(allCerts().certificates()); + } + +private Q_SLOTS: + void load_file() + { + QString fileName = + QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Identities (*.p12 *.pfx)")); + if (fileName.isEmpty()) + return; + + setEnabled(false); + users->addFromFile(fileName); + } + + void load_device() + { + KeySelectDlg *w = new KeySelectDlg(this); + w->setAttribute(Qt::WA_DeleteOnClose, true); + w->setWindowModality(Qt::WindowModal); + connect( + w, SIGNAL(selected(const QCA::KeyStoreEntry &)), SLOT(load_device_finished(const QCA::KeyStoreEntry &))); + connect(w, + SIGNAL(viewCertificate(const QCA::CertificateChain &)), + SLOT(keyselect_viewCertificate(const QCA::CertificateChain &))); + w->setIcon(KeySelectDlg::IconCert, g_icons->cert); + w->setIcon(KeySelectDlg::IconCrl, g_icons->crl); + w->setIcon(KeySelectDlg::IconKeyBundle, g_icons->keybundle); + w->setIcon(KeySelectDlg::IconPgpPub, g_icons->pgppub); + w->setIcon(KeySelectDlg::IconPgpSec, g_icons->pgpsec); + w->show(); + } + + void load_device_finished(const QCA::KeyStoreEntry &entry) + { + users->addFromKeyStore(entry); + } + + void load_root() + { + QString fileName = + QFileDialog::getOpenFileName(this, tr("Open File"), QString(), tr("X.509 Certificates (*.pem *.crt)")); + if (fileName.isEmpty()) + return; + + QCA::Certificate cert = QCA::Certificate::fromPEMFile(fileName); + if (cert.isNull()) { + QMessageBox::information(this, tr("Error"), tr("Error opening certificate file.")); + return; + } + + roots->addUser(cert); + } + + void users_addSuccess(int req_id, int id) + { + if (req_id == auto_import_req_id) { + auto_import_req_id = -1; + + CertItem i = users->itemFromId(id); + + QMessageBox::information(this, + tr("User added"), + tr("This signature was made by a previously unknown user, and so the " + "user has now been added to the keyring as \"%1\".") + .arg(i.name())); + + verify_next(); + return; + } + + ui.lv_users->selectionModel()->select(users->index(users->rowFromId(id)), + QItemSelectionModel::Clear | QItemSelectionModel::Select | + QItemSelectionModel::Current); + + setEnabled(true); + } + + void users_addFailed(int req_id) + { + Q_UNUSED(req_id); + + setEnabled(true); + } + + void mod_config() + { + if (!Pkcs11ConfigDlg::isSupported()) { + QMessageBox::information( + this, tr("Error"), tr("No provider available supporting standard PKCS#11 configuration.")); + return; + } + + Pkcs11ConfigDlg *w = new Pkcs11ConfigDlg(this); + w->setAttribute(Qt::WA_DeleteOnClose, true); + w->setWindowModality(Qt::WindowModal); + w->show(); + } + + void users_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) + { + Q_UNUSED(deselected); + + int at = -1; + if (!selected.indexes().isEmpty()) { + QModelIndex index = selected.indexes().first(); + at = index.row(); + } + + bool usable = false; + if (at != -1 && users->itemFromRow(at).isUsable()) + usable = true; + + if (usable && !ui.pb_sign->isEnabled()) + ui.pb_sign->setEnabled(true); + else if (!usable && ui.pb_sign->isEnabled()) + ui.pb_sign->setEnabled(false); + } + + void item_view() + { + if (ui.lv_users->hasFocus()) { + QItemSelection selection = ui.lv_users->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + users_view(index.row()); + } else // lv_authorities + { + QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + roots_view(index.row()); + } + } + + void item_rename() + { + if (ui.lv_users->hasFocus()) { + QItemSelection selection = ui.lv_users->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + users_rename(index.row()); + } else // lv_authorities + { + QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + roots_rename(index.row()); + } + } + + void item_remove() + { + if (ui.lv_users->hasFocus()) { + QItemSelection selection = ui.lv_users->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + users_remove(index.row()); + } else // lv_authorities + { + QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + roots_remove(index.row()); + } + } + + void users_view(int at) + { + CertItem i = users->itemFromRow(at); + CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this); + w->setAttribute(Qt::WA_DeleteOnClose, true); + w->show(); + } + + void users_rename(int at) + { + QModelIndex index = users->index(at); + ui.lv_users->setFocus(); + ui.lv_users->setCurrentIndex(index); + ui.lv_users->selectionModel()->select( + index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); + ui.lv_users->edit(index); + } + + void users_remove(int at) + { + users->removeItem(users->idFromRow(at)); + } + + void roots_view(int at) + { + CertItem i = roots->itemFromRow(at); + CertViewDlg *w = new CertViewDlg(complete(i.certificateChain()), this); + w->setAttribute(Qt::WA_DeleteOnClose, true); + w->show(); + } + + void roots_rename(int at) + { + QModelIndex index = roots->index(at); + ui.lv_authorities->setFocus(); + ui.lv_authorities->setCurrentIndex(index); + ui.lv_authorities->selectionModel()->select( + index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); + ui.lv_authorities->edit(index); + } + + void roots_remove(int at) + { + roots->removeItem(roots->idFromRow(at)); + } + + void keyselect_viewCertificate(const QCA::CertificateChain &chain) + { + CertViewDlg *w = new CertViewDlg(complete(chain), (QWidget *)sender()); + w->setAttribute(Qt::WA_DeleteOnClose, true); + w->show(); + } + + void users_customContextMenuRequested(const QPoint &pos) + { + QItemSelection selection = ui.lv_users->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + + QMenu menu(this); + menu.addAction(actionView); + menu.addAction(actionRename); + menu.addAction(actionRemove); + menu.exec(ui.lv_users->viewport()->mapToGlobal(pos)); + } + + void roots_customContextMenuRequested(const QPoint &pos) + { + QItemSelection selection = ui.lv_authorities->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + + QMenu menu(this); + menu.addAction(actionView); + menu.addAction(actionRename); + menu.addAction(actionRemove); + menu.exec(ui.lv_authorities->viewport()->mapToGlobal(pos)); + } + + void do_sign() + { + QItemSelection selection = ui.lv_users->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + int at = index.row(); + + setEnabled(false); + + op = new SignOperation(ui.te_data->toPlainText().toUtf8(), users, users->idFromRow(at), cms, this); + connect(op, SIGNAL(loadError()), SLOT(sign_loadError())); + connect(op, SIGNAL(finished(const QString &)), SLOT(sign_finished(const QString &))); + connect(op, SIGNAL(error(const QString &)), SLOT(sign_error(const QString &))); + } + + void do_verify() + { + // prepare root certs + QCA::CertificateCollection col; + + // system store + col += QCA::systemStore(); + + // additional roots configured in application + foreach (const CertItem &i, roots->items()) + col.addCertificate(i.certificateChain().primary()); + + // consider self-signed users as roots + // (it is therefore not possible with this application to + // have people in your keyring that you don't trust) + foreach (const CertItem &i, users->items()) { + QCA::Certificate cert = i.certificateChain().primary(); + if (cert.isSelfSigned()) + col.addCertificate(cert); + } + + // the self signed verify cert, if applicable + if (!self_signed_verify_cert.isNull()) { + col.addCertificate(self_signed_verify_cert); + self_signed_verify_cert = QCA::Certificate(); + } + + cms->setTrustedCertificates(col); + + setEnabled(false); + + op = new VerifyOperation(ui.te_data->toPlainText().toUtf8(), ui.te_sig->toPlainText().toUtf8(), cms, this); + connect(op, SIGNAL(finished()), SLOT(verify_finished())); + connect(op, SIGNAL(error(const QString &)), SLOT(verify_error(const QString &))); + } + + void about() + { + int ver = qcaVersion(); + int maj = (ver >> 16) & 0xff; + int min = (ver >> 8) & 0xff; + int bug = ver & 0xff; + QString verstr; + verstr.sprintf("%d.%d.%d", maj, min, bug); + + QString str; + str += tr("CMS Signer version %1 by Justin Karneges").arg(VERSION) + '\n'; + str += tr("A simple tool for creating and verifying digital signatures.") + '\n'; + str += '\n'; + str += tr("Using QCA version %1").arg(verstr) + '\n'; + str += '\n'; + str += tr("Icons by Jason Kim") + '\n'; + + QCA::ProviderList list = QCA::providers(); + foreach (QCA::Provider *p, list) { + QString credit = p->credit(); + if (!credit.isEmpty()) { + str += '\n'; + str += credit; + } + } + + QMessageBox::about(this, tr("About CMS Signer"), str); + } + + void sign_loadError() + { + delete op; + op = 0; + + setEnabled(true); + } + + void sign_finished(const QString &sig) + { + delete op; + op = 0; + + ui.te_sig->setPlainText(sig); + + setEnabled(true); + } + + void sign_error(const QString &msg) + { + delete op; + op = 0; + + setEnabled(true); + + QMessageBox::information(this, tr("Error"), msg); + } + + void verify_finished() + { + QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer; + delete op; + op = 0; + + // import the cert? + QCA::SecureMessageKey skey = signer.key(); + if (!skey.isNull()) { + QCA::CertificateChain chain = skey.x509CertificateChain(); + + int at = -1; + QList items = users->items(); + for (int n = 0; n < items.count(); ++n) { + const CertItem &i = items[n]; + if (i.certificateChain().primary() == chain.primary()) { + at = n; + break; + } + } + + // add + if (at == -1) { + auto_import_req_id = users->addUser(chain); + return; + } + // update + else { + users->updateChain(users->idFromRow(at), chain); + } + } + + verify_next(); + } + + void verify_next() + { + setEnabled(true); + + QMessageBox::information(this, tr("Verify"), tr("Signature verified successfully.")); + } + + void verify_error(const QString &msg) + { + QCA::SecureMessageSignature signer = ((VerifyOperation *)op)->signer; + delete op; + op = 0; + + QCA::SecureMessageKey skey = signer.key(); + if (signer.keyValidity() == QCA::ErrorSelfSigned && !skey.isNull()) { + QCA::CertificateChain chain = skey.x509CertificateChain(); + if (chain.count() == 1 && chain.primary().isSelfSigned()) { + QCA::Certificate cert = chain.primary(); + + int ret = QMessageBox::warning( + this, + tr("Self-signed certificate"), + tr("The signature is made by an unknown user, and the certificate is self-signed.
\n" + "
\n" + "Common Name: %1
\n" + "SHA1 Fingerprint: %2
\n" + "
\n" + "Trust the certificate?
") + .arg(cert.commonName(), get_fingerprint(cert)), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No); + + if (ret == QMessageBox::Yes) { + self_signed_verify_cert = cert; + do_verify(); + return; + } + } + } + + setEnabled(true); + + QMessageBox::information(this, tr("Error"), msg); + } +}; + +int main(int argc, char **argv) +{ + QCA::Initializer qcaInit; + QApplication qapp(argc, argv); + + qapp.setApplicationName(MainWin::tr("CMS Signer")); + + if (!QCA::isSupported("cert,crl,cms")) { + QMessageBox::critical( + 0, + qapp.applicationName() + ": " + MainWin::tr("Error"), + MainWin::tr( + "No support for CMS is available. Please install an appropriate QCA plugin, such as qca-ossl.")); + return 1; + } + + QCA::KeyStoreManager::start(); + + MainWin mainWin; + mainWin.show(); + return qapp.exec(); +} + +#include "main.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/mainwin.ui b/local/recipes/libs/qca/source/examples/cmssigner/mainwin.ui new file mode 100644 index 0000000000..36dce9d2f8 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/mainwin.ui @@ -0,0 +1,226 @@ + + MainWin + + + + 0 + 0 + 577 + 501 + + + + CMS Signer + + + + + 9 + + + 6 + + + + + 0 + + + + Keyring + + + + 9 + + + 6 + + + + + + + + + Authorities + + + + 9 + + + 6 + + + + + + + + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + Text: + + + + + + + + + + + + 0 + + + 6 + + + + + Signature: + + + + + + + + + + + + + + 0 + + + 6 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &Sign + + + + + + + &Verify + + + + + + + + + + + 0 + 0 + 577 + 29 + + + + + &Help + + + + + + &File + + + + + + + + + + + + + + + + Load Identity From &File... + + + + + Load Identity From &Storage Device... + + + + + &Quit + + + + + About CMS Signer + + + + + Configure &PKCS#11 Modules... + + + + + Load &Authority... + + + + + tabWidget + lv_users + lv_authorities + te_data + te_sig + pb_sign + pb_verify + + + + + + diff --git a/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11config.ui b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11config.ui new file mode 100644 index 0000000000..054062f227 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11config.ui @@ -0,0 +1,624 @@ + + Pkcs11Config + + + + 0 + 0 + 570 + 458 + + + + PKCS#11 Module Configuration + + + + 9 + + + 6 + + + + + General + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + Allow Loading of Root CAs + + + + + + + Allow Protected Authentication + + + + + + + 0 + + + 6 + + + + + Log Level: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Remember PIN + + + true + + + false + + + + 9 + + + 6 + + + + + Until Session Ends + + + + + + + 0 + + + 6 + + + + + For a Time (in Seconds): + + + + + + + 86400 + + + 1 + + + 300 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + PKCS#11 Modules + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + + + + 0 + + + 6 + + + + + &New + + + + + + + Qt::Horizontal + + + + 20 + 40 + + + + + + + + Rem&ove + + + + + + + + + + + 0 + + + + File + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + Module File: + + + + + + + + + + + + 0 + + + 6 + + + + + Browse For Module File... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Slot Events + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + Method: + + + + + + + + Determine Automatically + + + + + Trigger + + + + + Polling + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Polling Interval + + + + 9 + + + 6 + + + + + No Preference, Use Internal Default + + + + + + + 0 + + + 6 + + + + + Custom (in Seconds): + + + + + + + 86400 + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Advanced + + + + 9 + + + 6 + + + + + Allow Protected Authentication + + + + + + + Certificates Stored As Private Objects + + + + + + + Private Key Modes + + + + 9 + + + 6 + + + + + Determine Automatically + + + + + + + 0 + + + 6 + + + + + Sign + + + + + + + Unwrap + + + + + + + Decrypt + + + + + + + Sign Recover + + + + + + + + + + + + Qt::Vertical + + + + 20 + 16 + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + ck_allowroot + ck_allowprotected + sb_loglevel + gb_pincache + rb_pincache_nolimit + rb_pincache_time + sb_pincache_time + lv_modules + pb_add + pb_remove + tb_details + le_library + pb_browse + cb_slotmethod + rb_polldefault + rb_pollcustom + sb_pollcustom + ck_modallowprotected + ck_certprivate + ck_modeauto + ck_modesign + ck_modesignrecover + ck_modedecrypt + ck_modeunwrap + buttonBox + + + + + buttonBox + accepted() + Pkcs11Config + accept() + + + 345 + 448 + + + 320 + 137 + + + + + buttonBox + rejected() + Pkcs11Config + reject() + + + 370 + 448 + + + 363 + 135 + + + + + diff --git a/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.cpp b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.cpp new file mode 100644 index 0000000000..9cb640d463 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.cpp @@ -0,0 +1,774 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "pkcs11configdlg.h" + +#include "ui_pkcs11config.h" +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------- +// Pkcs11ProviderConfig +//---------------------------------------------------------------------------- +class Pkcs11ProviderConfig +{ +public: + bool allow_protected_authentication; + bool cert_private; + bool enabled; + QString library; + QString name; + int private_mask; + QString slotevent_method; + int slotevent_timeout; + + Pkcs11ProviderConfig() + : allow_protected_authentication(true) + , cert_private(false) + , enabled(false) + , private_mask(0) + , slotevent_method("auto") + , slotevent_timeout(0) + { + } + + QVariantMap toVariantMap() const + { + QVariantMap out; + out["allow_protected_authentication"] = allow_protected_authentication; + out["cert_private"] = cert_private; + out["enabled"] = enabled; + out["library"] = library; + out["name"] = name; + out["private_mask"] = private_mask; + out["slotevent_method"] = slotevent_method; + out["slotevent_timeout"] = slotevent_timeout; + return out; + } + + bool fromVariantMap(const QVariantMap &in) + { + allow_protected_authentication = in["allow_protected_authentication"].toBool(); + cert_private = in["cert_private"].toBool(); + enabled = in["enabled"].toBool(); + library = in["library"].toString(); + name = in["name"].toString(); + private_mask = in["private_mask"].toInt(); + slotevent_method = in["slotevent_method"].toString(); + slotevent_timeout = in["slotevent_timeout"].toInt(); + return true; + } +}; + +//---------------------------------------------------------------------------- +// Pkcs11Config +//---------------------------------------------------------------------------- +class Pkcs11Config +{ +public: + bool allow_load_rootca; + bool allow_protected_authentication; + int log_level; + int pin_cache; + QList providers; + + QVariantMap orig_config; + + Pkcs11Config() + : allow_load_rootca(false) + , allow_protected_authentication(true) + , log_level(0) + , pin_cache(-1) + { + } + + QVariantMap toVariantMap() const + { + QVariantMap out = orig_config; + + // form type + out["formtype"] = "http://affinix.com/qca/forms/qca-pkcs11#1.0"; + + // base settings + out["allow_load_rootca"] = allow_load_rootca; + out["allow_protected_authentication"] = allow_protected_authentication; + out["log_level"] = log_level; + out["pin_cache"] = pin_cache; + + // provider settings (always write at least 10 providers) + for (int n = 0; n < 10 || n < providers.count(); ++n) { + QString prefix = QString().sprintf("provider_%02d_", n); + + Pkcs11ProviderConfig provider; + if (n < providers.count()) + provider = providers[n]; + + QVariantMap subconfig = provider.toVariantMap(); + QMapIterator it(subconfig); + while (it.hasNext()) { + it.next(); + out.insert(prefix + it.key(), it.value()); + } + } + + return out; + } + + bool fromVariantMap(const QVariantMap &in) + { + if (in["formtype"] != "http://affinix.com/qca/forms/qca-pkcs11#1.0") + return false; + + allow_load_rootca = in["allow_load_rootca"].toBool(); + allow_protected_authentication = in["allow_protected_authentication"].toBool(); + log_level = in["log_level"].toInt(); + pin_cache = in["pin_cache"].toInt(); + + for (int n = 0;; ++n) { + QString prefix = QString().sprintf("provider_%02d_", n); + + // collect all key/values with this prefix into a + // a separate container, leaving out the prefix + // from the keys. + QVariantMap subconfig; + QMapIterator it(in); + while (it.hasNext()) { + it.next(); + if (it.key().startsWith(prefix)) + subconfig.insert(it.key().mid(prefix.length()), it.value()); + } + + // if there are no config items with this prefix, we're done + if (subconfig.isEmpty()) + break; + + Pkcs11ProviderConfig provider; + if (!provider.fromVariantMap(subconfig)) + return false; + + // skip unnamed entries + if (provider.name.isEmpty()) + continue; + + // skip duplicate entries + bool have_name_already = false; + foreach (const Pkcs11ProviderConfig &i, providers) { + if (i.name == provider.name) { + have_name_already = true; + break; + } + } + if (have_name_already) + continue; + + providers += provider; + } + + orig_config = in; + return true; + } +}; + +//---------------------------------------------------------------------------- +// ModuleListModel +//---------------------------------------------------------------------------- +class ModuleListModel : public QAbstractListModel +{ + Q_OBJECT +public: + QList list; + + ModuleListModel(QObject *parent = 0) + : QAbstractListModel(parent) + { + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + Q_UNUSED(parent); + return list.count(); + } + + QVariant data(const QModelIndex &index, int role) const + { + if (!index.isValid()) + return QVariant(); + + if (index.row() >= list.count()) + return QVariant(); + + if (role == Qt::DisplayRole) + return list[index.row()].name; + else if (role == Qt::EditRole) + return list[index.row()].name; + else + return QVariant(); + } + + Qt::ItemFlags flags(const QModelIndex &index) const + { + if (!index.isValid()) + return Qt::ItemIsEnabled; + + return QAbstractItemModel::flags(index) | Qt::ItemIsEditable; + } + + bool setData(const QModelIndex &index, const QVariant &value, int role) + { + if (index.isValid() && role == Qt::EditRole) { + QString str = value.toString(); + + if (str.isEmpty()) { + emit editFailed(index, tr("Module name cannot be blank.")); + return false; + } + + bool have_name_already = false; + int at = index.row(); + for (int n = 0; n < list.count(); ++n) { + const Pkcs11ProviderConfig &i = list[n]; + + // skip self + if (n == at) + continue; + + if (i.name == str) { + have_name_already = true; + break; + } + } + if (have_name_already) { + emit editFailed(index, tr("There is already a module with this name.")); + return false; + } + + list[index.row()].name = str; + emit dataChanged(index, index); + return true; + } + return false; + } + + void addItems(const QList &items) + { + if (items.isEmpty()) + return; + + beginInsertRows(QModelIndex(), list.size(), list.size() + items.count() - 1); + list += items; + endInsertRows(); + } + + void addItem(const Pkcs11ProviderConfig &i) + { + beginInsertRows(QModelIndex(), list.size(), list.size()); + list += i; + endInsertRows(); + } + + void removeItem(int at) + { + beginRemoveRows(QModelIndex(), at, at); + list.removeAt(at); + endRemoveRows(); + } + +Q_SIGNALS: + void editFailed(const QModelIndex &index, const QString &reasonString); +}; + +//---------------------------------------------------------------------------- +// Pkcs11ConfigDlg +//---------------------------------------------------------------------------- +static QCA::Provider *get_pkcs11_provider(QVariantMap *_config = 0) +{ + QCA::ProviderList providers = QCA::providers(); + providers += QCA::defaultProvider(); + + QCA::Provider *provider = 0; + QVariantMap config; + foreach (QCA::Provider *p, providers) { + config = QCA::getProviderConfig(p->name()); + if (!config.isEmpty() && config["formtype"] == "http://affinix.com/qca/forms/qca-pkcs11#1.0") { + provider = p; + break; + } + } + + if (provider && _config) + *_config = config; + + return provider; +} + +class Pkcs11ConfigDlg::Private : public QObject +{ + Q_OBJECT +public: + Pkcs11ConfigDlg *q; + Ui_Pkcs11Config ui; + QString providerName; + ModuleListModel *model; + Pkcs11Config config; + bool dirty; + + // for safe dialog closing behavior during QListView editing + bool allow_close; + bool done; + + // for ignoring modifications that we cause when populating fields + bool ignore_dataChanged; + + Private(Pkcs11ConfigDlg *_q, const QString &_providerName, const QVariantMap &configmap) + : QObject(_q) + , q(_q) + , providerName(_providerName) + , dirty(false) + , allow_close(true) + , done(false) + , ignore_dataChanged(true) + { + ui.setupUi(q); + q->resize(q->minimumSize()); + + model = new ModuleListModel(this); + qRegisterMetaType("QModelIndex"); + // do this queued for two reasons: + // 1) if we throw an error dialog, it will occur after the + // row text has reverted, and the call stack completed + // (the latter may not be required, but it helps me + // sleep). + // 2) if the user accepts/rejects the dialog while editing, + // it is easy to ensure that the signal is not processed + // (if it gets delivered at all). + connect(model, + SIGNAL(editFailed(const QModelIndex &, const QString &)), + SLOT(model_editFailed(const QModelIndex &, const QString &)), + Qt::QueuedConnection); + + // set up widgets + ui.rb_pincache_nolimit->setChecked(true); + ui.sb_pincache_time->setEnabled(false); + ui.sb_pincache_time->setValue(300); + ui.lv_modules->setModel(model); + ui.lv_modules->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked | + QAbstractItemView::EditKeyPressed); + ui.pb_remove->setEnabled(false); + ui.tb_details->setEnabled(false); + ui.gb_poll->setEnabled(false); + ui.rb_polldefault->setChecked(true); + ui.sb_pollcustom->setEnabled(false); + ui.sb_pollcustom->setValue(5); + ui.ck_modeauto->setChecked(true); + + // disable this by default, enable on dataChanged + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + // general + connect(ui.ck_allowroot, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.ck_allowprotected, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.sb_loglevel, SIGNAL(valueChanged(int)), SLOT(dataChanged())); + connect(ui.gb_pincache, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.rb_pincache_nolimit, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.rb_pincache_time, SIGNAL(toggled(bool)), ui.sb_pincache_time, SLOT(setEnabled(bool))); + connect(ui.rb_pincache_time, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.sb_pincache_time, SIGNAL(valueChanged(int)), SLOT(dataChanged())); + + // modules + connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SLOT(dataChanged())); + connect(ui.lv_modules->selectionModel(), + SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), + SLOT(module_selectionChanged(const QItemSelection &, const QItemSelection &))); + connect(ui.pb_add, SIGNAL(clicked()), SLOT(module_add())); + connect(ui.pb_remove, SIGNAL(clicked()), SLOT(module_remove())); + connect(ui.le_library, SIGNAL(textChanged(const QString &)), SLOT(dataChanged())); + connect(ui.pb_browse, SIGNAL(clicked()), SLOT(library_browse())); + connect(ui.cb_slotmethod, SIGNAL(currentIndexChanged(int)), SLOT(slotmethod_currentIndexChanged(int))); + connect(ui.rb_polldefault, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.rb_pollcustom, SIGNAL(toggled(bool)), ui.sb_pollcustom, SLOT(setEnabled(bool))); + connect(ui.rb_pollcustom, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.sb_pollcustom, SIGNAL(valueChanged(int)), SLOT(dataChanged())); + connect(ui.ck_modallowprotected, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.ck_certprivate, SIGNAL(toggled(bool)), SLOT(dataChanged())); + connect(ui.ck_modeauto, SIGNAL(toggled(bool)), SLOT(modeauto_toggled(bool))); + connect(ui.ck_modesign, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool))); + connect(ui.ck_modesignrecover, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool))); + connect(ui.ck_modedecrypt, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool))); + connect(ui.ck_modeunwrap, SIGNAL(toggled(bool)), SLOT(modenonauto_toggled(bool))); + + // is this a valid config? + if (!providerName.isEmpty() && config.fromVariantMap(configmap)) { + // if so, load everything up + ui.ck_allowroot->setChecked(config.allow_load_rootca); + ui.ck_allowprotected->setChecked(config.allow_protected_authentication); + ui.sb_loglevel->setValue(config.log_level); + if (config.pin_cache != 0) { + ui.gb_pincache->setChecked(true); + if (config.pin_cache <= -1) + ui.rb_pincache_nolimit->setChecked(true); + else { + ui.rb_pincache_time->setChecked(true); + ui.sb_pincache_time->setValue(config.pin_cache); + } + } + + model->addItems(config.providers); + if (!model->list.isEmpty()) { + QModelIndex index = model->index(0); + ui.lv_modules->setCurrentIndex(index); + ui.lv_modules->selectionModel()->select( + index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); + } + ui.buttonBox->setFocus(); + ui.buttonBox->button(QDialogButtonBox::Cancel)->setFocus(); + } else { + // otherwise, disable everything + ui.gb_general->setEnabled(false); + ui.gb_modules->setEnabled(false); + ui.buttonBox->setFocus(); + ui.buttonBox->button(QDialogButtonBox::Cancel)->setFocus(); + } + + ignore_dataChanged = false; + } + + void save_module(int at) + { + // save all options (except the name, which is handled by the model) + Pkcs11ProviderConfig &i = model->list[at]; + + i.library = ui.le_library->text(); + i.enabled = true; + + int x = ui.cb_slotmethod->currentIndex(); + if (x == 0) + i.slotevent_method = "auto"; + else if (x == 1) + i.slotevent_method = "trigger"; + else // 2 + i.slotevent_method = "poll"; + if (x == 2) { + if (ui.rb_polldefault->isChecked()) + i.slotevent_timeout = 0; + else + i.slotevent_timeout = ui.sb_pollcustom->value(); + } else + i.slotevent_timeout = 0; + + i.allow_protected_authentication = ui.ck_modallowprotected->isChecked(); + i.cert_private = ui.ck_certprivate->isChecked(); + + i.private_mask = 0; + if (ui.ck_modesign->isChecked()) + i.private_mask |= 1; + if (ui.ck_modesignrecover->isChecked()) + i.private_mask |= 2; + if (ui.ck_modedecrypt->isChecked()) + i.private_mask |= 4; + if (ui.ck_modeunwrap->isChecked()) + i.private_mask |= 8; + } + + void save() + { + // save currently selected module, which may not be saved yet + QItemSelection selection = ui.lv_modules->selectionModel()->selection(); + if (!selection.indexes().isEmpty()) { + QModelIndex index = selection.indexes().first(); + save_module(index.row()); + } + + config.allow_load_rootca = ui.ck_allowroot->isChecked(); + config.allow_protected_authentication = ui.ck_allowprotected->isChecked(); + config.log_level = ui.sb_loglevel->value(); + if (ui.gb_pincache->isChecked()) { + if (ui.rb_pincache_nolimit->isChecked()) + config.pin_cache = -1; + else + config.pin_cache = ui.sb_pincache_time->value(); + } else + config.pin_cache = 0; + + config.providers = model->list; + + QVariantMap configmap = config.toVariantMap(); + QCA::setProviderConfig(providerName, configmap); + QCA::saveProviderConfig(providerName); + } + +private Q_SLOTS: + void model_editFailed(const QModelIndex &index, const QString &reasonString) + { + // if the dialog has already been dismissed, then don't + // bother with handling the editing failure + if (done) + return; + + // show error dialog, and don't allow dimissing the dialog + // during. we need this, because the dismiss request + // can be queued, and end up being invoked during the + // QMessageBox nested eventloop. + allow_close = false; + QMessageBox::information(q, tr("Module Configuration"), reasonString); + allow_close = true; + + // return to edit mode for the item + ui.lv_modules->setFocus(); + ui.lv_modules->setCurrentIndex(index); + ui.lv_modules->selectionModel()->select( + index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); + ui.lv_modules->edit(index); + } + + void dataChanged() + { + if (ignore_dataChanged) + return; + + if (dirty) + return; + + dirty = true; + ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + } + + void module_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) + { + if (!deselected.indexes().isEmpty()) { + QModelIndex index = deselected.indexes().first(); + save_module(index.row()); + } + + ignore_dataChanged = true; + + if (!selected.indexes().isEmpty()) { + if (deselected.indexes().isEmpty()) { + ui.pb_remove->setEnabled(true); + ui.tb_details->setEnabled(true); + } + + QModelIndex index = selected.indexes().first(); + const Pkcs11ProviderConfig &i = model->list[index.row()]; + + ui.le_library->setText(i.library); + + if (i.slotevent_method == "trigger") + ui.cb_slotmethod->setCurrentIndex(1); + else if (i.slotevent_method == "poll") { + ui.cb_slotmethod->setCurrentIndex(2); + if (i.slotevent_timeout <= 0) + ui.rb_polldefault->setChecked(true); + else { + ui.rb_pollcustom->setChecked(true); + ui.sb_pollcustom->setValue(i.slotevent_timeout); + } + } else // auto + ui.cb_slotmethod->setCurrentIndex(0); + if (i.slotevent_method != "poll") { + ui.rb_polldefault->setChecked(true); + ui.sb_pollcustom->setValue(5); + } + + ui.ck_modallowprotected->setChecked(i.allow_protected_authentication); + ui.ck_certprivate->setChecked(i.cert_private); + + if (i.private_mask == 0) + ui.ck_modeauto->setChecked(true); + else { + ui.ck_modesign->setChecked(i.private_mask & 1); + ui.ck_modesignrecover->setChecked(i.private_mask & 2); + ui.ck_modedecrypt->setChecked(i.private_mask & 4); + ui.ck_modeunwrap->setChecked(i.private_mask & 8); + } + } else if (selected.indexes().isEmpty() && !deselected.indexes().isEmpty()) { + // restore defaults for all details widgets + ui.le_library->setText(QString()); + ui.cb_slotmethod->setCurrentIndex(0); + ui.rb_polldefault->setChecked(true); + ui.sb_pollcustom->setValue(5); + ui.ck_modallowprotected->setChecked(false); + ui.ck_certprivate->setChecked(false); + ui.ck_modeauto->setChecked(true); + + // flip to first page, disable + ui.tb_details->setCurrentIndex(0); + ui.pb_remove->setEnabled(false); + ui.tb_details->setEnabled(false); + } + + ignore_dataChanged = false; + } + + void module_add() + { + // find unused default name + QString name; + for (int n = 1;; ++n) { + if (n == 1) + name = tr("New Module"); + else + name = tr("New Module (%1)").arg(n); + + bool have_name_already = false; + for (int n = 0; n < model->list.count(); ++n) { + const Pkcs11ProviderConfig &i = model->list[n]; + if (i.name == name) { + have_name_already = true; + break; + } + } + if (!have_name_already) + break; + } + + Pkcs11ProviderConfig i; + i.name = name; + i.enabled = true; + model->addItem(i); + + dataChanged(); + + QModelIndex index = model->index(model->list.count() - 1); + + // flip to first page + ui.tb_details->setCurrentIndex(0); + + // edit this item + ui.lv_modules->setFocus(); + ui.lv_modules->setCurrentIndex(index); + ui.lv_modules->selectionModel()->select( + index, QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Current); + ui.lv_modules->edit(index); + } + + void module_remove() + { + QItemSelection selection = ui.lv_modules->selectionModel()->selection(); + if (selection.indexes().isEmpty()) + return; + QModelIndex index = selection.indexes().first(); + model->removeItem(index.row()); + + dataChanged(); + } + + void library_browse() + { + QString fileName = + QFileDialog::getOpenFileName(q, tr("Select PKCS#11 Module"), QString(), tr("PKCS#11 Modules (*.*)")); + if (fileName.isEmpty()) + return; + + ui.le_library->setText(fileName); + } + + void slotmethod_currentIndexChanged(int index) + { + if (index == 2) // Polling + ui.gb_poll->setEnabled(true); + else + ui.gb_poll->setEnabled(false); + + dataChanged(); + } + + void modeauto_toggled(bool checked) + { + if (checked) { + if (ui.ck_modesign->isChecked()) + ui.ck_modesign->setChecked(false); + if (ui.ck_modesignrecover->isChecked()) + ui.ck_modesignrecover->setChecked(false); + if (ui.ck_modedecrypt->isChecked()) + ui.ck_modedecrypt->setChecked(false); + if (ui.ck_modeunwrap->isChecked()) + ui.ck_modeunwrap->setChecked(false); + } else { + if (!ui.ck_modesign->isChecked() && !ui.ck_modesignrecover->isChecked() && + !ui.ck_modedecrypt->isChecked() && !ui.ck_modeunwrap->isChecked()) { + ui.ck_modesign->setChecked(true); + ui.ck_modesignrecover->setChecked(true); + ui.ck_modedecrypt->setChecked(true); + ui.ck_modeunwrap->setChecked(true); + } + } + + dataChanged(); + } + + void modenonauto_toggled(bool checked) + { + if (checked) { + if (ui.ck_modeauto->isChecked()) + ui.ck_modeauto->setChecked(false); + } else { + if (!ui.ck_modesign->isChecked() && !ui.ck_modesignrecover->isChecked() && + !ui.ck_modedecrypt->isChecked() && !ui.ck_modeunwrap->isChecked()) { + ui.ck_modeauto->setChecked(true); + } + } + + dataChanged(); + } +}; + +Pkcs11ConfigDlg::Pkcs11ConfigDlg(QWidget *parent) + : QDialog(parent) +{ + QVariantMap config; + QCA::Provider *p = get_pkcs11_provider(&config); + if (p) + d = new Private(this, p->name(), config); + else + d = new Private(this, QString(), QVariantMap()); +} + +Pkcs11ConfigDlg::Pkcs11ConfigDlg(const QString &providerName, const QVariantMap &config, QWidget *parent) + : QDialog(parent) +{ + d = new Private(this, providerName, config); +} + +Pkcs11ConfigDlg::~Pkcs11ConfigDlg() +{ + delete d; +} + +void Pkcs11ConfigDlg::done(int r) +{ + if (!d->allow_close) + return; + + d->done = true; + if (r == Accepted) + d->save(); + QDialog::done(r); +} + +bool Pkcs11ConfigDlg::isSupported() +{ + return (get_pkcs11_provider() ? true : false); +} + +#include "pkcs11configdlg.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.h b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.h new file mode 100644 index 0000000000..a09df6f4d7 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/pkcs11configdlg/pkcs11configdlg.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef PKCS11CONFIGDLG_H +#define PKCS11CONFIGDLG_H + +#include +#include + +// support for the 'http://affinix.com/qca/forms/qca-pkcs11#1.0' provider form + +class Pkcs11ConfigDlg : public QDialog +{ +public: + Pkcs11ConfigDlg(QWidget *parent = 0); + Pkcs11ConfigDlg(const QString &providerName, const QVariantMap &config, QWidget *parent = 0); + ~Pkcs11ConfigDlg(); + + static bool isSupported(); + +protected slots: + virtual void done(int r); + +private: + class Private; + Private *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/examples/cmssigner/prompter.cpp b/local/recipes/libs/qca/source/examples/cmssigner/prompter.cpp new file mode 100644 index 0000000000..1647c3fa9e --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/prompter.cpp @@ -0,0 +1,298 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "prompter.h" + +#include +#include +#include +#include +#include +#include + +class Prompter::Private : public QObject +{ + Q_OBJECT +public: + Prompter *q; + + class Item + { + public: + int id; + QCA::Event event; + }; + + QCA::EventHandler handler; + QList pending; + bool prompting; + QMessageBox *token_prompt; + bool auto_accept; + + QCA::KeyStoreManager ksm; + QList keyStores; + + Private(Prompter *_q) + : QObject(_q) + , q(_q) + , handler(this) + , prompting(false) + , token_prompt(0) + , ksm(this) + { + connect(&handler, SIGNAL(eventReady(int, const QCA::Event &)), SLOT(ph_eventReady(int, const QCA::Event &))); + handler.start(); + + connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ks_available(const QString &))); + foreach (const QString &keyStoreId, ksm.keyStores()) + ks_available(keyStoreId); + } + + ~Private() + { + qDeleteAll(keyStores); + + while (!pending.isEmpty()) + handler.reject(pending.takeFirst().id); + } + +private Q_SLOTS: + void ph_eventReady(int id, const QCA::Event &event) + { + Item i; + i.id = id; + i.event = event; + pending += i; + nextEvent(); + } + + void nextEvent() + { + if (prompting || pending.isEmpty()) + return; + + prompting = true; + + const Item &i = pending.first(); + const int &id = i.id; + const QCA::Event &event = i.event; + + if (event.type() == QCA::Event::Password) { + QCA::SecureArray known = q->knownPassword(event); + if (!known.isEmpty()) { + handler.submitPassword(id, known); + goto end; + } + + QString type = Prompter::tr("password"); + if (event.passwordStyle() == QCA::Event::StylePassphrase) + type = Prompter::tr("passphrase"); + else if (event.passwordStyle() == QCA::Event::StylePIN) + type = Prompter::tr("PIN"); + + QString str; + if (event.source() == QCA::Event::KeyStore) { + QString name; + QCA::KeyStoreEntry entry = event.keyStoreEntry(); + if (!entry.isNull()) { + name = entry.name(); + } else { + if (event.keyStoreInfo().type() == QCA::KeyStore::SmartCard) + name = Prompter::tr("the '%1' token").arg(event.keyStoreInfo().name()); + else + name = event.keyStoreInfo().name(); + } + str = Prompter::tr("Enter %1 for %2").arg(type, name); + } else if (!event.fileName().isEmpty()) { + QFileInfo fi(event.fileName()); + str = Prompter::tr("Enter %1 for %2:").arg(type, fi.fileName()); + } else + str = Prompter::tr("Enter %1:").arg(type); + + bool ok; + QString pass = QInputDialog::getText(0, + QApplication::instance()->applicationName() + ": " + tr("Prompt"), + str, + QLineEdit::Password, + QString(), + &ok); + if (ok) { + QCA::SecureArray password = pass.toUtf8(); + q->userSubmitted(password, event); + handler.submitPassword(id, password); + } else + handler.reject(id); + } else if (event.type() == QCA::Event::Token) { + // even though we're being prompted for a missing token, + // we should still check if the token is present, due to + // a possible race between insert and token request. + bool found = false; + + // token-only + if (event.keyStoreEntry().isNull()) { + foreach (QCA::KeyStore *ks, keyStores) { + if (ks->id() == event.keyStoreInfo().id()) { + found = true; + break; + } + } + } + // token-entry + else { + QCA::KeyStoreEntry kse = event.keyStoreEntry(); + + QCA::KeyStore *ks = 0; + foreach (QCA::KeyStore *i, keyStores) { + if (i->id() == event.keyStoreInfo().id()) { + ks = i; + break; + } + } + if (ks) { + QList list = ks->entryList(); + foreach (const QCA::KeyStoreEntry &e, list) { + if (e.id() == kse.id() && kse.isAvailable()) { + found = true; + break; + } + } + } + } + if (found) { + // auto-accept + handler.tokenOkay(id); + return; + } + + QCA::KeyStoreEntry entry = event.keyStoreEntry(); + QString name; + if (!entry.isNull()) { + name = Prompter::tr("Please make %1 (of %2) available").arg(entry.name(), entry.storeName()); + } else { + name = Prompter::tr("Please insert the '%1' token").arg(event.keyStoreInfo().name()); + } + + QString str = Prompter::tr("%1 and click OK.").arg(name); + + QMessageBox msgBox(QMessageBox::Information, + QApplication::instance()->applicationName() + ": " + tr("Prompt"), + str, + QMessageBox::Ok | QMessageBox::Cancel, + 0); + token_prompt = &msgBox; + auto_accept = false; + if (msgBox.exec() == QMessageBox::Ok || auto_accept) + handler.tokenOkay(id); + else + handler.reject(id); + token_prompt = 0; + } else + handler.reject(id); + + end: + pending.removeFirst(); + prompting = false; + + if (!pending.isEmpty()) + QMetaObject::invokeMethod(this, "nextEvent", Qt::QueuedConnection); + } + + void ks_available(const QString &keyStoreId) + { + QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm); + connect(ks, SIGNAL(updated()), SLOT(ks_updated())); + connect(ks, SIGNAL(unavailable()), SLOT(ks_unavailable())); + keyStores += ks; + ks->startAsynchronousMode(); + + // are we currently in a token-only prompt? + if (token_prompt && pending.first().event.type() == QCA::Event::Token && + pending.first().event.keyStoreEntry().isNull()) { + // was the token we're looking for just inserted? + if (pending.first().event.keyStoreInfo().id() == keyStoreId) { + // auto-accept + auto_accept = true; + token_prompt->accept(); + } + } + } + + void ks_unavailable() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + keyStores.removeAll(ks); + delete ks; + } + + void ks_updated() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + + // are we currently in a token-entry prompt? + if (token_prompt && pending.first().event.type() == QCA::Event::Token && + !pending.first().event.keyStoreEntry().isNull()) { + QCA::KeyStoreEntry kse = pending.first().event.keyStoreEntry(); + + // was the token of the entry we're looking for updated? + if (pending.first().event.keyStoreInfo().id() == ks->id()) { + // is the entry available? + bool avail = false; + QList list = ks->entryList(); + foreach (const QCA::KeyStoreEntry &e, list) { + if (e.id() == kse.id()) { + avail = kse.isAvailable(); + break; + } + } + if (avail) { + // auto-accept + auto_accept = true; + token_prompt->accept(); + } + } + } + } +}; + +Prompter::Prompter(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +Prompter::~Prompter() +{ + delete d; +} + +QCA::SecureArray Prompter::knownPassword(const QCA::Event &event) +{ + Q_UNUSED(event); + return QCA::SecureArray(); +} + +void Prompter::userSubmitted(const QCA::SecureArray &password, const QCA::Event &event) +{ + Q_UNUSED(password); + Q_UNUSED(event); +} + +#include "prompter.moc" diff --git a/local/recipes/libs/qca/source/examples/cmssigner/prompter.h b/local/recipes/libs/qca/source/examples/cmssigner/prompter.h new file mode 100644 index 0000000000..f0a060a3d2 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/cmssigner/prompter.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef PROMPTER_H +#define PROMPTER_H + +#include + +namespace QCA { +class SecureArray; +class Event; +} + +class Prompter : public QObject +{ + Q_OBJECT +public: + Prompter(QObject *parent = nullptr); + ~Prompter(); + +protected: + // called with every password event, to check for a known value. + // reimplement it to provide known/cached passwords. + virtual QCA::SecureArray knownPassword(const QCA::Event &event); + + // called when a user-entered password is submitted. note that this + // does not mean the password was correct. to know if the password + // was correct, you'll have to match up the event information with + // the operation that triggered it. + virtual void userSubmitted(const QCA::SecureArray &password, const QCA::Event &event); + +private: + class Private; + friend class Private; + Private *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/examples/eventhandlerdemo/CMakeLists.txt b/local/recipes/libs/qca/source/examples/eventhandlerdemo/CMakeLists.txt new file mode 100644 index 0000000000..0458dedfc3 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/eventhandlerdemo/CMakeLists.txt @@ -0,0 +1,5 @@ +set(eventhandlerdemo_bin_SRCS eventhandlerdemo.cpp) + +add_executable(eventhandlerdemo ${eventhandlerdemo_bin_SRCS}) + +target_link_qca_libraries(eventhandlerdemo) diff --git a/local/recipes/libs/qca/source/examples/eventhandlerdemo/eventhandlerdemo.cpp b/local/recipes/libs/qca/source/examples/eventhandlerdemo/eventhandlerdemo.cpp new file mode 100644 index 0000000000..4605ac7973 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/eventhandlerdemo/eventhandlerdemo.cpp @@ -0,0 +1,168 @@ +/* + Copyright (C) 2007 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +/** + We need a class on the client side to handle password requests. +*/ +class ClientPassphraseHandler : public QObject +{ + Q_OBJECT +public: + ClientPassphraseHandler(QObject *parent = nullptr) + : QObject(parent) + { + // When the PasswordAsker or TokenAsker needs to interact + // with the user, it raises a signal. We connect that to a + // local slot to get the required information. + connect(&m_handler, &QCA::EventHandler::eventReady, this, &ClientPassphraseHandler::my_eventReady); + + // Now that we are set up, we can start the EventHandler. Nothing + // will happen if you don't call this method. + m_handler.start(); + } + +private Q_SLOTS: + // This slot gets called when the provider needs a token inserted, + // or to get a passphrase / password / PIN. + void my_eventReady(int id, const QCA::Event &event) + { + // We can sanity check the event + if (event.isNull()) { + return; + } + + // Events can be associated with a a keystore or a file/bytearray + // You can tell which by looking at the Source + if (event.source() == QCA::Event::KeyStore) { + std::cout << "Event is associated with a key store operation" << std::endl; + } else if (event.source() == QCA::Event::Data) { + std::cout << "Event is associated with a file or some other data" << std::endl; + // if the event comes from a file type operation, you can get the + // name / label using fileName() + std::cout << " Filename: " << qPrintable(event.fileName()) << std::endl; + } else { + std::cout << "Unexpected Source for Event" << std::endl; + } + + // There are different kinds of events. + if (event.type() == QCA::Event::Token) { + // You would typically ask the user to insert the token here + std::cout << "Request for token" << std::endl; + // we just fake it for this demo. + m_handler.tokenOkay(id); + // you could use m_handler.reject( id ) to refuse the token request + + } else if (event.type() == QCA::Event::Password) { + std::cout << "Request for password, passphrase or PIN" << std::endl; + // and within the Password type, we have a few different styles. + if (event.passwordStyle() == QCA::Event::StylePassword) { + std::cout << " [Password request]" << std::endl; + } else if (event.passwordStyle() == QCA::Event::StylePassphrase) { + std::cout << " [Passphrase request]" << std::endl; + } else if (event.passwordStyle() == QCA::Event::StylePIN) { + std::cout << " [PIN request]" << std::endl; + } else { + std::cout << " [unexpect request style]" << std::endl; + } + // You would typically request the password/PIN/passphrase. + // again, we just fake it. + m_handler.submitPassword(id, QCA::SecureArray("hello")); + + } else { + std::cout << "Unexpected event type" << std::endl; + } + } + +private: + QCA::EventHandler m_handler; +}; + +void asker_procedure(); + +class AskerThread : public QThread +{ + Q_OBJECT +protected: + void run() override + { + asker_procedure(); + } +}; + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication exampleApp(argc, argv); + + ClientPassphraseHandler cph; + + // handler and asker cannot occur in the same thread + AskerThread askerThread; + QObject::connect(&askerThread, &AskerThread::finished, &exampleApp, &QCoreApplication::quit); + askerThread.start(); + + exampleApp.exec(); + return 0; +} + +void asker_procedure() +{ + QCA::PasswordAsker pwAsker; + + pwAsker.ask(QCA::Event::StylePassword, QStringLiteral("foo.tmp"), nullptr); + + pwAsker.waitForResponse(); + + std::cout << "Password was: " << pwAsker.password().toByteArray().data() << std::endl; + + std::cout << std::endl << "Now do token:" << std::endl; + + QCA::TokenAsker tokenAsker; + + tokenAsker.ask( + QCA::KeyStoreInfo(QCA::KeyStore::SmartCard, QStringLiteral("Token Id"), QStringLiteral("Token Name")), + QCA::KeyStoreEntry(), + nullptr); + + tokenAsker.waitForResponse(); + + if (tokenAsker.accepted()) { + std::cout << "Token was accepted" << std::endl; + } else { + std::cout << "Token was not accepted" << std::endl; + } +} + +#include "eventhandlerdemo.moc" diff --git a/local/recipes/libs/qca/source/examples/examples.doco b/local/recipes/libs/qca/source/examples/examples.doco new file mode 100644 index 0000000000..3dfc2be49e --- /dev/null +++ b/local/recipes/libs/qca/source/examples/examples.doco @@ -0,0 +1,182 @@ +/** \example aes-cmac.cpp + +This example shows how to implement a client side "provider". + +There are three important parts to this: + - the class derived from QCA::Provider (in this example called + "ClientSideProvider"), that generates the context class + - one or more context classes (in this example only one, implementing + AES-CMAC, called "AESCMACContext") + - a call to QCA::insertProvider, to add the QCA::Provider subclass + into QCA + +*/ + + +/** \example base64test.cpp + +The code below shows some simple operations on a QCA::Base64 object, converting +between QCA::SecureArray and QString. + +*/ + + +/** \example certtest.cpp + +This example shows how QCA::Certificate and QCA::CertificateCollection +can be used. Note that the argument, if you provide it, must be a +PEM encoded file collection. + +*/ + + +/** \example ciphertest.cpp + +The code below shows the normal way to use the QCA::Cipher class. + +*/ + + +/* \example cmssigner/main.cpp + +The code below shows how to use Cryptographic Message Syntax (CMS) +in a GUI application. + +\include certitem.h +\include certitem.cpp +\include certviewdlg.h +\include certviewdlg.cpp +\include keyselectdlg.h +\include keyselectdlg.cpp +\include prompter.h +\include prompter.cpp + +*/ + + +/** \example eventhandlerdemo.cpp + +The code below shows to implement a client side handler for +password / passphrase / PIN and token requests from QCA and any +associated providers. + +*/ + + +/** \example hashtest.cpp + +The code below shows how to use the QCA::Hash class + +*/ + + +/** \example hextest.cpp + +The code below shows some simple operations on a QCA::Hex object, converting +between QCA::SecureArray and QString. + +*/ + + +/** \example keyloader.cpp + +The code below shows how to load a private key from a PEM format file, +including handling any requirement for a passphrase. This is done using +the QCA::KeyLoader class. + +*/ + + +/** \example mactest.cpp + +The code below shows how to use the QCA::MessageAuthenticationCode class + +*/ + + +/** \example md5crypt.cpp + +The code below shows how to calculate an md5crypt based password. This +code is compatible with the glibc code. + +*/ + + +/** \example providertest.cpp + +The code below shows some simple operations on a QCA::Provider object, including +use of iterators and some member functions. + +*/ + + +/** \example publickeyexample.cpp + +The code below shows how to do public key encryption, decryption, +signing and verification. +*/ + + +/** \example randomtest.cpp + +The code below shows the normal way to use the QCA::Random class. + +*/ + + +/** \example rsatest.cpp + +The code below shows some of the capabilities for how to use +RSA. This example also shows how to export and import a key +to a file, using PEM encoding. + +*/ + + +/** \example saslserver.cpp + +The code below shows how to create a SASL server. + +*/ + + +/** \example saslclient.cpp + +The code below shows how to create a SASL client. + +*/ + + +/** \example sslservtest.cpp + +The code below shows how to create an SSL server. + +Note that this server returns a self-signed certificate +for "example.com", and that the certificate is expired. + +The design used here only allows for one connection +at a time. If you want to allow for more, you should +probably create a "TlsConnection" object that agregates +a QCA::TLS object and a QTcpSocket (plus a little bit of +state information) that handles a single connection. Then +just create a TlsConnection for each server connection. + +*/ + +/** \example ssltest.cpp + +The code below shows how to create an SSL client + +*/ + +/** \example tlssocket.cpp + +The code below shows how to create a socket that can operate +over an Transport Layer Security (TLS, also known as SSL) connection. + +\include tlssocket/tlssocket.h +\include tlssocket/main.cpp +*/ + + + diff --git a/local/recipes/libs/qca/source/examples/hashtest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/hashtest/CMakeLists.txt new file mode 100644 index 0000000000..890b0d8e6c --- /dev/null +++ b/local/recipes/libs/qca/source/examples/hashtest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(hashtest_bin_SRCS hashtest.cpp) + +add_executable(hashtest ${hashtest_bin_SRCS}) + +target_link_qca_libraries(hashtest) diff --git a/local/recipes/libs/qca/source/examples/hashtest/hashtest.cpp b/local/recipes/libs/qca/source/examples/hashtest/hashtest.cpp new file mode 100644 index 0000000000..c44af73f50 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/hashtest/hashtest.cpp @@ -0,0 +1,77 @@ +/* + Copyright (C) 2004 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto/QtCrypto has the declarations for all of QCA +#include + +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // we use the first argument if provided, or + // use "hello" if no arguments + QCA::SecureArray arg = (argc >= 2) ? argv[1] : "hello"; + + // must always check that an algorithm is supported before using it + if (!QCA::isSupported("sha1")) + printf("SHA1 not supported!\n"); + else { + // this shows the "all in one" approach + QString result = QCA::Hash(QStringLiteral("sha1")).hashToString(arg); + printf("sha1(\"%s\") = [%s]\n", arg.data(), qPrintable(result)); + } + + // must always check that an algorithm is supported before using it + if (!QCA::isSupported("md5")) + printf("MD5 not supported!\n"); + else { + // this shows the incremental approach. Naturally + // for this simple job, we could use the "all in one" + // approach - this is an example, after all :-) + QCA::SecureArray part1(arg.toByteArray().left(3)); // three chars - "hel" + QCA::SecureArray part2(arg.toByteArray().mid(3)); // the rest - "lo" + + // create the required object. + QCA::Hash hashObject(QStringLiteral("md5")); + // we split it into two parts to show incremental update + hashObject.update(part1); + hashObject.update(part2); + // no more updates after calling final. + QCA::SecureArray resultArray = hashObject.final(); + // convert the result into printable hexadecimal. + QString result = QCA::arrayToHex(resultArray.toByteArray()); + printf("md5(\"%s\") = [%s]\n", arg.data(), qPrintable(result)); + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/hextest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/hextest/CMakeLists.txt new file mode 100644 index 0000000000..278d6e91f6 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/hextest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(hextest_bin_SRCS hextest.cpp) + +add_executable(hextest ${hextest_bin_SRCS}) + +target_link_qca_libraries(hextest) diff --git a/local/recipes/libs/qca/source/examples/hextest/hextest.cpp b/local/recipes/libs/qca/source/examples/hextest/hextest.cpp new file mode 100644 index 0000000000..c1a1b486bd --- /dev/null +++ b/local/recipes/libs/qca/source/examples/hextest/hextest.cpp @@ -0,0 +1,69 @@ +/* + Copyright (C) 2005 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // we use the first argument as the data to encode / decode + // if an argument is provided. Use "hello" if no argument + QByteArray arg; // empty array + arg.append((argc >= 2) ? argv[1] : "hello"); + + // create our object, which does encoding by default + // QCA::Hex encoder(QCA::Encode); is equivalent + QCA::Hex encoder; + + // You might prefer to use encoder.encode(); and have + // it return a QCA::SecureArray, depending on your needs + QString encoded = encoder.arrayToString(arg); + + std::cout << arg.data() << " in hex encoding is "; + std::cout << encoded.toLatin1().data() << std::endl; + + // This time, we'll create an object to decode hexadecimal. + // We could also have reused the existing object, calling + // clear(); and setup(QCA::Decode); on it. + QCA::Hex decoder(QCA::Decode); + + // This time, we convert a QString into a QString + QString decoded = decoder.decodeString(encoded); + + std::cout << encoded.toLatin1().data() << " decoded from hex is "; + std::cout << decoded.toLatin1().data() << std::endl; + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/keyloader/CMakeLists.txt b/local/recipes/libs/qca/source/examples/keyloader/CMakeLists.txt new file mode 100644 index 0000000000..2865a79ba9 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/keyloader/CMakeLists.txt @@ -0,0 +1,5 @@ +set(keyloader_bin_SRCS keyloader.cpp) + +add_executable(keyloader ${keyloader_bin_SRCS}) + +target_link_qca_libraries(keyloader) diff --git a/local/recipes/libs/qca/source/examples/keyloader/keyloader.cpp b/local/recipes/libs/qca/source/examples/keyloader/keyloader.cpp new file mode 100644 index 0000000000..335678f02d --- /dev/null +++ b/local/recipes/libs/qca/source/examples/keyloader/keyloader.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class PassphraseHandler : public QObject +{ + Q_OBJECT +public: + QCA::EventHandler handler; + + PassphraseHandler(QObject *parent = nullptr) + : QObject(parent) + { + connect(&handler, &QCA::EventHandler::eventReady, this, &PassphraseHandler::eh_eventReady); + handler.start(); + } + +private Q_SLOTS: + void eh_eventReady(int id, const QCA::Event &event) + { + if (event.type() == QCA::Event::Password) { + QCA::SecureArray pass; + QCA::ConsolePrompt prompt; + prompt.getHidden(QStringLiteral("Passphrase")); + prompt.waitForFinished(); + pass = prompt.result(); + handler.submitPassword(id, pass); + } else + handler.reject(id); + } +}; + +class App : public QObject +{ + Q_OBJECT +public: + QCA::KeyLoader keyLoader; + QString str; + + App() + { + connect(&keyLoader, &QCA::KeyLoader::finished, this, &App::kl_finished); + } + +public Q_SLOTS: + void start() + { + keyLoader.loadPrivateKeyFromPEMFile(str); + } + +Q_SIGNALS: + void quit(); + +private Q_SLOTS: + void kl_finished() + { + if (keyLoader.convertResult() == QCA::ConvertGood) { + QCA::PrivateKey key = keyLoader.privateKey(); + printf("Loaded successfully. Bits: %d\n", key.bitSize()); + } else + printf("Unable to load.\n"); + + emit quit(); + } +}; + +int main(int argc, char **argv) +{ + QCA::Initializer init; + QCoreApplication qapp(argc, argv); + + if (argc < 2) { + printf("usage: keyloader [privatekey.pem]\n"); + return 0; + } + + PassphraseHandler passphraseHandler; + App app; + app.str = QFile::decodeName(argv[1]); + QObject::connect(&app, &App::quit, &qapp, QCoreApplication::quit); + QTimer::singleShot(0, &app, &App::start); + qapp.exec(); + return 0; +} + +#include "keyloader.moc" diff --git a/local/recipes/libs/qca/source/examples/mactest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/mactest/CMakeLists.txt new file mode 100644 index 0000000000..2f61cb9657 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/mactest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(mactest_bin_SRCS mactest.cpp) + +add_executable(mactest ${mactest_bin_SRCS}) + +target_link_qca_libraries(mactest) diff --git a/local/recipes/libs/qca/source/examples/mactest/mactest.cpp b/local/recipes/libs/qca/source/examples/mactest/mactest.cpp new file mode 100644 index 0000000000..37d54e688a --- /dev/null +++ b/local/recipes/libs/qca/source/examples/mactest/mactest.cpp @@ -0,0 +1,85 @@ +/* + Copyright (C) 2004, 2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include +#include + +// needed for printf +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + qDebug() << "This example shows hashed MAC"; + + // we use the first argument as the data to authenticate + // if an argument is provided. Use "hello" if no argument + QByteArray arg = (argc >= 2) ? argv[1] : "hello"; + + // we use the second argument as the key to authenticate + // with, if two arguments are provided. Use "secret" as + // the key if less than two arguments. + QCA::SecureArray key((argc >= 3) ? argv[2] : "secret"); + + // must always check that an algorithm is supported before using it + if (!QCA::isSupported("hmac(sha1)")) { + printf("HMAC(SHA1) not supported!\n"); + } else { + // create the required object using HMAC with SHA-1, and an + // empty key. + QCA::MessageAuthenticationCode hmacObject(QStringLiteral("hmac(sha1)"), QCA::SecureArray()); + + // create the key + QCA::SymmetricKey keyObject(key); + + // set the HMAC object to use the key + hmacObject.setup(key); + // that could also have been done in the + // QCA::MessageAuthenticationCode constructor + + // we split it into two parts to show incremental update + QCA::SecureArray part1(arg.left(3)); // three chars - "hel" + QCA::SecureArray part2(arg.mid(3)); // the rest - "lo" + hmacObject.update(part1); + hmacObject.update(part2); + + // no more updates after calling final. + QCA::SecureArray resultArray = hmacObject.final(); + + // convert the result into printable hexadecimal. + QString result = QCA::arrayToHex(resultArray.toByteArray()); + printf("HMAC(SHA1) of \"%s\" with \"%s\" = [%s]\n", arg.data(), key.data(), result.toLatin1().data()); + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/md5crypt/CMakeLists.txt b/local/recipes/libs/qca/source/examples/md5crypt/CMakeLists.txt new file mode 100644 index 0000000000..6bcf96b7f6 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/md5crypt/CMakeLists.txt @@ -0,0 +1,7 @@ +set(md5crypt_bin_SRCS md5crypt.cpp) + +add_executable(md5crypt ${md5crypt_bin_SRCS}) + +target_link_qca_libraries(md5crypt) + +#add "crypt" to the libs if you are trying the crypt() equivalent diff --git a/local/recipes/libs/qca/source/examples/md5crypt/md5crypt.cpp b/local/recipes/libs/qca/source/examples/md5crypt/md5crypt.cpp new file mode 100644 index 0000000000..9d33e70dd6 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/md5crypt/md5crypt.cpp @@ -0,0 +1,193 @@ +/* + Copyright (C) 2007 Carlo Todeschini - Metarete s.r.l. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + Algorithm inspired by Vladimir Silva's "Secure Java apps on Linux using + MD5 crypt" article + (http://www-128.ibm.com/developerworks/linux/library/l-md5crypt/) +*/ + +#include +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +QString to64(long v, int size) +{ + // Character set of the encrypted password: A-Za-z0-9./ + QString itoa64 = QStringLiteral("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + QString result; + + while (--size >= 0) { + result.append(itoa64.at((int)(v & 0x3f))); + v = v >> 6; + } + + return result; +} + +int byte2unsigned(int byteValue) +{ + int integerToReturn; + integerToReturn = (int)byteValue & 0xff; + return integerToReturn; +} + +QString qca_md5crypt(const QCA::SecureArray &password, const QCA::SecureArray &salt) +{ + QCA::SecureArray finalState, magic_string = "$1$"; + + // The md5crypt algorithm uses two separate hashes + QCA::Hash hash1(QStringLiteral("md5")); + QCA::Hash hash2(QStringLiteral("md5")); + + // MD5 Hash #1: pwd, magic string and salt + hash1.update(password); + hash1.update(magic_string); + hash1.update(salt); + + // MD5 Hash #2: password, salt, password + hash2.update(password); + hash2.update(salt); + hash2.update(password); + + finalState = hash2.final(); + + // Two sets of transformations based on the length of the password + for (int i = password.size(); i > 0; i -= 16) { + // Update hash1 from offset value (i > 16 ? 16 : i) + hash1.update(finalState.toByteArray().left(i > 16 ? 16 : i)); + } + + // Clear array bits + finalState.fill(0); + + for (int i = password.size(); i != 0; i = i >> 1) { + if ((i & 1) != 0) { + hash1.update(finalState.toByteArray().left(1)); + } else { + hash1.update(password.toByteArray().left(1)); + } + } + + finalState = hash1.final(); + + // Now build a 1000 entry dictionary... + for (int i = 0; i < 1000; i++) { + hash2.clear(); + + if ((i & 1) != 0) { + hash2.update(password); + } else { + hash2.update(finalState.toByteArray().left(16)); + } + + if ((i % 3) != 0) { + hash2.update(salt); + } + + if ((i % 7) != 0) { + hash2.update(password); + } + + if ((i & 1) != 0) { + hash2.update(finalState.toByteArray().left(16)); + } else { + hash2.update(password); + } + + finalState = hash2.final(); + } + + // Create an output string + // Salt is part of the encoded password ($1$$) + QString encodedString; + + encodedString.append(QString::fromLatin1(magic_string.toByteArray())); + encodedString.append(QString::fromLatin1(salt.toByteArray())); + encodedString.append(QStringLiteral("$")); + + long l; + + l = (byte2unsigned(finalState.toByteArray().at(0)) << 16 | (byte2unsigned(finalState.toByteArray().at(6))) << 8 | + byte2unsigned(finalState.toByteArray().at(12))); + encodedString.append(to64(l, 4)); + + l = (byte2unsigned(finalState.toByteArray().at(1)) << 16 | (byte2unsigned(finalState.toByteArray().at(7))) << 8 | + byte2unsigned(finalState.toByteArray().at(13))); + encodedString.append(to64(l, 4)); + + l = (byte2unsigned(finalState.toByteArray().at(2)) << 16 | (byte2unsigned(finalState.toByteArray().at(8))) << 8 | + byte2unsigned(finalState.toByteArray().at(14))); + encodedString.append(to64(l, 4)); + + l = (byte2unsigned(finalState.toByteArray().at(3)) << 16 | (byte2unsigned(finalState.toByteArray().at(9))) << 8 | + byte2unsigned(finalState.toByteArray().at(15))); + encodedString.append(to64(l, 4)); + + l = (byte2unsigned(finalState.toByteArray().at(4)) << 16 | (byte2unsigned(finalState.toByteArray().at(10))) << 8 | + byte2unsigned(finalState.toByteArray().at(5))); + encodedString.append(to64(l, 4)); + + l = byte2unsigned(finalState.toByteArray().at(11)); + encodedString.append(to64(l, 2)); + + return encodedString; +} + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + QCA::SecureArray password, salt; + + if (argc < 3) { + printf("Usage: %s password salt (salt without $1$)\n", argv[0]); + return 1; + } + + password.append(argv[1]); + + salt.append(argv[2]); + + // must always check that an algorithm is supported before using it + if (!QCA::isSupported("md5")) + printf("MD5 hash not supported!\n"); + else { + QString result = qca_md5crypt(password, salt); + + printf("md5crypt [ %s , %s ] = '%s'\n", password.data(), salt.data(), qPrintable(result)); + + // this is equivalent if you have GNU libc 2.0 + // printf( "GNU md5crypt [ %s , %s ] = '%s'\n", password.data(), salt.data(), crypt( password.data(), ( + // "$1$"+salt ).data() ) ); + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/providertest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/providertest/CMakeLists.txt new file mode 100644 index 0000000000..c7b022c0c9 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/providertest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(providertest_bin_SRCS providertest.cpp) + +add_executable(providertest ${providertest_bin_SRCS}) + +target_link_qca_libraries(providertest) diff --git a/local/recipes/libs/qca/source/examples/providertest/providertest.cpp b/local/recipes/libs/qca/source/examples/providertest/providertest.cpp new file mode 100644 index 0000000000..d4074fa02d --- /dev/null +++ b/local/recipes/libs/qca/source/examples/providertest/providertest.cpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 2004 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include +#include + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // get all the available providers loaded. + // you don't normally need this (because you test using isSupported()) + // but this is a special case. + QCA::scanForPlugins(); + + // this gives us all the plugin providers as a list + const QCA::ProviderList qcaProviders = QCA::providers(); + for (const QCA::Provider *provider : qcaProviders) { + // each provider has a name, which we can display + std::cout << provider->name().toLatin1().data() << ": "; + // ... and also a list of features + QStringList capabilities = provider->features(); + // we turn the string list back into a single string, + // and display it as well + std::cout << capabilities.join(QStringLiteral(", ")).toLatin1().data() << std::endl; + } + + // Note that the default provider isn't included in + // the result of QCA::providers() + std::cout << "default: "; + // However it is still possible to get the features + // supported by the default provider + QStringList capabilities = QCA::defaultFeatures(); + std::cout << capabilities.join(QStringLiteral(", ")).toLatin1().data() << std::endl; + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/publickeyexample/CMakeLists.txt b/local/recipes/libs/qca/source/examples/publickeyexample/CMakeLists.txt new file mode 100644 index 0000000000..ed3074b5d0 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/publickeyexample/CMakeLists.txt @@ -0,0 +1,5 @@ +set(publickeyexample_bin_SRCS publickeyexample.cpp) + +add_executable(publickeyexample ${publickeyexample_bin_SRCS}) + +target_link_qca_libraries(publickeyexample) diff --git a/local/recipes/libs/qca/source/examples/publickeyexample/publickeyexample.cpp b/local/recipes/libs/qca/source/examples/publickeyexample/publickeyexample.cpp new file mode 100644 index 0000000000..32563dfe50 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/publickeyexample/publickeyexample.cpp @@ -0,0 +1,114 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2005 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // We need to ensure that we have certificate handling support + if (!QCA::isSupported("cert")) { + std::cout << "Sorry, no PKI certificate support" << std::endl; + return 1; + } + + // Read in a private key + QCA::PrivateKey privKey; + QCA::ConvertResult convRes; + QCA::SecureArray passPhrase = "start"; + privKey = QCA::PrivateKey::fromPEMFile(QStringLiteral("Userkey.pem"), passPhrase, &convRes); + if (convRes != QCA::ConvertGood) { + std::cout << "Sorry, could not import Private Key" << std::endl; + return 1; + } + + // Read in a matching public key cert + // you could also build this using the fromPEMFile() method + QCA::Certificate pubCert(QStringLiteral("User.pem")); + if (pubCert.isNull()) { + std::cout << "Sorry, could not import public key certificate" << std::endl; + return 1; + } + // We are building the certificate into a SecureMessageKey object, via a + // CertificateChain + QCA::SecureMessageKey secMsgKey; + QCA::CertificateChain chain; + chain += pubCert; + secMsgKey.setX509CertificateChain(chain); + + // build up a SecureMessage object, based on our public key certificate + QCA::CMS cms; + QCA::SecureMessage msg(&cms); + msg.setRecipient(secMsgKey); + + // Some plain text - we use the first command line argument if provided + QByteArray plainText = (argc >= 2) ? argv[1] : "What do ya want for nuthin'"; + + // Now use the SecureMessage object to encrypt the plain text. + msg.startEncrypt(); + msg.update(plainText); + msg.end(); + // I think it is reasonable to wait for 1 second for this + msg.waitForFinished(1000); + + // check to see if it worked + if (!msg.success()) { + std::cout << "Error encrypting: " << msg.errorCode() << std::endl; + return 1; + } + + // get the result + QCA::SecureArray cipherText = msg.read(); + QCA::Base64 enc; + std::cout << plainText.data() << " encrypts to (in base 64): "; + std::cout << qPrintable(enc.arrayToString(cipherText)) << std::endl; + + // Show we can decrypt it with the private key + if (!privKey.canDecrypt()) { + std::cout << "Private key cannot be used to decrypt" << std::endl; + return 1; + } + QCA::SecureArray plainTextResult; + if (0 == privKey.decrypt(cipherText, &plainTextResult, QCA::EME_PKCS1_OAEP)) { + std::cout << "Decryption process failed" << std::endl; + return 1; + } + + std::cout << qPrintable(enc.arrayToString(cipherText)); + std::cout << " (in base 64) decrypts to: "; + std::cout << plainTextResult.data() << std::endl; + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/randomtest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/randomtest/CMakeLists.txt new file mode 100644 index 0000000000..608e47ef2d --- /dev/null +++ b/local/recipes/libs/qca/source/examples/randomtest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(randomtest_bin_SRCS randomtest.cpp) + +add_executable(randomtest ${randomtest_bin_SRCS}) + +target_link_qca_libraries(randomtest) diff --git a/local/recipes/libs/qca/source/examples/randomtest/randomtest.cpp b/local/recipes/libs/qca/source/examples/randomtest/randomtest.cpp new file mode 100644 index 0000000000..6dfa6336ae --- /dev/null +++ b/local/recipes/libs/qca/source/examples/randomtest/randomtest.cpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2004, 2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// QtCrypto has the declarations for all of QCA +#include + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // the Initializer object sets things up, and + // also does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + qDebug() << "This example generates random numbers"; + + int randInt; + // This is the standard way to generate a random integer. + randInt = QCA::Random::randomInt(); + qDebug() << "A random number: " << randInt; + + // If you wanted a random character (octet), you could + // use something like: + unsigned char randChar; + randChar = QCA::Random::randomChar(); + // It might not be printable, so this may not produce output + std::cout << "A random character: " << randChar << std::endl; + + QCA::SecureArray tenBytes(10); + // If you need more random values, you may want to + // get an array, as shown below. + tenBytes = QCA::Random::randomArray(10); + + // To make this viewable, we convert to hexadecimal. + std::cout << "A random 10 byte array (in hex): "; + std::cout << qPrintable(QCA::Hex().arrayToString(tenBytes)) << std::endl; + + // Under some circumstances, you may want to create a + // Random object, rather than a static public member function. + // This isn't normally the easiest way, but it does work + QCA::Random myRandomObject; + randChar = myRandomObject.nextByte(); + tenBytes = myRandomObject.nextBytes(10); + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/rsatest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/rsatest/CMakeLists.txt new file mode 100644 index 0000000000..d617cc4d40 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/rsatest/CMakeLists.txt @@ -0,0 +1,5 @@ +set(rsatest_bin_SRCS rsatest.cpp) + +add_executable(rsatest ${rsatest_bin_SRCS}) + +target_link_qca_libraries(rsatest) diff --git a/local/recipes/libs/qca/source/examples/rsatest/rsatest.cpp b/local/recipes/libs/qca/source/examples/rsatest/rsatest.cpp new file mode 100644 index 0000000000..be166e633e --- /dev/null +++ b/local/recipes/libs/qca/source/examples/rsatest/rsatest.cpp @@ -0,0 +1,151 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2005 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +int main(int argc, char **argv) +{ + // The Initializer object sets things up, and also + // does cleanup when it goes out of scope + QCA::Initializer init; + + QCoreApplication app(argc, argv); + + // we use the first argument if provided, or + // use "hello" if no arguments + QCA::SecureArray arg = (argc >= 2) ? argv[1] : "hello"; + + // We demonstrate PEM usage here, so we need to test for + // supportedIOTypes, not just supportedTypes + if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) + std::cout << "RSA not supported!\n"; + else { + // When creating a public / private key pair, you make the + // private key, and then extract the public key component from it + // Using RSA is very common, however DSA can provide equivalent + // signature/verification. This example applies to DSA to the + // extent that the operations work on that key type. + + // QCA provides KeyGenerator as a convenient source of new keys, + // however you could also import an existing key instead. + QCA::PrivateKey seckey = QCA::KeyGenerator().createRSA(1024); + if (seckey.isNull()) { + std::cout << "Failed to make private RSA key" << std::endl; + return 1; + } + + QCA::PublicKey pubkey = seckey.toPublicKey(); + + // check if the key can encrypt + if (!pubkey.canEncrypt()) { + std::cout << "Error: this kind of key cannot encrypt" << std::endl; + return 1; + } + + // encrypt some data - note that only the public key is required + // you must also choose the algorithm to be used + QCA::SecureArray result = pubkey.encrypt(arg, QCA::EME_PKCS1_OAEP); + if (result.isEmpty()) { + std::cout << "Error encrypting" << std::endl; + return 1; + } + + // output the encrypted data + QString rstr = QCA::arrayToHex(result.toByteArray()); + std::cout << "\"" << arg.data() << "\" encrypted with RSA is \""; + std::cout << qPrintable(rstr) << "\"" << std::endl; + + // save the private key - in a real example, make sure this goes + // somewhere secure and has a good pass phrase + // You can use the same technique with the public key too. + QCA::SecureArray passPhrase = "pass phrase"; + seckey.toPEMFile(QStringLiteral("keyprivate.pem"), passPhrase); + + // Read that key back in, checking if the read succeeded + QCA::ConvertResult conversionResult; + QCA::PrivateKey privateKey = + QCA::PrivateKey::fromPEMFile(QStringLiteral("keyprivate.pem"), passPhrase, &conversionResult); + if (!(QCA::ConvertGood == conversionResult)) { + std::cout << "Private key read failed" << std::endl; + } + + // now decrypt that encrypted data using the private key that + // we read in. The algorithm is the same. + QCA::SecureArray decrypt; + if (0 == privateKey.decrypt(result, &decrypt, QCA::EME_PKCS1_OAEP)) { + std::cout << "Error decrypting.\n"; + return 1; + } + + // output the resulting decrypted string + std::cout << "\"" << qPrintable(rstr) << "\" decrypted with RSA is \""; + std::cout << decrypt.data() << "\"" << std::endl; + + // Some private keys can also be used for producing signatures + if (!privateKey.canSign()) { + std::cout << "Error: this kind of key cannot sign" << std::endl; + return 1; + } + privateKey.startSign(QCA::EMSA3_MD5); + privateKey.update(arg); // just reuse the same message + QByteArray argSig = privateKey.signature(); + + // instead of using the startSign(), update(), signature() calls, + // you may be better doing the whole thing in one go, using the + // signMessage call. Of course you need the whole message in one + // hit, which may or may not be a problem + + // output the resulting signature + rstr = QCA::arrayToHex(argSig); + std::cout << "Signature for \"" << arg.data() << "\" using RSA, is "; + std::cout << "\"" << qPrintable(rstr) << "\"" << std::endl; + + // to check a signature, we must check that the key is + // appropriate + if (pubkey.canVerify()) { + pubkey.startVerify(QCA::EMSA3_MD5); + pubkey.update(arg); + if (pubkey.validSignature(argSig)) { + std::cout << "Signature is valid" << std::endl; + } else { + std::cout << "Bad signature" << std::endl; + } + } + + // We can also do the verification in a single step if we + // have all the message + if (pubkey.canVerify() && pubkey.verifyMessage(arg, argSig, QCA::EMSA3_MD5)) { + std::cout << "Signature is valid" << std::endl; + } else { + std::cout << "Signature could not be verified" << std::endl; + } + } + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/saslclient/CMakeLists.txt b/local/recipes/libs/qca/source/examples/saslclient/CMakeLists.txt new file mode 100644 index 0000000000..d03b59094b --- /dev/null +++ b/local/recipes/libs/qca/source/examples/saslclient/CMakeLists.txt @@ -0,0 +1,6 @@ +set(saslclient_bin_SRCS saslclient.cpp) + +add_executable(saslclient ${saslclient_bin_SRCS}) + +target_link_qca_libraries(saslclient) +target_link_libraries(saslclient Qt${QT_MAJOR_VERSION}::Network) diff --git a/local/recipes/libs/qca/source/examples/saslclient/saslclient.cpp b/local/recipes/libs/qca/source/examples/saslclient/saslclient.cpp new file mode 100644 index 0000000000..fb2c402775 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/saslclient/saslclient.cpp @@ -0,0 +1,561 @@ +/* + Copyright (C) 2003-2008 Justin Karneges + Copyright (C) 2006 Michail Pishchagin + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +// QtCrypto has the declarations for all of QCA +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +static QString prompt(const QString &s) +{ + printf("* %s ", qPrintable(s)); + fflush(stdout); + char line[256]; + fgets(line, 255, stdin); + QString result = QString::fromLatin1(line); + if (result[result.length() - 1] == QLatin1Char('\n')) + result.truncate(result.length() - 1); + return result; +} + +static QString socketErrorToString(QAbstractSocket::SocketError x) +{ + QString s; + switch (x) { + case QAbstractSocket::ConnectionRefusedError: + s = QStringLiteral("connection refused or timed out"); + break; + case QAbstractSocket::RemoteHostClosedError: + s = QStringLiteral("remote host closed the connection"); + break; + case QAbstractSocket::HostNotFoundError: + s = QStringLiteral("host not found"); + break; + case QAbstractSocket::SocketAccessError: + s = QStringLiteral("access error"); + break; + case QAbstractSocket::SocketResourceError: + s = QStringLiteral("too many sockets"); + break; + case QAbstractSocket::SocketTimeoutError: + s = QStringLiteral("operation timed out"); + break; + case QAbstractSocket::DatagramTooLargeError: + s = QStringLiteral("datagram was larger than system limit"); + break; + case QAbstractSocket::NetworkError: + s = QStringLiteral("network error"); + break; + case QAbstractSocket::AddressInUseError: + s = QStringLiteral("address is already in use"); + break; + case QAbstractSocket::SocketAddressNotAvailableError: + s = QStringLiteral("address does not belong to the host"); + break; + case QAbstractSocket::UnsupportedSocketOperationError: + s = QStringLiteral("operation is not supported by the local operating system"); + break; + default: + s = QStringLiteral("unknown socket error"); + break; + } + return s; +} + +static QString saslAuthConditionToString(QCA::SASL::AuthCondition x) +{ + QString s; + switch (x) { + case QCA::SASL::NoMechanism: + s = QStringLiteral("no appropriate mechanism could be negotiated"); + break; + case QCA::SASL::BadProtocol: + s = QStringLiteral("bad SASL protocol"); + break; + case QCA::SASL::BadServer: + s = QStringLiteral("server failed mutual authentication"); + break; + // AuthFail or unknown (including those defined for server only) + default: + s = QStringLiteral("generic authentication failure"); + break; + }; + return s; +} + +class ClientTest : public QObject +{ + Q_OBJECT + +private: + QString host, proto, authzid, realm, user, pass; + int port; + bool no_authzid, no_realm; + int mode; // 0 = receive mechanism list, 1 = sasl negotiation, 2 = app + QTcpSocket *sock; + QCA::SASL *sasl; + QByteArray inbuf; + bool sock_done; + int waitCycles; + +public: + ClientTest(const QString &_host, + int _port, + const QString &_proto, + const QString &_authzid, + const QString &_realm, + const QString &_user, + const QString &_pass, + bool _no_authzid, + bool _no_realm) + : host(_host) + , proto(_proto) + , authzid(_authzid) + , realm(_realm) + , user(_user) + , pass(_pass) + , port(_port) + , no_authzid(_no_authzid) + , no_realm(_no_realm) + , sock_done(false) + , waitCycles(0) + { + sock = new QTcpSocket(this); + connect(sock, &QTcpSocket::connected, this, &ClientTest::sock_connected); + connect(sock, &QTcpSocket::readyRead, this, &ClientTest::sock_readyRead); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sock, &QTcpSocket::errorOccurred, this, &ClientTest::sock_error); +#else + connect(sock, QOverload::of(&QTcpSocket::error), this, &ClientTest::sock_error); +#endif + + sasl = new QCA::SASL(this); + connect(sasl, &QCA::SASL::clientStarted, this, &ClientTest::sasl_clientFirstStep); + connect(sasl, &QCA::SASL::nextStep, this, &ClientTest::sasl_nextStep); + connect(sasl, &QCA::SASL::needParams, this, &ClientTest::sasl_needParams); + connect(sasl, &QCA::SASL::authenticated, this, &ClientTest::sasl_authenticated); + connect(sasl, &QCA::SASL::readyRead, this, &ClientTest::sasl_readyRead); + connect(sasl, &QCA::SASL::readyReadOutgoing, this, &ClientTest::sasl_readyReadOutgoing); + connect(sasl, &QCA::SASL::error, this, &ClientTest::sasl_error); + } + +public Q_SLOTS: + void start() + { + mode = 0; // mech list mode + + int flags = 0; + flags |= QCA::SASL::AllowPlain; + flags |= QCA::SASL::AllowAnonymous; + sasl->setConstraints((QCA::SASL::AuthFlags)flags, 0, 256); + + if (!user.isEmpty()) + sasl->setUsername(user); + if (!authzid.isEmpty()) + sasl->setAuthzid(authzid); + if (!pass.isEmpty()) + sasl->setPassword(pass.toUtf8()); + if (!realm.isEmpty()) + sasl->setRealm(realm); + + printf("Connecting to %s:%d, for protocol %s\n", qPrintable(host), port, qPrintable(proto)); + sock->connectToHost(host, port); + } + +Q_SIGNALS: + void quit(); + +private Q_SLOTS: + void sock_connected() + { + printf("Connected to server. Awaiting mechanism list...\n"); + } + + void sock_error(QAbstractSocket::SocketError x) + { + if (x == QAbstractSocket::RemoteHostClosedError) { + if (mode == 2) // app mode, where disconnect means completion + { + sock_done = true; + tryFinished(); + return; + } else // any other mode, where disconnect is an error + { + printf("Error: server closed connection unexpectedly.\n"); + emit quit(); + return; + } + } + + printf("Error: socket: %s\n", qPrintable(socketErrorToString(x))); + emit quit(); + } + + void sock_readyRead() + { + if (mode == 2) // app mode + { + QByteArray a = sock->readAll(); + printf("Read %d bytes\n", int(a.size())); + + // there is a possible flaw in the qca 2.0 api, in + // that if sasl data is received from the peer + // followed by a disconnect from the peer, there is + // no clear approach to salvaging the bytes. tls is + // not affected because tls has the concept of + // closing a session. with sasl, there is no + // closing, and since the qca api is asynchronous, + // we could potentially wait forever for decoded + // data, if the last write was a partial packet. + // + // for now, we can perform a simple workaround of + // waiting at least three event loop cycles for + // decoded data before giving up and assuming the + // last write was partial. the fact is, all current + // qca sasl providers respond within this time + // frame, so this fix should work fine for now. in + // qca 2.1, we should revise the api to handle this + // situation better. + // + // further note: i guess this only affects application + // protocols that have no close message of their + // own, and rely on the tcp-level close. examples + // are http, and of course this qcatest protocol. + if (waitCycles == 0) { + waitCycles = 3; + QMetaObject::invokeMethod(this, "waitWriteIncoming", Qt::QueuedConnection); + } + + sasl->writeIncoming(a); + } else // mech list or sasl negotiation mode + { + if (sock->canReadLine()) { + QString line = QString::fromLatin1(sock->readLine()); + line.truncate(line.length() - 1); // chop the newline + handleLine(line); + } + } + } + + void sasl_clientFirstStep(bool clientInit, const QByteArray &clientInitData) + { + printf("Choosing mech: %s\n", qPrintable(sasl->mechanism())); + QString line = sasl->mechanism(); + if (clientInit) { + line += QLatin1Char(' '); + line += arrayToString(clientInitData); + } + sendLine(line); + } + + void sasl_nextStep(const QByteArray &stepData) + { + QString line = QStringLiteral("C"); + if (!stepData.isEmpty()) { + line += QLatin1Char(','); + line += arrayToString(stepData); + } + sendLine(line); + } + + void sasl_needParams(const QCA::SASL::Params ¶ms) + { + if (params.needUsername()) { + user = prompt(QStringLiteral("Username:")); + sasl->setUsername(user); + } + + if (params.canSendAuthzid() && !no_authzid) { + authzid = prompt(QStringLiteral("Authorize As (enter to skip):")); + if (!authzid.isEmpty()) + sasl->setAuthzid(authzid); + } + + if (params.needPassword()) { + QCA::ConsolePrompt prompt; + prompt.getHidden(QStringLiteral("* Password")); + prompt.waitForFinished(); + QCA::SecureArray pass = prompt.result(); + sasl->setPassword(pass); + } + + if (params.canSendRealm() && !no_realm) { + QStringList realms = sasl->realmList(); + printf("Available realms:\n"); + if (realms.isEmpty()) + printf(" (none specified)\n"); + foreach (const QString &s, realms) + printf(" %s\n", qPrintable(s)); + realm = prompt(QStringLiteral("Realm (enter to skip):")); + if (!realm.isEmpty()) + sasl->setRealm(realm); + } + + sasl->continueAfterParams(); + } + + void sasl_authenticated() + { + printf("SASL success!\n"); + printf("SSF: %d\n", sasl->ssf()); + } + + void sasl_readyRead() + { + QByteArray a = sasl->read(); + inbuf += a; + processInbuf(); + } + + void sasl_readyReadOutgoing() + { + QByteArray a = sasl->readOutgoing(); + sock->write(a); + } + + void sasl_error() + { + int e = sasl->errorCode(); + if (e == QCA::SASL::ErrorInit) + printf("Error: sasl: initialization failed.\n"); + else if (e == QCA::SASL::ErrorHandshake) + printf("Error: sasl: %s.\n", qPrintable(saslAuthConditionToString(sasl->authCondition()))); + else if (e == QCA::SASL::ErrorCrypt) + printf("Error: sasl: broken security layer.\n"); + else + printf("Error: sasl: unknown error.\n"); + + emit quit(); + } + + void waitWriteIncoming() + { + --waitCycles; + if (waitCycles > 0) { + QMetaObject::invokeMethod(this, "waitWriteIncoming", Qt::QueuedConnection); + return; + } + + tryFinished(); + } + +private: + void tryFinished() + { + if (sock_done && waitCycles == 0) { + printf("Finished, server closed connection.\n"); + + // if we give up on waiting for a response to + // writeIncoming, then it might come late. in + // theory this shouldn't happen if we wait enough + // cycles, but if one were to arrive then it could + // occur between the request to quit the app and + // the actual quit of the app. to assist with + // debugging, then, we'll explicitly stop listening + // for signals here. otherwise the response may + // still be received and displayed, giving a false + // sense of correctness. + sasl->disconnect(this); + + emit quit(); + } + } + + QString arrayToString(const QByteArray &ba) + { + return QCA::Base64().arrayToString(ba); + } + + QByteArray stringToArray(const QString &s) + { + return QCA::Base64().stringToArray(s).toByteArray(); + } + + void sendLine(const QString &line) + { + printf("Writing: {%s}\n", qPrintable(line)); + QString s = line + QLatin1Char('\n'); + QByteArray a = s.toUtf8(); + if (mode == 2) // app mode + sasl->write(a); // write to sasl + else // mech list or sasl negotiation + sock->write(a); // write to socket + } + + void processInbuf() + { + // collect completed lines from inbuf + QStringList list; + int at; + while ((at = inbuf.indexOf('\n')) != -1) { + list += QString::fromUtf8(inbuf.mid(0, at)); + inbuf = inbuf.mid(at + 1); + } + + // process the lines + foreach (const QString &line, list) + handleLine(line); + } + + void handleLine(const QString &line) + { + printf("Reading: [%s]\n", qPrintable(line)); + if (mode == 0) { + // first line is the method list + const QStringList mechlist = line.split(QLatin1Char(' ')); + mode = 1; // switch to sasl negotiation mode + sasl->startClient(proto, host, mechlist); + } else if (mode == 1) { + QString type, rest; + int n = line.indexOf(QLatin1Char(',')); + if (n != -1) { + type = line.mid(0, n); + rest = line.mid(n + 1); + } else + type = line; + + if (type == QLatin1String("C")) { + sasl->putStep(stringToArray(rest)); + } else if (type == QLatin1String("E")) { + if (!rest.isEmpty()) + printf("Error: server says: %s.\n", qPrintable(rest)); + else + printf("Error: server error, unspecified.\n"); + emit quit(); + return; + } else if (type == QLatin1String("A")) { + printf("Authentication success.\n"); + mode = 2; // switch to app mode + + // at this point, the server may send us text + // lines for us to display and then close. + + sock_readyRead(); // any extra data? + return; + } else { + printf("Error: Bad format from peer, closing.\n"); + emit quit(); + return; + } + } + } +}; + +void usage() +{ + printf("usage: saslclient (options) host(:port) (user) (pass)\n"); + printf("options: --proto=x, --authzid=x, --realm=x\n"); +} + +int main(int argc, char **argv) +{ + QCA::Initializer init; + QCoreApplication qapp(argc, argv); + + QStringList args = qapp.arguments(); + args.removeFirst(); + + // options + QString proto = QStringLiteral("qcatest"); // default protocol + QString authzid, realm; + bool no_authzid = false; + bool no_realm = false; + for (int n = 0; n < args.count(); ++n) { + if (!args[n].startsWith(QLatin1String("--"))) + continue; + + QString opt = args[n].mid(2); + QString var, val; + int at = opt.indexOf(QLatin1Char('=')); + if (at != -1) { + var = opt.mid(0, at); + val = opt.mid(at + 1); + } else + var = opt; + + if (var == QLatin1String("proto")) { + proto = val; + } else if (var == QLatin1String("authzid")) { + // specifying empty authzid means force unspecified + if (val.isEmpty()) + no_authzid = true; + else + authzid = val; + } else if (var == QLatin1String("realm")) { + // specifying empty realm means force unspecified + if (val.isEmpty()) + no_realm = true; + else + realm = val; + } + + args.removeAt(n); + --n; // adjust position + } + + if (args.count() < 1) { + usage(); + return 0; + } + + QString host, user, pass; + int port = 8001; // default port + + QString hostinput = args[0]; + if (args.count() >= 2) + user = args[1]; + if (args.count() >= 3) + pass = args[2]; + + int at = hostinput.indexOf(QLatin1Char(':')); + if (at != -1) { + host = hostinput.mid(0, at); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + port = QStringView(hostinput).mid(at + 1).toInt(); +#else + port = hostinput.midRef(at + 1).toInt(); +#endif + } else + host = hostinput; + + if (!QCA::isSupported("sasl")) { + printf("Error: SASL support not found.\n"); + return 1; + } + + ClientTest client(host, port, proto, authzid, realm, user, pass, no_authzid, no_realm); + QObject::connect(&client, &ClientTest::quit, &qapp, &QCoreApplication::quit); + QTimer::singleShot(0, &client, &ClientTest::start); + qapp.exec(); + + return 0; +} + +#include "saslclient.moc" diff --git a/local/recipes/libs/qca/source/examples/saslserver/CMakeLists.txt b/local/recipes/libs/qca/source/examples/saslserver/CMakeLists.txt new file mode 100644 index 0000000000..718e975a2e --- /dev/null +++ b/local/recipes/libs/qca/source/examples/saslserver/CMakeLists.txt @@ -0,0 +1,6 @@ +set(saslserver_bin_SRCS saslserver.cpp) + +add_executable(saslserver ${saslserver_bin_SRCS}) + +target_link_qca_libraries(saslserver) +target_link_libraries(saslserver Qt${QT_MAJOR_VERSION}::Network) diff --git a/local/recipes/libs/qca/source/examples/saslserver/saslserver.cpp b/local/recipes/libs/qca/source/examples/saslserver/saslserver.cpp new file mode 100644 index 0000000000..2e73497407 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/saslserver/saslserver.cpp @@ -0,0 +1,524 @@ +/* + Copyright (C) 2003-2008 Justin Karneges + Copyright (C) 2006 Michail Pishchagin + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +// QtCrypto has the declarations for all of QCA +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +static QString socketErrorToString(QAbstractSocket::SocketError x) +{ + QString s; + switch (x) { + case QAbstractSocket::ConnectionRefusedError: + s = QStringLiteral("connection refused or timed out"); + break; + case QAbstractSocket::RemoteHostClosedError: + s = QStringLiteral("remote host closed the connection"); + break; + case QAbstractSocket::HostNotFoundError: + s = QStringLiteral("host not found"); + break; + case QAbstractSocket::SocketAccessError: + s = QStringLiteral("access error"); + break; + case QAbstractSocket::SocketResourceError: + s = QStringLiteral("too many sockets"); + break; + case QAbstractSocket::SocketTimeoutError: + s = QStringLiteral("operation timed out"); + break; + case QAbstractSocket::DatagramTooLargeError: + s = QStringLiteral("datagram was larger than system limit"); + break; + case QAbstractSocket::NetworkError: + s = QStringLiteral("network error"); + break; + case QAbstractSocket::AddressInUseError: + s = QStringLiteral("address is already in use"); + break; + case QAbstractSocket::SocketAddressNotAvailableError: + s = QStringLiteral("address does not belong to the host"); + break; + case QAbstractSocket::UnsupportedSocketOperationError: + s = QStringLiteral("operation is not supported by the local operating system"); + break; + default: + s = QStringLiteral("unknown socket error"); + break; + } + return s; +} + +static QString saslAuthConditionToString(QCA::SASL::AuthCondition x) +{ + QString s; + switch (x) { + case QCA::SASL::NoMechanism: + s = QStringLiteral("no appropriate mechanism could be negotiated"); + break; + case QCA::SASL::BadProtocol: + s = QStringLiteral("bad SASL protocol"); + break; + case QCA::SASL::BadAuth: + s = QStringLiteral("authentication failed"); + break; + case QCA::SASL::NoAuthzid: + s = QStringLiteral("authorization failed"); + break; + case QCA::SASL::TooWeak: + s = QStringLiteral("mechanism too weak for this user"); + break; + case QCA::SASL::NeedEncrypt: + s = QStringLiteral("encryption is needed to use this mechanism"); + break; + case QCA::SASL::Expired: + s = QStringLiteral("passphrase expired"); + break; + case QCA::SASL::Disabled: + s = QStringLiteral("account is disabled"); + break; + case QCA::SASL::NoUser: + s = QStringLiteral("user not found"); + break; + case QCA::SASL::RemoteUnavailable: + s = QStringLiteral("needed remote service is unavailable"); + break; + // AuthFail or unknown (including those defined for client only) + default: + s = QStringLiteral("generic authentication failure"); + break; + }; + return s; +} + +// --- ServerTest declaration + +class ServerTest : public QObject +{ + Q_OBJECT + +private: + QString host, proto, realm, str; + int port; + QTcpServer *tcpServer; + QList ids; + +public: + ServerTest(const QString &_host, int _port, const QString &_proto, const QString &_realm, const QString &_str); + + int reserveId(); + void releaseId(int id); + +public Q_SLOTS: + void start(); + +Q_SIGNALS: + void quit(); + +private Q_SLOTS: + void server_newConnection(); +}; + +// --- ServerTestHandler + +class ServerTestHandler : public QObject +{ + Q_OBJECT + +private: + ServerTest *serverTest; + QTcpSocket *sock; + QCA::SASL *sasl; + int id; + QString host, proto, realm, str; + int mode; // 0 = receive mechanism list, 1 = sasl negotiation, 2 = app + int toWrite; + +public: + ServerTestHandler(ServerTest *_serverTest, + QTcpSocket *_sock, + const QString &_host, + const QString &_proto, + const QString &_realm, + const QString &_str) + : serverTest(_serverTest) + , sock(_sock) + , host(_host) + , proto(_proto) + , realm(_realm) + , str(_str) + { + id = serverTest->reserveId(); + + sock->setParent(this); + connect(sock, &QTcpSocket::disconnected, this, &ServerTestHandler::sock_disconnected); + connect(sock, &QTcpSocket::readyRead, this, &ServerTestHandler::sock_readyRead); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sock, &QTcpSocket::errorOccurred, this, &ServerTestHandler::sock_error); +#else + connect(sock, + QOverload::of(&QTcpSocket::error), + this, + &ServerTestHandler::sock_error); +#endif + connect(sock, &QTcpSocket::bytesWritten, this, &ServerTestHandler::sock_bytesWritten); + + sasl = new QCA::SASL(this); + connect(sasl, &QCA::SASL::authCheck, this, &ServerTestHandler::sasl_authCheck); + connect(sasl, &QCA::SASL::nextStep, this, &ServerTestHandler::sasl_nextStep); + connect(sasl, &QCA::SASL::authenticated, this, &ServerTestHandler::sasl_authenticated); + connect(sasl, &QCA::SASL::readyRead, this, &ServerTestHandler::sasl_readyRead); + connect(sasl, &QCA::SASL::readyReadOutgoing, this, &ServerTestHandler::sasl_readyReadOutgoing); + connect(sasl, &QCA::SASL::error, this, &ServerTestHandler::sasl_error); + connect(sasl, &QCA::SASL::serverStarted, this, &ServerTestHandler::sasl_serverStarted); + + mode = 0; // mech list mode + toWrite = 0; + + int flags = 0; + flags |= QCA::SASL::AllowPlain; + flags |= QCA::SASL::AllowAnonymous; + sasl->setConstraints((QCA::SASL::AuthFlags)flags, 0, 256); + + printf("%d: Connection received! Starting SASL handshake...\n", id); + sasl->startServer(proto, host, realm); + } + + ~ServerTestHandler() override + { + serverTest->releaseId(id); + } + +private Q_SLOTS: + void sasl_serverStarted() + { + sendLine(sasl->mechanismList().join(QStringLiteral(" "))); + } + + void sock_disconnected() + { + printf("%d: Connection closed.\n", id); + discard(); + } + + void sock_error(QAbstractSocket::SocketError x) + { + if (x == QAbstractSocket::RemoteHostClosedError) { + printf("%d: Error: client closed connection unexpectedly.\n", id); + discard(); + return; + } + + printf("%d: Error: socket: %s\n", id, qPrintable(socketErrorToString(x))); + discard(); + } + + void sock_readyRead() + { + if (sock->canReadLine()) { + QString line = QString::fromLatin1(sock->readLine()); + line.truncate(line.length() - 1); // chop the newline + handleLine(line); + } + } + + void sock_bytesWritten(qint64 x) + { + if (mode == 2) // app mode + { + toWrite -= sasl->convertBytesWritten(x); + if (toWrite == 0) { + printf("%d: Sent, closing.\n", id); + sock->close(); + } + } + } + + void sasl_nextStep(const QByteArray &stepData) + { + QString line = QStringLiteral("C"); + if (!stepData.isEmpty()) { + line += QLatin1Char(','); + line += arrayToString(stepData); + } + sendLine(line); + } + + void sasl_authCheck(const QString &user, const QString &authzid) + { + printf("%d: AuthCheck: User: [%s], Authzid: [%s]\n", id, qPrintable(user), qPrintable(authzid)); + + // user - who has logged in, confirmed by sasl + // authzid - the identity the user wishes to act as, which + // could be another user or just any arbitrary string (in + // XMPP, this field holds a Jabber ID, for example). this + // field is not necessarily confirmed by sasl, and the + // decision about whether the user can act as the authzid + // must be made by the app. + + // for this simple example program, we allow anyone to use + // the service, and simply continue onward with the + // negotiation. + sasl->continueAfterAuthCheck(); + } + + void sasl_authenticated() + { + sendLine(QStringLiteral("A")); + printf("%d: Authentication success.\n", id); + mode = 2; // switch to app mode + printf("%d: SSF: %d\n", id, sasl->ssf()); + sendLine(str); + } + + void sasl_readyRead() + { + QByteArray a = sasl->read(); + printf("%d: Warning, client sent %d bytes unexpectedly.\n", id, int(a.size())); + } + + void sasl_readyReadOutgoing() + { + sock->write(sasl->readOutgoing()); + } + + void sasl_error() + { + int e = sasl->errorCode(); + if (e == QCA::SASL::ErrorInit) { + printf("%d: Error: sasl: initialization failed.\n", id); + } else if (e == QCA::SASL::ErrorHandshake) { + QString errstr = saslAuthConditionToString(sasl->authCondition()); + sendLine(QStringLiteral("E,") + errstr); + printf("%d: Error: sasl: %s.\n", id, qPrintable(errstr)); + } else if (e == QCA::SASL::ErrorCrypt) { + printf("%d: Error: sasl: broken security layer.\n", id); + } else { + printf("%d: Error: sasl: unknown error.\n", id); + } + + sock->close(); + } + +private: + void discard() + { + deleteLater(); + } + + void handleLine(const QString &line) + { + printf("%d: Reading: [%s]\n", id, qPrintable(line)); + if (mode == 0) { + int n = line.indexOf(QLatin1Char(' ')); + if (n != -1) { + QString mech = line.mid(0, n); + QString rest = QString::fromLatin1(line.mid(n + 1).toUtf8()); + sasl->putServerFirstStep(mech, stringToArray(rest)); + } else + sasl->putServerFirstStep(line); + ++mode; + } else if (mode == 1) { + QString type, rest; + int n = line.indexOf(QLatin1Char(',')); + if (n != -1) { + type = line.mid(0, n); + rest = line.mid(n + 1); + } else { + type = line; + rest = QLatin1String(""); + } + + if (type == QLatin1String("C")) { + sasl->putStep(stringToArray(rest)); + } else { + printf("%d: Bad format from peer, closing.\n", id); + sock->close(); + return; + } + } + } + + QString arrayToString(const QByteArray &ba) + { + QCA::Base64 encoder; + return encoder.arrayToString(ba); + } + + QByteArray stringToArray(const QString &s) + { + QCA::Base64 decoder(QCA::Decode); + return decoder.stringToArray(s).toByteArray(); + } + + void sendLine(const QString &line) + { + printf("%d: Writing: {%s}\n", id, qPrintable(line)); + QString s = line + QLatin1Char('\n'); + QByteArray a = s.toUtf8(); + if (mode == 2) // app mode + { + toWrite += a.size(); + sasl->write(a); // write to sasl + } else // mech list or sasl negotiation + sock->write(a); // write to socket + } +}; + +// --- ServerTest implementation + +ServerTest::ServerTest(const QString &_host, + int _port, + const QString &_proto, + const QString &_realm, + const QString &_str) + : host(_host) + , proto(_proto) + , realm(_realm) + , str(_str) + , port(_port) +{ + tcpServer = new QTcpServer(this); + connect(tcpServer, &QTcpServer::newConnection, this, &ServerTest::server_newConnection); +} + +int ServerTest::reserveId() +{ + int n = 0; + while (ids.contains(n)) + ++n; + ids += n; + return n; +} + +void ServerTest::releaseId(int id) +{ + ids.removeAll(id); +} + +void ServerTest::start() +{ + if (!tcpServer->listen(QHostAddress::Any, port)) { + printf("Error: unable to bind to port %d.\n", port); + emit quit(); + return; + } + + printf("Serving on %s:%d, for protocol %s ...\n", qPrintable(host), port, qPrintable(proto)); +} + +void ServerTest::server_newConnection() +{ + QTcpSocket *sock = tcpServer->nextPendingConnection(); + new ServerTestHandler(this, sock, host, proto, realm, str); +} + +// --- + +void usage() +{ + printf("usage: saslserver host (message)\n"); + printf("options: --proto=x, --realm=x\n"); +} + +int main(int argc, char **argv) +{ + QCA::Initializer init; + QCoreApplication qapp(argc, argv); + + QCA::setAppName(QStringLiteral("saslserver")); + + QStringList args = qapp.arguments(); + args.removeFirst(); + + // options + QString proto = QStringLiteral("qcatest"); // default protocol + QString realm; + for (int n = 0; n < args.count(); ++n) { + if (!args[n].startsWith(QLatin1String("--"))) + continue; + + QString opt = args[n].mid(2); + QString var, val; + int at = opt.indexOf(QLatin1Char('=')); + if (at != -1) { + var = opt.mid(0, at); + val = opt.mid(at + 1); + } else + var = opt; + + if (var == QLatin1String("proto")) + proto = val; + else if (var == QLatin1String("realm")) + realm = val; + + args.removeAt(n); + --n; // adjust position + } + + if (args.count() < 1) { + usage(); + return 0; + } + + QString host; + int port = 8001; // default port + + QString hostinput = args[0]; + QString str = QStringLiteral("Hello, World"); + if (args.count() >= 2) + str = args[1]; + + int at = hostinput.indexOf(QLatin1Char(':')); + if (at != -1) { + host = hostinput.mid(0, at); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + port = QStringView(hostinput).mid(at + 1).toInt(); +#else + port = hostinput.midRef(at + 1).toInt(); +#endif + } else + host = hostinput; + + if (!QCA::isSupported("sasl")) { + printf("Error: SASL support not found.\n"); + return 1; + } + + ServerTest server(host, port, proto, realm, str); + QObject::connect(&server, &ServerTest::quit, &qapp, &QCoreApplication::quit); + QTimer::singleShot(0, &server, &ServerTest::start); + qapp.exec(); + + return 0; +} + +#include "saslserver.moc" diff --git a/local/recipes/libs/qca/source/examples/sslservtest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/sslservtest/CMakeLists.txt new file mode 100644 index 0000000000..7bf01d0b5a --- /dev/null +++ b/local/recipes/libs/qca/source/examples/sslservtest/CMakeLists.txt @@ -0,0 +1,6 @@ +set(sslservtest_bin_SRCS sslservtest.cpp) + +add_executable(sslservtest ${sslservtest_bin_SRCS}) + +target_link_qca_libraries(sslservtest) +target_link_libraries(sslservtest Qt${QT_MAJOR_VERSION}::Network) diff --git a/local/recipes/libs/qca/source/examples/sslservtest/sslservtest.cpp b/local/recipes/libs/qca/source/examples/sslservtest/sslservtest.cpp new file mode 100644 index 0000000000..bfbd8c190f --- /dev/null +++ b/local/recipes/libs/qca/source/examples/sslservtest/sslservtest.cpp @@ -0,0 +1,282 @@ +/* + Copyright (C) 2003 Justin Karneges + Copyright (C) 2006 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +char pemdata_cert[] = + "-----BEGIN CERTIFICATE-----\n" + "MIICeTCCAeKgAwIBAgIRAKKKnOj6Aarmwf0phApitVAwDQYJKoZIhvcNAQEFBQAw\n" + "ODELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0V4YW1wbGUgT3JnMRMwEQYDVQQDEwpF\n" + "eGFtcGxlIENBMB4XDTA2MDMxNTA3MDU1MloXDTA3MDMxNTA3MDU1MlowOjEVMBMG\n" + "A1UEAxMMRXhhbXBsZSBVc2VyMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBs\n" + "ZSBPcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPkKn0FfHMvRZv+3uFcw\n" + "VrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9sEAY\n" + "YNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6YjR2\n" + "NEvIKt1P4mHzYXLmwoF24C1bAgMBAAGjgYAwfjAdBgNVHQ4EFgQUmQIdzyDaPYWF\n" + "fPJ8PPOOm1eSsucwHwYDVR0jBBgwFoAUkCglAizTO7iqwLeaO6r/8kJuqhMwDAYD\n" + "VR0TAQH/BAIwADAeBgNVHREEFzAVgRNleGFtcGxlQGV4YW1wbGUuY29tMA4GA1Ud\n" + "DwEB/wQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQAuhbiUgy2a++EUccaonID7eTJZ\n" + "F3D5qXMqUpQxlYxU8du+9AxDD7nFxTMkQC2pzfmEc1znRNmJ1ZeLRL72VYsVndcT\n" + "psyM8ABkvPp1d2jWIyccVjGpt+/RN5IPKm/YIbtIZcywvWuXrOp1lanVmppLfPnO\n" + "6yneBkC9iqjOv/+Q+A==\n" + "-----END CERTIFICATE-----\n"; + +char pemdata_privkey[] = + "-----BEGIN PRIVATE KEY-----\n" + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPkKn0FfHMvRZv+3\n" + "uFcwVrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9\n" + "sEAYYNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6\n" + "YjR2NEvIKt1P4mHzYXLmwoF24C1bAgMBAAECgYEAyIjJHDaeVXDU42zovyxpZE4n\n" + "PcOEryY+gdFJE8DFgUD4f1huFsj4iCuNg+PaG42p+hf9IARNvSho/RcEaVg4AJrV\n" + "jRP8r7fSqcIGr6lGuvDFFv3SU5ddy84g5oqLYGKvuPSHMGfVsZSxAwOrzD4bH19L\n" + "SNqtNcpdBsBd7ZiEE4ECQQD/oJGui9D5Dx3QVcS+QV4F8wuyN9jYIANmX/17o0fl\n" + "BL0bwRU4RICwadrcybi5N0JQLIYSUm2HGqNvAJbtnuQxAkEA+WeYLLYPeawcy+WU\n" + "kGcOR7BUjHiG71+6cvU4XIDW2bezA04fqWXkZRFAwHTMpQb785/XalFftgS21kql\n" + "8yLDSwJAHkeT2hwftdDPlEUEmBDAJW5DvWmWGwu3u2G1cfbGZl9oUyhM7ixXHg57\n" + "6VlPs0jTZxHPE86FwNIr99MXDbCbkQJBAMDFOJK+ecGirXNP1P+0GA6DFSap9inJ\n" + "BRTbwx+EmgwX966DUOefEOSpbDIVVSPs/Qr2LgtIMEFA7Y0+j3wZD3cCQBsTwccd\n" + "ASQx59xakpq11eOlTYz14rjwodr4QMyj26WxEPJtz7hKokx/+EH6fWuPIUSrROM5\n" + "07y2gaVbYxtis0s=\n" + "-----END PRIVATE KEY-----\n"; + +class SecureServer : public QObject +{ + Q_OBJECT + +public: + enum + { + Idle, + Handshaking, + Active, + Closing + }; + + SecureServer(quint16 _port) + : port(_port) + { + server = new QTcpServer; + connect(server, &QTcpServer::newConnection, this, &SecureServer::server_handleConnection); + + ssl = new QCA::TLS; + connect(ssl, &QCA::TLS::handshaken, this, &SecureServer::ssl_handshaken); + connect(ssl, &QCA::TLS::readyRead, this, &SecureServer::ssl_readyRead); + connect(ssl, &QCA::TLS::readyReadOutgoing, this, &SecureServer::ssl_readyReadOutgoing); + connect(ssl, &QCA::TLS::closed, this, &SecureServer::ssl_closed); + connect(ssl, &QCA::TLS::error, this, &SecureServer::ssl_error); + + cert = QCA::Certificate::fromPEM(QString::fromLatin1(pemdata_cert)); + privkey = QCA::PrivateKey::fromPEM(QString::fromLatin1(pemdata_privkey)); + + mode = Idle; + } + + ~SecureServer() override + { + delete ssl; + delete server; + } + + void start() + { + if (cert.isNull()) { + qDebug() << "Error loading cert!"; + QTimer::singleShot(0, this, &SecureServer::quit); + return; + } + if (privkey.isNull()) { + qDebug() << "Error loading private key!"; + QTimer::singleShot(0, this, &SecureServer::quit); + return; + } + if (false == server->listen(QHostAddress::Any, port)) { + qDebug() << "Error binding to port " << port; + QTimer::singleShot(0, this, &SecureServer::quit); + return; + } + qDebug() << "Listening on port" << port; + } + +Q_SIGNALS: + void quit(); + +private Q_SLOTS: + void sock_readyRead() + { + QByteArray buf(sock->bytesAvailable(), 0x00); + + int num = sock->read(buf.data(), buf.size()); + + if (-1 == num) + qDebug() << "Error reading data from socket"; + + if (num < buf.size()) + buf.resize(num); + + ssl->writeIncoming(buf); + } + + void server_handleConnection() + { + // Note: only 1 connection supported at a time in this example! + if (mode != Idle) { + QTcpSocket *tmp = server->nextPendingConnection(); + tmp->close(); + connect(tmp, &QTcpSocket::disconnected, tmp, &QTcpSocket::deleteLater); + qDebug() << "throwing away extra connection"; + return; + } + mode = Handshaking; + sock = server->nextPendingConnection(); + connect(sock, &QTcpSocket::readyRead, this, &SecureServer::sock_readyRead); + connect(sock, &QTcpSocket::disconnected, this, &SecureServer::sock_disconnected); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sock, &QTcpSocket::errorOccurred, this, &SecureServer::sock_error); +#else + connect(sock, QOverload::of(&QTcpSocket::error), this, &SecureServer::sock_error); +#endif + connect(sock, &QTcpSocket::bytesWritten, this, &SecureServer::sock_bytesWritten); + + qDebug() << "Connection received! Starting TLS handshake."; + ssl->setCertificate(cert, privkey); + ssl->startServer(); + } + + void sock_disconnected() + { + qDebug() << "Connection closed."; + } + + void sock_bytesWritten(qint64 x) + { + if (mode == Active && sent) { + qint64 bytes = ssl->convertBytesWritten(x); + bytesLeft -= bytes; + + if (bytesLeft == 0) { + mode = Closing; + qDebug() << "Data transfer complete - SSL shutting down"; + ssl->close(); + } + } + } + + void sock_error(QAbstractSocket::SocketError error) + { + qDebug() << "Socket error: " << (unsigned)error; + } + + void ssl_handshaken() + { + qDebug() << "Successful SSL handshake. Waiting for newline."; + bytesLeft = 0; + sent = false; + mode = Active; + ssl->continueAfterStep(); + } + + void ssl_readyRead() + { + ssl->read(); + QByteArray b = + "\n" + "Test\n" + "this is only a test\n" + "\n"; + + qDebug() << "Sending test response."; + sent = true; + ssl->write(b); + } + + void ssl_readyReadOutgoing() + { + int plainBytes; + QByteArray outgoingData = ssl->readOutgoing(&plainBytes); + sock->write(outgoingData); + } + + void ssl_closed() + { + qDebug() << "Closing socket."; + sock->close(); + mode = Idle; + } + + void ssl_error() + { + if (ssl->errorCode() == QCA::TLS::ErrorHandshake) { + qDebug() << "SSL Handshake Error! Closing."; + sock->close(); + } else { + qDebug() << "SSL Error! Closing."; + sock->close(); + } + mode = Idle; + } + +private: + quint16 port; + QTcpServer *server; + QTcpSocket *sock; + QCA::TLS *ssl; + QCA::Certificate cert; + QCA::PrivateKey privkey; + + bool sent; + int mode; + qint64 bytesLeft; +}; + +#include "sslservtest.moc" + +int main(int argc, char **argv) +{ + QCA::Initializer init; + + QCoreApplication app(argc, argv); + int port = argc > 1 ? QString::fromLatin1(argv[1]).toInt() : 8000; + + if (!QCA::isSupported("tls")) { + qDebug() << "TLS not supported!"; + return 1; + } + + SecureServer *server = new SecureServer(port); + QObject::connect(server, &SecureServer::quit, &app, &QCoreApplication::quit); + server->start(); + app.exec(); + delete server; + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/ssltest/CMakeLists.txt b/local/recipes/libs/qca/source/examples/ssltest/CMakeLists.txt new file mode 100644 index 0000000000..ffa6f9dd7f --- /dev/null +++ b/local/recipes/libs/qca/source/examples/ssltest/CMakeLists.txt @@ -0,0 +1,6 @@ +set(ssltest_bin_SRCS ssltest.cpp) + +add_executable(ssltest ${ssltest_bin_SRCS}) + +target_link_qca_libraries(ssltest) +target_link_libraries(ssltest Qt${QT_MAJOR_VERSION}::Network) diff --git a/local/recipes/libs/qca/source/examples/ssltest/ssltest.cpp b/local/recipes/libs/qca/source/examples/ssltest/ssltest.cpp new file mode 100644 index 0000000000..89a405e1ab --- /dev/null +++ b/local/recipes/libs/qca/source/examples/ssltest/ssltest.cpp @@ -0,0 +1,331 @@ +/* + Copyright (C) 2003-2005 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +char exampleCA_cert[] = + "-----BEGIN CERTIFICATE-----\n" + "MIICSzCCAbSgAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRMwEQYDVQQDEwpFeGFt\n" + "cGxlIENBMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwHhcNMDYw\n" + "MzE1MDY1ODMyWhcNMDYwNDE1MDY1ODMyWjA4MRMwEQYDVQQDEwpFeGFtcGxlIENB\n" + "MQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwgZ8wDQYJKoZIhvcN\n" + "AQEBBQADgY0AMIGJAoGBAL6ULdOxmpeZ+G/ypV12eNO4qnHSVIPTrYPkQuweXqPy\n" + "atwGFheG+hLVsNIh9GGOS0tCe7a3hBBKN0BJg1ppfk2x39cDx7hefYqjBuZvp/0O\n" + "8Ja3qlQiJLezITZKLxMBrsibcvcuH8zpfUdys2yaN+YGeqNfjQuoNN3Byl1TwuGJ\n" + "AgMBAAGjZTBjMB0GA1UdDgQWBBSQKCUCLNM7uKrAt5o7qv/yQm6qEzASBgNVHRMB\n" + "Af8ECDAGAQEBAgEIMB4GA1UdEQQXMBWBE2V4YW1wbGVAZXhhbXBsZS5jb20wDgYD\n" + "VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAAh+SIeT1Ao5qInw8oMSoTdO\n" + "lQ6h67ec/Jk5KmK4OoskuimmHI0Sp0C5kOCLehXbsVWW8pXsNC2fv0d2HkdaSUcX\n" + "hwLzqgyZXd4mupIYlaOTZhuHDwWPCAOZS4LVsi2tndTRHKCP12441JjNKhmZRhkR\n" + "u5zzD60nWgM9dKTaxuZM\n" + "-----END CERTIFICATE-----\n"; + +void showCertInfo(const QCA::Certificate &cert) +{ + printf("-- Cert --\n"); + printf(" CN: %s\n", qPrintable(cert.commonName())); + printf(" Valid from: %s, until %s\n", + qPrintable(cert.notValidBefore().toString()), + qPrintable(cert.notValidAfter().toString())); + printf(" PEM:\n%s\n", qPrintable(cert.toPEM())); +} + +static QString validityToString(QCA::Validity v) +{ + QString s; + switch (v) { + case QCA::ValidityGood: + s = QStringLiteral("Validated"); + break; + case QCA::ErrorRejected: + s = QStringLiteral("Root CA is marked to reject the specified purpose"); + break; + case QCA::ErrorUntrusted: + s = QStringLiteral("Certificate not trusted for the required purpose"); + break; + case QCA::ErrorSignatureFailed: + s = QStringLiteral("Invalid signature"); + break; + case QCA::ErrorInvalidCA: + s = QStringLiteral("Invalid CA certificate"); + break; + case QCA::ErrorInvalidPurpose: + s = QStringLiteral("Invalid certificate purpose"); + break; + case QCA::ErrorSelfSigned: + s = QStringLiteral("Certificate is self-signed"); + break; + case QCA::ErrorRevoked: + s = QStringLiteral("Certificate has been revoked"); + break; + case QCA::ErrorPathLengthExceeded: + s = QStringLiteral("Maximum certificate chain length exceeded"); + break; + case QCA::ErrorExpired: + s = QStringLiteral("Certificate has expired"); + break; + case QCA::ErrorExpiredCA: + s = QStringLiteral("CA has expired"); + break; + case QCA::ErrorValidityUnknown: + default: + s = QStringLiteral("General certificate validation error"); + break; + } + return s; +} + +class SecureTest : public QObject +{ + Q_OBJECT +public: + SecureTest() + { + sock_done = false; + ssl_done = false; + + sock = new QTcpSocket; + connect(sock, &QTcpSocket::connected, this, &SecureTest::sock_connected); + connect(sock, &QTcpSocket::readyRead, this, &SecureTest::sock_readyRead); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sock, &QTcpSocket::errorOccurred, this, &SecureTest::sock_error); +#else + connect(sock, QOverload::of(&QTcpSocket::error), this, &SecureTest::sock_error); +#endif + + ssl = new QCA::TLS; + connect(ssl, &QCA::TLS::certificateRequested, this, &SecureTest::ssl_certificateRequested); + connect(ssl, &QCA::TLS::handshaken, this, &SecureTest::ssl_handshaken); + connect(ssl, &QCA::TLS::readyRead, this, &SecureTest::ssl_readyRead); + connect(ssl, &QCA::TLS::readyReadOutgoing, this, &SecureTest::ssl_readyReadOutgoing); + connect(ssl, &QCA::TLS::closed, this, &SecureTest::ssl_closed); + connect(ssl, &QCA::TLS::error, this, &SecureTest::ssl_error); + } + + ~SecureTest() override + { + delete ssl; + delete sock; + } + + void start(const QString &_host) + { + int n = _host.indexOf(QLatin1Char(':')); + int port; + if (n != -1) { + host = _host.mid(0, n); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + port = QStringView(_host).mid(n + 1).toInt(); +#else + port = _host.midRef(n + 1).toInt(); +#endif + } else { + host = _host; + port = 443; + } + + printf("Trying %s:%d...\n", qPrintable(host), port); + sock->connectToHost(host, port); + } + +Q_SIGNALS: + void quit(); + +private Q_SLOTS: + void sock_connected() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + printf("Connected, starting TLS handshake...\n"); + + QCA::CertificateCollection rootCerts = QCA::systemStore(); + + // We add this one to show how, and to make it work with + // the server example. + rootCerts.addCertificate(QCA::Certificate::fromPEM(QString::fromLatin1(exampleCA_cert))); + + if (!QCA::haveSystemStore()) + printf("Warning: no root certs\n"); + else + ssl->setTrustedCertificates(rootCerts); + + ssl->startClient(host); + } + + void sock_readyRead() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + ssl->writeIncoming(sock->readAll()); + } + + void sock_connectionClosed() + { + printf("\nConnection closed.\n"); + sock_done = true; + + if (ssl_done && sock_done) + emit quit(); + } + + void sock_error(QAbstractSocket::SocketError x) + { + if (x == QAbstractSocket::RemoteHostClosedError) { + sock_connectionClosed(); + return; + } + + printf("\nSocket error.\n"); + emit quit(); + } + + void ssl_handshaken() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + QCA::TLS::IdentityResult r = ssl->peerIdentityResult(); + + printf("Successful SSL handshake using %s (%i of %i bits)\n", + qPrintable(ssl->cipherSuite()), + ssl->cipherBits(), + ssl->cipherMaxBits()); + if (r != QCA::TLS::NoCertificate) { + cert = ssl->peerCertificateChain().primary(); + if (!cert.isNull()) + showCertInfo(cert); + } + + QString str = QStringLiteral("Peer Identity: "); + if (r == QCA::TLS::Valid) + str += QStringLiteral("Valid"); + else if (r == QCA::TLS::HostMismatch) + str += QStringLiteral("Error: Wrong certificate"); + else if (r == QCA::TLS::InvalidCertificate) + str += QStringLiteral("Error: Invalid certificate.\n -> Reason: ") + + validityToString(ssl->peerCertificateValidity()); + else + str += QStringLiteral("Error: No certificate"); + printf("%s\n", qPrintable(str)); + + ssl->continueAfterStep(); + + printf("Let's try a GET request now.\n"); + QString req = QStringLiteral("GET / HTTP/1.0\nHost: ") + host + QStringLiteral("\n\n"); + ssl->write(req.toLatin1()); + } + + void ssl_certificateRequested() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + printf("Server requested client certificate.\n"); + QList issuerList = ssl->issuerList(); + if (!issuerList.isEmpty()) { + printf("Allowed issuers:\n"); + foreach (QCA::CertificateInfoOrdered i, issuerList) + printf(" %s\n", qPrintable(i.toString())); + } + + ssl->continueAfterStep(); + } + + void ssl_readyRead() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + QByteArray a = ssl->read(); + printf("%s", a.data()); + } + + void ssl_readyReadOutgoing() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + sock->write(ssl->readOutgoing()); + } + + void ssl_closed() + { + printf("SSL session closed.\n"); + ssl_done = true; + + if (ssl_done && sock_done) + emit quit(); + } + + void ssl_error() + { + // We just do this to help doxygen... + QCA::TLS *ssl = SecureTest::ssl; + + int x = ssl->errorCode(); + if (x == QCA::TLS::ErrorHandshake) { + printf("SSL Handshake Error!\n"); + emit quit(); + } else { + printf("SSL Error!\n"); + emit quit(); + } + } + +private: + QString host; + QTcpSocket *sock; + QCA::TLS *ssl; + QCA::Certificate cert; + bool sock_done, ssl_done; +}; + +#include "ssltest.moc" + +int main(int argc, char **argv) +{ + QCA::Initializer init; + + QCoreApplication app(argc, argv); + QString host = argc > 1 ? QString::fromLocal8Bit(argv[1]) : QStringLiteral("andbit.net"); + + if (!QCA::isSupported("tls")) { + printf("TLS not supported!\n"); + return 1; + } + + SecureTest *s = new SecureTest; + QObject::connect(s, &SecureTest::quit, &app, &QCoreApplication::quit); + s->start(host); + app.exec(); + delete s; + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/tlssocket/CMakeLists.txt b/local/recipes/libs/qca/source/examples/tlssocket/CMakeLists.txt new file mode 100644 index 0000000000..8863decf02 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/tlssocket/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(tlssocket tlssocket.cpp main.cpp) + +target_link_qca_libraries(tlssocket) +target_link_libraries(tlssocket Qt${QT_MAJOR_VERSION}::Network) diff --git a/local/recipes/libs/qca/source/examples/tlssocket/main.cpp b/local/recipes/libs/qca/source/examples/tlssocket/main.cpp new file mode 100644 index 0000000000..1219aacb16 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/tlssocket/main.cpp @@ -0,0 +1,38 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "tlssocket.h" + +#include + +int main(int argc, char **argv) +{ + QCA::Initializer init; + QCoreApplication qapp(argc, argv); + + TLSSocket socket; + socket.connectToHostEncrypted(QStringLiteral("www.paypal.com"), 443); + socket.write("GET / HTTP/1.0\r\n\r\n"); + while (socket.waitForReadyRead()) + printf("%s", socket.readAll().constData()); + + return 0; +} diff --git a/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.cpp b/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.cpp new file mode 100644 index 0000000000..e84a908edb --- /dev/null +++ b/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.cpp @@ -0,0 +1,222 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "tlssocket.h" + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class TLSSocket::Private : public QObject +{ + Q_OBJECT +public: + TLSSocket *q; + QTcpSocket *sock; + QCA::TLS *tls; + QString host; + bool encrypted; + bool error, done; + QByteArray readbuf, writebuf; + QCA::Synchronizer sync; + bool waiting; + + Private(TLSSocket *_q) + : QObject(_q) + , q(_q) + , sync(_q) + { + sock = new QTcpSocket(this); + connect(sock, &QTcpSocket::connected, this, &TLSSocket::Private::sock_connected); + connect(sock, &QTcpSocket::readyRead, this, &TLSSocket::Private::sock_readyRead); + connect(sock, &QTcpSocket::bytesWritten, this, &TLSSocket::Private::sock_bytesWritten); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(sock, &QTcpSocket::errorOccurred, this, &TLSSocket::Private::sock_error); +#else + connect(sock, + QOverload::of(&QTcpSocket::error), + this, + &TLSSocket::Private::sock_error); +#endif + + tls = new QCA::TLS(this); + connect(tls, &QCA::TLS::handshaken, this, &TLSSocket::Private::tls_handshaken); + connect(tls, &QCA::TLS::readyRead, this, &TLSSocket::Private::tls_readyRead); + connect(tls, &QCA::TLS::readyReadOutgoing, this, &TLSSocket::Private::tls_readyReadOutgoing); + connect(tls, &QCA::TLS::closed, this, &TLSSocket::Private::tls_closed); + connect(tls, &QCA::TLS::error, this, &TLSSocket::Private::tls_error); + tls->setTrustedCertificates(QCA::systemStore()); + encrypted = false; + error = false; + waiting = false; + done = false; + } + + bool waitForReadyRead(int msecs) + { + waiting = true; + bool ok = sync.waitForCondition(msecs); + // while(1) + // QCoreApplication::instance()->processEvents(); + waiting = false; + if (error || done) + return false; + return ok; + } + +private Q_SLOTS: + void sock_connected() + { + // printf("sock connected\n"); + tls->startClient(host); + } + + void sock_readyRead() + { + // printf("sock ready read\n"); + QByteArray buf = sock->readAll(); + // printf("%d bytes\n", buf.size()); + tls->writeIncoming(buf); + } + + void sock_bytesWritten(qint64 x) + { + Q_UNUSED(x); + // printf("sock bytes written: %d\n", (int)x); + } + + void sock_error(QAbstractSocket::SocketError x) + { + // printf("sock error: %d\n", x); + Q_UNUSED(x); + done = true; + if (waiting) + sync.conditionMet(); + } + + void tls_handshaken() + { + // printf("tls handshaken\n"); + if (tls->peerIdentityResult() != QCA::TLS::Valid) { + printf("not valid\n"); + sock->abort(); + tls->reset(); + error = true; + } else { + // printf("valid\n"); + encrypted = true; + // printf("%d bytes in writebuf\n", writebuf.size()); + if (!writebuf.isEmpty()) { + // printf("[%s]\n", writebuf.data()); + tls->write(writebuf); + writebuf.clear(); + } + } + if (waiting) + sync.conditionMet(); + } + + void tls_readyRead() + { + // printf("tls ready read\n"); + if (waiting) + sync.conditionMet(); + } + + void tls_readyReadOutgoing() + { + // printf("tls ready read outgoing\n"); + QByteArray buf = tls->readOutgoing(); + // printf("%d bytes\n", buf.size()); + sock->write(buf); + } + + void tls_closed() + { + // printf("tls closed\n"); + } + + void tls_error() + { + // printf("tls error\n"); + } +}; + +TLSSocket::TLSSocket(QObject *parent) + : QTcpSocket(parent) +{ + d = new Private(this); +} + +TLSSocket::~TLSSocket() +{ + delete d; +} + +void TLSSocket::connectToHostEncrypted(const QString &host, quint16 port) +{ + d->host = host; + setOpenMode(QIODevice::ReadWrite); + d->sock->connectToHost(host, port); +} + +QCA::TLS *TLSSocket::tls() +{ + return d->tls; +} + +bool TLSSocket::waitForReadyRead(int msecs) +{ + /*if(d->readbuf.isEmpty()) + return false; + + if(d->tls->bytesAvailable() == 0) + return false;*/ + + return d->waitForReadyRead(msecs); +} + +qint64 TLSSocket::readData(char *data, qint64 maxlen) +{ + if (!d->error) + d->readbuf += d->tls->read(); + unsigned char *p = (unsigned char *)d->readbuf.data(); + int size = d->readbuf.size(); + int readsize = qMin(size, (int)maxlen); + int newsize = size - readsize; + memcpy(data, p, readsize); + memmove(p, p + readsize, newsize); + d->readbuf.resize(newsize); + return readsize; +} + +qint64 TLSSocket::writeData(const char *data, qint64 len) +{ + // printf("write %d bytes\n", (int)len); + QByteArray buf(data, len); + if (d->encrypted) + d->tls->write(buf); + else + d->writebuf += buf; + return len; +} + +#include "tlssocket.moc" diff --git a/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.h b/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.h new file mode 100644 index 0000000000..92fb113c87 --- /dev/null +++ b/local/recipes/libs/qca/source/examples/tlssocket/tlssocket.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2007 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef TLSSOCKET_H + +#include +#include + +class TLSSocket : public QTcpSocket +{ + Q_OBJECT +public: + TLSSocket(QObject *parent = nullptr); + ~TLSSocket() override; + + void connectToHostEncrypted(const QString &host, quint16 port); + QCA::TLS *tls(); + + bool waitForReadyRead(int msecs = -1) override; + +protected: + // from qiodevice + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + +private: + class Private; + friend class Private; + Private *d; +}; + +#endif diff --git a/local/recipes/libs/qca/source/hooks/pre-commit b/local/recipes/libs/qca/source/hooks/pre-commit new file mode 100644 index 0000000000..6337bbbde6 --- /dev/null +++ b/local/recipes/libs/qca/source/hooks/pre-commit @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +readonly output=$(git clang-format -v --diff) + +if [[ "$output" == *"no modified files to format"* ]]; then exit 0; fi +if [[ "$output" == *"clang-format did not modify any files"* ]]; then exit 0; fi + +echo "ERROR: you need to run git clang-format on your commit" +echo " git clang-format -f is potentially what you want" +exit 1 diff --git a/local/recipes/libs/qca/source/include/QtCrypto/QtCrypto b/local/recipes/libs/qca/source/include/QtCrypto/QtCrypto new file mode 100644 index 0000000000..e9f2249e84 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/QtCrypto @@ -0,0 +1 @@ +#include "qca.h" diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca.h b/local/recipes/libs/qca/source/include/QtCrypto/qca.h new file mode 100644 index 0000000000..cb4987a31a --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca.h @@ -0,0 +1,48 @@ +/* + * qca.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2005 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca.h + + Summary header file for %QCA. + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_H +#define QCA_H + +#include "qca_basic.h" +#include "qca_cert.h" +#include "qca_core.h" +#include "qca_keystore.h" +#include "qca_publickey.h" +#include "qca_safetimer.h" +#include "qca_securelayer.h" +#include "qca_securemessage.h" +#include "qca_textfilter.h" +#include "qcaprovider.h" +#include "qpipe.h" + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_basic.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_basic.h new file mode 100644 index 0000000000..54ca19f474 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_basic.h @@ -0,0 +1,1150 @@ +/* + * qca_basic.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004-2007 Brad Hards + * Copyright (C) 2013-2016 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_basic.h + + Header file for classes for cryptographic primitives (basic operations). + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_BASIC_H +#define QCA_BASIC_H + +#include "qca_core.h" + +#include + +namespace QCA { + +/** + \defgroup UserAPI QCA user API + + This is the main set of QCA classes, intended for use + in standard applications. +*/ + +/** + \class Random qca_basic.h QtCrypto + + Source of random numbers. + + QCA provides a built in source of random numbers, which + can be accessed through this class. You can also use + an alternative random number source, by implementing + another provider. + + The normal use of this class is expected to be through the + static members - randomChar(), randomInt() and randomArray(). + + \ingroup UserAPI + */ +class QCA_EXPORT Random : public Algorithm +{ +public: + /** + Standard Constructor + + \param provider the name of the provider library for the random + number generation + */ + Random(const QString &provider = QString()); + + /** + Copy constructor + + \param from the %Random object to copy from + */ + Random(const Random &from); + + ~Random() override; + + /** + Assignment operator + + \param from the %Random object to copy state from + */ + Random &operator=(const Random &from); + + /** + Provide a random byte. + + This method isn't normally required - you should use + the static randomChar() method instead. + + \sa randomChar + */ + uchar nextByte(); + + /** + Provide a specified number of random bytes. + + This method isn't normally required - you should use + the static randomArray() method instead. + + \param size the number of bytes to provide + + \sa randomArray + */ + SecureArray nextBytes(int size); + + /** + Provide a random character (byte) + + This is the normal way of obtaining a single random char + (i.e. 8 bit byte), as shown below: + \code +myRandomChar = QCA::Random::randomChar(); + \endcode + + If you need a number of bytes, perhaps randomArray() may be of use. + */ + static uchar randomChar(); + + /** + Provide a random integer. + + This is the normal way of obtaining a single random integer, + as shown below: + \code +myRandomInt = QCA::Random::randomInt(); + \endcode + */ + static int randomInt(); + + /** + Provide a specified number of random bytes. + + \code +// build a 30 byte secure array. +SecureArray arry = QCA::Random::randomArray(30); + \endcode + + \param size the number of bytes to provide + */ + static SecureArray randomArray(int size); + +private: + class Private; + Private *d; +}; + +/** + \class Hash qca_basic.h QtCrypto + + General class for hashing algorithms. + + Hash is the class for the various hashing algorithms + within %QCA. SHA256, SHA1 or RIPEMD160 are recommended for + new applications, although MD2, MD4, MD5 or SHA0 may be + applicable (for interoperability reasons) for some + applications. + + To perform a hash, you create a Hash object, call update() + with the data that needs to be hashed, and then call + final(), which returns a QByteArray of the hash result. An + example (using the SHA1 hash, with 1000 updates of a 1000 + byte string) is shown below: + + \code +if(!QCA::isSupported("sha1")) + printf("SHA1 not supported!\n"); +else +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + QCA::Hash shaHash("sha1"); + for (int i=0; i<1000; i++) + shaHash.update(fillerString); + QByteArray hashResult = shaHash.final(); + if ( "34aa973cd4c4daa4f61eeb2bdbad27316534016f" == QCA::arrayToHex(hashResult) ) + { + printf("big SHA1 is OK\n"); + } + else + { + printf("big SHA1 failed\n"); + } +} + \endcode + + If you only have a simple hash requirement - a single + string that is fully available in memory at one time - then + you may be better off with one of the convenience + methods. So, for example, instead of creating a QCA::Hash + object, then doing a single update() and the final() call; + you could simply call QCA::Hash("algoName").hash() with the + data that you would otherwise have provided to the update() + call. + + For more information on hashing algorithms, see \ref hashing. + + \ingroup UserAPI +*/ +class QCA_EXPORT Hash : public Algorithm, public BufferedComputation +{ +public: + /** + Constructor + + \param type label for the type of hash to be + created (for example, "sha1" or "md2") + \param provider the name of the provider plugin + for the subclass (eg "qca-ossl") + */ + explicit Hash(const QString &type, const QString &provider = QString()); + + /** + Copy constructor + + \param from the Hash object to copy from + */ + Hash(const Hash &from); + + ~Hash() override; + + /** + Assignment operator + + \param from the Hash object to copy state from + */ + Hash &operator=(const Hash &from); + + /** + Returns a list of all of the hash types available + + \param provider the name of the provider to get a list from, if one + provider is required. If not specified, available hash types from all + providers will be returned. + */ + static QStringList supportedTypes(const QString &provider = QString()); + + /** + Return the hash type + */ + QString type() const; + + /** + Reset a hash, dumping all previous parts of the + message. + + This method clears (or resets) the hash algorithm, + effectively undoing any previous update() + calls. You should use this call if you are re-using + a Hash sub-class object to calculate additional + hashes. + */ + void clear() override; + + /** + Update a hash, adding more of the message contents + to the digest. The whole message needs to be added + using this method before you call final(). + + If you find yourself only calling update() once, + you may be better off using a convenience method + such as hash() or hashToString() instead. + + \param a the byte array to add to the hash + */ + void update(const MemoryRegion &a) override; + + /** + \overload + + \param a the QByteArray to add to the hash + */ + void update(const QByteArray &a); + + /** + \overload + + This method is provided to assist with code that + already exists, and is being ported to %QCA. You are + better off passing a SecureArray (as shown above) + if you are writing new code. + + \param data pointer to a char array + \param len the length of the array. If not specified + (or specified as a negative number), the length will be + determined with strlen(), which may not be what you want + if the array contains a null (0x00) character. + */ + void update(const char *data, int len = -1); + + /** + \overload + + This allows you to read from a file or other + I/O device. Note that the device must be already + open for reading + + \param file an I/O device + + If you are trying to calculate the hash of + a whole file (and it isn't already open), you + might want to use code like this: + \code +QFile f( "file.dat" ); +if ( f.open( QIODevice::ReadOnly ) ) +{ + QCA::Hash hashObj("sha1"); + hashObj.update( &f ); + QByteArray output = hashObj.final().toByteArray(); +} + \endcode + */ + void update(QIODevice *file); + + /** + Finalises input and returns the hash result + + After calling update() with the required data, the + hash results are finalised and produced. + + Note that it is not possible to add further data (with + update()) after calling final(), because of the way + the hashing works - null bytes are inserted to pad + the results up to a fixed size. If you want to + reuse the Hash object, you should call clear() and + start to update() again. + */ + MemoryRegion final() override; + + /** + %Hash a byte array, returning it as another + byte array + + This is a convenience method that returns the + hash of a SecureArray. + + \code +SecureArray sampleArray(3); +sampleArray.fill('a'); +SecureArray outputArray = QCA::Hash("md2")::hash(sampleArray); + \endcode + + \param array the QByteArray to hash + + If you need more flexibility (e.g. you are constructing + a large byte array object just to pass it to hash(), then + consider creating an Hash object, and then calling + update() and final(). + */ + MemoryRegion hash(const MemoryRegion &array); + + /** + %Hash a byte array, returning it as a printable + string + + This is a convenience method that returns the + hash of a SecureArray as a hexadecimal + representation encoded in a QString. + + \param array the QByteArray to hash + + If you need more flexibility, you can create a Hash + object, call Hash::update() as required, then call + Hash::final(), before using the static arrayToHex() method. + */ + QString hashToString(const MemoryRegion &array); + +private: + class Private; + Private *d; +}; + +/** + \page hashing Hashing Algorithms + + There are a range of hashing algorithms available in + %QCA. Hashing algorithms are used with the Hash and + MessageAuthenticationCode classes. + + The MD2 algorithm takes an arbitrary data stream, known as the + message and outputs a condensed 128 bit (16 byte) + representation of that data stream, known as the message + digest. This algorithm is considered slightly more secure than MD5, + but is more expensive to compute. Unless backward + compatibility or interoperability are considerations, you + are better off using the SHA1 or RIPEMD160 hashing algorithms. + For more information on %MD2, see B. Kalinski RFC1319 "The %MD2 + Message-Digest Algorithm". The label for MD2 is "md2". + + The MD4 algorithm takes an arbitrary data stream, known as the + message and outputs a condensed 128 bit (16 byte) + representation of that data stream, known as the message + digest. MD4 is not considered to be secure, based on + known attacks. It should only be used for applications where + collision attacks are not a consideration (for example, as + used in the rsync algorithm for fingerprinting blocks of + data). If a secure hash is required, you are better off using + the SHA1 or RIPEMD160 hashing algorithms. MD2 and MD5 are both + stronger 128 bit hashes. For more information on MD4, see + R. Rivest RFC1320 "The %MD4 Message-Digest Algorithm". The + label for MD4 is "md4". + + The MD5 takes an arbitrary data stream, known as the message + and outputs a condensed 128 bit (16 byte) representation of + that data stream, known as the message digest. MD5 is not + considered to be secure, based on known attacks. It should + only be used for applications where collision attacks are not + a consideration. If a secure hash is required, you are better + off using the SHA1 or RIPEMD160 hashing algorithms. For more + information on MD5, see R. Rivest RFC1321 "The %MD5 + Message-Digest Algorithm". The label for MD5 is "md5". + + The RIPEMD160 algorithm takes an arbitrary data stream, known + as the message (up to \f$2^{64}\f$ bits in length) and outputs + a condensed 160 bit (20 byte) representation of that data + stream, known as the message digest. The RIPEMD160 algorithm + is considered secure in that it is considered computationally + infeasible to find the message that produced the message + digest. The label for RIPEMD160 is "ripemd160". + + The SHA-0 algorithm is a 160 bit hashing function, no longer + recommended for new applications because of known (partial) + attacks against it. The label for SHA-0 is "sha0". + + The SHA-1 algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{64}\f$ bits in length) and outputs a + condensed 160 bit (20 byte) representation of that data + stream, known as the message digest. SHA-1 is considered + secure in that it is considered computationally infeasible to + find the message that produced the message digest. For more + information on the SHA-1 algorithm,, see Federal Information + Processing Standard Publication 180-2 "Specifications for the + Secure %Hash Standard", available from + http://csrc.nist.gov/publications/. The label for SHA-1 is + "sha1". + + The SHA-224 algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{64}\f$ bits in length) and outputs a + condensed 224 bit (28 byte) representation of that data + stream, known as the message digest. SHA-224 is a "cut down" + version of SHA-256, and you may be better off using SHA-256 in + new designs. The SHA-224 algorithm is considered secure in + that it is considered computationally infeasible to find the + message that produced the message digest. For more information + on SHA-224, see Federal Information Processing Standard + Publication 180-2 "Specifications for the Secure %Hash + Standard", with change notice 1, available from + http://csrc.nist.gov/publications/. The label for SHA-224 is + "sha224". + + The SHA-256 algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{64}\f$ bits in length) and outputs a + condensed 256 bit (32 byte) representation of that data + stream, known as the message digest. The SHA-256 algorithm is + considered secure in that it is considered computationally + infeasible to find the message that produced the message + digest. For more information on SHA-256, see Federal + Information Processing Standard Publication 180-2 + "Specifications for the Secure %Hash Standard", available from + http://csrc.nist.gov/publications/. The label for SHA-256 is + "sha256". + + The SHA-384 algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{128}\f$ bits in length) and outputs a + condensed 384 bit (48 byte) representation of that data + stream, known as the message digest. The SHA-384 algorithm is + a "cut down" version of SHA-512, and you may be better off + using SHA-512 in new designs. The SHA-384 algorithm is + considered secure in that it is considered computationally + infeasible to find the message that produced the message + digest. For more information on SHA-384, see Federal + Information Processing Standard Publication 180-2 + "Specifications for the Secure %Hash Standard", available from + http://csrc.nist.gov/publications/. The label for SHA-384 is + "sha384". + + The SHA-512 algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{128}\f$ bits in length) and outputs a + condensed 512 bit (64 byte) representation of that data + stream, known as the message digest. The SHA-512 algorithm is + considered secure in that it is considered computationally + infeasible to find the message that produced the message + digest. For more information on SHA-512, see Federal + Information Processing Standard Publication 180-2 + "Specifications for the Secure %Hash Standard", available from + http://csrc.nist.gov/publications/. The label for SHA-512 is + "sha512". + + The Whirlpool algorithm takes an arbitrary data stream, known as + the message (up to \f$2^{256}\f$ bits in length) and outputs a + condensed 512 bit (64 byte) representation of that data + stream, known as the message digest. The Whirlpool algorithm is + considered secure in that it is considered computationally + infeasible to find the message that produced the message + digest. For more information on Whirlpool, see + http://paginas.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html + or ISO/IEC 10118-3:2004. The label for Whirlpool is + "whirlpool". +*/ + +/** + \page paddingDescription Padding + + For those Cipher sub-classes that are block based, there are modes + that require a full block on encryption and decryption - %Cipher Block + Chaining mode and Electronic Code Book modes are good examples. + + Since real world messages are not always a convenient multiple of a + block size, we have to adding padding. There are a number of + padding modes that %QCA supports, including not doing any padding + at all. + + If you are not going to use padding, then you can pass + QCA::Cipher::NoPadding as the pad argument to the Cipher sub-class, + however it is then your responsibility to pass in appropriate data for + the mode that you are using. + + The most common padding scheme is known as PKCS#7 (also PKCS#1), and + it specifies that the pad bytes are all equal to the length of the + padding ( for example, if you need three pad bytes to complete the block, + then the padding is 0x03 0x03 0x03 ). PKCS#5 padding is a subset of + PKCS#7 padding for 8 byte block sizes. For explanation, see + http://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding/9044#9044. + + On encryption, for algorithm / mode combinations that require + padding, you will get a block of ciphertext when the input plain + text block is complete. When you call final(), you will get out the + ciphertext that corresponds to the last part of the plain text, + plus any padding. If you had provided plaintext that matched up + with a block size, then the cipher text block is generated from + pure padding - you always get at least some padding, to ensure that + the padding can be safely removed on decryption. + + On decryption, for algorithm / mode combinations that use padding, + you will get back a block of plaintext when the input ciphertext block + is complete. When you call final(), you will get a block that has been + stripped of ciphertext. +*/ + +/** + \class Cipher qca_basic.h QtCrypto + + General class for cipher (encryption / decryption) algorithms. + + Cipher is the class for the various algorithms that perform + low level encryption and decryption within %QCA. + + AES128, AES192 and AES256 are recommended for new applications. + + Standard names for ciphers are: + - Blowfish - "blowfish" + - TripleDES - "tripledes" + - DES - "des" + - AES128 - "aes128" + - AES192 - "aes192" + - AES256 - "aes256" + - CAST5 (CAST-128) - "cast5" + + When checking for the availability of a particular kind + of cipher operation (e.g. AES128 in CBC mode with PKCS7 + padding), you append the mode and padding type (in that + example "aes128-cbc-pkcs7"). CFB and OFB modes don't use + padding, so they are always just the cipher name followed + by the mode (e.g. "blowfish-cfb" or "aes192-ofb"). If + you are not using padding with CBC mode (i.e. you are + ensuring block size operations yourself), just use + the cipher name followed by "-cbc" (e.g. "blowfish-cbc" + or "aes256-cbc"). + + \ingroup UserAPI +*/ + +class QCA_EXPORT Cipher : public Algorithm, public Filter +{ +public: + /** + Mode settings for cipher algorithms. + + \note ECB is almost never what you want, unless you + are trying to implement a %Cipher variation that is not + supported by %QCA. + */ + enum Mode + { + CBC, ///< operate in %Cipher Block Chaining mode + CFB, ///< operate in %Cipher FeedBack mode + ECB, ///< operate in Electronic Code Book mode + OFB, ///< operate in Output FeedBack Mode + CTR, ///< operate in CounTer Mode + GCM, ///< operate in Galois Counter Mode + CCM ///< operate in Counter with CBC-MAC + }; + + /** + Padding variations for cipher algorithms. + + See the \ref paddingDescription description for more details on + padding schemes. + */ + enum Padding + { + DefaultPadding, ///< Default for cipher-mode + NoPadding, ///< Do not use padding + PKCS7 ///< Pad using the scheme in PKCS#7 + }; + + /** + Standard constructor + + \param type the name of the cipher specialisation to use (e.g. + "aes128") + \param mode the operating Mode to use (e.g. QCA::Cipher::CBC) + \param pad the type of Padding to use + \param dir the Direction that this Cipher should use (Encode for + encryption, Decode for decryption) + \param key the SymmetricKey array that is the key + \param iv the InitializationVector to use (not used for ECB mode) + \param provider the name of the Provider to use + + \note Padding only applies to CBC and ECB modes. CFB and OFB + ciphertext is always the length of the plaintext. + */ + Cipher(const QString &type, + Mode mode, + Padding pad = DefaultPadding, + Direction dir = Encode, + const SymmetricKey &key = SymmetricKey(), + const InitializationVector &iv = InitializationVector(), + const QString &provider = QString()); + + /** + Standard constructor + + \param type the name of the cipher specialisation to use (e.g. + "aes128") + \param mode the operating Mode to use (e.g. QCA::Cipher::CBC) + \param pad the type of Padding to use + \param dir the Direction that this Cipher should use (Encode for + encryption, Decode for decryption) + \param key the SymmetricKey array that is the key + \param iv the InitializationVector to use (not used for ECB mode) + \param tag the AuthTag to use (only for GCM and CCM modes) + \param provider the name of the Provider to use + + \note Padding only applies to CBC and ECB modes. CFB and OFB + ciphertext is always the length of the plaintext. + */ + Cipher(const QString &type, + Mode mode, + Padding pad, + Direction dir, + const SymmetricKey &key, + const InitializationVector &iv, + const AuthTag &tag, + const QString &provider = QString()); + + /** + Standard copy constructor + + \param from the Cipher to copy state from + */ + Cipher(const Cipher &from); + + ~Cipher() override; + + /** + Assignment operator + + \param from the Cipher to copy state from + */ + Cipher &operator=(const Cipher &from); + + /** + Returns a list of all of the cipher types available + + \param provider the name of the provider to get a list from, if one + provider is required. If not specified, available cipher types from all + providers will be returned. + */ + static QStringList supportedTypes(const QString &provider = QString()); + + /** + Return the cipher type + */ + QString type() const; + + /** + Return the cipher mode + */ + Mode mode() const; + + /** + Return the cipher padding type + */ + Padding padding() const; + + /** + Return the cipher direction + */ + Direction direction() const; + + /** + Return acceptable key lengths + */ + KeyLength keyLength() const; + + /** + Test if a key length is valid for the cipher algorithm + + \param n the key length in bytes + \return true if the key would be valid for the current algorithm + */ + bool validKeyLength(int n) const; + + /** + return the block size for the cipher object + */ + int blockSize() const; + + /** + return the authentication tag for the cipher object + */ + AuthTag tag() const; + + /** + reset the cipher object, to allow re-use + */ + void clear() override; + + /** + pass in a byte array of data, which will be encrypted or decrypted + (according to the Direction that was set in the constructor or in + setup() ) and returned. + + \param a the array of data to encrypt / decrypt + */ + MemoryRegion update(const MemoryRegion &a) override; + + /** + complete the block of data, padding as required, and returning + the completed block + */ + MemoryRegion final() override; + + /** + Test if an update() or final() call succeeded. + + \return true if the previous call succeeded + */ + bool ok() const override; + + /** + Reset / reconfigure the Cipher + + You can use this to re-use an existing Cipher, rather than creating + a new object with a slightly different configuration. + + \param dir the Direction that this Cipher should use (Encode for + encryption, Decode for decryption) + \param key the SymmetricKey array that is the key + \param iv the InitializationVector to use (not used for ECB Mode) + + \note You should not leave iv empty for any Mode except ECB. + */ + void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv = InitializationVector()); + + /** + Reset / reconfigure the Cipher + + You can use this to re-use an existing Cipher, rather than creating + a new object with a slightly different configuration. + + \param dir the Direction that this Cipher should use (Encode for + encryption, Decode for decryption) + \param key the SymmetricKey array that is the key + \param iv the InitializationVector to use (not used for ECB Mode) + \param tag the AuthTag to use (only for GCM and CCM modes) + + \note You should not leave iv empty for any Mode except ECB. + */ + void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag); + + /** + Construct a Cipher type string + + \param cipherType the name of the algorithm (eg AES128, DES) + \param modeType the mode to operate the cipher in (eg QCA::CBC, + QCA::CFB) + \param paddingType the padding required (eg QCA::NoPadding, + QCA::PCKS7) + */ + static QString withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType); + +private: + class Private; + Private *d; +}; + +/** + \class MessageAuthenticationCode qca_basic.h QtCrypto + + General class for message authentication code (MAC) algorithms. + + MessageAuthenticationCode is a class for accessing the various + message authentication code algorithms within %QCA. + HMAC using SHA1 ("hmac(sha1)") or HMAC using SHA256 ("hmac(sha256)") + is recommended for new applications. + + Note that if your application is potentially susceptable to "replay + attacks" where the message is sent more than once, you should include a + counter in the message that is covered by the MAC, and check that the + counter is always incremented every time you receive a message and MAC. + + For more information on HMAC, see H. Krawczyk et al. RFC2104 + "HMAC: Keyed-Hashing for Message Authentication" + + \ingroup UserAPI +*/ +class QCA_EXPORT MessageAuthenticationCode : public Algorithm, public BufferedComputation +{ +public: + /** + Standard constructor + + \param type the name of the MAC (and algorithm, if applicable) to + use + \param key the shared key + \param provider the provider to use, if a particular provider is + required + */ + MessageAuthenticationCode(const QString &type, const SymmetricKey &key, const QString &provider = QString()); + + /** + Standard copy constructor + + Copies the state (including key) from one MessageAuthenticationCode + to another + + \param from the MessageAuthenticationCode to copy state from + */ + MessageAuthenticationCode(const MessageAuthenticationCode &from); + + ~MessageAuthenticationCode() override; + + /** + Assignment operator. + + Copies the state (including key) from one MessageAuthenticationCode + to another + + \param from the MessageAuthenticationCode to assign from. + */ + MessageAuthenticationCode &operator=(const MessageAuthenticationCode &from); + + /** + Returns a list of all of the message authentication code types + available + + \param provider the name of the provider to get a list from, if one + provider is required. If not specified, available message authentication + codes types from all providers will be returned. + */ + static QStringList supportedTypes(const QString &provider = QString()); + + /** + Return the MAC type + */ + QString type() const; + + /** + Return acceptable key lengths + */ + KeyLength keyLength() const; + + /** + Test if a key length is valid for the MAC algorithm + + \param n the key length in bytes + \return true if the key would be valid for the current algorithm + */ + bool validKeyLength(int n) const; + + /** + Reset a MessageAuthenticationCode, dumping all + previous parts of the message. + + This method clears (or resets) the algorithm, + effectively undoing any previous update() + calls. You should use this call if you are re-using + a %MessageAuthenticationCode sub-class object + to calculate additional MACs. Note that if the key + doesn't need to be changed, you don't need to call + setup() again, since the key can just be reused. + */ + void clear() override; + + /** + Update the MAC, adding more of the message contents + to the digest. The whole message needs to be added + using this method before you call final(). + + \param array the message contents + */ + void update(const MemoryRegion &array) override; + + /** + Finalises input and returns the MAC result + + After calling update() with the required data, the + hash results are finalised and produced. + + Note that it is not possible to add further data (with + update()) after calling final(). If you want to + reuse the %MessageAuthenticationCode object, you + should call clear() and start to update() again. + */ + MemoryRegion final() override; + + /** + Initialise the MAC algorithm + + \param key the key to use for the algorithm + */ + void setup(const SymmetricKey &key); + +private: + class Private; + Private *d; +}; + +/** + \class KeyDerivationFunction qca_basic.h QtCrypto + + General superclass for key derivation algorithms. + + %KeyDerivationFunction is a superclass for the various + key derivation function algorithms within %QCA. You should + not need to use it directly unless you are + adding another key derivation capability to %QCA - you should be + using a sub-class. PBKDF2 using SHA1 is recommended for new applications. + + \ingroup UserAPI + +*/ +class QCA_EXPORT KeyDerivationFunction : public Algorithm +{ +public: + /** + Standard copy constructor + + \param from the KeyDerivationFunction to copy from + */ + KeyDerivationFunction(const KeyDerivationFunction &from); + + ~KeyDerivationFunction() override; + + /** + Assignment operator + + Copies the state (including key) from one KeyDerivationFunction + to another + + \param from the KeyDerivationFunction to assign from + */ + KeyDerivationFunction &operator=(const KeyDerivationFunction &from); + + /** + Generate the key from a specified secret and salt value + + \note key length is ignored for some functions + + \param secret the secret (password or passphrase) + \param salt the salt to use + \param keyLength the length of key to return + \param iterationCount the number of iterations to perform + + \return the derived key + */ + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount); + + /** + Generate the key from a specified secret and salt value + + \note key length is ignored for some functions + + \param secret the secret (password or passphrase) + \param salt the salt to use + \param keyLength the length of key to return + \param msecInterval the maximum time to compute the key, in milliseconds + \param iterationCount a pointer to store the number of iteration done for the specified time + + \return the derived key + */ + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount); + + /** + Construct the name of the algorithm + + You can use this to build a standard name string. + You probably only need this method if you are + creating a new subclass. + + \param kdfType the type of key derivation function + \param algType the name of the algorithm to use with the key derivation function + + \return the name of the KDF/algorithm pair + */ + static QString withAlgorithm(const QString &kdfType, const QString &algType); + +protected: + /** + Special constructor for subclass initialisation + + \param type the algorithm to create + \param provider the name of the provider to create the key derivation function in. + */ + KeyDerivationFunction(const QString &type, const QString &provider); + +private: + class Private; + Private *d; +}; + +/** + \class PBKDF1 qca_basic.h QtCrypto + + Password based key derivation function version 1 + + This class implements Password Based Key Derivation Function version 1, + as specified in RFC2898, and also in PKCS#5. + + \ingroup UserAPI +*/ +class QCA_EXPORT PBKDF1 : public KeyDerivationFunction +{ +public: + /** + Standard constructor + + \param algorithm the name of the hashing algorithm to use + \param provider the name of the provider to use, if available + */ + explicit PBKDF1(const QString &algorithm = QStringLiteral("sha1"), const QString &provider = QString()) + : KeyDerivationFunction(withAlgorithm(QStringLiteral("pbkdf1"), algorithm), provider) + { + } +}; + +/** + \class PBKDF2 qca_basic.h QtCrypto + + Password based key derivation function version 2 + + This class implements Password Based Key Derivation Function version 2, + as specified in RFC2898, and also in PKCS#5. + + \ingroup UserAPI +*/ +class QCA_EXPORT PBKDF2 : public KeyDerivationFunction +{ +public: + /** + Standard constructor + + \param algorithm the name of the hashing algorithm to use + \param provider the name of the provider to use, if available + */ + explicit PBKDF2(const QString &algorithm = QStringLiteral("sha1"), const QString &provider = QString()) + : KeyDerivationFunction(withAlgorithm(QStringLiteral("pbkdf2"), algorithm), provider) + { + } +}; + +/** + \class HKDF qca_basic.h QtCrypto + \since 2.3 + + HMAC-based extract-and-expand key derivation function + + This class implements HMAC-based Extract-and-Expand Key Derivation Function, + as specified in RFC5869. + + \ingroup UserAPI +*/ +class QCA_EXPORT HKDF : public Algorithm +{ +public: + /** + Standard constructor + + \param algorithm the name of the hashing algorithm to use + \param provider the name of the provider to use, if available + */ + explicit HKDF(const QString &algorithm = QStringLiteral("sha256"), const QString &provider = QString()); + + /** + Standard copy constructor + + \param from the KeyDerivationFunction to copy from + */ + HKDF(const HKDF &from); + + ~HKDF() override; + + /** + Assignment operator + + Copies the state (including key) from one HKDF + to another + + \param from the HKDF to assign from + */ + HKDF &operator=(const HKDF &from); + + /** + Generate the key from a specified secret, salt value, and an additional info + + \note key length is ignored for some functions + + \param secret the secret (password or passphrase) + \param salt the salt to use + \param info the info to use + \param keyLength the length of key to return + + \return the derived key + */ + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + const InitializationVector &info, + unsigned int keyLength); +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_cert.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_cert.h new file mode 100644 index 0000000000..a5dde9d932 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_cert.h @@ -0,0 +1,2722 @@ +/* + * qca_cert.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_cert.h + + Header file for PGP key and X.509 certificate related classes + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_CERT_H +#define QCA_CERT_H + +#include "qca_core.h" +#include "qca_publickey.h" +#include + +namespace QCA { + +class CertContext; +class CSRContext; +class CRLContext; +class Certificate; +class CRL; +class CertificateCollection; +class CertificateChain; + +/** + Certificate Request Format +*/ +enum CertificateRequestFormat +{ + PKCS10, ///< standard PKCS#10 format + SPKAC ///< Signed Public Key and Challenge (Netscape) format +}; + +/** + Known types of information stored in certificates + + This enumerator offers a convenient way to work with common types. +*/ +enum CertificateInfoTypeKnown +{ + CommonName, ///< The common name (eg person), id = "2.5.4.3" + Email, ///< Email address, id = "GeneralName.rfc822Name" + EmailLegacy, ///< PKCS#9 Email field, id = "1.2.840.113549.1.9.1" + Organization, ///< An organisation (eg company), id = "2.5.4.10" + OrganizationalUnit, ///< An part of an organisation (eg a division or branch), id = "2.5.4.11" + Locality, ///< The locality (eg city, a shire, or part of a state), id = "2.5.4.7" + IncorporationLocality, ///< The locality of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.1" + State, ///< The state within the country, id = "2.5.4.8" + IncorporationState, ///< The state of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.2" + Country, ///< The country, id = "2.5.4.6" + IncorporationCountry, ///< The country of incorporation (EV certificates), id = "1.3.6.1.4.1.311.60.2.1.3" + URI, ///< Uniform Resource Identifier, id = "GeneralName.uniformResourceIdentifier" + DNS, ///< DNS name, id = "GeneralName.dNSName" + IPAddress, ///< IP address, id = "GeneralName.iPAddress" + XMPP ///< XMPP address (see http://www.ietf.org/rfc/rfc3920.txt), id = "1.3.6.1.5.5.7.8.5" +}; + +/** + \class CertificateInfoType qca_cert.h QtCrypto + + Certificate information type + + This class represents a type of information being stored in + a certificate. It can be created either using a known type + (from the Known enumerator) or an identifier string (usually + an OID). Types created either way are interchangeable. + + Types also have the notion of a Section. Some types may + reside in the Distinguished Name field of a certificate, and + some types may reside in the Subject Alternative Name field. + This class is capable of representing a type from either + section. + + In the general case, applications will want to use the + CertificateInfoTypeKnown enumerator types. These are from RFC3280 + (http://www.ietf.org/rfc/rfc3280.txt) except where shown. + + The entries for IncorporationLocality, IncorporationState + and IncorporationCountry are the same as Locality, State + and Country respectively, except that the Extended + Validation (EV) certificate guidelines (published by the + %Certificate Authority / Browser Forum, see + http://www.cabforum.org) distinguish between the place of + where the company does business (which is the Locality / + State / Country combination) and the jurisdiction where the + company is legally incorporated (the IncorporationLocality + / IncorporationState / IncorporationCountry combination). + + \sa Certificate::subjectInfo() and Certificate::issuerInfo() + \sa CRL::issuerInfo() + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateInfoType +{ +public: + /** + Section of the certificate that the information belongs in + */ + enum Section + { + DN, ///< Distinguished name (the primary name) + AlternativeName ///< Alternative name + }; + + /** + Standard constructor + */ + CertificateInfoType(); + + /** + Construct a new type + + The section will be derived by \a known. + + \param known the type as part of the CertificateInfoTypeKnown + enumerator + */ + CertificateInfoType(CertificateInfoTypeKnown known); + + /** + Construct a new type + + \param id the type as an identifier string (OID or internal) + \param section the section this type belongs in + + \sa id + */ + CertificateInfoType(const QString &id, Section section); + + /** + Standard copy constructor + + \param from the certificate information to copy from + */ + CertificateInfoType(const CertificateInfoType &from); + + ~CertificateInfoType(); + + /** + Standard assignment operator + + \param from the certificate information to assign from + */ + CertificateInfoType &operator=(const CertificateInfoType &from); + + /** + The section the type is part of + */ + Section section() const; + + /** + The type as part of the CertificateInfoTypeKnown enumerator + + This function may return a value that does not exist in the + enumerator. In that case, you may use id() to determine the + type. + */ + CertificateInfoTypeKnown known() const; + + /** + The type as an identifier string + + For types that have OIDs, this function returns an OID in string + form. For types that do not have OIDs, this function returns an + internal identifier string whose first character is not a digit + (this allows you to tell the difference between an OID and an + internal identifier). + + It is hereby stated that General Names (of the X.509 Subject + Alternative Name) shall use the internal identifier format + "GeneralName.[rfc field name]". For example, the rfc822Name + field would have the identifier "GeneralName.rfc822Name". + + Applications should not store, use, or compare against internal + identifiers unless the identifiers are explicitly documented + (e.g. GeneralName). + */ + QString id() const; + + /** + Comparison operator + + \param other the certificate information to compare with this + certificate information. + */ + bool operator<(const CertificateInfoType &other) const; + + /** + Comparison operator + + \param other the certificate information to compare with this + certificate information. + */ + bool operator==(const CertificateInfoType &other) const; + + /** + Inequality operator + + \param other the certificate information to compare with this + certificate information. + */ + inline bool operator!=(const CertificateInfoType &other) const + { + return !(*this == other); + } + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class CertificateInfoPair qca_cert.h QtCrypto + + One entry in a certificate information list + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateInfoPair +{ +public: + /** + Standard constructor + */ + CertificateInfoPair(); + + /** + Construct a new pair + + \param type the type of information stored in this pair + \param value the value of the information to be stored + */ + CertificateInfoPair(const CertificateInfoType &type, const QString &value); + + /** + Standard copy constructor + + \param from the information pair to copy from + */ + CertificateInfoPair(const CertificateInfoPair &from); + + ~CertificateInfoPair(); + + /** + Standard assignment operator + + \param from the information pair to assign from + */ + CertificateInfoPair &operator=(const CertificateInfoPair &from); + + /** + The type of information stored in the pair + */ + CertificateInfoType type() const; + + /** + The value of the information stored in the pair + */ + QString value() const; + + /** + Comparison operator + + \param other the certificate information pair to compare with this + certificate information pair. + */ + bool operator==(const CertificateInfoPair &other) const; + + /** + Inequality operator + + \param other the certificate information pair to compare with this + certificate information pair. + */ + inline bool operator!=(const CertificateInfoPair &other) const + { + return !(*this == other); + } + +private: + class Private; + QSharedDataPointer d; +}; + +/** + Known types of certificate constraints + + This enumerator offers a convenient way to work with common types. +*/ +enum ConstraintTypeKnown +{ + // KeyUsage + DigitalSignature, ///< %Certificate can be used to create digital signatures, id = "KeyUsage.digitalSignature" + NonRepudiation, ///< %Certificate can be used for non-repudiation, id = "KeyUsage.nonRepudiation" + KeyEncipherment, ///< %Certificate can be used for encrypting / decrypting keys, id = "KeyUsage.keyEncipherment" + DataEncipherment, ///< %Certificate can be used for encrypting / decrypting data, id = "KeyUsage.dataEncipherment" + KeyAgreement, ///< %Certificate can be used for key agreement, id = "KeyUsage.keyAgreement" + KeyCertificateSign, ///< %Certificate can be used for key certificate signing, id = "KeyUsage.keyCertSign" + CRLSign, ///< %Certificate can be used to sign %Certificate Revocation Lists, id = "KeyUsage.crlSign" + EncipherOnly, ///< %Certificate can only be used for encryption, id = "KeyUsage.encipherOnly" + DecipherOnly, ///< %Certificate can only be used for decryption, id = "KeyUsage.decipherOnly" + + // ExtKeyUsage + ServerAuth, ///< %Certificate can be used for server authentication (e.g. web server), id = "1.3.6.1.5.5.7.3.1". + ///< This is an extended usage constraint. + ClientAuth, ///< %Certificate can be used for client authentication (e.g. web browser), id = "1.3.6.1.5.5.7.3.2". + ///< This is an extended usage constraint. + CodeSigning, ///< %Certificate can be used to sign code, id = "1.3.6.1.5.5.7.3.3". This is an extended usage + ///< constraint. + EmailProtection, ///< %Certificate can be used to sign / encrypt email, id = "1.3.6.1.5.5.7.3.4". This is an + ///< extended usage constraint. + IPSecEndSystem, ///< %Certificate can be used to authenticate a endpoint in IPSEC, id = "1.3.6.1.5.5.7.3.5". This is + ///< an extended usage constraint. + IPSecTunnel, ///< %Certificate can be used to authenticate a tunnel in IPSEC, id = "1.3.6.1.5.5.7.3.6". This is an + ///< extended usage constraint. + IPSecUser, ///< %Certificate can be used to authenticate a user in IPSEC, id = "1.3.6.1.5.5.7.3.7". This is an + ///< extended usage constraint. + TimeStamping, ///< %Certificate can be used to create a "time stamp" signature, id = "1.3.6.1.5.5.7.3.8". This is an + ///< extended usage constraint. + OCSPSigning ///< %Certificate can be used to sign an Online %Certificate Status Protocol (OCSP) assertion, id = + ///< "1.3.6.1.5.5.7.3.9". This is an extended usage constraint. +}; + +/** + \class ConstraintType qca_cert.h QtCrypto + + Certificate constraint + + X.509 certificates can be constrained in their application - that is, some + certificates can only be used for certain purposes. This class is used to + identify an approved purpose for a certificate. + + \note It is common for a certificate to have more than one purpose. + + \ingroup UserAPI +*/ +class QCA_EXPORT ConstraintType +{ +public: + /** + Section of the certificate that the constraint belongs in + */ + enum Section + { + KeyUsage, ///< Stored in the key usage section + ExtendedKeyUsage ///< Stored in the extended key usage section + }; + + /** + Standard constructor + */ + ConstraintType(); + + /** + Construct a new constraint + + The section will be derived by \a known. + + \param known the type as part of the ConstraintTypeKnown + enumerator + */ + ConstraintType(ConstraintTypeKnown known); + + /** + Construct a new constraint + + \param id the type as an identifier string (OID or internal) + \param section the section this type belongs in + + \sa id + */ + ConstraintType(const QString &id, Section section); + + /** + Standard copy constructor + + \param from the constraint type to copy from + */ + ConstraintType(const ConstraintType &from); + + ~ConstraintType(); + + /** + Standard assignment operator + + \param from the constraint type to assign from + */ + ConstraintType &operator=(const ConstraintType &from); + + /** + The section the constraint is part of + */ + Section section() const; + + /** + The type as part of the ConstraintTypeKnown enumerator + + This function may return a value that does not exist in the + enumerator. In that case, you may use id() to determine the + type. + */ + ConstraintTypeKnown known() const; + + /** + The type as an identifier string + + For types that have OIDs, this function returns an OID in string + form. For types that do not have OIDs, this function returns an + internal identifier string whose first character is not a digit + (this allows you to tell the difference between an OID and an + internal identifier). + + It is hereby stated that the KeyUsage bit fields shall use the + internal identifier format "KeyUsage.[rfc field name]". For + example, the keyEncipherment field would have the identifier + "KeyUsage.keyEncipherment". + + Applications should not store, use, or compare against internal + identifiers unless the identifiers are explicitly documented + (e.g. KeyUsage). + */ + QString id() const; + + /** + Comparison operator + + \param other the constraint type to compare with this constraint + */ + bool operator<(const ConstraintType &other) const; + + /** + Comparison operator + + \param other the constraint type to compare with this constraint + */ + bool operator==(const ConstraintType &other) const; + + /** + Inequality operator + + \param other the constraint type to compare with this constraint + */ + inline bool operator!=(const ConstraintType &other) const + { + return !(*this == other); + } + +private: + class Private; + QSharedDataPointer d; +}; + +/** + Specify the intended usage of a certificate +*/ +enum UsageMode +{ + UsageAny = 0x00, ///< Any application, or unspecified + UsageTLSServer = 0x01, ///< server side of a TLS or SSL connection + UsageTLSClient = 0x02, ///< client side of a TLS or SSL connection + UsageCodeSigning = 0x04, ///< code signing certificate + UsageEmailProtection = 0x08, ///< email (S/MIME) certificate + UsageTimeStamping = 0x10, ///< time stamping certificate + UsageCRLSigning = 0x20 ///< certificate revocation list signing certificate +}; + +/** + The validity (or otherwise) of a certificate +*/ +enum Validity +{ + ValidityGood, ///< The certificate is valid + ErrorRejected, ///< The root CA rejected the certificate purpose + ErrorUntrusted, ///< The certificate is not trusted + ErrorSignatureFailed, ///< The signature does not match + ErrorInvalidCA, ///< The Certificate Authority is invalid + ErrorInvalidPurpose, ///< The purpose does not match the intended usage + ErrorSelfSigned, ///< The certificate is self-signed, and is not found in the list of trusted certificates + ErrorRevoked, ///< The certificate has been revoked + ErrorPathLengthExceeded, ///< The path length from the root CA to this certificate is too long + ErrorExpired, ///< The certificate has expired, or is not yet valid (e.g. current time is earlier than notBefore + ///< time) + ErrorExpiredCA, ///< The Certificate Authority has expired + ErrorValidityUnknown = 64 ///< Validity is unknown +}; + +/** + The conditions to validate for a certificate +*/ +enum ValidateFlags +{ + ValidateAll = 0x00, // Verify all conditions + ValidateRevoked = 0x01, // Verify the certificate was not revoked + ValidateExpired = 0x02, // Verify the certificate has not expired + ValidatePolicy = 0x04 // Verify the certificate can be used for a specified purpose +}; + +/** + Certificate properties type + + With this container, the information is not necessarily stored + in the same sequence as the certificate format itself. Use this + container if the order the information is/was stored does not + matter for you (this is the case with most applications). + + Additionally, the EmailLegacy type should not be used with this + container. Use Email instead. +*/ +typedef QMultiMap CertificateInfo; + +/** + \class CertificateInfoOrdered qca_cert.h QtCrypto + + Ordered certificate properties type + + This container stores the information in the same sequence as + the certificate format itself. + + \ingroup UserAPI +*/ +class CertificateInfoOrdered : public QList +{ +public: + /** + Convert to RFC 1779 string format + */ + inline QString toString() const; + + /** + Return a new CertificateInfoOrdered that only contains + the Distinguished Name (DN) types found in this object. + */ + inline CertificateInfoOrdered dnOnly() const; +}; + +/** + Convert to RFC 1779 string format + + \param in the certificate info to convert +*/ +QCA_EXPORT QString orderedToDNString(const CertificateInfoOrdered &in); + +/** + Return a new CertificateInfoOrdered that only contains + the Distinguished Name (DN) types found in the input object. + + \param in the certificate info to extract from +*/ +QCA_EXPORT CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in); + +inline QString CertificateInfoOrdered::toString() const +{ + return orderedToDNString(*this); +} + +inline CertificateInfoOrdered CertificateInfoOrdered::dnOnly() const +{ + return orderedDNOnly(*this); +} + +/** + %Certificate constraints type +*/ +typedef QList Constraints; + +/** + Create a list of unique friendly names among a list of certificates + + \param list the list of certificates for which a friendly name is required. + +*/ +QCA_EXPORT QStringList makeFriendlyNames(const QList &list); + +/** + \class CertificateOptions qca_cert.h QtCrypto + + %Certificate options + + \note In SPKAC mode, all options are ignored except for challenge + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateOptions +{ +public: + /** + Create a Certificate options set + + \param format the format to create the certificate request in + */ + CertificateOptions(CertificateRequestFormat format = PKCS10); + + /** + Standard copy constructor + + \param from the Certificate Options to copy into this object + */ + CertificateOptions(const CertificateOptions &from); + ~CertificateOptions(); + + /** + Standard assignment operator + + \param from the Certificate Options to copy into this object + */ + CertificateOptions &operator=(const CertificateOptions &from); + + /** + test the format type for this certificate + */ + CertificateRequestFormat format() const; + + /** + Specify the format for this certificate + + \param f the format to use + */ + void setFormat(CertificateRequestFormat f); + + /** + Test if the certificate options object is valid + + \return true if the certificate options object is valid + */ + bool isValid() const; + + /** + The challenge part of the certificate + + For CertificateRequest only + + \sa setChallenge + */ + QString challenge() const; + + /** + Information on the subject of the certificate + + \sa setInfo + */ + CertificateInfo info() const; + + /** + Information on the subject of the certificate, in the + exact order the items will be written + + \sa setInfoOrdered + */ + CertificateInfoOrdered infoOrdered() const; + + /** + List the constraints on this certificate + */ + Constraints constraints() const; + + /** + list the policies on this certificate + */ + QStringList policies() const; + + /** + list of URI locations for CRL files + + each URI refers to the same CRL file + + For Certificate creation only + */ + QStringList crlLocations() const; + + /** + list of URI locations for issuer certificate files + + each URI refers to the same issuer file + + For Certificate creation only + */ + QStringList issuerLocations() const; + + /** + list of URI locations for OCSP services + + For Certificate creation only + */ + QStringList ocspLocations() const; + + /** + test if the certificate is a CA cert + + \sa setAsCA + \sa setAsUser + */ + bool isCA() const; + + /** + return the path limit on this certificate + */ + int pathLimit() const; + + /** + The serial number for the certificate + + For Certificate creation only + */ + BigInteger serialNumber() const; + + /** + the first time the certificate will be valid + + For Certificate creation only + */ + QDateTime notValidBefore() const; + + /** + the last time the certificate is valid + + For Certificate creation only + */ + QDateTime notValidAfter() const; + + /** + Specify the challenge associated with this + certificate + + \param s the challenge string + + \sa challenge() + */ + void setChallenge(const QString &s); + + /** + Specify information for the subject associated with the + certificate + + \param info the information for the subject + + \sa info() + */ + void setInfo(const CertificateInfo &info); + + /** + Specify information for the subject associated with the + certificate + + \param info the information for the subject + + \sa info() + */ + void setInfoOrdered(const CertificateInfoOrdered &info); + + /** + set the constraints on the certificate + + \param constraints the constraints to be used for the certificate + */ + void setConstraints(const Constraints &constraints); + + /** + set the policies on the certificate + + \param policies the policies to be used for the certificate + */ + void setPolicies(const QStringList &policies); + + /** + set the CRL locations of the certificate + + each location refers to the same CRL. + + \param locations a list of URIs to CRL files + */ + void setCRLLocations(const QStringList &locations); + + /** + set the issuer certificate locations of the certificate + + each location refers to the same issuer file. + + \param locations a list of URIs to issuer certificate files + */ + void setIssuerLocations(const QStringList &locations); + + /** + set the OCSP service locations of the certificate + + \param locations a list of URIs to OCSP services + */ + void setOCSPLocations(const QStringList &locations); + + /** + set the certificate to be a CA cert + + \param pathLimit the number of intermediate certificates allowable + */ + void setAsCA(int pathLimit = 8); // value from Botan + + /** + set the certificate to be a user cert (this is the default) + */ + void setAsUser(); + + /** + Set the serial number property on this certificate + + \param i the serial number to use + */ + void setSerialNumber(const BigInteger &i); + + /** + Set the validity period for the certificate + + \param start the first time this certificate becomes valid + \param end the last time this certificate is valid + */ + void setValidityPeriod(const QDateTime &start, const QDateTime &end); + +private: + class Private; + Private *d; +}; + +/** + \class Certificate qca_cert.h QtCrypto + + Public Key (X.509) certificate + + This class contains one X.509 certificate + + \ingroup UserAPI +*/ +class QCA_EXPORT Certificate : public Algorithm +{ +public: + /** + Create an empty Certificate + */ + Certificate(); + + /** + Create a Certificate from a PEM encoded file + + \param fileName the name (and path, if required) + of the file that contains the PEM encoded certificate + */ + Certificate(const QString &fileName); + + /** + Create a Certificate with specified options and a specified private + key + + \param opts the options to use + \param key the private key for this certificate + \param provider the provider to use to create this key, if a + particular provider is required + */ + Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider = QString()); + + /** + Standard copy constructor + + \param from the certificate to copy from + */ + Certificate(const Certificate &from); + + ~Certificate() override; + + /** + Standard assignment operator + + \param from the Certificate to assign from + */ + Certificate &operator=(const Certificate &from); + + /** + Test if the certificate is empty (null) + \return true if the certificate is null + */ + bool isNull() const; + + /** + The earliest date that the certificate is valid + */ + QDateTime notValidBefore() const; + + /** + The latest date that the certificate is valid + */ + QDateTime notValidAfter() const; + + /** + Properties of the subject of the certificate, as a QMultiMap + + This is the method that provides information on the + subject organisation, common name, DNS name, and so + on. The list of information types (i.e. the key to + the multi-map) is a CertificateInfoType. The values + are a list of QString. + + An example of how you can iterate over the list is: + \code +foreach( QString dns, info.values(QCA::DNS) ) +{ + std::cout << " " << qPrintable(dns) << std::endl; +} + \endcode + */ + CertificateInfo subjectInfo() const; + + /** + Properties of the subject of the certificate, as + an ordered list (QList of CertificateInfoPair). + + This allows access to the certificate information + in the same order as they appear in a certificate. + Each pair in the list has a type and a value. + + For example: + \code +CertificateInfoOrdered info = cert.subjectInfoOrdered(); +// info[0].type == CommonName +// info[0].value == "example.com" + \endcode + + \sa subjectInfo for an unordered version + \sa issuerInfoOrdered for the ordered information on the issuer + \sa CertificateInfoPair for the elements in the list + */ + CertificateInfoOrdered subjectInfoOrdered() const; + + /** + Properties of the issuer of the certificate + + \sa subjectInfo for how the return value works. + */ + CertificateInfo issuerInfo() const; + + /** + Properties of the issuer of the certificate, as + an ordered list (QList of CertificateInfoPair). + + This allows access to the certificate information + in the same order as they appear in a certificate. + Each pair in the list has a type and a value. + + \sa issuerInfo for an unordered version + \sa subjectInfoOrdered for the ordered information on the subject + \sa CertificateInfoPair for the elements in the list + */ + CertificateInfoOrdered issuerInfoOrdered() const; + + /** + The constraints that apply to this certificate + */ + Constraints constraints() const; + + /** + The policies that apply to this certificate + + Policies are specified as strings containing OIDs + */ + QStringList policies() const; + + /** + List of URI locations for CRL files + + Each URI refers to the same CRL file + */ + QStringList crlLocations() const; + + /** + List of URI locations for issuer certificate files + + Each URI refers to the same issuer file + */ + QStringList issuerLocations() const; + + /** + List of URI locations for OCSP services + */ + QStringList ocspLocations() const; + + /** + The common name of the subject of the certificate + + Common names are normally the name of a person, company or + organisation + */ + QString commonName() const; + + /** + The serial number of the certificate + */ + BigInteger serialNumber() const; + + /** + The public key associated with the subject of the certificate + */ + PublicKey subjectPublicKey() const; + + /** + Test if the Certificate is valid as a %Certificate Authority + + \return true if the Certificate is valid as a %Certificate Authority + */ + bool isCA() const; + + /** + Test if the Certificate is self-signed + + \return true if the certificate is self-signed + */ + bool isSelfSigned() const; + + /** + Test if the Certificate has signed another Certificate + object and is therefore the issuer + + \param other the certificate to test + + \return true if this certificate is the issuer of the argument + */ + bool isIssuerOf(const Certificate &other) const; + + /** + The upper bound of the number of links in the certificate + chain, if any + */ + int pathLimit() const; + + /** + The signature algorithm used for the signature on this certificate + */ + SignatureAlgorithm signatureAlgorithm() const; + + /** + The key identifier associated with the subject + */ + QByteArray subjectKeyId() const; + + /** + The key identifier associated with the issuer + */ + QByteArray issuerKeyId() const; + + /** + Check the validity of a certificate + + \param trusted a collection of trusted certificates + \param untrusted a collection of additional certificates, not + necessarily trusted + \param u the use required for the certificate + \param vf the conditions to validate + + \note This function may block + */ + Validity validate(const CertificateCollection &trusted, + const CertificateCollection &untrusted, + UsageMode u = UsageAny, + ValidateFlags vf = ValidateAll) const; + + /** + Export the Certificate into a DER format + */ + QByteArray toDER() const; + + /** + Export the Certificate into a PEM format + */ + QString toPEM() const; + + /** + Export the Certificate into PEM format in a file + + \param fileName the name of the file to use + */ + bool toPEMFile(const QString &fileName) const; + + /** + Import the certificate from DER + + \param a the array containing the certificate in DER format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the Certificate corresponding to the certificate in the + provided array + */ + static Certificate + fromDER(const QByteArray &a, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the certificate from PEM format + + \param s the string containing the certificate in PEM format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the Certificate corresponding to the certificate in the + provided string + */ + static Certificate fromPEM(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the certificate from a file + + \param fileName the name (and path, if required) of the file + containing the certificate in PEM format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the Certificate corresponding to the certificate in the + provided string + */ + static Certificate + fromPEMFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Test if the subject of the certificate matches a specified host + name + + This will return true (indicating a match), if the specified host + name meets the RFC 2818 validation rules with this certificate. + + If the host is an internationalized domain name, then it must be + provided in unicode format, not in IDNA ACE/punycode format. + + \param host the name of the host to compare to + */ + bool matchesHostName(const QString &host) const; + + /** + Test for equality of two certificates + + \param a the certificate to compare this certificate with + + \return true if the two certificates are the same + */ + bool operator==(const Certificate &a) const; + + /** + Inequality operator + + \param other the certificate to compare this certificate with + */ + inline bool operator!=(const Certificate &other) const + { + return !(*this == other); + } + + /** + \internal + + \param c context (internal) + */ + void change(CertContext *c); + +private: + class Private; + friend class Private; + QSharedDataPointer d; + + friend class CertificateChain; + Validity chain_validate(const CertificateChain &chain, + const CertificateCollection &trusted, + const QList &untrusted_crls, + UsageMode u, + ValidateFlags vf) const; + CertificateChain + chain_complete(const CertificateChain &chain, const QList &issuers, Validity *result) const; +}; + +/** + \class CertificateChain qca_cert.h QtCrypto + + A chain of related Certificates + + CertificateChain is a list (a QList) of certificates that are related by + the signature from one to another. If Certificate C signs Certificate B, + and Certificate B signs Certificate A, then C, B and A form a chain. + + The normal use of a CertificateChain is from a end-user Certificate (called + the primary, equivalent to QList::first()) through some intermediate + Certificates to some other Certificate (QList::last()), which might be a + root %Certificate Authority, but does not need to be. + + You can build up the chain using normal QList operations, such as + QList::append(). + + \sa QCA::CertificateCollection for an alternative way to represent a group + of Certificates that do not necessarily have a chained relationship. + + \ingroup UserAPI +*/ +class CertificateChain : public QList +{ +public: + /** + Create an empty certificate chain + */ + inline CertificateChain() + { + } + + /** + Create a certificate chain, starting at the specified certificate + + \param primary the end-user certificate that forms one end of the + chain + */ + inline CertificateChain(const Certificate &primary) + { + append(primary); + } + + /** + Return the primary (end-user) Certificate + */ + inline const Certificate &primary() const + { + return first(); + } + + /** + Check the validity of a certificate chain + + \param trusted a collection of trusted certificates + \param untrusted_crls a list of additional CRLs, not necessarily + trusted + \param u the use required for the primary certificate + \param vf the conditions to validate + + \note This function may block + + \sa Certificate::validate() + */ + inline Validity validate(const CertificateCollection &trusted, + const QList &untrusted_crls = QList(), + UsageMode u = UsageAny, + ValidateFlags vf = ValidateAll) const; + + /** + Complete a certificate chain for the primary certificate, using the + rest of the certificates in the chain object, as well as those in + \a issuers, as possible issuers in the chain. If there are issuers + missing, then the chain might be incomplete (at the worst case, if + no issuers exist for the primary certificate, then the resulting + chain will consist of just the primary certificate). Use the + \a result argument to find out if there was a problem during + completion. A result of ValidityGood means the chain was completed + successfully. + + The newly constructed CertificateChain is returned. + + If the certificate chain is empty, then this will return an empty + CertificateChain object. + + \param issuers a pool of issuers to draw from as necessary + \param result the result of the completion operation + + \note This function may block + + \sa validate + */ + inline CertificateChain complete(const QList &issuers = QList(), + Validity *result = nullptr) const; +}; + +inline Validity CertificateChain::validate(const CertificateCollection &trusted, + const QList &untrusted_crls, + UsageMode u, + ValidateFlags vf) const +{ + if (isEmpty()) + return ErrorValidityUnknown; + return first().chain_validate(*this, trusted, untrusted_crls, u, vf); +} + +inline CertificateChain CertificateChain::complete(const QList &issuers, Validity *result) const +{ + if (isEmpty()) + return CertificateChain(); + return first().chain_complete(*this, issuers, result); +} + +/** + \class CertificateRequest qca_cert.h QtCrypto + + %Certificate Request + + A CertificateRequest is a unsigned request for a Certificate + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateRequest : public Algorithm +{ +public: + /** + Create an empty certificate request + */ + CertificateRequest(); + + /** + Create a certificate request based on the contents of a file + + \param fileName the file (and path, if necessary) containing a PEM + encoded certificate request + */ + CertificateRequest(const QString &fileName); + + /** + Create a certificate request based on specified options + + \param opts the options to use in the certificate request + \param key the private key that matches the certificate being + requested + \param provider the provider to use, if a specific provider is + required + */ + CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider = QString()); + + /** + Standard copy constructor + + \param from the request to copy from + */ + CertificateRequest(const CertificateRequest &from); + + ~CertificateRequest() override; + + /** + Standard assignment operator + + \param from the request to assign from + */ + CertificateRequest &operator=(const CertificateRequest &from); + + /** + test if the certificate request is empty + + \return true if the certificate request is empty, otherwise false + */ + bool isNull() const; + + /** + Test if the certificate request can use a specified format + + \param f the format to test for + \param provider the provider to use, if a specific provider is + required + + \return true if the certificate request can use the specified + format + */ + static bool canUseFormat(CertificateRequestFormat f, const QString &provider = QString()); + + /** + the format that this Certificate request is in + */ + CertificateRequestFormat format() const; + + /** + Information on the subject of the certificate being requested + + \note this only applies to PKCS#10 format certificate requests + + \sa subjectInfoOrdered for a version that maintains order + in the subject information. + */ + CertificateInfo subjectInfo() const; + + /** + Information on the subject of the certificate being requested, as + an ordered list (QList of CertificateInfoPair). + + \note this only applies to PKCS#10 format certificate requests + + \sa subjectInfo for a version that does not maintain order, but + allows access based on a multimap. + \sa CertificateInfoPair for the elements in the list + */ + CertificateInfoOrdered subjectInfoOrdered() const; + + /** + The constraints that apply to this certificate request + + \note this only applies to PKCS#10 format certificate requests + */ + Constraints constraints() const; + + /** + The policies that apply to this certificate request + + \note this only applies to PKCS#10 format certificate requests + */ + QStringList policies() const; + + /** + The public key belonging to the issuer + */ + PublicKey subjectPublicKey() const; + + /** + Test if this %Certificate Request is for a %Certificate Authority + certificate + + \note this only applies to PKCS#10 format certificate requests + */ + bool isCA() const; + + /** + The path limit for the certificate in this %Certificate Request + + \note this only applies to PKCS#10 format certificate requests + */ + int pathLimit() const; + + /** + The challenge associated with this certificate request + */ + QString challenge() const; + + /** + The algorithm used to make the signature on this certificate + request + */ + SignatureAlgorithm signatureAlgorithm() const; + + /** + Test for equality of two certificate requests + + \param csr the certificate request to be compared to this certificate request + + \return true if the two certificate requests are the same + */ + bool operator==(const CertificateRequest &csr) const; + + /** + Inequality operator + + \param other the certificate request to be compared to this certificate request + */ + inline bool operator!=(const CertificateRequest &other) const + { + return !(*this == other); + } + + /** + Export the %Certificate Request into a DER format + + \note this only applies to PKCS#10 format certificate requests + */ + QByteArray toDER() const; + + /** + Export the %Certificate Request into a PEM format + + \note this only applies to PKCS#10 format certificate requests + */ + QString toPEM() const; + + /** + Export the Certificate into PEM format in a file + + \param fileName the name of the file to use + + \note this only applies to PKCS#10 format certificate requests + */ + bool toPEMFile(const QString &fileName) const; + + /** + Import the certificate request from DER + + \param a the array containing the certificate request in DER format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateRequest corresponding to the certificate + request in the provided array + + \note this only applies to PKCS#10 format certificate requests + */ + static CertificateRequest + fromDER(const QByteArray &a, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the certificate request from PEM format + + \param s the string containing the certificate request in PEM + format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateRequest corresponding to the certificate + request in the provided string + + \note this only applies to PKCS#10 format certificate requests + */ + static CertificateRequest + fromPEM(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the certificate request from a file + + \param fileName the name (and path, if required) of the file + containing the certificate request in PEM format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateRequest corresponding to the certificate + request in the provided string + + \note this only applies to PKCS#10 format certificate requests + */ + static CertificateRequest + fromPEMFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Export the CertificateRequest to a string + + \return the string corresponding to the certificate request + + \note this only applies to SPKAC format certificate requests + */ + QString toString() const; + + /** + Import the CertificateRequest from a string + + \param s the string containing to the certificate request + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateRequest corresponding to the certificate + request in the provided string + + \note this only applies to SPKAC format certificate requests + */ + static CertificateRequest + fromString(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + \internal + + \param c context (internal) + */ + void change(CSRContext *c); + +private: + class Private; + friend class Private; + QSharedDataPointer d; +}; + +/** + \class CRLEntry qca_cert.h QtCrypto + + Part of a CRL representing a single certificate + + \ingroup UserAPI +*/ +class QCA_EXPORT CRLEntry +{ +public: + /** + The reason why the certificate has been revoked + */ + enum Reason + { + Unspecified, ///< reason is unknown + KeyCompromise, ///< private key has been compromised + CACompromise, ///< certificate authority has been compromised + AffiliationChanged, + Superseded, ///< certificate has been superseded + CessationOfOperation, + CertificateHold, ///< certificate is on hold + RemoveFromCRL, ///< certificate was previously in a CRL, but is now valid + PrivilegeWithdrawn, + AACompromise ///< attribute authority has been compromised + }; + + /** + create an empty CRL entry + */ + CRLEntry(); + + /** + create a CRL entry + + \param c the certificate to revoke + \param r the reason that the certificate is being revoked + */ + explicit CRLEntry(const Certificate &c, Reason r = Unspecified); + + /** + create a CRL entry + + \param serial the serial number of the Certificate being revoked + \param time the time the Certificate was revoked (or will be + revoked) + \param r the reason that the certificate is being revoked + */ + CRLEntry(const BigInteger serial, const QDateTime &time, Reason r = Unspecified); + + /** + Copy constructor + + \param from the CRLEntry to copy from + */ + CRLEntry(const CRLEntry &from); + + ~CRLEntry(); + + /** + Standard assignment operator + + \param from the CRLEntry to copy from + */ + CRLEntry &operator=(const CRLEntry &from); + + /** + The serial number of the certificate that is the subject of this CRL entry + */ + BigInteger serialNumber() const; + + /** + The time this CRL entry was created + */ + QDateTime time() const; + + /** + Test if this CRL entry is empty + */ + bool isNull() const; + + /** + The reason that this CRL entry was created + + Alternatively, you might like to think of this as the reason that + the subject certificate has been revoked + */ + Reason reason() const; + + /** + Test if one CRL entry is "less than" another + + CRL entries are compared based on their serial number + + \param a the CRL entry to be compared to this CRL entry. + */ + bool operator<(const CRLEntry &a) const; + + /** + Test for equality of two CRL Entries + + \param a the CRL entry to be compared to this CRL entry. + + \return true if the two certificates are the same + */ + bool operator==(const CRLEntry &a) const; + + /** + Inequality operator + + \param other the CRL entry to be compared to this CRL entry. + */ + inline bool operator!=(const CRLEntry &other) const + { + return !(*this == other); + } + +private: + BigInteger _serial; + QDateTime _time; + Reason _reason; + + class Private; + Private *d; +}; + +/** + \class CRL qca_cert.h QtCrypto + + %Certificate Revocation List + + A %CRL is a list of certificates that are special in some + way. The normal reason for including a certificate on a %CRL + is that the certificate should no longer be used. For + example, if a key is compromised, then the associated + certificate may no longer provides appropriate + security. There are other reasons why a certificate may be + placed on a %CRL, as shown in the CRLEntry::Reason + enumeration. + + \sa CertificateCollection for a way to handle Certificates + and CRLs as a single entity. + \sa CRLEntry for the %CRL segment representing a single Certificate. + + \ingroup UserAPI +*/ +class QCA_EXPORT CRL : public Algorithm +{ +public: + CRL(); + + /** + Standard copy constructor + + \param from the revocation list to copy from + */ + CRL(const CRL &from); + + ~CRL() override; + + /** + Standard assignment operator + + \param from the revocation list to assign from + */ + CRL &operator=(const CRL &from); + + /** + Test if the CRL is empty + + \return true if the CRL is empty, otherwise return false + */ + bool isNull() const; + + /** + Information on the issuer of the CRL as a QMultiMap. + + \sa issuerInfoOrdered for a version that maintains the order + of information fields as per the underlying CRL. + */ + CertificateInfo issuerInfo() const; + + /** + Information on the issuer of the CRL as an ordered list + (QList of CertificateInfoPair). + + \sa issuerInfo for a version that allows lookup based on + a multimap. + \sa CertificateInfoPair for the elements in the list + */ + CertificateInfoOrdered issuerInfoOrdered() const; + + /** + The CRL serial number. Note that serial numbers are a + CRL extension, and not all certificates have one. + + \return the CRL serial number, or -1 if there is no serial number + */ + int number() const; + + /** + the time that this CRL became (or becomes) valid + */ + QDateTime thisUpdate() const; + + /** + the time that this CRL will be obsoleted + + you should obtain an updated CRL at this time + */ + QDateTime nextUpdate() const; + + /** + a list of the revoked certificates in this CRL + */ + QList revoked() const; + + /** + The signature algorithm used for the signature on this CRL + */ + SignatureAlgorithm signatureAlgorithm() const; + + /** + The key identification of the CRL issuer + */ + QByteArray issuerKeyId() const; + + /** + Test for equality of two %Certificate Revocation Lists + + \param a the CRL to be compared to this CRL + + \return true if the two CRLs are the same + */ + bool operator==(const CRL &a) const; + + /** + Inequality operator + + \param other the CRL to be compared to this CRL + */ + inline bool operator!=(const CRL &other) const + { + return !(*this == other); + } + + /** + Export the %Certificate Revocation List (CRL) in DER format + + \return an array containing the CRL in DER format + */ + QByteArray toDER() const; + + /** + Export the %Certificate Revocation List (CRL) in PEM format + + \return a string containing the CRL in PEM format + */ + QString toPEM() const; + + /** + Export the %Certificate Revocation List (CRL) into PEM format in a + file + + \param fileName the name of the file to use + */ + bool toPEMFile(const QString &fileName) const; + + /** + Import a DER encoded %Certificate Revocation List (CRL) + + \param a the array containing the CRL in DER format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CRL corresponding to the contents of the array + */ + static CRL fromDER(const QByteArray &a, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import a PEM encoded %Certificate Revocation List (CRL) + + \param s the string containing the CRL in PEM format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CRL corresponding to the contents of the string + */ + static CRL fromPEM(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import a PEM encoded %Certificate Revocation List (CRL) from a file + + \param fileName the name (and path, if required) of the file + containing the certificate in PEM format + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CRL in the file + */ + static CRL + fromPEMFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + \internal + + \param c context (internal) + */ + void change(CRLContext *c); + +private: + class Private; + friend class Private; + QSharedDataPointer d; +}; + +/** + \class CertificateCollection qca_cert.h QtCrypto + + Bundle of Certificates and CRLs + + CertificateCollection provides a bundle of Certificates and Certificate + Revocation Lists (CRLs), not necessarily related. + + \sa QCA::CertificateChain for a representation of a chain of Certificates + related by signatures. + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateCollection +{ +public: + /** + Create an empty Certificate / CRL collection + */ + CertificateCollection(); + + /** + Standard copy constructor + + \param from the CertificateCollection to copy from + */ + CertificateCollection(const CertificateCollection &from); + + ~CertificateCollection(); + + /** + Standard assignment operator + + \param from the CertificateCollection to copy from + */ + CertificateCollection &operator=(const CertificateCollection &from); + + /** + Append a Certificate to this collection + + \param cert the Certificate to add to this CertificateCollection + */ + void addCertificate(const Certificate &cert); + + /** + Append a CRL to this collection + + \param crl the certificate revokation list to add to this + CertificateCollection + */ + void addCRL(const CRL &crl); + + /** + The Certificates in this collection + */ + QList certificates() const; + + /** + The CRLs in this collection + */ + QList crls() const; + + /** + Add another CertificateCollection to this collection + + \param other the CertificateCollection to add to this collection + */ + void append(const CertificateCollection &other); + + /** + Add another CertificateCollection to this collection + + \param other the CertificateCollection to add to this collection + */ + CertificateCollection operator+(const CertificateCollection &other) const; + + /** + Add another CertificateCollection to this collection + + \param other the CertificateCollection to add to this collection + */ + CertificateCollection &operator+=(const CertificateCollection &other); + + /** + test if the CertificateCollection can be imported and exported to + PKCS#7 format + + \param provider the provider to use, if a specific provider is + required + + \return true if the CertificateCollection can be imported and + exported to PKCS#7 format + */ + static bool canUsePKCS7(const QString &provider = QString()); + + /** + export the CertificateCollection to a plain text file + + \param fileName the name (and path, if required) to write the + contents of the CertificateCollection to + + \return true if the export succeeded, otherwise false + */ + bool toFlatTextFile(const QString &fileName); + + /** + export the CertificateCollection to a PKCS#7 file + + \param fileName the name (and path, if required) to write the + contents of the CertificateCollection to + \param provider the provider to use, if a specific provider is + required + + \return true if the export succeeded, otherwise false + */ + bool toPKCS7File(const QString &fileName, const QString &provider = QString()); + + /** + import a CertificateCollection from a text file + + \param fileName the name (and path, if required) to read the + certificate collection from + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateCollection corresponding to the contents of + the file specified in fileName + */ + static CertificateCollection + fromFlatTextFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + import a CertificateCollection from a PKCS#7 file + + \param fileName the name (and path, if required) to read the + certificate collection from + \param result a pointer to a ConvertResult, which if not-null will + be set to the conversion status + \param provider the provider to use, if a specific provider is + required + + \return the CertificateCollection corresponding to the contents of + the file specified in fileName + */ + static CertificateCollection + fromPKCS7File(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class CertificateAuthority qca_cert.h QtCrypto + + A %Certificate Authority is used to generate Certificates and + %Certificate Revocation Lists (CRLs). + + \ingroup UserAPI +*/ +class QCA_EXPORT CertificateAuthority : public Algorithm +{ +public: + /** + Create a new %Certificate Authority + + \param cert the CA certificate + \param key the private key associated with the CA certificate + \param provider the provider to use, if a specific provider is + required + */ + CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider); + + /** + Copy constructor + + \param from the CertificateAuthority to copy from + */ + CertificateAuthority(const CertificateAuthority &from); + + ~CertificateAuthority() override; + + /** + Standard assignment operator + + \param from the CertificateAuthority to copy from + */ + CertificateAuthority &operator=(const CertificateAuthority &from); + + /** + The Certificate belonging to the %CertificateAuthority + + This is the Certificate that was passed as an argument to the + constructor + */ + Certificate certificate() const; + + /** + Create a new Certificate by signing the provider CertificateRequest + + \param req the CertificateRequest to sign + \param notValidAfter the last date that the Certificate will be + valid + */ + Certificate signRequest(const CertificateRequest &req, const QDateTime ¬ValidAfter) const; + + /** + Create a new Certificate + + \param key the Public Key to use to create the Certificate + \param opts the options to use for the new Certificate + */ + Certificate createCertificate(const PublicKey &key, const CertificateOptions &opts) const; + + /** + Create a new %Certificate Revocation List (CRL) + + \param nextUpdate the date that the CRL will be updated + + \return an empty CRL + */ + CRL createCRL(const QDateTime &nextUpdate) const; + + /** + Update the CRL to include new entries + + \param crl the CRL to update + \param entries the entries to add to the CRL + \param nextUpdate the date that this CRL will be updated + + \return the update CRL + */ + CRL updateCRL(const CRL &crl, const QList &entries, const QDateTime &nextUpdate) const; + +private: + class Private; + Private *d; +}; + +/** + \class KeyBundle qca_cert.h QtCrypto + + Certificate chain and private key pair + + KeyBundle is essentially a convience class that holds a + certificate chain and an associated private key. This class + has a number of methods that make it particularly suitable + for accessing a PKCS12 (.p12) format file, however it can + be used as just a container for a Certificate, its + associated PrivateKey and optionally additional + X.509 Certificate that form a chain. + + For more information on PKCS12 "Personal Information + Exchange Syntax Standard", see ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf. + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyBundle +{ +public: + /** + Create an empty KeyBundle + */ + KeyBundle(); + + /** + Create a KeyBundle from a PKCS12 (.p12) encoded + file + + This constructor requires appropriate plugin (provider) + support. You must check for the "pkcs12" feature + before using this constructor. + + \param fileName the name of the file to read from + \param passphrase the passphrase that is applicable to the file + + \sa fromFile for a more flexible version of the + same capability. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + explicit KeyBundle(const QString &fileName, const SecureArray &passphrase = SecureArray()); + + /** + Standard copy constructor + + \param from the KeyBundle to use as source + */ + KeyBundle(const KeyBundle &from); + + ~KeyBundle(); + + /** + Standard assignment operator + + \param from the KeyBundle to use as source + */ + KeyBundle &operator=(const KeyBundle &from); + + /** + Test if this key is empty (null) + */ + bool isNull() const; + + /** + The name associated with this key. + + This is also known as the "friendly name", and if + present, is typically suitable to be displayed to + the user. + + \sa setName + */ + QString name() const; + + /** + The public certificate part of this bundle + + \sa setCertificateChainAndKey + */ + CertificateChain certificateChain() const; + + /** + The private key part of this bundle + + \sa setCertificateChainAndKey + */ + PrivateKey privateKey() const; + + /** + Specify the name of this bundle + + \param s the name to use + */ + void setName(const QString &s); + + /** + Set the public certificate and private key + + \param c the CertificateChain containing the public part of the + Bundle + \param key the private key part of the Bundle + + \sa privateKey, certificateChain for getters + */ + void setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key); + + /** + Export the key bundle to an array in PKCS12 format. + + This method requires appropriate plugin (provider) + support - you must check for the "pkcs12" feature, + as shown below. + + \code +if( QCA::isSupported("pkcs12") ) +{ + // can use I/O + byteArray = bundle.toArray( "pass phrase" ); +} +else +{ + // not possible to use I/O +} + \endcode + + \param passphrase the passphrase to use to protect the bundle + \param provider the provider to use, if a specific provider is + required + */ + QByteArray toArray(const SecureArray &passphrase, const QString &provider = QString()) const; + + /** + Export the key bundle to a file in PKCS12 (.p12) format + + This method requires appropriate plugin (provider) + support - you must check for the "pkcs12" feature, + as shown below. + + \code +if( QCA::isSupported("pkcs12") ) +{ + // can use I/O + bool result = bundle.toFile( filename, "pass phrase" ); +} +else +{ + // not possible to use I/O +} + \endcode + + \param fileName the name of the file to save to + \param passphrase the passphrase to use to protect the bundle + \param provider the provider to use, if a specific provider is + required + */ + bool toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider = QString()) const; + + /** + Import the key bundle from an array in PKCS12 format + + This method requires appropriate plugin (provider) + support - you must check for the "pkcs12" feature, + as shown below. + + \code +if( QCA::isSupported("pkcs12") ) +{ + // can use I/O + bundle = QCA::KeyBundle::fromArray( array, "pass phrase" ); +} +else +{ + // not possible to use I/O +} + \endcode + + \param a the array to import from + \param passphrase the passphrase for the encoded bundle + \param result pointer to the result of the import process + \param provider the provider to use, if a specific provider is + required + + \sa QCA::KeyLoader for an asynchronous loader approach. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + static KeyBundle fromArray(const QByteArray &a, + const SecureArray &passphrase = SecureArray(), + ConvertResult *result = nullptr, + const QString &provider = QString()); + + /** + Import the key bundle from a file in PKCS12 (.p12) format + + This method requires appropriate plugin (provider) + support - you must check for the "pkcs12" feature, + as shown below. + + \code +if( QCA::isSupported("pkcs12") ) +{ + // can use I/O + bundle = QCA::KeyBundle::fromFile( filename, "pass phrase" ); +} +else +{ + // not possible to use I/O +} + \endcode + + \param fileName the name of the file to read from + \param passphrase the passphrase for the encoded bundle + \param result pointer to the result of the import process + \param provider the provider to use, if a specific provider is + required + + \sa QCA::KeyLoader for an asynchronous loader approach. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + static KeyBundle fromFile(const QString &fileName, + const SecureArray &passphrase = SecureArray(), + ConvertResult *result = nullptr, + const QString &provider = QString()); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class PGPKey qca_cert.h QtCrypto + + Pretty Good Privacy key + + This holds either a reference to an item in a real PGP keyring, + or a standalone item created using the from*() functions. + + Note that with the latter method, the key is of no use besides + being informational. The key must be in a keyring + (that is, inKeyring() == true) to actually do crypto with it. + + \ingroup UserAPI +*/ +class QCA_EXPORT PGPKey : public Algorithm +{ +public: + /** + Create an empty PGP key + */ + PGPKey(); + + /** + Create a PGP key from an encoded file + + \param fileName the name (and path, if required) of the file + that the PGP key is to be loaded from. + + \sa fromFile for a version that allows better error checking / validation + \sa toFile for a method to write out the key. + */ + PGPKey(const QString &fileName); + + /** + Standard copy constructor + + \param from the PGPKey to use as the source + */ + PGPKey(const PGPKey &from); + + ~PGPKey() override; + + /** + Standard assignment operator + + \param from the PGPKey to use as the source + */ + PGPKey &operator=(const PGPKey &from); + + /** + Test if the PGP key is empty (null) + + \return true if the PGP key is null + */ + bool isNull() const; + + /** + The Key identification for the PGP key + */ + QString keyId() const; + + /** + The primary user identification for the key + */ + QString primaryUserId() const; + + /** + The list of all user identifications associated with the key + */ + QStringList userIds() const; + + /** + Test if the PGP key is the secret key + + \return true if the PGP key is the secret key + */ + bool isSecret() const; + + /** + The creation date for the key + */ + QDateTime creationDate() const; + + /** + The expiration date for the key + */ + QDateTime expirationDate() const; + + /** + The key fingerpint + + This will return the PGP fingerprint as a string. It comprises 40 + hex digits, without spaces. + */ + QString fingerprint() const; + + /** + Test if this key is in a keyring + + \return true if the key is in a keyring + + \note keys that are not in a keyring cannot be used for encryption, + decryption, signing or verification + */ + bool inKeyring() const; + + /** + Test if the key is trusted + + \return true if the key is trusted + */ + bool isTrusted() const; + + /** + Export the key to an array. + + This will export the key in a binary format (that is, not in an + "ascii armoured" form). + + \sa fromArray for a static import method. + \sa toString for an "ascii armoured" export method. + */ + QByteArray toArray() const; + + /** + Export the key to a string + + This will export the key in an "ascii armoured" form. + + \sa fromString for a static import method. + \sa toArray for a binary format export method. + */ + QString toString() const; + + /** + Export the key to a file + + \param fileName the name of the file to save the key to + */ + bool toFile(const QString &fileName) const; + + /** + Import the key from an array + + \param a the array to import from + \param result if not null, this will be set to the result of the + import process + \param provider the provider to use, if a particular provider is + required + */ + static PGPKey fromArray(const QByteArray &a, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the key from a string + + \param s the string to import from + \param result if not null, this will be set to the result of the + import process + \param provider the provider to use, if a particular provider is + required + */ + static PGPKey fromString(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import the key from a file + + \param fileName string containing the name of the file to import + from + \param result if not null, this will be set to the result of the + import process + \param provider the provider to use, if a particular provider is + required + */ + static PGPKey + fromFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + +private: + class Private; + Private *d; +}; + +/** + \class KeyLoader qca_cert.h QtCrypto + + Asynchronous private key loader + + GUI applications generally must use KeyLoader to load private keys. This + is because the synchronous private key loading functions, for example + QCA::PrivateKey::fromPEMFile(), cannot be used within the same thread as an + EventHandler, and most GUI applications will use EventHandler from the main + thread. KeyLoader does not have this problem. It can be used from any + thread, including the same thread as EventHandler. + + The KeyLoader class allows you to asynchronously load stand-alone private + keys (QCA::PrivateKey) or private keys with a certificate (QCA::KeyBundle) + with a signal that advises of completion. + + To use this class to load a PrivateKey, you create a KeyLoader object then + use one of the loadPrivateKeyFrom...() functions, depending on the format + for your key. These functions return immediately. When you get the + finished() signal, you can check that the loading operation succeeded + (using convertResult()) and then obtain the PrivateKey using the + privateKey() function. + + The same process applies for loading a KeyBundle, except that you use + either loadKeyBundleFromFile() or loadKeyBundleFromArray() instead of the + loadPrivateKeyFrom...() function, and use keyBundle() instead of + privateKey(). + + The loader may need a passphrase to complete the loading of the key or key + bundle. You should use the QCA::EventHandler class to ensure that you deal + with this correctly. + + \note %QCA also provides synchronous private key loading using + QCA::PrivateKey::fromPEMFile(), QCA::PrivateKey::fromPEM() and + QCA::PrivateKey::fromDER(). %QCA provides synchronous key bundle loading + using QCA::KeyBundle::fromArray() and QCA::KeyBundle::fromFile(). + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyLoader : public QObject +{ + Q_OBJECT +public: + /** + Create a KeyLoader object. + + \param parent the parent object for this object + */ + KeyLoader(QObject *parent = nullptr); + ~KeyLoader() override; + + /** + Initiate an asynchronous loading of a PrivateKey from a PEM format + file. + + This function will return immediately. + + \param fileName the name of the file (and path, if necessary) to + load the key from + */ + void loadPrivateKeyFromPEMFile(const QString &fileName); + + /** + Initiate an asynchronous loading of a PrivateKey from a PEM format + string. + + This function will return immediately. + + \param s the string containing the PEM formatted key + */ + void loadPrivateKeyFromPEM(const QString &s); + + /** + Initiate an asynchronous loading of a PrivateKey from a DER format + array. + + This function will return immediately. + + \param a the array containing the DER formatted key + */ + void loadPrivateKeyFromDER(const SecureArray &a); + + /** + Initiate an asynchronous loading of a KeyBundle from a file + + This function will return immediately. + + \param fileName the name of the file (and path, if necessary) to + load the key bundle from + */ + void loadKeyBundleFromFile(const QString &fileName); + + /** + Initiate an asynchronous loading of a KeyBundle from an array + + This function will return immediately. + + \param a the array containing the key bundle + */ + void loadKeyBundleFromArray(const QByteArray &a); + + /** + The result of the loading process. + + This is not valid until the finished() signal has been emitted. + */ + ConvertResult convertResult() const; + + /** + The private key that has been loaded. + + This is only valid if loadPrivateKeyFromPEMFile(), + loadPrivateKeyFromPEM() or loadPrivateKeyFromDER() has been used, + the load has completed (that is, finished() has been emitted), and + the conversion succeeded (that is, convertResult() returned + ConvertGood). + */ + PrivateKey privateKey() const; + + /** + The key bundle that has been loaded. + + This is only valid if loadKeyBundleFromFile() or + loadKeyBundleFromArray() has been used, the load has completed + (that is, finished() has been emitted), and the conversion + succeeded (that is, convertResult() returned ConvertGood). + */ + KeyBundle keyBundle() const; + +Q_SIGNALS: + /** + Signal that is emitted when the load process has completed. + + \note The load process may not have completed successfully - check + the result of convertResult() to confirm this before using the + privateKey() or keyBundle() results. + */ + void finished(); + +private: + Q_DISABLE_COPY(KeyLoader) + + class Private; + friend class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_core.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_core.h new file mode 100644 index 0000000000..423281ac74 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_core.h @@ -0,0 +1,1815 @@ +/* + * qca_core.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * Copyright (C) 2014-2016 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_core.h + + Header file for core %QCA infrastructure + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_CORE_H +#define QCA_CORE_H + +#include "qca_export.h" +#include "qca_support.h" +#include "qca_tools.h" +#include "qca_version.h" +#include +#include +#include +#include +#include + +/** + The current version of %QCA. + + This is equivalent to ::QCA_VERSION, except it provides + a runtime check of the version of %QCA that is being used. +*/ +QCA_EXPORT int qcaVersion(); + +/** + The current version of %QCA. + + This is equivalent to ::QCA_VERSION_STR, except it provides + a runtime check of the version of %QCA that is being used. +*/ +QCA_EXPORT const char *qcaVersionStr(); + +/** + The current version of %QCA. + + This is equivalent to ::QCA_MAJOR_VERSION, except it provides + a runtime check of the version of %QCA that is being used. +*/ +QCA_EXPORT int qcaMajorVersion(); + +/** + The current version of %QCA. + + This is equivalent to ::QCA_MINOR_VERSION, except it provides + a runtime check of the version of %QCA that is being used. +*/ +QCA_EXPORT int qcaMinorVersion(); + +/** + The current version of %QCA. + + This is equivalent to ::QCA_PATCH_VERSION, except it provides + a runtime check of the version of %QCA that is being used. +*/ +QCA_EXPORT int qcaPatchVersion(); + +/** + QCA - the Qt Cryptographic Architecture +*/ +namespace QCA { + +class Provider; +class Random; +class CertificateCollection; +class Global; +class KeyStore; +class KeyStoreEntry; +class KeyStoreInfo; +class KeyStoreManager; +class Logger; + +/** + Convenience representation for the plugin providers + + You can get a list of providers using the providers() + function + + \sa ProviderListIterator + \sa providers() +*/ +typedef QList ProviderList; + +/** + Mode settings for memory allocation + + QCA can use secure memory, however most operating systems + restrict the amount of memory that can be pinned by user + applications, to prevent a denial-of-service attack. + + QCA supports two approaches to getting memory - the mlock + method, which generally requires root (administrator) level + privileges, and the mmap method which is not as secure, but + which should be able to be used by any process. + + \sa Initializer +*/ +enum MemoryMode +{ + Practical, ///< mlock and drop root if available, else mmap + Locking, ///< mlock and drop root + LockingKeepPrivileges ///< mlock, retaining root privileges +}; + +/** + Direction settings for symmetric algorithms + + For some algorithms, it makes sense to have a "direction", such + as Cipher algorithms which can be used to encrypt or decrypt. +*/ +enum Direction +{ + Encode, ///< Operate in the "forward" direction; for example, encrypting + Decode ///< Operate in the "reverse" direction; for example, decrypting +}; + +/** + Initialise %QCA. + This call is not normally required, because it is cleaner + to use an Initializer. +*/ +QCA_EXPORT void init(); + +/** + \overload + + \param m the MemoryMode to use + \param prealloc the amount of memory in kilobytes to allocate + for secure storage +*/ +QCA_EXPORT void init(MemoryMode m, int prealloc); + +/** + Clean up routine + + This routine cleans up %QCA, including memory allocations + This call is not normally required, because it is cleaner + to use an Initializer +*/ +QCA_EXPORT void deinit(); + +/** + Test if secure storage memory is available + + \return true if secure storage memory is available +*/ +QCA_EXPORT bool haveSecureMemory(); + +/** + Test if secure random is available + + Secure random is considered available if the global random + provider is not the default provider. + + \return true if secure random is available +*/ +QCA_EXPORT bool haveSecureRandom(); + +/** + Test if a capability (algorithm) is available. + + Since capabilities are made available at runtime, you + should always check before using a capability the first + time, as shown below. + \code +QCA::init(); +if(!QCA::isSupported("sha1")) + printf("SHA1 not supported!\n"); +else +{ + QString result = QCA::SHA1::hashToString(myString); + printf("sha1(\"%s\") = [%s]\n", myString.data(), qPrintable(result)); +} + \endcode + + \param features the name of the capability to test for + \param provider if specified, only check for the capability in that + specific provider. If not provided, or provided as an empty + string, then check for capabilities in all available providers + \return true if the capability is available, otherwise false + + Note that you can test for a combination of capabilities, + using a comma delimited list: + \code +QCA::isSupported("sha1,md5"): + \endcode + which will return true if all of the capabilities listed + are present. +*/ +QCA_EXPORT bool isSupported(const char *features, const QString &provider = QString()); + +/** + \overload + + \param features a list of features to test for + \param provider if specified, only check for the capability in that + specific provider. If not provided, or provided as an empty + string, then check for capabilities in all available providers +*/ +QCA_EXPORT bool isSupported(const QStringList &features, const QString &provider = QString()); + +/** + Generate a list of all the supported features in plugins, + and in built in capabilities + + \return a list containing the names of the features + + The following code writes a list of features to standard out + \code +QStringList capabilities; +capabilities = QCA::supportedFeatures(); +std::cout << "Supported:" << capabilities.join(",") << std::endl; + \endcode + \sa isSupported(const char *features) + \sa isSupported(const QStringList &features) + \sa defaultFeatures() +*/ +QCA_EXPORT QStringList supportedFeatures(); + +/** + Generate a list of the built in features. This differs from + supportedFeatures() in that it does not include features provided + by plugins. + + \return a list containing the names of the features + + The following code writes a list of features to standard out + \code +QStringList capabilities; +capabilities = QCA::defaultFeatures(); +std::cout << "Default:" << capabilities.join(",") << std::endl; + \endcode + + \sa isSupported + \sa supportedFeatures() +*/ +QCA_EXPORT QStringList defaultFeatures(); + +/** + Add a provider to the current list of providers + + This function allows you to add a provider to the + current plugin providers at a specified priority. If + a provider with the name already exists, this call fails. + + QCA takes ownership of the provider. + + \param p a pointer to a Provider object, which must be + set up. + \param priority the priority level to set the provider to + \return true if the provider is added, and false if the + provider is not added (failure) + + \sa unloadProvider for unloading specified providers + \sa setProviderPriority for a description of the provider priority system +*/ +QCA_EXPORT bool insertProvider(Provider *p, int priority = 0); + +/** + Unload specified provider + + The specified provider is removed from the list of providers + and deleted. If no provider with the name is found, this call fails. + + \param name the name of the provider + \return true if the provider is unloaded, and false if the provider + cannot be found + + \sa insertProvider for adding providers +*/ +QCA_EXPORT bool unloadProvider(const QString &name); + +/** + Change the priority of a specified provider + + QCA supports a number of providers, and if a number of providers + support the same algorithm, it needs to choose between them. You + can do this at object instantiation time (by specifying the name + of the provider that should be used). Alternatively, you can provide a + relative priority level at an application level, using this call. + + Priority is used at object instantiation time. The provider is selected + according to the following logic: + - if a particular provider is nominated, and that provider supports + the required algorithm, then the nominated provider is used + - if no provider is nominated, or it doesn't support the required + algorithm, then the provider with the lowest priority number will be used, + if that provider supports the algorithm. + - if the provider with the lowest priority number doesn't support + the required algorithm, the provider with the next lowest priority number + will be tried, and so on through to the provider with the largest priority + number + - if none of the plugin providers support the required algorithm, then + the default (built-in) provider will be tried. + + \param name the name of the provider + \param priority the new priority of the provider. As a special case, if + you pass in -1, then this provider gets the same priority as the + the last provider that was added or had its priority set using this + call. + + \sa providerPriority +*/ +QCA_EXPORT void setProviderPriority(const QString &name, int priority); + +/** + Return the priority of a specified provider + + The name of the provider (eg "qca-ossl") is used to look up the + current priority associated with that provider. If the provider + is not found (or something else went wrong), -1 is returned. + + \param name the name of the provider + + \return the current priority level + + \sa setProviderPriority for a description of the provider priority system +*/ +QCA_EXPORT int providerPriority(const QString &name); + +/** + Return a list of the current providers + + The current plugin providers are provided as a list, which you + can iterate over using ProviderListIterator. + + \sa ProviderList + \sa ProviderListIterator +*/ +QCA_EXPORT ProviderList providers(); + +/** + Return the named provider, or 0 if not found + + \param name the name of the provider to search for. +*/ +QCA_EXPORT Provider *findProvider(const QString &name); + +/** + Return the default provider +*/ +QCA_EXPORT Provider *defaultProvider(); + +/** + Retrieve plugin paths. It consists of: + 1. QCA_PLUGIN_PATH environment if set. + 2. \c %QCoreApplication::libraryPaths() . + 3. Directory where plugins were installed. + + QCA_PLUGIN_PATH is paths list like PATH or QT_PLUGIN_PATH. + It uses system path separator. \";\" on Windows and \":\" on Unix. + + This function was introduced in %QCA 2.1. +*/ +QCA_EXPORT QStringList pluginPaths(); + +/** + Scan for new plugins +*/ +QCA_EXPORT void scanForPlugins(); + +/** + Unload the current plugins +*/ +QCA_EXPORT void unloadAllPlugins(); + +/** + Retrieve plugin diagnostic text +*/ +QCA_EXPORT QString pluginDiagnosticText(); + +/** + Clear plugin diagnostic text +*/ +QCA_EXPORT void clearPluginDiagnosticText(); + +/** + Add plugin diagnostic text + + This function should only be called by providers. + + \param text the diagnostic message to append +*/ +QCA_EXPORT void appendPluginDiagnosticText(const QString &text); + +/** + Set a global property + + \param name the name of the property + \param value the value to set the property to + + \sa getProperty +*/ +QCA_EXPORT void setProperty(const QString &name, const QVariant &value); + +/** + Retrieve a global property + + \param name the name of the property to look up + + \sa setProperty +*/ +QCA_EXPORT QVariant getProperty(const QString &name); + +/** + Set provider configuration + + Allowed value types: QString, int, bool + + \param name the name of the provider to set the configuration to + \param config the configuration +*/ +QCA_EXPORT void setProviderConfig(const QString &name, const QVariantMap &config); + +/** + Retrieve provider configuration + + \param name the name of the provider to retrieve the configuration of +*/ +QCA_EXPORT QVariantMap getProviderConfig(const QString &name); + +/** + Save provider configuration to persistent storage + + \param name the name of the provider to have its configuration saved +*/ +QCA_EXPORT void saveProviderConfig(const QString &name); + +/** + Return the name of the global random number provider +*/ +QCA_EXPORT QString globalRandomProvider(); + +/** + Change the global random number provider + + The Random capabilities of %QCA are provided as part of the + built in capabilities, however the generator can be changed + if required. + + \param provider the name of the provider to use as the global random + provider. +*/ +QCA_EXPORT void setGlobalRandomProvider(const QString &provider); + +/** + Return a reference to the %QCA Logger, which is used for diagnostics + and error recording. + + The system Logger is automatically created for you on start. +*/ +QCA_EXPORT Logger *logger(); + +/** + Log a text message. This is an efficient function + to avoid overhead of argument executions when log level + blocks the message. + + \param message the text to log + \param severity the type of information to log + + \note This is a macro, so arguments may or may not be evaluated. +*/ +#define QCA_logTextMessage(message, severity) \ + do { \ + QCA::Logger::Severity s = severity; \ + QCA::Logger *l = QCA::logger(); \ + if (s <= l->level()) { \ + l->logTextMessage(message, s); \ + } \ + } while (false) + +/** + Log a binary message. This is an efficient function + to avoid overhead of argument executions when log level + blocks the message. + + \param blob the blob to log + \param severity the type of information to log + + \note This is a macro, so arguments may or may not be evaluated. +*/ +#define QCA_logBinaryMessage(blob, severity) \ + do { \ + QCA::Logger::Severity s = severity; \ + QCA::Logger *l = QCA::logger(); \ + if (s <= l->level()) { \ + l->logBinaryMessage(blob, s); \ + } \ + } while (false) + +/** + Test if QCA can access the root CA certificates + + If root certificates are available, this function returns true, + otherwise it returns false. + + \sa systemStore +*/ +QCA_EXPORT bool haveSystemStore(); + +/** + Get system-wide root Certificate Authority (CA) certificates + + Many operating systems (or distributions, on Linux-type systems) + come with some trusted certificates. Typically, these include + the root certificates for major Certificate Authorities (for + example, Verisign, Comodo) and some additional certificates that + are used for system updates. They are provided in different ways + for different systems. + + This function provides an common way to access the system + certificates. There are other ways to access certificates - see + the various I/O methods (such as fromDER() and fromPEM()) + in the Certificate and CertificateCollection classes. + + \note Availability of the system certificates depends on how + %QCA was built. You can test whether the system certificates + are available using the haveSystemStore() function. + +*/ +QCA_EXPORT CertificateCollection systemStore(); + +/** + Get the application name that will be used by SASL server mode + + The application name is used by SASL in server mode, as some systems might + have different security policies depending on the app. + The default application name is 'qca' +*/ +QCA_EXPORT QString appName(); + +/** + Set the application name that will be used by SASL server mode + + The application name is used by SASL in server mode, as some systems might + have different security policies depending on the app. This should be set + before using SASL objects, and it cannot be changed later. + + \param name the name string to use for SASL server mode +*/ +QCA_EXPORT void setAppName(const QString &name); + +/** + Convert a byte array to printable hexadecimal + representation. + + This is a convenience function to convert an arbitrary + QByteArray to a printable representation. + + \code +QByteArray test(10); +test.fill('a'); +// 0x61 is 'a' in ASCII +if (QString("61616161616161616161") == QCA::arrayToHex(test) ) +{ + printf ("arrayToHex passed\n"); +} + \endcode + + \param array the array to be converted + \return a printable representation +*/ +QCA_EXPORT QString arrayToHex(const QByteArray &array); + +/** + Convert a QString containing a hexadecimal representation + of a byte array into a QByteArray + + This is a convenience function to convert a printable + representation into a QByteArray - effectively the inverse + of QCA::arrayToHex. + + \code +QCA::init(); +QByteArray test(10); + +test.fill('b'); // 0x62 in hexadecimal +test[7] = 0x00; // can handle strings with nulls + +if (QCA::hexToArray(QString("62626262626262006262") ) == test ) +{ + printf ("hexToArray passed\n"); +} + \endcode + + \param hexString the string containing a printable + representation to be converted + \return the equivalent QByteArray +*/ +QCA_EXPORT QByteArray hexToArray(const QString &hexString); + +/** + Convert a byte array to printable base64 + representation. + + This is a convenience function to convert an arbitrary + QByteArray to a printable representation. + + \param array the array to be converted + \return a printable representation +*/ +QCA_EXPORT QString arrayToBase64(const QByteArray &array); + +/** + Convert a QString containing a base64 representation + of a byte array into a QByteArray + + This is a convenience function to convert a printable + representation into a QByteArray - effectively the inverse + of QCA::arrayToBase64. + + \param base64String the string containing a printable + representation to be converted + \return the equivalent QByteArray +*/ +QCA_EXPORT QByteArray base64ToArray(const QString &base64String); + +/** + \class Initializer qca_core.h QtCrypto + + Convenience method for initialising and cleaning up %QCA + + To ensure that QCA is properly initialised and cleaned up, + it is convenient to create an Initializer object, and let it + go out of scope at the end of %QCA usage. + + \ingroup UserAPI +*/ +class QCA_EXPORT Initializer +{ +public: + /** + Standard constructor + + \param m the MemoryMode to use for secure memory + \param prealloc the amount of secure memory to pre-allocate, + in units of 1024 bytes (1K). + */ + explicit Initializer(MemoryMode m = Practical, int prealloc = 64); + ~Initializer(); + + Initializer(const Initializer &) = delete; + Initializer &operator=(const Initializer &) = delete; +}; + +/** + \class KeyLength qca_core.h QtCrypto + + Simple container for acceptable key lengths + + The KeyLength specifies the minimum and maximum byte sizes + allowed for a key, as well as a "multiple" which the key + size must evenly divide into. + + As an example, if the key can be 4, 8 or 12 bytes, you can + express this as + \code +KeyLength keyLen( 4, 12, 4 ); + \endcode + + If you want to express a KeyLength that takes any number + of bytes (including zero), you may want to use + \code +#include +KeyLength( 0, std::numeric_limits::max(), 1 ); + \endcode + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyLength +{ +public: + /** + Construct a %KeyLength object + + \param min the minimum length of the key, in bytes + \param max the maximum length of the key, in bytes + \param multiple the number of bytes that the key must be a + multiple of. + */ + KeyLength(int min, int max, int multiple) + : _min(min) + , _max(max) + , _multiple(multiple) + { + } + + /** + Obtain the minimum length for the key, in bytes + */ + int minimum() const + { + return _min; + } + + /** + Obtain the maximum length for the key, in bytes + */ + int maximum() const + { + return _max; + } + + /** + Return the number of bytes that the key must be a multiple of + + If this is one, then anything between minimum and maximum (inclusive) + is acceptable. + */ + int multiple() const + { + return _multiple; + } + +private: + const int _min, _max, _multiple; +}; + +/** + \class Provider qca_core.h QtCrypto + + Algorithm provider + + Provider represents a plugin provider (or as a special case, the + built-in provider). This is the class you need to inherit + from to create your own plugin. You don't normally need to + worry about this class if you are just using existing + QCA capabilities and plugins, however there is nothing stopping + you from using it to obtain information about specific plugins, + as shown in the example below. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT Provider +{ +public: + virtual ~Provider(); + + class Context; + + /** + Initialisation routine + + This routine will be called when your plugin + is loaded, so this is a good place to do any + one-off initialisation tasks. If you don't need + any initialisation, just implement it as an empty + routine. + */ + virtual void init(); + + /** + Deinitialisation routine + + This routine will be called just before provider destruction. + Notably, during QCA shutdown, deinit() will be called on all + providers before any of the providers are destructed. Use this + opportunity to free any resources that may be used by other + providers. + */ + virtual void deinit(); + + /** + Version number of the plugin + + The format is the same as QCA itself. Version 1.2.3 would be + represented as 0x010203. + + The default returns 0 (version 0.0.0). + */ + virtual int version() const; + + /** + Target QCA version for the provider. + + This is used to verify compatibility between the + provider and QCA. For a provider to be used, it + must supply major and minor version numbers here that are + less-than or equal to the actual QCA version (the patch + version number is ignored). This means an older + provider may be used with a newer QCA, but a newer + provider cannot be used with an older QCA. + */ + virtual int qcaVersion() const = 0; + + /** + The name of the provider. + + Typically you just return a string containing a + convenient name. + + \code +QString name() const +{ + return "qca-myplugin"; +} + \endcode + + \note The name is used to tell if a provider is + already loaded, so you need to make sure it is + unique amongst the various plugins. + */ + virtual QString name() const = 0; + + /** + The capabilities (algorithms) of the provider. + + Typically you just return a fixed QStringList: + \code +QStringList features() const +{ + QStringList list; + list += "sha1"; + list += "sha256"; + list += "hmac(sha1)"; + return list; +} + \endcode + */ + virtual QStringList features() const = 0; + + /** + Optional credit text for the provider. + + You might display this information in a credits or + "About" dialog. Returns an empty string if the + provider has no credit text. Only report credit text + when absolutely required (for example, an "advertisement + clause" related to licensing). Do not use it for + reporting general author information. + */ + virtual QString credit() const; + + /** + Routine to create a plugin context + + You need to return a pointer to an algorithm + Context that corresponds with the algorithm + name specified. + + \param type the name of the algorithm required + + \code +Context *createContext(const QString &type) +{ + if ( type == "sha1" ) + return new SHA1Context( this ); + else if ( type == "sha256" ) + return new SHA0256Context( this ); + else if ( type == "hmac(sha1)" ) + return new HMACSHA1Context( this ); + else + return 0; +} + \endcode + + Naturally you also need to implement + the specified Context subclasses as well. + */ + virtual Context *createContext(const QString &type) = 0; + + /** + Method to set up the default configuration options. + + If your provider needs some configuration options, + this method allows you to establish default options. + The user can then change the configuration options + as required, and set them using configChanged(). + + You need to return a QVariantMap that has configuration + options as the keys, and the default configuration + as the values, as shown below: + \code +QVariantMap defaultConfig() const +{ + QVariantMap myConfig; + myConfig[ "firstOption" ] = QString("firstOptionValue"); + myConfig[ "secondOption" ] = true; + myConfig[ "thirdOpt" ] = 1243; + return myConfig; +} + \endcode + + \sa configChanged for how to set the configuration; + */ + virtual QVariantMap defaultConfig() const; + + /** + Method to set the configuration options. + + If your provider supports configuration options, you + will be advised of user changes to the configuration + when this method is called. + + \param config the new configuration to be used by the provider + */ + virtual void configChanged(const QVariantMap &config); +}; + +/** + \class QCA::Provider::Context qca_core.h QtCrypto + + Internal context class used for the plugin + + \internal + + \ingroup ProviderAPI +*/ +class QCA_EXPORT Provider::Context : public QObject +{ + Q_OBJECT +public: + ~Context() override; + + /** + The Provider associated with this Context + */ + Provider *provider() const; + + /** + The type of context, as passed to the constructor + */ + QString type() const; + + /** + Create a duplicate of this Context + */ + virtual Context *clone() const = 0; + + /** + Test if two Contexts have the same Provider + + \param c pointer to the Context to compare to + + \return true if the argument and this Context + have the same provider. + */ + bool sameProvider(const Context *c) const; + +protected: + /** + Standard constructor + + \param parent the parent provider for this + context + \param type the name of the provider context type + */ + Context(Provider *parent, const QString &type); + + /** + Copy constructor + + \param from the Context to copy from + */ + Context(const Context &from); + +private: + // disable assignment + Context &operator=(const Context &from); + + Provider *_provider; + QString _type; +}; + +/** + \class BasicContext qca_core.h QtCrypto + + Base class to use for primitive provider contexts + + \internal + + This class inherits Provider::Context and calls moveToThread(0) on + itself, thereby disabling the event properties of the underlying + QObject. Context types that need to be a QObject should inherit from + Provider::Context, those that don't should inherit from BasicContext. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT BasicContext : public Provider::Context +{ + Q_OBJECT +public: + ~BasicContext() override; + +protected: + /** + Standard constructor + + \param parent the parent provider for this + context + \param type the name of the provider context type + */ + BasicContext(Provider *parent, const QString &type); + + /** + Copy constructor + + \param from the Context to copy from + */ + BasicContext(const BasicContext &from); + +private: + // disable assignment + BasicContext &operator=(const BasicContext &from); +}; + +/** + \class BufferedComputation qca_core.h QtCrypto + + General superclass for buffered computation algorithms + + A buffered computation is characterised by having the + algorithm take data in an incremental way, then having + the results delivered at the end. Conceptually, the + algorithm has some internal state that is modified + when you call update() and returned when you call + final(). + + \ingroup UserAPI +*/ +class QCA_EXPORT BufferedComputation +{ +public: + virtual ~BufferedComputation(); + + /** + Reset the internal state + */ + virtual void clear() = 0; + + /** + Update the internal state with a byte array + + \param a the byte array of data that is to + be used to update the internal state. + */ + virtual void update(const MemoryRegion &a) = 0; + + /** + Complete the algorithm and return the internal state + */ + virtual MemoryRegion final() = 0; + + /** + Perform an "all in one" update, returning + the result. This is appropriate if you + have all the data in one array - just + call process on that array, and you will + get back the results of the computation. + + \note This will invalidate any previous + computation using this object. + + \param a the data to process. + */ + MemoryRegion process(const MemoryRegion &a); +}; + +/** + \class Filter qca_core.h QtCrypto + + General superclass for filtering transformation algorithms + + A filtering computation is characterised by having the + algorithm take input data in an incremental way, with results + delivered for each input, or block of input. Some internal + state may be managed, with the transformation completed + when final() is called. + + If this seems a big vague, then you might try deriving + your class from a subclass with stronger semantics, or if your + update() function is always returning null results, and + everything comes out at final(), try BufferedComputation. + + \ingroup UserAPI +*/ +class QCA_EXPORT Filter +{ +public: + virtual ~Filter(); + + /** + Reset the internal state + */ + virtual void clear() = 0; + + /** + Process more data, returning the corresponding + filtered version of the data. + + \param a the array containing data to process + */ + virtual MemoryRegion update(const MemoryRegion &a) = 0; + + /** + Complete the algorithm, returning any + additional results. + */ + virtual MemoryRegion final() = 0; + + /** + Test if an update() or final() call succeeded. + + \return true if the previous call succeeded + */ + virtual bool ok() const = 0; + + /** + Perform an "all in one" update, returning + the result. This is appropriate if you + have all the data in one array - just + call process on that array, and you will + get back the results of the computation. + + \note This will invalidate any previous + computation using this object. + + \param a the data to process in this step + */ + MemoryRegion process(const MemoryRegion &a); +}; + +/** + \class Algorithm qca_core.h QtCrypto + + General superclass for an algorithm. + + This is a fairly abstract class, mainly used for + implementing the backend "provider" interface. + + \ingroup UserAPI +*/ +class QCA_EXPORT Algorithm +{ +public: + /** + Standard copy constructor + + \param from the Algorithm to copy from + */ + Algorithm(const Algorithm &from); + + virtual ~Algorithm(); + + /** + Assignment operator + + \param from the Algorithm to copy state from + */ + Algorithm &operator=(const Algorithm &from); + + /** + The name of the algorithm type. + */ + QString type() const; + + /** + The name of the provider + + Each algorithm is implemented by a provider. This + allows you to figure out which provider is associated + */ + Provider *provider() const; + + // Note: The next five functions are not public! + + /** + \internal + + The context associated with this algorithm + */ + Provider::Context *context(); + + /** + \internal + + The context associated with this algorithm + */ + const Provider::Context *context() const; + + /** + \internal + + Set the Provider for this algorithm + + \param c the context for the Provider to use + */ + void change(Provider::Context *c); + + /** + \internal + + \overload + + \param type the name of the algorithm to use + \param provider the name of the preferred provider + */ + void change(const QString &type, const QString &provider); + + /** + \internal + + Take the Provider from this algorithm + */ + Provider::Context *takeContext(); + +protected: + /** + Constructor for empty algorithm + */ + Algorithm(); + + /** + Constructor of a particular algorithm. + + \param type the algorithm to construct + \param provider the name of a particular Provider + */ + Algorithm(const QString &type, const QString &provider); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class SymmetricKey qca_core.h QtCrypto + + Container for keys for symmetric encryption algorithms. + + \ingroup UserAPI +*/ +class QCA_EXPORT SymmetricKey : public SecureArray +{ +public: + /** + Construct an empty (zero length) key + */ + SymmetricKey(); + + /** + Construct an key of specified size, with random contents + + This is intended to be used as a random session key. + + \param size the number of bytes for the key + */ + SymmetricKey(int size); + + /** + Construct a key from a provided byte array + + \param a the byte array to copy + */ + SymmetricKey(const SecureArray &a); + + /** + Construct a key from a provided byte array + + \param a the byte array to copy + */ + SymmetricKey(const QByteArray &a); + + /** + Test for weak DES keys + + \return true if the key is a weak key for DES + */ + bool isWeakDESKey(); +}; + +/** + \class InitializationVector qca_core.h QtCrypto + + Container for initialisation vectors and nonces + + \ingroup UserAPI +*/ +class QCA_EXPORT InitializationVector : public SecureArray +{ +public: + /** + Construct an empty (zero length) initialization vector + */ + InitializationVector(); + + /** + Construct an initialization vector of the specified size + + \param size the length of the initialization vector, in bytes + */ + InitializationVector(int size); + + /** + Construct an initialization vector from a provided byte array + + \param a the byte array to copy + */ + InitializationVector(const SecureArray &a); + + /** + Construct an initialization vector from a provided byte array + + \param a the byte array to copy + */ + InitializationVector(const QByteArray &a); +}; + +/** + \class AuthTag qca_core.h QtCrypto + + Container for authentication tag + + \ingroup UserAPI +*/ +class QCA_EXPORT AuthTag : public SecureArray +{ +public: + /** + Construct an empty authentication tag + */ + AuthTag(); + + /** + Construct an empty authentication tag of the specified size + + \param size the length of the authentication tag, in bytes + */ + AuthTag(int size); + + /** + Construct an authentication tag from a provided byte array + + \param a the byte array to copy + */ + AuthTag(const SecureArray &a); + + /** + Construct an authentication tag from a provided byte array + + \param a the byte array to copy + */ + AuthTag(const QByteArray &a); +}; + +/** + \class Event qca_core.h QtCrypto + + An asynchronous event + + Events are produced in response to the library's need for some user + intervention, such as entering a pin or password, or inserting a + cryptographic token. + + Event is an abstraction, so you can handle this need in a way that makes + sense for your application. + + \ingroup UserAPI +*/ +class QCA_EXPORT Event +{ +public: + /** + %Type of event + + \sa type() + */ + enum Type + { + Password, ///< Asking for a password, PIN or passphrase. + Token ///< Asking for a token + }; + + /** + %Source of the event + + Events are associated with access to a KeyStore, or access to + a file (or bytearray/stream or equivalent). This tells you the + type of source that caused the Event. + + \sa source() + \sa fileName() for the name, if source is Event::Data + \sa keyStoreInfo() and keyStoreEntry() for the keystore and entry, + if the source is Event::KeyStore + */ + enum Source + { + KeyStore, ///< KeyStore generated the event + Data ///< File or bytearray generated the event + }; + + /** + password variation + + If the Type of Event is Password, PasswordStyle tells you whether + it is a PIN, passphrase or password. + + \sa passwordStyle() + */ + enum PasswordStyle + { + StylePassword, ///< User should be prompted for a "Password" + StylePassphrase, ///< User should be prompted for a "Passphrase" + StylePIN ///< User should be prompted for a "PIN" + }; + + /** + Constructor + */ + Event(); + + /** + Copy constructor + + \param from the Event to copy from + */ + Event(const Event &from); + + /** + Destructor + */ + ~Event(); + + /** + Assignment operator + + \param from the Event to copy from + */ + Event &operator=(const Event &from); + + /** + test if this event has been setup correctly + */ + bool isNull() const; + + /** + the Type of this event + */ + Type type() const; + + /** + the Source of this event + */ + Source source() const; + + /** + the style of password required. + + This is not meaningful unless the Type is Event::Password. + + \sa PasswordStyle + */ + PasswordStyle passwordStyle() const; + + /** + The info of the KeyStore associated with this event + + This is not meaningful unless the Source is KeyStore. + */ + KeyStoreInfo keyStoreInfo() const; + + /** + The KeyStoreEntry associated with this event + + This is not meaningful unless the Source is KeyStore. + */ + KeyStoreEntry keyStoreEntry() const; + + /** + Name or other identifier for the file or byte array + associated with this event. + + This is not meaningful unless the Source is Data. + */ + QString fileName() const; + + /** + opaque data + */ + void *ptr() const; + + /** + Set the values for this Event + + This creates a Password type event, for a keystore. + + \param pstyle the style of information required (e.g. PIN, + password or passphrase) + \param keyStoreInfo info about the keystore that the information + is required for + \param keyStoreEntry the entry in the keystore that the + information is required for + \param ptr opaque data + */ + void setPasswordKeyStore(PasswordStyle pstyle, + const KeyStoreInfo &keyStoreInfo, + const KeyStoreEntry &keyStoreEntry, + void *ptr); + + /** + Set the values for this Event + + This creates a Password type event, for a file. + + \param pstyle the style of information required (e.g. PIN, + password or passphrase) + \param fileName the name of the file (or other identifier) that + the information is required for + \param ptr opaque data + */ + void setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr); + + /** + Set the values for this Event + + This creates a Token type event. + + \param keyStoreInfo info about the keystore that the token is + required for + \param keyStoreEntry the entry in the keystore that the token is + required for + \param ptr opaque data + */ + void setToken(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class EventHandler qca_core.h QtCrypto + + Interface class for password / passphrase / PIN and token handlers + + This class is used on client side applications to handle + the provision of passwords, passphrases and PINs by users, and + to indicate that tokens have been correctly inserted. + + The concept behind this class is that the library can raise + events (typically using PasswordAsker or TokenAsker), which + may (or may not) be handled by the application using a + handler object (that has-a EventHandler, or possibly is-a + EventHandler) that is connected to the eventReady() signal. + + \ingroup UserAPI +*/ +class QCA_EXPORT EventHandler : public QObject +{ + Q_OBJECT +public: + /** + Constructor + + \param parent the parent object for this object + */ + EventHandler(QObject *parent = nullptr); + ~EventHandler() override; + + /** + mandatory function to call after connecting the + signal to a slot in your application specific password + / passphrase / PIN or token handler + */ + void start(); + + /** + function to call to return the user provided + password, passphrase or PIN. + + \param id the id corresponding to the password request + \param password the user-provided password, passphrase or PIN. + + \note the id parameter is the same as that provided in the + eventReady() signal. + */ + void submitPassword(int id, const SecureArray &password); + + /** + function to call to indicate that the token has been inserted + by the user. + + \param id the id corresponding to the password request + + \note the id parameter is the same as that provided in the + eventReady() signal. + */ + void tokenOkay(int id); + + /** + function to call to indicate that the user declined to + provide a password, passphrase, PIN or token. + + \param id the id corresponding to the password request + + \note the id parameter is the same as that provided in the + eventReady() signal. + */ + void reject(int id); + +Q_SIGNALS: + /** + signal emitted when an Event requires attention. + + You typically need to connect this signal to + a compatible slot in your callback handler + + \param id the identification number for the event + \param context information about the type of response required + */ + void eventReady(int id, const QCA::Event &context); + +private: + Q_DISABLE_COPY(EventHandler) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class PasswordAsker qca_core.h QtCrypto + + User password / passphrase / PIN handler + + This class is used to obtain a password from a user. + + \ingroup UserAPI +*/ +class QCA_EXPORT PasswordAsker : public QObject +{ + Q_OBJECT +public: + /** + Construct a new asker + + \param parent the parent object for this QObject + */ + PasswordAsker(QObject *parent = nullptr); + ~PasswordAsker() override; + + /** + queue a password / passphrase request associated with a key store + + \param pstyle the type of information required (e.g. PIN, + passphrase or password) + \param keyStoreInfo info of the key store that the information is + required for + \param keyStoreEntry the item in the key store that the + information is required for (if applicable) + \param ptr opaque data + */ + void + ask(Event::PasswordStyle pstyle, const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); + + /** + queue a password / passphrase request associated with a file + + \param pstyle the type of information required (e.g. PIN, + passphrase or password) + \param fileName the name of the file that the information is + required for + \param ptr opaque data + */ + void ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr); + + /** + Cancel the pending password / passphrase request + */ + void cancel(); + + /** + Block until the password / passphrase request is + completed + + You can use the responseReady signal instead of + blocking, if appropriate. + */ + void waitForResponse(); + + /** + Determine whether the password / passphrase was accepted or not + + In this context, returning true is indicative of the user clicking + "Ok" or equivalent; and returning false indicates that either the + user clicked "Cancel" or equivalent, or that the cancel() function + was called, or that the request is still pending. + */ + bool accepted() const; + + /** + The password / passphrase / PIN provided by the user in response + to the asker request. This may be empty. + */ + SecureArray password() const; + +Q_SIGNALS: + /** + Emitted when the asker process has been completed. + + You should check whether the user accepted() the response + prior to relying on the password(). + */ + void responseReady(); + +private: + Q_DISABLE_COPY(PasswordAsker) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class TokenAsker qca_core.h QtCrypto + + User token handler + + This class is used to request the user to insert a token. + + \ingroup UserAPI +*/ +class QCA_EXPORT TokenAsker : public QObject +{ + Q_OBJECT +public: + /** + Construct a new asker + + \param parent the parent object for this QObject + */ + TokenAsker(QObject *parent = nullptr); + ~TokenAsker() override; + + /** + queue a token request associated with a key store + + \param keyStoreInfo info of the key store that the information is + required for + \param keyStoreEntry the item in the key store that the + information is required for (if applicable) + \param ptr opaque data + */ + void ask(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr); + + /** + Cancel the pending password / passphrase request + */ + void cancel(); + + /** + Block until the token request is completed + + You can use the responseReady signal instead of + blocking, if appropriate. + */ + void waitForResponse(); + + /** + Test if the token request was accepted or not. + + \return true if the token request was accepted + */ + bool accepted() const; + +Q_SIGNALS: + /** + Emitted when the asker process has been completed. + + You should check whether the user accepted() the response + prior to relying on token being present. + */ + void responseReady(); + +private: + Q_DISABLE_COPY(TokenAsker) + + class Private; + friend class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_keystore.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_keystore.h new file mode 100644 index 0000000000..86d0c46370 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_keystore.h @@ -0,0 +1,798 @@ +/* + * qca_keystore.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_keystore.h + + Header file for classes that provide and manage keys + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_KEYSTORE_H +#define QCA_KEYSTORE_H + +#include "qca_cert.h" +#include "qca_core.h" + +namespace QCA { + +class KeyStoreTracker; +class KeyStoreManagerPrivate; +class KeyStorePrivate; + +/** + \class KeyStoreEntry qca_keystore.h QtCrypto + + Single entry in a KeyStore + + This is a container for any kind of object in a KeyStore + (such as PGP keys, or X.509 certificates / private keys). + + KeyStoreEntry objects are obtained through KeyStore or loaded from a + serialized string format. The latter method requires a KeyStoreEntry + obtained through KeyStore to be serialized for future loading. For + example: + + \code +QString str = someKeyStoreEntry.toString(); +[ app saves str to disk ] +[ app quits ] +... +[ app launches ] +[ app reads str from disk ] +KeyStoreEntry entry(str); +printf("Entry name: [%s]\n", qPrintable(entry.name())); + \endcode + + KeyStoreEntry objects may or may not be available. An entry is + unavailable if it has a private content that is not present. The + private content might exist on external hardware. To determine if an + entry is available, call isAvailable(). To ensure an entry is available + before performing a private key operation, call ensureAvailable. For + example: + + \code +if(entry.ensureAvailable()) +{ + entry.keyBundle().privateKey().signMessage(...); + ... +} + \endcode + + ensureAvailable() blocks and may cause hardware access, but + if it completes successfully then you may use the entry's private + content. It also means, in the case of a Smart Card token, that + it is probably inserted. + + To watch this entry asynchronously, you would do: + + \code +KeyStoreEntryWatcher *watcher = new KeyStoreEntryWatcher(entry); +connect(watcher, &KeyStoreEntryWatcher::available, this, &YourClass::entry_available); +... +void entry_available() +{ + // entry now available + watcher->entry().keyBundle().privateKey().signMessage(...); +} + \endcode + + Unlike private content, public content is always usable even if the + entry is not available. Serialized entry data contains all of the + metadata necessary to reconstruct the public content. + + Now, even though an entry may be available, it does not + mean you have access to use it for operations. For + example, even though a KeyBundle entry offered by a Smart Card + may be available, as soon as you try to use the PrivateKey object + for a signing operation, a PIN might be asked for. You can call + ensureAccess() if you want to synchronously provide the PIN + early on: + + \code +if(entry.ensureAccess()) +{ + // do private key stuff + ... +} + \endcode + + Note that you don't have to call ensureAvailable() before + ensureAccess(). Calling the latter is enough to imply + both. + + After an application is configured to use a particular key, + it is expected that its usual running procedure will be: + + 1) Construct KeyStoreEntry from the serialized data. + 2) If the content object is not available, wait for it + (with either ensureAvailable() or KeyStoreEntryWatcher). + 3) Pass the content object(s) to a high level operation like TLS. + + In this case, any PIN prompting and private key operations + would be caused/handled from the TLS object. Omit step 2 and + the private key operations might cause token prompting. + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyStoreEntry : public Algorithm +{ +public: + /** + The type of entry in the KeyStore + */ + enum Type + { + TypeKeyBundle, + TypeCertificate, + TypeCRL, + TypePGPSecretKey, + TypePGPPublicKey + }; + + /** + Create an empty KeyStoreEntry + */ + KeyStoreEntry(); + + /** + Create a passive KeyStoreEntry based on a serialized + string + + \param serialized the string containing the keystore entry information + + \sa fromString + */ + KeyStoreEntry(const QString &serialized); + + /** + Standard copy constructor + + \param from the source entry + */ + KeyStoreEntry(const KeyStoreEntry &from); + + ~KeyStoreEntry() override; + + /** + Standard assignment operator + + \param from the source entry + */ + KeyStoreEntry &operator=(const KeyStoreEntry &from); + + /** + Test if this key is empty (null) + */ + bool isNull() const; + + /** + Test if the key is available for use. + + A key is considered available if the key's private + content is present. + + \sa ensureAvailable + \sa isAccessible + */ + bool isAvailable() const; + + /** + Test if the key is currently accessible. + + This means that the private key part can be used + at this time. For a smartcard, this means that all + required operations (e.g. login / PIN entry) are + completed. + + If isAccessible() is true, then the key + is necessarily available (i.e. isAvailable() is + also true). + + \sa ensureAccessible + \sa isAvailable + */ + bool isAccessible() const; + + /** + Determine the type of key stored in this object + */ + Type type() const; + + /** + The name associated with the key stored in this object + */ + QString name() const; + + /** + The ID associated with the key stored in this object. + */ + QString id() const; + + /** + The name of the KeyStore for this key object + */ + QString storeName() const; + + /** + The id of the KeyStore for this key object + + \sa KeyStore::id() + */ + QString storeId() const; + + /** + Serialize into a string for use as a passive entry + */ + QString toString() const; + + /** + Load a passive entry by using a serialized string + as input + + \param serialized the string containing the keystore entry information + + \return the newly created KeyStoreEntry + */ + static KeyStoreEntry fromString(const QString &serialized); + + /** + If a KeyBundle is stored in this object, return that + bundle. + */ + KeyBundle keyBundle() const; + + /** + If a Certificate is stored in this object, return that + certificate. + */ + Certificate certificate() const; + + /** + If a CRL is stored in this object, return the value + of the CRL + */ + CRL crl() const; + + /** + If the key stored in this object is a private + PGP key, return the contents of that key. + */ + PGPKey pgpSecretKey() const; + + /** + If the key stored in this object is either an + public or private PGP key, extract the public key + part of that PGP key. + */ + PGPKey pgpPublicKey() const; + + /** + Returns true if the entry is available, otherwise false. + + Available means that any private content for this entry is + present and ready for use. In the case of a smart card, this + will ensure the card is inserted, and may invoke a token + prompt. + + Calling this function on an already available entry may cause + the entry to be refreshed. + + \sa isAvailable + \sa ensureAccess + + \note This function is blocking. + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + bool ensureAvailable(); + + /** + Like ensureAvailable, but will also ensure + that the PIN is provided if needed. + + \sa isAccessible + \sa ensureAvailable + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + bool ensureAccess(); + +private: + class Private; + Private *d; + + friend class KeyStoreTracker; +}; + +/** + \class KeyStoreEntryWatcher qca_keystore.h QtCrypto + + Class to monitor the availability of a KeyStoreEntry + + Some KeyStore types have the concept of an entry that can be + available only part of the time (for example, a smart card that + can be removed). This class allows you to identify when a + KeyStoreEntry becomes available / unavailable. + + \note You can also monitor availability of a whole KeyStore, + using KeyStoreManager::keyStoreAvailable() signal, and + the KeyStore::unavailable() signal. + + \sa KeyStore for more discussion on availability of + keys and related objects. + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyStoreEntryWatcher : public QObject +{ + Q_OBJECT +public: + /** + Standard constructor. + + This creates an object that monitors the specified KeyStore entry, + emitting available() and unavailable() as the entry becomes available + and unavailable respectively. + + \param e the KeyStoreEntry to monitor + \param parent the parent object for this object + */ + explicit KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent = nullptr); + + ~KeyStoreEntryWatcher() override; + + /** + The KeyStoreEntry that is being monitored + */ + KeyStoreEntry entry() const; + +Q_SIGNALS: + /** + This signal is emitted when the entry that is being monitored + becomes available. + */ + void available(); + + /** + This signal is emitted when the entry that is being monitored + becomes unavailble. + */ + void unavailable(); + +private: + Q_DISABLE_COPY(KeyStoreEntryWatcher) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class KeyStore qca_keystore.h QtCrypto + + General purpose key storage object + + Examples of use of this are: + - systemstore: System TrustedCertificates + - accepted self-signed: Application TrustedCertificates + - apple keychain: User Identities + - smartcard: SmartCard Identities + - gnupg: PGPKeyring Identities,PGPPublicKeys + + \note + - there can be multiple KeyStore objects referring to the same id + - when a KeyStore is constructed, it refers to a given id (deviceId) + and internal contextId. if the context goes away, the KeyStore + becomes invalid (isValid() == false), and unavailable() is emitted. + even if the device later reappears, the KeyStore remains invalid. + a new KeyStore will have to be created to use the device again. + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyStore : public QObject, public Algorithm +{ + Q_OBJECT +public: + /** + The type of keystore + */ + enum Type + { + System, ///< objects such as root certificates + User, ///< objects such as Apple Keychain, KDE Wallet + Application, ///< for caching accepted self-signed certificates + SmartCard, ///< for smartcards + PGPKeyring ///< for a PGP keyring + }; + + /** + Obtain a specific KeyStore + + \param id the identification for the key store + \param keyStoreManager the parent manager for this keystore + */ + KeyStore(const QString &id, KeyStoreManager *keyStoreManager); + + ~KeyStore() override; + + /** + Check if this KeyStore is valid + + \return true if the KeyStore is valid + */ + bool isValid() const; + + /** + The KeyStore Type + */ + Type type() const; + + /** + The name associated with the KeyStore + */ + QString name() const; + + /** + The ID associated with the KeyStore + */ + QString id() const; + + /** + Test if the KeyStore is writeable or not + + \return true if the KeyStore is read-only + */ + bool isReadOnly() const; + + /** + Turns on asynchronous mode for this KeyStore instance. + + Normally, entryList() and writeEntry() are blocking + calls. However, if startAsynchronousMode() is called, + then these functions will return immediately. entryList() + will return with the latest known entries, or an empty + list if none are known yet (in this mode, updated() will + be emitted once the initial entries are known, even if the + store has not actually been altered). writeEntry() will + always return an empty string, and the entryWritten() + signal indicates the result of a write. + */ + void startAsynchronousMode(); + + /** + A list of the KeyStoreEntry objects in this store + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler + (this is not a concern if asynchronous mode is enabled). + + \sa startAsynchronousMode + */ + QList entryList() const; + + /** + test if the KeyStore holds trusted certificates (and CRLs) + */ + bool holdsTrustedCertificates() const; + + /** + test if the KeyStore holds identities (eg KeyBundle or PGPSecretKey) + */ + bool holdsIdentities() const; + + /** + test if the KeyStore holds PGPPublicKey objects + */ + bool holdsPGPPublicKeys() const; + + /** + Add a entry to the KeyStore + + Returns the entryId of the written entry or an empty + string on failure. + + \param kb the KeyBundle to add to the KeyStore + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler + (this is not a concern if asynchronous mode is enabled). + + \sa startAsynchronousMode + */ + QString writeEntry(const KeyBundle &kb); + + /** + \overload + + \param cert the Certificate to add to the KeyStore + */ + QString writeEntry(const Certificate &cert); + + /** + \overload + + \param crl the CRL to add to the KeyStore + */ + QString writeEntry(const CRL &crl); + + /** + \overload + + \param key the PGPKey to add to the KeyStore + + \return a ref to the key in the keyring + */ + QString writeEntry(const PGPKey &key); + + /** + Delete the a specified KeyStoreEntry from this KeyStore + + \param id the ID for the entry to be deleted + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler + (this is not a concern if asynchronous mode is enabled). + + \sa startAsynchronousMode + */ + bool removeEntry(const QString &id); + +Q_SIGNALS: + /** + Emitted when the KeyStore is changed + + This occurs if entries are added, removed, or changed in this + KeyStore, including changes in entry availability. + */ + void updated(); + + /** + Emitted when the KeyStore becomes unavailable + */ + void unavailable(); + + /** + Emitted when an entry has been written, in asynchronous + mode. + + \param entryId is the newly written entry id on success, + or an empty string if the write failed. + */ + void entryWritten(const QString &entryId); + + /** + Emitted when an entry has been removed, in asynchronous + mode. + + \param success indicates if the removal succeeded (true) or not (false). + */ + void entryRemoved(bool success); + +private: + Q_DISABLE_COPY(KeyStore) + + friend class KeyStorePrivate; + KeyStorePrivate *d; + + friend class KeyStoreManagerPrivate; +}; + +/** + \class KeyStoreInfo qca_keystore.h QtCrypto + + Key store information, outside of a KeyStore object + + This class is used in conjunction with the Event class, + and related classes such as PasswordAsker and TokenAsker, + to describe the key store source of the Event. + + Each KeyStoreInfo represents a single KeyStore, and describes + the type of store (e.g. smartcard or PGP keyring - see + KeyStore::Type), and a couple of names. The id() of a KeyStore + is used to reference it, and is typically of the form + "qca-mystorename". The name() of a KeyStore is used to describe + it (i.e. this is the "pretty" name to show the user), and is + typically of the form "My Store Name". + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyStoreInfo +{ +public: + /** + Constructor. + + \note This form of constructor for KeyStoreInfo + produces an object that does not describe any + KeyStore, and isNull() will return true. + */ + KeyStoreInfo(); + + /** + Standard constructor. + + This builds a KeyStoreInfo object that descibes a + KeyStore. + + \param type the type of KeyStore + \param id the identification of the KeyStore + \param name the descriptive name of the KeyStore + */ + KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name); + + /** + Copy constructor. + + \param from the KeyStoreInfo to copy from + */ + KeyStoreInfo(const KeyStoreInfo &from); + + ~KeyStoreInfo(); + + /** + Assignment operator. + + \param from the KeyStoreInfo to copy from + */ + KeyStoreInfo &operator=(const KeyStoreInfo &from); + + /** + Test if this object is valid + + \return true if the object is not valid + */ + bool isNull() const; + + /** + The Type of KeyStore that this KeyStoreInfo object + describes. + */ + KeyStore::Type type() const; + + /** + The unique identification of the KeyStore that + this KeyStoreInfo object describes. + */ + QString id() const; + + /** + The descriptive name of the KeyStore that this + KeyStoreInfo object describes. + */ + QString name() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + \class KeyStoreManager qca_keystore.h QtCrypto + + Access keystores, and monitor keystores for changes. + + Before you can access a KeyStore, you must create a + KeyStoreManager. You then need to start() + the KeyStoreManager, and either wait for the busyFinished() + signal, or block using waitForBusyFinished(). + + If you know the KeyStoreEntry that you need, you can + use KeyStore passively, as described in the KeyStoreEntry + documentation. + + \ingroup UserAPI +*/ +class QCA_EXPORT KeyStoreManager : public QObject +{ + Q_OBJECT +public: + /** + Create a new KeyStoreManager + + \param parent the parent for this object +*/ + KeyStoreManager(QObject *parent = nullptr); + ~KeyStoreManager() override; + + /** + Initialize all key store providers + */ + static void start(); + + /** + Initialize a specific key store provider + + \param provider the name of the provider to start + */ + static void start(const QString &provider); + + /** + Indicates if the manager is busy looking for key stores + */ + bool isBusy() const; + + /** + Blocks until the manager is done looking for key stores + */ + void waitForBusyFinished(); + + /** + A list of all the key stores + */ + QStringList keyStores() const; + + /** + The diagnostic result of key store operations, such as + warnings and errors + */ + static QString diagnosticText(); + + /** + Clears the diagnostic result log + */ + static void clearDiagnosticText(); + + /** + If you are not using the eventloop, call this to update + the object state to the present + */ + void sync(); + +Q_SIGNALS: + /** + emitted when the manager has started looking for key stores + */ + void busyStarted(); + + /** + emitted when the manager has finished looking for key stores + */ + void busyFinished(); + + /** + emitted when a new key store becomes available + + \param id the name of the key store that has become available + */ + void keyStoreAvailable(const QString &id); + +private: + Q_DISABLE_COPY(KeyStoreManager) + + friend class KeyStoreManagerPrivate; + KeyStoreManagerPrivate *d; + + friend class Global; + friend class KeyStorePrivate; + + static void scan(); + static void shutdown(); +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_publickey.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_publickey.h new file mode 100644 index 0000000000..8a3c7de1eb --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_publickey.h @@ -0,0 +1,1562 @@ +/* + * qca_publickey.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_publickey.h + + Header file for PublicKey and PrivateKey related classes + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_PUBLICKEY_H +#define QCA_PUBLICKEY_H + +#include "qca_core.h" +#include + +namespace QCA { + +class PublicKey; +class PrivateKey; +class KeyGenerator; +class RSAPublicKey; +class RSAPrivateKey; +class DSAPublicKey; +class DSAPrivateKey; +class DHPublicKey; +class DHPrivateKey; + +/** + Encryption algorithms +*/ +enum EncryptionAlgorithm +{ + EME_PKCS1v15, ///< Block type 2 (PKCS#1, Version 1.5) + EME_PKCS1_OAEP, ///< Optimal asymmetric encryption padding (PKCS#1, Version 2.0) + EME_PKCS1v15_SSL, ///< PKCS#1, Version 1.5 with an SSL-specific modification + EME_NO_PADDING ///< Raw RSA encryption +}; + +/** + Signature algorithm variants + + Note that most signature algorithms follow a process of first hashing the + plaintext data to be signed, creating a payload format that wraps the hash + value (among other things), and then signing the payload with the private + key. So, for example, an EMSA3(SHA1) signature outputted by QCA cannot be + verified by merely performing RSA and SHA1 operations (e.g. + "openssl rsautl -verify" and comparing with sha1sum), because that would not + take the EMSA3 payload format into consideration. +*/ +enum SignatureAlgorithm +{ + SignatureUnknown, ///< Unknown signing algorithm + EMSA1_SHA1, ///< SHA1, with EMSA1 (IEEE1363-2000) encoding (this is the usual DSA algorithm - FIPS186) + EMSA3_SHA1, ///< SHA1, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_MD5, ///< MD5, with EMSA3 (ie PKCS#1 Version 1.5) encoding (this is the usual RSA algorithm) + EMSA3_MD2, ///< MD2, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_RIPEMD160, ///< RIPEMD160, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_Raw, ///< EMSA3 without computing a message digest or a DigestInfo encoding (identical to PKCS#11's + ///< CKM_RSA_PKCS mechanism) + EMSA3_SHA224, ///< SHA224, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_SHA256, ///< SHA256, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_SHA384, ///< SHA384, with EMSA3 (ie PKCS#1 Version 1.5) encoding + EMSA3_SHA512 ///< SHA512, with EMSA3 (ie PKCS#1 Version 1.5) encoding +}; + +/** + Signature formats (DSA only) +*/ +enum SignatureFormat +{ + DefaultFormat, ///< For DSA, this is the same as IEEE_1363 + IEEE_1363, ///< 40-byte format from IEEE 1363 (Botan/.NET) + DERSequence ///< Signature wrapped in DER formatting (OpenSSL/Java) +}; + +/** + Password-based encryption +*/ +enum PBEAlgorithm +{ + PBEDefault, ///< Use modern default (same as PBES2_TripleDES_SHA1) + PBES2_DES_SHA1, ///< PKCS#5 v2.0 DES/CBC,SHA1 + PBES2_TripleDES_SHA1, ///< PKCS#5 v2.0 TripleDES/CBC,SHA1 + PBES2_AES128_SHA1, ///< PKCS#5 v2.0 AES-128/CBC,SHA1 + PBES2_AES192_SHA1, ///< PKCS#5 v2.0 AES-192/CBC,SHA1 + PBES2_AES256_SHA1 ///< PKCS#5 v2.0 AES-256/CBC,SHA1 +}; + +/** + Return value from a format conversion + + Note that if you are checking for any result other than ConvertGood, + then you may be introducing a provider specific dependency. +*/ +enum ConvertResult +{ + ConvertGood, ///< Conversion succeeded, results should be valid + ErrorDecode, ///< General failure in the decode stage + ErrorPassphrase, ///< Failure because of incorrect passphrase + ErrorFile ///< Failure because of incorrect file +}; + +/** + Well known discrete logarithm group sets + + These sets are derived from three main sources: + Java Cryptographic Extensions, + RFC2412 and + RFC3526. +*/ +enum DLGroupSet +{ + DSA_512, ///< 512 bit group, for compatibility with JCE + DSA_768, ///< 768 bit group, for compatibility with JCE + DSA_1024, ///< 1024 bit group, for compatibility with JCE + IETF_768, ///< Group 1 from RFC 2412, Section E.1 + IETF_1024, ///< Group 2 from RFC 2412, Section E.2 + IETF_1536, ///< 1536-bit MODP Group ("group 5") from RFC3526 Section 2. + IETF_2048, ///< 2048-bit MODP Group ("group 14") from RFC3526 Section 3. + IETF_3072, ///< 3072-bit MODP Group ("group 15") from RFC3526 Section 4. + IETF_4096, ///< 4096-bit MODP Group ("group 16") from RFC3526 Section 5. + IETF_6144, ///< 6144-bit MODP Group ("group 17") from RFC3526 Section 6. + IETF_8192 ///< 8192-bit MODP Group ("group 18") from RFC3526 Section 7. + +}; + +/** + Encode a hash result in EMSA3 (PKCS#1) format + + This is a convenience function for providers that only have access + to raw RSA signing (mainly smartcard providers). This is a built-in + function of QCA and does not utilize a provider. SHA1, MD5, MD2, + and RIPEMD160 are supported. + + \param hashName the hash type used to create the digest + \param digest the digest to encode in EMSA3 format + \param size the desired size of the encoding output (-1 for automatic size) +*/ +QCA_EXPORT QByteArray emsa3Encode(const QString &hashName, const QByteArray &digest, int size = -1); + +/** + \class DLGroup qca_publickey.h QtCrypto + + A discrete logarithm group + + \ingroup UserAPI +*/ +class QCA_EXPORT DLGroup +{ +public: + DLGroup(); + + /** + Construct a discrete logarithm group from raw parameters + + \param p the P parameter + \param q the Q parameter + \param g the G parameter + */ + DLGroup(const BigInteger &p, const BigInteger &q, const BigInteger &g); + + /** + Construct a discrete logarithm group from raw parameters + + \param p the P parameter + \param g the G parameter + */ + DLGroup(const BigInteger &p, const BigInteger &g); + + /** + Standard copy constructor + + \param from the group to copy from + */ + DLGroup(const DLGroup &from); + ~DLGroup(); + + /** + Standard assignment operator + + \param from the DLGroup to copy from + */ + DLGroup &operator=(const DLGroup &from); + + /** + Provide a list of the supported group sets + + \param provider the provider to report which group sets are + available. If not specified, all providers will be checked + */ + static QList supportedGroupSets(const QString &provider = QString()); + + /** + Test if the group is empty + */ + bool isNull() const; + + /** + Provide the p component of the group + */ + BigInteger p() const; + + /** + Provide the q component of the group + */ + BigInteger q() const; + + /** + Provide the g component of the group + */ + BigInteger g() const; + +private: + class Private; + Private *d; +}; + +/** + \class PKey qca_publickey.h QtCrypto + + General superclass for public (PublicKey) and private (PrivateKey) keys + used with asymmetric encryption techniques. + + \ingroup UserAPI + +*/ +class QCA_EXPORT PKey : public Algorithm +{ +public: + /** + Types of public key cryptography keys supported by QCA + */ + enum Type + { + RSA, ///< RSA key + DSA, ///< DSA key + DH ///< Diffie Hellman key + }; + + /** + Standard constructor + */ + PKey(); + + /** + Standard copy constructor + + \param from the key to copy from + */ + PKey(const PKey &from); + + ~PKey() override; + + /** + Standard assignment operator + + \param from the PKey to copy from + */ + PKey &operator=(const PKey &from); + + /** + Test what types of keys are supported. + + Normally you would just test if the capability is present, however + for PKey, you also need to test which types of keys are available. + So if you want to figure out if RSA keys are supported, you need to + do something like: + \code +if(!QCA::isSupported("pkey") || + !QCA::PKey::supportedTypes().contains(QCA::PKey::RSA)) +{ + // then there is no RSA key support +} +else +{ + // there is RSA key support +} + \endcode + + To make things a bit more complex, supportedTypes() only + checks for basic functionality. If you want to check that + you can do operations with PEM or DER (eg toPEM(), fromPEM(), and + the equivalent DER and PEMfile operations, plus anything else + that uses them, including the constructor form that takes a + fileName), then you need to check for supportedIOTypes() instead. + + \param provider the name of the provider to use, if a particular + provider is required. + + \sa supportedIOTypes() + */ + static QList supportedTypes(const QString &provider = QString()); + + /** + Test what types of keys are supported for IO operations + + If you are using PKey DER or PEM operations, then you need + to check for appropriate support using this method. For example, + if you want to check if you can export or import an RSA key, then + you need to do something like: + \code +if(!QCA::isSupported("pkey") || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) +{ + // then there is no RSA key IO support +} +else +{ + // there is RSA key IO support +} + \endcode + + Note that if you only want to check for basic functionality + (ie not PEM or DER import/export), then you can use + supportedTypes(). There is no need to use both - if the key type + is supported for IO, then is also supported for basic operations. + + \param provider the name of the provider to use, if a particular + provider is required. + + \sa supportedTypes() + */ + static QList supportedIOTypes(const QString &provider = QString()); + + /** + Test if the key is null (empty) + + \return true if the key is null + */ + bool isNull() const; + + /** + Report the Type of key (eg RSA, DSA or Diffie Hellman) + + \sa isRSA, isDSA and isDH for boolean tests. + */ + Type type() const; + + /** + Report the number of bits in the key + */ + int bitSize() const; + + /** + Test if the key is an RSA key + */ + bool isRSA() const; + + /** + Test if the key is a DSA key + */ + bool isDSA() const; + + /** + Test if the key is a Diffie Hellman key + */ + bool isDH() const; + + /** + Test if the key is a public key + */ + bool isPublic() const; + + /** + Test if the key is a private key + */ + bool isPrivate() const; + + /** + Test if the key data can be exported. If the key resides on a + smart card or other such device, this will likely return false. + */ + bool canExport() const; + + /** + Test if the key can be used for key agreement + */ + bool canKeyAgree() const; + + /** + Interpret this key as a PublicKey + + \sa toRSAPublicKey(), toDSAPublicKey() and toDHPublicKey() + for protected forms of this call. + */ + PublicKey toPublicKey() const; + + /** + Interpret this key as a PrivateKey + */ + PrivateKey toPrivateKey() const; + + /** + test if two keys are equal + + \param a the key to compare with this key + */ + bool operator==(const PKey &a) const; + + /** + test if two keys are not equal + + \param a the key to compare with this key + */ + bool operator!=(const PKey &a) const; + +protected: + /** + Create a key of the specified type + + \param type the name of the type of key to create + \param provider the name of the provider to create the key in + */ + PKey(const QString &type, const QString &provider); + + /** + Set the key + + \param k the key to assign from + */ + void set(const PKey &k); + + /** + Interpret this key as an RSAPublicKey + + \note This function is essentially a convenience cast - if the + key was created as a DSA key, this function cannot turn it into + an RSA key. + + \sa toPublicKey() for the public version of this method + */ + RSAPublicKey toRSAPublicKey() const; + + /** + Interpret this key as an RSAPrivateKey + + \note This function is essentially a convenience cast - if the + key was created as a DSA key, this function cannot turn it into + a RSA key. + + \sa toPrivateKey() for the public version of this method + */ + RSAPrivateKey toRSAPrivateKey() const; + + /** + Interpret this key as an DSAPublicKey + + \note This function is essentially a convenience cast - if the + key was created as an RSA key, this function cannot turn it into + a DSA key. + + \sa toPublicKey() for the public version of this method + */ + DSAPublicKey toDSAPublicKey() const; + + /** + Interpret this key as a DSAPrivateKey + + \note This function is essentially a convenience cast - if the + key was created as an RSA key, this function cannot turn it into + a DSA key. + + \sa toPrivateKey() for the public version of this method + */ + DSAPrivateKey toDSAPrivateKey() const; + + /** + Interpret this key as an DHPublicKey + + \note This function is essentially a convenience cast - if the + key was created as a DSA key, this function cannot turn it into + a DH key. + + \sa toPublicKey() for the public version of this method + */ + DHPublicKey toDHPublicKey() const; + + /** + Interpret this key as a DHPrivateKey + + \note This function is essentially a convenience cast - if the + key was created as a DSA key, this function cannot turn it into + a DH key. + + \sa toPrivateKey() for the public version of this method + */ + DHPrivateKey toDHPrivateKey() const; + +private: + void assignToPublic(PKey *dest) const; + void assignToPrivate(PKey *dest) const; + + class Private; + Private *d; +}; + +/** + \class PublicKey qca_publickey.h QtCrypto + + Generic public key + + \ingroup UserAPI + +*/ +class QCA_EXPORT PublicKey : public PKey +{ +public: + /** + Create an empty (null) public key + */ + PublicKey(); + + /** + Create a public key based on a specified private key + + \param k the private key to extract the public key parts from + */ + PublicKey(const PrivateKey &k); + + /** + Import a public key from a PEM representation in a file + + \param fileName the name of the file containing the public key + + \sa fromPEMFile for an alternative method + */ + PublicKey(const QString &fileName); + + /** + Copy constructor + + \param from the PublicKey to copy from + */ + PublicKey(const PublicKey &from); + + ~PublicKey() override; + + /** + Assignment operator + + \param from the PublicKey to copy from + */ + PublicKey &operator=(const PublicKey &from); + + /** + Convenience method to convert this key to an RSAPublicKey + + Note that if the key is not an RSA key (eg it is DSA or DH), + then this will produce a null key. + */ + RSAPublicKey toRSA() const; + + /** + Convenience method to convert this key to a DSAPublicKey + + Note that if the key is not an DSA key (eg it is RSA or DH), + then this will produce a null key. + */ + DSAPublicKey toDSA() const; + + /** + Convenience method to convert this key to a DHPublicKey + + Note that if the key is not an DH key (eg it is DSA or RSA), + then this will produce a null key. + */ + DHPublicKey toDH() const; + + /** + Test if this key can be used for encryption + + \return true if the key can be used for encryption + */ + bool canEncrypt() const; + + /** + Test if this key can be used for decryption + + \return true if the key can be used for decryption + */ + bool canDecrypt() const; + + /** + Test if the key can be used for verifying signatures + + \return true of the key can be used for verification + */ + bool canVerify() const; + + /** + The maximum message size that can be encrypted with a specified + algorithm + + \param alg the algorithm to check + */ + int maximumEncryptSize(EncryptionAlgorithm alg) const; + + /** + Encrypt a message using a specified algorithm + + \param a the message to encrypt + \param alg the algorithm to use + */ + SecureArray encrypt(const SecureArray &a, EncryptionAlgorithm alg); + + /** + Decrypt the message + + \param in the cipher (encrypted) data + \param out the plain text data + \param alg the algorithm to use + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg); + + /** + Initialise the signature verification process + + \param alg the algorithm to use for signing + \param format the specific format to use, for DSA + */ + void startVerify(SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); + + /** + Update the signature verification process with more data + + \param a the array containing the data that should be added to the signature + */ + void update(const MemoryRegion &a); + + /** + Check the signature is valid for the message + + The process to check that a signature is correct is shown below: + \code +// note that pubkey is a PublicKey +if( pubkey.canVerify() ) +{ + pubkey.startVerify( QCA::EMSA3_MD5 ); + pubkey.update( theMessage ); // might be called multiple times + if ( pubkey.validSignature( theSignature ) ) + { + // then signature is valid + } + else + { + // then signature is invalid + } +} + \endcode + + \param sig the signature to check + + \return true if the signature is correct + */ + bool validSignature(const QByteArray &sig); + + /** + Single step message verification + + If you have the whole message to be verified, then this offers a + more convenient approach to verification. + + \param a the message to check the signature on + \param sig the signature to be checked + \param alg the algorithm to use + \param format the signature format to use, for DSA + + \return true if the signature is valid for the message + */ + bool verifyMessage(const MemoryRegion &a, + const QByteArray &sig, + SignatureAlgorithm alg, + SignatureFormat format = DefaultFormat); + + /** + Export the key in Distinguished Encoding Rules (DER) format + */ + QByteArray toDER() const; + + /** + Export the key in Privacy Enhanced Mail (PEM) format + + \sa toPEMFile provides a convenient way to save the PEM encoded key + to a file + \sa fromPEM provides an inverse of toPEM, converting the PEM + encoded key back to a PublicKey + */ + QString toPEM() const; + + /** + Export the key in Privacy Enhanced Mail (PEM) to a file + + \param fileName the name (and path, if necessary) of the file to + save the PEM encoded key to. + + \sa toPEM for a version that exports to a QString, which may be + useful if you need to do more sophisticated handling + \sa fromPEMFile provides an inverse of toPEMFile, reading a PEM + encoded key from a file + */ + bool toPEMFile(const QString &fileName) const; + + /** + Import a key in Distinguished Encoding Rules (DER) format + + This function takes a binary array, which is assumed to contain a + public key in DER encoding, and returns the key. Unless you don't + care whether the import succeeded, you should test the result, as + shown below. + + \code +QCA::ConvertResult conversionResult; +QCA::PublicKey publicKey = QCA::PublicKey::fromDER(keyArray, &conversionResult); +if (! QCA::ConvertGood == conversionResult) +{ + std::cout << "Public key read failed" << std::endl; +} + \endcode + + \param a the array containing a DER encoded key + \param result pointer to a variable, which returns whether the + conversion succeeded (ConvertGood) or not + \param provider the name of the provider to use for the import. + */ + static PublicKey fromDER(const QByteArray &a, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import a key in Privacy Enhanced Mail (PEM) format + + This function takes a string, which is assumed to contain a public + key in PEM encoding, and returns that key. Unless you don't care + whether the import succeeded, you should test the result, as shown + below. + + \code +QCA::ConvertResult conversionResult; +QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(keyAsString, &conversionResult); +if (! QCA::ConvertGood == conversionResult) +{ + std::cout << "Public key read failed" << std::endl; +} + \endcode + + \param s the string containing a PEM encoded key + \param result pointer to a variable, which returns whether the + conversion succeeded (ConvertGood) or not + \param provider the name of the provider to use for the import. + + \sa toPEM, which provides an inverse of fromPEM() + \sa fromPEMFile, which provides an import direct from a file. + */ + static PublicKey fromPEM(const QString &s, ConvertResult *result = nullptr, const QString &provider = QString()); + + /** + Import a key in Privacy Enhanced Mail (PEM) format from a file + + This function takes the name of a file, which is assumed to contain + a public key in PEM encoding, and returns that key. Unless you + don't care whether the import succeeded, you should test the + result, as shown below. + + \code +QCA::ConvertResult conversionResult; +QCA::PublicKey publicKey = QCA::PublicKey::fromPEMFile(fileName, &conversionResult); +if (! QCA::ConvertGood == conversionResult) +{ + std::cout << "Public key read failed" << std::endl; +} + \endcode + + \param fileName a string containing the name of the file + \param result pointer to a variable, which returns whether the + conversion succeeded (ConvertGood) or not + \param provider the name of the provider to use for the import. + + \sa toPEMFile, which provides an inverse of fromPEMFile() + \sa fromPEM, which provides an import from a string + + \note there is also a constructor form that can import from a file + */ + static PublicKey + fromPEMFile(const QString &fileName, ConvertResult *result = nullptr, const QString &provider = QString()); + +protected: + /** + Create a new key of a specified type + + \param type the type of key to create + \param provider the provider to use, if required + */ + PublicKey(const QString &type, const QString &provider); + +private: + class Private; + Private *d; +}; + +/** + \class PrivateKey qca_publickey.h QtCrypto + + Generic private key + + \ingroup UserAPI + +*/ +class QCA_EXPORT PrivateKey : public PKey +{ +public: + /** + Create an empty private key + */ + PrivateKey(); + + /** + Import a private key from a PEM representation in a file + + \param fileName the name of the file containing the private key + \param passphrase the pass phrase for the private key + + \sa fromPEMFile for an alternative method + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + explicit PrivateKey(const QString &fileName, const SecureArray &passphrase = SecureArray()); + + /** + Copy constructor + + \param from the PrivateKey to copy from + */ + PrivateKey(const PrivateKey &from); + + ~PrivateKey() override; + + /** + Assignment operator + + \param from the PrivateKey to copy from + */ + PrivateKey &operator=(const PrivateKey &from); + + /** + Interpret / convert the key to an RSA key + */ + RSAPrivateKey toRSA() const; + + /** + Interpret / convert the key to a DSA key + */ + DSAPrivateKey toDSA() const; + + /** + Interpret / convert the key to a Diffie-Hellman key + */ + DHPrivateKey toDH() const; + + /** + Test if this key can be used for decryption + + \return true if the key can be used for decryption + */ + bool canDecrypt() const; + + /** + Test if this key can be used for encryption + + \return true if the key can be used for encryption + */ + bool canEncrypt() const; + + /** + Test if this key can be used for signing + + \return true if the key can be used to make a signature + */ + bool canSign() const; + + /** + The maximum message size that can be encrypted with a specified + algorithm + + \param alg the algorithm to check + */ + int maximumEncryptSize(EncryptionAlgorithm alg) const; + + /** + Decrypt the message + + \param in the cipher (encrypted) data + \param out the plain text data + \param alg the algorithm to use + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg); + + /** + Encrypt a message using a specified algorithm + + \param a the message to encrypt + \param alg the algorithm to use + */ + SecureArray encrypt(const SecureArray &a, EncryptionAlgorithm alg); + + /** + Initialise the message signature process + + \param alg the algorithm to use for the message signature process + \param format the signature format to use, for DSA + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + void startSign(SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); + + /** + Update the signature process + + \param a the message to use to update the signature + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + void update(const MemoryRegion &a); + + /** + The resulting signature + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + QByteArray signature(); + + /** + One step signature process + + \param a the message to sign + \param alg the algorithm to use for the signature + \param format the signature format to use, for DSA + + \return the signature + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + QByteArray signMessage(const MemoryRegion &a, SignatureAlgorithm alg, SignatureFormat format = DefaultFormat); + + /** + Derive a shared secret key from a public key + + \param theirs the public key to derive from + */ + SymmetricKey deriveKey(const PublicKey &theirs); + + /** + List the supported Password Based Encryption Algorithms that can be + used to protect the key. + + \param provider the provider to use, if a particular provider is + required + */ + static QList supportedPBEAlgorithms(const QString &provider = QString()); + + /** + Export the key in Distinguished Encoding Rules (DER) format + + \param passphrase the pass phrase to use to protect the key + \param pbe the symmetric encryption algorithm to use to protect the + key + + \sa fromDER provides an inverse of toDER, converting the DER + encoded key back to a PrivateKey + */ + SecureArray toDER(const SecureArray &passphrase = SecureArray(), PBEAlgorithm pbe = PBEDefault) const; + + /** + Export the key in Privacy Enhanced Mail (PEM) format + + \param passphrase the pass phrase to use to protect the key + \param pbe the symmetric encryption algorithm to use to protect the + key + + \sa toPEMFile provides a convenient way to save the PEM encoded key + to a file + \sa fromPEM provides an inverse of toPEM, converting the PEM + encoded key back to a PrivateKey + */ + QString toPEM(const SecureArray &passphrase = SecureArray(), PBEAlgorithm pbe = PBEDefault) const; + + /** + Export the key in Privacy Enhanced Mail (PEM) format to a file + + \param fileName the name (and path, if required) that the key + should be exported to. + \param passphrase the pass phrase to use to protect the key + \param pbe the symmetric encryption algorithm to use to protect the + key + + \return true if the export succeeds + + \sa toPEM provides a convenient way to save the PEM encoded key to + a file + \sa fromPEM provides an inverse of toPEM, converting the PEM + encoded key back to a PrivateKey + */ + bool toPEMFile(const QString &fileName, + const SecureArray &passphrase = SecureArray(), + PBEAlgorithm pbe = PBEDefault) const; + + /** + Import the key from Distinguished Encoding Rules (DER) format + + \param a the array containing the DER representation of the key + \param passphrase the pass phrase that is used to protect the key + \param result a pointer to a ConvertResult, that if specified, will + be set to reflect the result of the import + \param provider the provider to use, if a particular provider is + required + + \sa toDER provides an inverse of fromDER, exporting the key to an + array + + \sa QCA::KeyLoader for an asynchronous loader approach. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + static PrivateKey fromDER(const SecureArray &a, + const SecureArray &passphrase = SecureArray(), + ConvertResult *result = nullptr, + const QString &provider = QString()); + + /** + Import the key from Privacy Enhanced Mail (PEM) format + + \param s the string containing the PEM representation of the key + \param passphrase the pass phrase that is used to protect the key + \param result a pointer to a ConvertResult, that if specified, will + be set to reflect the result of the import + \param provider the provider to use, if a particular provider is + required + + \sa toPEM provides an inverse of fromPEM, exporting the key to a + string in PEM encoding. + + \sa QCA::KeyLoader for an asynchronous loader approach. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + static PrivateKey fromPEM(const QString &s, + const SecureArray &passphrase = SecureArray(), + ConvertResult *result = nullptr, + const QString &provider = QString()); + + /** + Import the key in Privacy Enhanced Mail (PEM) format from a file + + \param fileName the name (and path, if required) of the file + containing the PEM representation of the key + \param passphrase the pass phrase that is used to protect the key + \param result a pointer to a ConvertResult, that if specified, will + be set to reflect the result of the import + \param provider the provider to use, if a particular provider is + required + + \sa toPEMFile provides an inverse of fromPEMFile + \sa fromPEM which allows import from a string + + \sa QCA::KeyLoader for an asynchronous loader approach. + + \note there is also a constructor form, that allows you to create + the key directly + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + static PrivateKey fromPEMFile(const QString &fileName, + const SecureArray &passphrase = SecureArray(), + ConvertResult *result = nullptr, + const QString &provider = QString()); + +protected: + /** + Create a new private key + + \param type the type of key to create + \param provider the provider to use, if a specific provider is + required. + */ + PrivateKey(const QString &type, const QString &provider); + +private: + class Private; + Private *d; +}; + +/** + \class KeyGenerator qca_publickey.h QtCrypto + + Class for generating asymmetric key pairs + + This class is used for generating asymmetric keys (public/private key + pairs). + + \ingroup UserAPI + +*/ +class QCA_EXPORT KeyGenerator : public QObject +{ + Q_OBJECT +public: + /** + Create a new key generator + + \param parent the parent object, if applicable + */ + KeyGenerator(QObject *parent = nullptr); + + ~KeyGenerator() override; + + /** + Test whether the key generator is set to operate in blocking mode, + or not + + \return true if the key generator is in blocking mode + + \sa setBlockingEnabled + */ + bool blockingEnabled() const; + + /** + Set whether the key generator is in blocking mode, nor not + + \param b if true, the key generator will be set to operate in + blocking mode, otherwise it will operate in non-blocking mode + + \sa blockingEnabled() + */ + void setBlockingEnabled(bool b); + + /** + Test if the key generator is currently busy, or not + + \return true if the key generator is busy generating a key already + */ + bool isBusy() const; + + /** + Generate an RSA key of the specified length + + This method creates both the public key and corresponding private + key. You almost certainly want to extract the public key part out - + see PKey::toPublicKey for an easy way. + + Key length is a tricky judgment - using less than 2048 is probably + being too liberal for long term use. Don't use less than 1024 + without serious analysis. + + \param bits the length of key that is required + \param exp the exponent - typically 3, 17 or 65537 + \param provider the name of the provider to use, if a particular + provider is required + */ + PrivateKey createRSA(int bits, int exp = 65537, const QString &provider = QString()); + + /** + Generate a DSA key + + This method creates both the public key and corresponding private + key. You almost certainly want to extract the public key part out - + see PKey::toPublicKey for an easy way. + + \param domain the discrete logarithm group that this key should be + generated from + \param provider the name of the provider to use, if a particular + provider is required + + \note Not every DLGroup makes sense for DSA. You should use one of + DSA_512, DSA_768 and DSA_1024. + */ + PrivateKey createDSA(const DLGroup &domain, const QString &provider = QString()); + + /** + Generate a Diffie-Hellman key + + This method creates both the public key and corresponding private + key. You almost certainly want to extract the public key part out - + see PKey::toPublicKey for an easy way. + + \param domain the discrete logarithm group that this key should be + generated from + \param provider the name of the provider to use, if a particular + provider is required + \note For compatibility, you should use one of the IETF_ groupsets + as the domain argument. + */ + PrivateKey createDH(const DLGroup &domain, const QString &provider = QString()); + + /** + Return the last generated key + + This is really only useful when you are working with non-blocking + key generation + */ + PrivateKey key() const; + + /** + Create a new discrete logarithm group + + \param set the set of discrete logarithm parameters to generate + from + \param provider the name of the provider to use, if a particular + provider is required. + */ + DLGroup createDLGroup(QCA::DLGroupSet set, const QString &provider = QString()); + + /** + The current discrete logarithm group + */ + DLGroup dlGroup() const; + +Q_SIGNALS: + /** + Emitted when the key generation is complete. + + This is only used in non-blocking mode + */ + void finished(); + +private: + Q_DISABLE_COPY(KeyGenerator) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class RSAPublicKey qca_publickey.h QtCrypto + + RSA Public Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT RSAPublicKey : public PublicKey +{ +public: + /** + Generate an empty RSA public key + */ + RSAPublicKey(); + + /** + Generate an RSA public key from specified parameters + + \param n the public key value + \param e the public key exponent + \param provider the provider to use, if a particular provider is + required + */ + RSAPublicKey(const BigInteger &n, const BigInteger &e, const QString &provider = QString()); + + /** + Extract the public key components from an RSA private key + + \param k the private key to use as the basis for the public key + */ + RSAPublicKey(const RSAPrivateKey &k); + + /** + The public key value + + This value is the actual public key value (the product of p and q, + the random prime numbers used to generate the RSA key), also known + as the public modulus. + */ + BigInteger n() const; + + /** + The public key exponent + + This value is the exponent chosen in the original key generator + step + */ + BigInteger e() const; +}; + +/** + \class RSAPrivateKey qca_publickey.h QtCrypto + + RSA Private Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT RSAPrivateKey : public PrivateKey +{ +public: + /** + Generate an empty RSA private key + */ + RSAPrivateKey(); + + /** + Generate an RSA private key from specified parameters + + \param n the public key value + \param e the public key exponent + \param p one of the two chosen primes + \param q the other of the two chosen primes + \param d inverse of the exponent, modulo (p-1)(q-1) + \param provider the provider to use, if a particular provider is + required + */ + RSAPrivateKey(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d, + const QString &provider = QString()); + + /** + The public key value + + This value is the actual public key value (the product of p and q, + the random prime numbers used to generate the RSA key), also known + as the public modulus. + */ + BigInteger n() const; + + /** + The public key exponent + + This value is the exponent chosen in the original key generator + step + */ + BigInteger e() const; + + /** + One of the two random primes used to generate the private key + */ + BigInteger p() const; + + /** + The second of the two random primes used to generate the private + key + */ + BigInteger q() const; + + /** + The inverse of the exponent, module (p-1)(q-1) + */ + BigInteger d() const; +}; + +/** + \class DSAPublicKey qca_publickey.h QtCrypto + + Digital Signature %Algorithm Public Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT DSAPublicKey : public PublicKey +{ +public: + /** + Create an empty DSA public key + */ + DSAPublicKey(); + + /** + Create a DSA public key + + \param domain the discrete logarithm group to use + \param y the public random value + \param provider the provider to use, if a specific provider is + required + */ + DSAPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider = QString()); + + /** + Create a DSA public key from a specified private key + + \param k the DSA private key to use as the source + */ + DSAPublicKey(const DSAPrivateKey &k); + + /** + The discrete logarithm group that is being used + */ + DLGroup domain() const; + + /** + The public random value associated with this key + */ + BigInteger y() const; +}; + +/** + \class DSAPrivateKey qca_publickey.h QtCrypto + + Digital Signature %Algorithm Private Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT DSAPrivateKey : public PrivateKey +{ +public: + /** + Create an empty DSA private key + */ + DSAPrivateKey(); + + /** + Create a DSA public key + + \param domain the discrete logarithm group to use + \param y the public random value + \param x the private random value + \param provider the provider to use, if a specific provider is + required + */ + DSAPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider = QString()); + + /** + The discrete logarithm group that is being used + */ + DLGroup domain() const; + + /** + the public random value + */ + BigInteger y() const; + + /** + the private random value + */ + BigInteger x() const; +}; + +/** + \class DHPublicKey qca_publickey.h QtCrypto + + Diffie-Hellman Public Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT DHPublicKey : public PublicKey +{ +public: + /** + Create an empty Diffie-Hellman public key + */ + DHPublicKey(); + + /** + Create a Diffie-Hellman public key + + \param domain the discrete logarithm group to use + \param y the public random value + \param provider the provider to use, if a specific provider is + required + */ + DHPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider = QString()); + + /** + Create a Diffie-Hellman public key from a specified private key + + \param k the Diffie-Hellman private key to use as the source + */ + DHPublicKey(const DHPrivateKey &k); + + /** + The discrete logarithm group that is being used + */ + DLGroup domain() const; + + /** + The public random value associated with this key + */ + BigInteger y() const; +}; + +/** + \class DHPrivateKey qca_publickey.h QtCrypto + + Diffie-Hellman Private Key + + \ingroup UserAPI + +*/ +class QCA_EXPORT DHPrivateKey : public PrivateKey +{ +public: + /** + Create an empty Diffie-Hellman private key + */ + DHPrivateKey(); + + /** + Create a Diffie-Hellman private key + + \param domain the discrete logarithm group to use + \param y the public random value + \param x the private random value + \param provider the provider to use, if a particular provider is + required + */ + DHPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider = QString()); + + /** + The discrete logarithm group that is being used + */ + DLGroup domain() const; + + /** + The public random value associated with this key + */ + BigInteger y() const; + + /** + The private random value associated with this key + */ + BigInteger x() const; +}; +/*@}*/ +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_safetimer.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_safetimer.h new file mode 100644 index 0000000000..fb0ffb7147 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_safetimer.h @@ -0,0 +1,74 @@ +/* + * qca_safetimer.h - Qt Cryptographic Architecture + * Copyright (C) 2014 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef QCA_SAFETIMER_H +#define QCA_SAFETIMER_H + +#include "qca_export.h" +#include + +class QEvent; +class QTimerEvent; + +namespace QCA { + +class QCA_EXPORT SafeTimer : public QObject +{ + Q_OBJECT +public: + SafeTimer(QObject *parent = nullptr); + ~SafeTimer() override; + + int interval() const; + bool isActive() const; + bool isSingleShot() const; + void setInterval(int msec); + void setSingleShot(bool singleShot); + int timerId() const; + +public Q_SLOTS: + void start(int msec); + void start(); + void stop(); + +Q_SIGNALS: + void timeout(); + +protected: + bool event(QEvent *event) override; + void timerEvent(QTimerEvent *event) override; + +private: + // Functions is used internally. Outer world mustn't have access them. + void startTimer() + { + } + void killTimer(int) + { + } + + class Private; + Private *d; +}; + +} + +#endif // QCA_SAFETIMER_H diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_securelayer.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_securelayer.h new file mode 100644 index 0000000000..ca76db5878 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_securelayer.h @@ -0,0 +1,1254 @@ +/* + * qca_securelayer.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_securelayer.h + + Header file for SecureLayer and its subclasses + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ +#ifndef QCA_SECURELAYER_H +#define QCA_SECURELAYER_H + +#include "qca_cert.h" +#include "qca_core.h" +#include "qca_publickey.h" +#include + +namespace QCA { + +/** + Specify the lower-bound for acceptable TLS/SASL security layers + + For TLS, the interpretation of these levels is: + - Any cipher suite that provides non-authenticated communications + (usually anonymous Diffie-Hellman) is SL_Integrity. + - Any cipher suite that is limited to 40 bits (export-version + crippled forms of RC2, RC4 or DES) is SL_Export. Standard + DES (56 bits) and some forms of RC4 (64 bits) are also SL_Export. + - Any normal cipher (AES, Camellia, RC4 or similar) with 128 bits, or + Elliptic Curve Ciphers with 283 bits, is SL_Baseline + - AES or Camellia at least 192 bits, triple-DES and similar + ciphers are SL_High. ECC with 409 or more bits is also SL_High. + - Highest does not have an equivalent strength. It + indicates that the provider should use the strongest + ciphers available (but not less than SL_High). + */ +enum SecurityLevel +{ + SL_None, ///< indicates that no security is ok + SL_Integrity, ///< must at least get integrity protection + SL_Export, ///< must be export level bits or more + SL_Baseline, ///< must be 128 bit or more + SL_High, ///< must be more than 128 bit + SL_Highest ///< SL_High or max possible, whichever is greater +}; + +/** + \class SecureLayer qca_securelayer.h QtCrypto + + Abstract interface to a security layer + + SecureLayer is normally used between an application and a + potentially insecure network. It provides secure + communications over that network. + + The concept is that (after some initial setup), the + application can write() some data to the SecureLayer + implementation, and that data is encrypted (or otherwise + protected, depending on the setup). The SecureLayer + implementation then emits the readyReadOutgoing() signal, + and the application uses readOutgoing() to retrieve the + encrypted data from the SecureLayer implementation. The + encrypted data is then sent out on the network. + + When some encrypted data comes back from the network, the + application does a writeIncoming() to the SecureLayer + implementation. Some time later, the SecureLayer + implementation may emit readyRead() to the application, + which then read()s the decrypted data from the SecureLayer + implementation. + + Note that sometimes data is sent or received between the + SecureLayer implementation and the network without any data + being sent between the application and the SecureLayer + implementation. This is a result of the initial negotiation + activities (which require network traffic to agree a + configuration to use) and other overheads associated with + the secure link. + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureLayer : public QObject +{ + Q_OBJECT +public: + /** + Constructor for an abstract secure communications + layer + + \param parent the parent object for this object + */ + SecureLayer(QObject *parent = nullptr); + + /** + Returns true if the layer has a meaningful "close". + */ + virtual bool isClosable() const; + + /** + Returns the number of bytes available to be read() + on the application side. + */ + virtual int bytesAvailable() const = 0; + + /** + Returns the number of bytes available to be + readOutgoing() on the network side. + */ + virtual int bytesOutgoingAvailable() const = 0; + + /** + Close the link. Note that this may not be + meaningful / possible for all implementations. + + \sa isClosable() for a test that verifies if the + link can be %closed. + */ + virtual void close(); + + /** + This method writes unencrypted (plain) data to + the SecureLayer implementation. You normally + call this function on the application side. + + \param a the source of the application-side data + */ + virtual void write(const QByteArray &a) = 0; + + /** + This method reads decrypted (plain) data from + the SecureLayer implementation. You normally call + this function on the application side after receiving + the readyRead() signal. + */ + virtual QByteArray read() = 0; + + /** + This method accepts encoded (typically encrypted) data + for processing. You normally call this function using + data read from the network socket (e.g. using + QTcpSocket::readAll()) after receiving a signal that + indicates that the socket has data to read. + + \param a the ByteArray to take network-side data from + */ + virtual void writeIncoming(const QByteArray &a) = 0; + + /** + This method provides encoded (typically encrypted) + data. You normally call this function to get data + to write out to the network socket (e.g. using + QTcpSocket::write()) after receiving the + readyReadOutgoing() signal. + + \param plainBytes the number of bytes that were read. + */ + virtual QByteArray readOutgoing(int *plainBytes = nullptr) = 0; + + /** + This allows you to read data without having it + decrypted first. This is intended to be used for + protocols that close off the connection and return + to plain text transfer. You do not normally need to + use this function. + */ + virtual QByteArray readUnprocessed(); + + /** + Convert encrypted bytes written to plain text bytes written + + \param encryptedBytes the number of bytes to convert + */ + virtual int convertBytesWritten(qint64 encryptedBytes) = 0; + +Q_SIGNALS: + /** + This signal is emitted when SecureLayer has + decrypted (application side) data ready to be + read. Typically you will connect this signal to a + slot that reads the data (using read()). + */ + void readyRead(); + + /** + This signal is emitted when SecureLayer has encrypted + (network side) data ready to be read. Typically you + will connect this signal to a slot that reads the data + (using readOutgoing()) and writes it to a network socket. + */ + void readyReadOutgoing(); + + /** + This signal is emitted when the SecureLayer connection + is %closed. + */ + void closed(); + + /** + This signal is emitted when an error is detected. You + can determine the error type using errorCode(). + */ + void error(); + +private: + Q_DISABLE_COPY(SecureLayer) +}; + +/** + \class TLSSession qca_securelayer.h QtCrypto + + Session token, used for TLS resuming + + \ingroup UserAPI + +*/ +class QCA_EXPORT TLSSession : public Algorithm +{ +public: + TLSSession(); + + /** + Copy constructor + + \param from the session token to copy from + */ + TLSSession(const TLSSession &from); + + ~TLSSession() override; + + /** + Assignment operator + + \param from the session token to assign from + */ + TLSSession &operator=(const TLSSession &from); + + /** + Test if the session token is valid + */ + bool isNull() const; +}; + +/** + \class TLS qca_securelayer.h QtCrypto + + Transport Layer Security / Secure Socket Layer + + Transport Layer Security (%TLS) is the current + state-of-the-art in secure transport mechanisms over the + internet. It can be used in a way where only one side of + the link needs to authenticate to the other. This makes it + very useful for servers to provide their identity to + clients. Note that is is possible to use %TLS to + authenticate both client and server. + + %TLS is a IETF standard (RFC2712 for + TLS version 1.0, and RFC4346 for + TLS version 1.1) based on earlier Netscape work on Secure + Socket Layer (SSL version 2 and SSL version 3). New + applications should use at least TLS 1.0, and SSL version 2 + should be avoided due to known security problems. + + \ingroup UserAPI +*/ +class QCA_EXPORT TLS : public SecureLayer, public Algorithm +{ + Q_OBJECT +public: + /** + Operating mode + */ + enum Mode + { + Stream, ///< stream mode + Datagram ///< datagram mode + }; + + /** + Version of %TLS or SSL + */ + enum Version + { + TLS_v1, ///< Transport Layer Security, version 1 + SSL_v3, ///< Secure Socket Layer, version 3 + SSL_v2, ///< Secure Socket Layer, version 2 + DTLS_v1 ///< Datagram Transport Layer Security, version 1 + }; + + /** + Type of error + */ + enum Error + { + ErrorSignerExpired, ///< local certificate is expired + ErrorSignerInvalid, ///< local certificate is invalid in some way + ErrorCertKeyMismatch, ///< certificate and private key don't match + ErrorInit, ///< problem starting up %TLS + ErrorHandshake, ///< problem during the negotiation + ErrorCrypt ///< problem at anytime after + }; + + /** + Type of identity + */ + enum IdentityResult + { + Valid, ///< identity is verified + HostMismatch, ///< valid cert provided, but wrong owner + InvalidCertificate, ///< invalid cert + NoCertificate ///< identity unknown + }; + + /** + Constructor for Transport Layer Security connection + + This produces a Stream (normal %TLS) rather than Datagram (DTLS) + object. + If you want to do DTLS, see below. + + \param parent the parent object for this object + \param provider the name of the provider, if a specific provider + is required + */ + explicit TLS(QObject *parent = nullptr, const QString &provider = QString()); + + /** + Constructor for Transport Layer Security connection. + + This constructor can be used for both normal %TLS (set mode to TLS::Stream) + or DTLS (set mode to TLS::Datagram). + + \param mode the connection Mode + \param parent the parent object for this object + \param provider the name of the provider, if a specific provider is + required + */ + explicit TLS(Mode mode, QObject *parent = nullptr, const QString &provider = QString()); + + /** + Destructor + */ + ~TLS() override; + + /** + Reset the connection + */ + void reset(); + + /** + Get the list of cipher suites that are available for use. + + A cipher suite is a combination of key exchange, + encryption and hashing algorithms that are agreed + during the initial handshake between client and + server. + + \param version the protocol Version that the cipher + suites are required for + + \return list of the names of the cipher suites + supported. + */ + QStringList supportedCipherSuites(const Version &version = TLS_v1) const; + + /** + The local certificate to use. This is the + certificate that will be provided to the peer. This + is almost always required on the server side + (because the server has to provide a certificate to + the client), and may be used on the client side. + + \param cert a chain of certificates that + link the host certificate to a trusted root + certificate. + \param key the private key for the certificate + chain + */ + void setCertificate(const CertificateChain &cert, const PrivateKey &key); + + /** + \overload + + Allows setting a certificate from a KeyBundle. + + \param kb key bundle containing the local certificate + and associated private key. + */ + void setCertificate(const KeyBundle &kb); + + /** + Return the trusted certificates set for this object + */ + CertificateCollection trustedCertificates() const; + + /** + Set up the set of trusted certificates that will be used to verify + that the certificate provided is valid. + + Typically, this will be the collection of root certificates from + the system, which you can get using QCA::systemStore(), however you + may choose to pass whatever certificates match your assurance + needs. + + \param trusted a bundle of trusted certificates. + */ + void setTrustedCertificates(const CertificateCollection &trusted); + + /** + The security level required for this link + + \param s the level required for this link. + */ + void setConstraints(SecurityLevel s); + + /** + \overload + + \param minSSF the minimum Security Strength Factor + required for this link. + \param maxSSF the maximum Security Strength Factor + required for this link. + */ + void setConstraints(int minSSF, int maxSSF); + + /** + \overload + + \param cipherSuiteList a list of the names of + cipher suites that can be used for this link. + + \note the names are the same as the names in the + applicable IETF RFCs (or Internet Drafts if there + is no applicable RFC). + */ + void setConstraints(const QStringList &cipherSuiteList); + + /** + Retrieve the list of allowed issuers by the server, + if the server has provided them. Only DN types will + be present. + + \code +Certificate someCert = ... +PrivateKey someKey = ... + +// see if the server will take our cert +CertificateInfoOrdered issuerInfo = someCert.issuerInfoOrdered().dnOnly(); +foreach(const CertificateInfoOrdered &info, tls->issuerList()) +{ + if(info == issuerInfo) + { + // server will accept someCert, let's present it + tls->setCertificate(someCert, someKey); + break; + } +} + \endcode + */ + QList issuerList() const; + + /** + Sets the issuer list to present to the client. For + use with servers only. Only DN types are allowed. + + \param issuers the list of valid issuers to be used. + */ + void setIssuerList(const QList &issuers); + + /** + Resume a %TLS session using the given session object + + \param session the session state to use for resumption. + */ + void setSession(const TLSSession &session); + + /** + Test if the link can use compression + + \return true if the link can use compression + */ + bool canCompress() const; + + /** + Test if the link can specify a hostname (Server Name + Indication) + + \return true if the link can specify a hostname + */ + bool canSetHostName() const; + + /** + Returns true if compression is enabled + + This only indicates whether or not the object is configured to use + compression, not whether or not the link is actually compressed. + Use isCompressed() for that. + */ + bool compressionEnabled() const; + + /** + Set the link to use compression + + \param b true if the link should use compression, or false to + disable compression + */ + void setCompressionEnabled(bool b); + + /** + Returns the host name specified or an empty string if no host + name is specified. + */ + QString hostName() const; + + /** + Start the %TLS/SSL connection as a client + + Typically, you'll want to perform RFC 2818 validation on the + server's certificate, based on the hostname you're intending + to connect to. Pass a value for \a host in order to have the + validation for you. If you want to bypass this behavior and + do the validation yourself, pass an empty string for \a host. + + If the host is an internationalized domain name, then it must be + provided in unicode format, not in IDNA ACE/punycode format. + + \param host the hostname that you want to connect to + + \note The hostname will be used for Server Name Indication + extension (see + RFC 3546 Section + 3.1) if supported by the backend provider. + */ + void startClient(const QString &host = QString()); + + /** + Start the %TLS/SSL connection as a server. + */ + void startServer(); + + /** + Resumes %TLS processing. + + Call this function after hostNameReceived(), certificateRequested() + peerCertificateAvailable() or handshaken() is emitted. By + requiring this function to be called in order to proceed, + applications are given a chance to perform user interaction between + steps in the %TLS process. + */ + void continueAfterStep(); + + /** + test if the handshake is complete + + \return true if the handshake is complete + + \sa handshaken + */ + bool isHandshaken() const; + + /** + test if the link is compressed + + \return true if the link is compressed + */ + bool isCompressed() const; + + /** + The protocol version that is in use for this connection. + */ + Version version() const; + + /** + The cipher suite that has been negotiated for this connection. + + The name returned here is the name used in the applicable RFC + (or Internet Draft, where there is no RFC). + */ + QString cipherSuite() const; + + /** + The number of effective bits of security being used for this + connection. + + This can differ from the actual number of bits in + the cipher for certain + older "export ciphers" that are deliberately crippled. If you + want that information, use cipherMaxBits(). + */ + int cipherBits() const; + + /** + The number of bits of security that the cipher could use. + + This is normally the same as cipherBits(), but can be greater + for older "export ciphers". + */ + int cipherMaxBits() const; + + /** + The session object of the %TLS connection, which can be used + for resuming. + */ + TLSSession session() const; + + /** + This method returns the type of error that has + occurred. You should only need to check this if the + error() signal is emitted. + */ + Error errorCode() const; + + /** + After the SSL/%TLS handshake is complete, this + method allows you to determine if the other end + of the connection (if the application is a client, + this is the server; if the application is a server, + this is the client) has a valid identity. + + Note that the security of %TLS/SSL depends on + checking this. It is not enough to check that the + certificate is valid - you must check that the + certificate is valid for the entity that you are + trying to communicate with. + + \note If this returns QCA::TLS::InvalidCertificate, + you may wish to use peerCertificateValidity() to + determine whether to proceed or not. + */ + IdentityResult peerIdentityResult() const; + + /** + After the SSL/%TLS handshake is valid, this method + allows you to check if the received certificate + from the other end is valid. As noted in + peerIdentityResult(), you also need to check that + the certificate matches the entity you are trying + to communicate with. + */ + Validity peerCertificateValidity() const; + + /** + The CertificateChain for the local host + certificate. + */ + CertificateChain localCertificateChain() const; + + /** + The PrivateKey for the local host + certificate. + */ + PrivateKey localPrivateKey() const; + + /** + The CertificateChain from the peer (other end of + the connection to the trusted root certificate). + */ + CertificateChain peerCertificateChain() const; + + // reimplemented + bool isClosable() const override; + int bytesAvailable() const override; + int bytesOutgoingAvailable() const override; + void close() override; + void write(const QByteArray &a) override; + QByteArray read() override; + void writeIncoming(const QByteArray &a) override; + QByteArray readOutgoing(int *plainBytes = nullptr) override; + QByteArray readUnprocessed() override; + int convertBytesWritten(qint64 encryptedBytes) override; + + /** + Determine the number of packets available to be + read on the application side. + + \note this is only used with DTLS. + */ + int packetsAvailable() const; + + /** + Determine the number of packets available to be + read on the network side. + + \note this is only used with DTLS. + */ + int packetsOutgoingAvailable() const; + + /** + Return the currently configured maximum packet size + + \note this is only used with DTLS + */ + int packetMTU() const; + + /** + Set the maximum packet size to use. + + \param size the number of bytes to set as the MTU. + + \note this is only used with DTLS. + */ + void setPacketMTU(int size) const; + +Q_SIGNALS: + /** + Emitted if a host name is set by the client. At + this time, the server can inspect the hostName(). + + You must call continueAfterStep() in order for %TLS + processing to resume after this signal is emitted. + + This signal is only emitted in server mode. + + \sa continueAfterStep + */ + void hostNameReceived(); + + /** + Emitted when the server requests a certificate. At + this time, the client can inspect the issuerList(). + + You must call continueAfterStep() in order for %TLS + processing to resume after this signal is emitted. + + This signal is only emitted in client mode. + + \sa continueAfterStep + */ + void certificateRequested(); + + /** + Emitted when a certificate is received from the peer. + At this time, you may inspect peerIdentityResult(), + peerCertificateValidity(), and peerCertificateChain(). + + You must call continueAfterStep() in order for %TLS + processing to resume after this signal is emitted. + + \sa continueAfterStep + */ + void peerCertificateAvailable(); + + /** + Emitted when the protocol handshake is complete. At + this time, all available information about the %TLS + session can be inspected. + + You must call continueAfterStep() in order for %TLS + processing to resume after this signal is emitted. + + \sa continueAfterStep + \sa isHandshaken + */ + void handshaken(); + +protected: + /** + Called when a connection is made to a particular signal + + \param signal the name of the signal that has been + connected to. + */ + void connectNotify(const QMetaMethod &signal) override; + + /** + Called when a connection is removed from a particular signal + + \param signal the name of the signal that has been + disconnected from. + */ + void disconnectNotify(const QMetaMethod &signal) override; + +private: + Q_DISABLE_COPY(TLS) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class SASL qca_securelayer.h QtCrypto + + Simple Authentication and Security Layer protocol implementation + + This class implements the Simple Authenication and Security Layer protocol, + which is described in RFC2222 - see + http://www.ietf.org/rfc/rfc2222.txt. + + As the name suggests, %SASL provides authentication (eg, a "login" of some + form), for a connection oriented protocol, and can also provide protection + for the subsequent connection. + + The %SASL protocol is designed to be extensible, through a range of + "mechanisms", where a mechanism is the actual authentication method. + Example mechanisms include Anonymous, LOGIN, Kerberos V4, and GSSAPI. + Mechanisms can be added (potentially without restarting the server + application) by the system administrator. + + It is important to understand that %SASL is neither "network aware" nor + "protocol aware". That means that %SASL does not understand how the client + connects to the server, and %SASL does not understand the actual + application protocol. + + \ingroup UserAPI + +*/ +class QCA_EXPORT SASL : public SecureLayer, public Algorithm +{ + Q_OBJECT +public: + /** + Possible errors that may occur when using %SASL + */ + enum Error + { + ErrorInit, ///< problem starting up %SASL + ErrorHandshake, ///< problem during the authentication process + ErrorCrypt ///< problem at anytime after + }; + + /** + Possible authentication error states + */ + enum AuthCondition + { + AuthFail, ///< Generic authentication failure + NoMechanism, ///< No compatible/appropriate authentication mechanism + BadProtocol, ///< Bad protocol or cancelled + BadServer, ///< Server failed mutual authentication (client side only) + BadAuth, ///< Authentication failure (server side only) + NoAuthzid, ///< Authorization failure (server side only) + TooWeak, ///< Mechanism too weak for this user (server side only) + NeedEncrypt, ///< Encryption is needed in order to use mechanism (server side only) + Expired, ///< Passphrase expired, has to be reset (server side only) + Disabled, ///< Account is disabled (server side only) + NoUser, ///< User not found (server side only) + RemoteUnavailable ///< Remote service needed for auth is gone (server side only) + }; + + /** + Authentication requirement flag values + */ + enum AuthFlags + { + AuthFlagsNone = 0x00, + AllowPlain = 0x01, + AllowAnonymous = 0x02, + RequireForwardSecrecy = 0x04, + RequirePassCredentials = 0x08, + RequireMutualAuth = 0x10, + RequireAuthzidSupport = 0x20 // server-only + }; + + /** + Mode options for client side sending + */ + enum ClientSendMode + { + AllowClientSendFirst, + DisableClientSendFirst + }; + + /** + Mode options for server side sending + */ + enum ServerSendMode + { + AllowServerSendLast, + DisableServerSendLast + }; + + /** + \class Params qca_securelayer.h QtCrypto + + Parameter flags for the %SASL authentication + + This is used to indicate which parameters are needed by %SASL + in order to complete the authentication process. + + \ingroup UserAPI + */ + class QCA_EXPORT Params + { + public: + Params(); + + /** + Standard constructor. + + The concept behind this is that you set each of the + flags depending on which parameters are needed. + + \param user the username is required + \param authzid the authorization identity is required + \param pass the password is required + \param realm the realm is required + */ + Params(bool user, bool authzid, bool pass, bool realm); + + /** + Standard copy constructor + + \param from the Params object to copy + */ + Params(const Params &from); + ~Params(); + + /** + Standard assignment operator + + \param from the Params object to assign from + */ + Params &operator=(const Params &from); + + /** + User is needed + */ + bool needUsername() const; + + /** + An Authorization ID can be sent if desired + */ + bool canSendAuthzid() const; + + /** + Password is needed + */ + bool needPassword() const; + + /** + A Realm can be sent if desired + */ + bool canSendRealm() const; + + private: + class Private; + Private *d; + }; + + /** + Standard constructor + + \param parent the parent object for this %SASL connection + \param provider if specified, the provider to use. If not + specified, or specified as empty, then any provider is + acceptable. + */ + explicit SASL(QObject *parent = nullptr, const QString &provider = QString()); + + ~SASL() override; + + /** + Reset the %SASL mechanism + */ + void reset(); + + /** + Specify connection constraints + + %SASL supports a range of authentication requirements, and + a range of security levels. This method allows you to + specify the requirements for your connection. + + \param f the authentication requirements, which you typically + build using a binary OR function (eg AllowPlain | AllowAnonymous) + \param s the security level of the encryption, if used. See + SecurityLevel for details of what each level provides. + */ + void setConstraints(AuthFlags f, SecurityLevel s = SL_None); + + /** + \overload + + Unless you have a specific reason for directly specifying a + strength factor, you probably should use the method above. + + \param f the authentication requirements, which you typically + build using a binary OR function (eg AllowPlain | AllowAnonymous) + \param minSSF the minimum security strength factor that is required + \param maxSSF the maximum security strength factor that is required + + \note Security strength factors are a rough approximation to key + length in the encryption function (eg if you are securing with + plain DES, the security strength factor would be 56). + */ + void setConstraints(AuthFlags f, int minSSF, int maxSSF); + + /** + Specify the local address. + + \param addr the address of the local part of the connection + \param port the port number of the local part of the connection + */ + void setLocalAddress(const QString &addr, quint16 port); + + /** + Specify the peer address. + + \param addr the address of the peer side of the connection + \param port the port number of the peer side of the connection + */ + void setRemoteAddress(const QString &addr, quint16 port); + + /** + Specify the id of the externally secured connection + + \param authid the id of the connection + */ + void setExternalAuthId(const QString &authid); + + /** + Specify a security strength factor for an externally secured + connection + + \param strength the security strength factor of the connection + */ + void setExternalSSF(int strength); + + /** + Initialise the client side of the connection + + startClient must be called on the client side of the connection. + clientStarted will be emitted when the operation is completed. + + \param service the name of the service + \param host the client side host name + \param mechlist the list of mechanisms which can be used + \param mode the mode to use on the client side + */ + void startClient(const QString &service, + const QString &host, + const QStringList &mechlist, + ClientSendMode mode = AllowClientSendFirst); + + /** + Initialise the server side of the connection + + startServer must be called on the server side of the connection. + serverStarted will be emitted when the operation is completed. + + \param service the name of the service + \param host the server side host name + \param realm the realm to use + \param mode which mode to use on the server side + */ + void startServer(const QString &service, + const QString &host, + const QString &realm, + ServerSendMode mode = DisableServerSendLast); + + /** + Process the first step in server mode (server) + + Call this with the mechanism selected by the client. If there + is initial client data, call the other version of this function + instead. + + \param mech the mechanism to be used. + */ + void putServerFirstStep(const QString &mech); + + /** + Process the first step in server mode (server) + + Call this with the mechanism selected by the client, and initial + client data. If there is no initial client data, call the other + version of this function instead. + + \param mech the mechanism to be used + \param clientInit the initial data provided by the client side + */ + void putServerFirstStep(const QString &mech, const QByteArray &clientInit); + + /** + Process an authentication step + + Call this with authentication data received from the network. + The only exception is the first step in server mode, in which + case putServerFirstStep must be called. + + \param stepData the authentication data from the network + */ + void putStep(const QByteArray &stepData); + + /** + Return the mechanism selected (client) + */ + QString mechanism() const; + + /** + Return the mechanism list (server) + */ + QStringList mechanismList() const; + + /** + Return the realm list, if available (client) + */ + QStringList realmList() const; + + /** + Return the security strength factor of the connection + */ + int ssf() const; + + /** + Return the error code + */ + Error errorCode() const; + + /** + Return the reason for authentication failure + */ + AuthCondition authCondition() const; + + /** + Specify the username to use in authentication + + \param user the username to use + */ + void setUsername(const QString &user); + + /** + Specify the authorization identity to use in authentication + + \param auth the authorization identity to use + */ + void setAuthzid(const QString &auth); + + /** + Specify the password to use in authentication + + \param pass the password to use + */ + void setPassword(const SecureArray &pass); + + /** + Specify the realm to use in authentication + + \param realm the realm to use + */ + void setRealm(const QString &realm); + + /** + Continue negotiation after parameters have been set (client) + */ + void continueAfterParams(); + + /** + Continue negotiation after auth ids have been checked (server) + */ + void continueAfterAuthCheck(); + + // reimplemented + int bytesAvailable() const override; + int bytesOutgoingAvailable() const override; + void write(const QByteArray &a) override; + QByteArray read() override; + void writeIncoming(const QByteArray &a) override; + QByteArray readOutgoing(int *plainBytes = nullptr) override; + int convertBytesWritten(qint64 encryptedBytes) override; + +Q_SIGNALS: + /** + This signal is emitted when the client has been successfully + started + + \param clientInit true if the client should send an initial + response to the server + \param clientInitData the initial response to send to the server. + Do note that there is a difference in SASL between an empty initial + response and no initial response, and so even if clientInitData is + an empty array, you still need to send an initial response if + clientInit is true. + */ + void clientStarted(bool clientInit, const QByteArray &clientInitData); + + /** + This signal is emitted after the server has been + successfully started + */ + void serverStarted(); + + /** + This signal is emitted when there is data required + to be sent over the network to complete the next + step in the authentication process. + + \param stepData the data to send over the network + */ + void nextStep(const QByteArray &stepData); + + /** + This signal is emitted when the client needs + additional parameters + + After receiving this signal, the application should set + the required parameter values appropriately and then call + continueAfterParams(). + + \param params the parameters that are required by the client + */ + void needParams(const QCA::SASL::Params ¶ms); + + /** + This signal is emitted when the server needs to + perform the authentication check + + If the user and authzid are valid, call continueAfterAuthCheck(). + + \param user the user identification name + \param authzid the user authorization name + */ + void authCheck(const QString &user, const QString &authzid); + + /** + This signal is emitted when authentication is complete. + */ + void authenticated(); + +private: + Q_DISABLE_COPY(SASL) + + class Private; + friend class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_securemessage.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_securemessage.h new file mode 100644 index 0000000000..cbbc8893ee --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_securemessage.h @@ -0,0 +1,957 @@ +/* + * qca_securemessage.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_securemessage.h + + Header file for secure message (PGP, CMS) classes + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_SECUREMESSAGE_H +#define QCA_SECUREMESSAGE_H + +#include "qca_cert.h" +#include "qca_core.h" +#include "qca_publickey.h" +#include + +class QDateTime; + +namespace QCA { + +class SecureMessageSystem; + +/** + \class SecureMessageKey qca_securemessage.h QtCrypto + + Key for SecureMessage system + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureMessageKey +{ +public: + /** + The key type + */ + enum Type + { + None, ///< no key + PGP, ///< Pretty Good Privacy key + X509 ///< X.509 CMS key + }; + + /** + Construct an empty key + */ + SecureMessageKey(); + + /** + Standard copy constructor + + \param from the source key + */ + SecureMessageKey(const SecureMessageKey &from); + + ~SecureMessageKey(); + + /** + Standard assignment operator + + \param from the source key + */ + SecureMessageKey &operator=(const SecureMessageKey &from); + + /** + Returns true for null object + */ + bool isNull() const; + + /** + The key type + */ + Type type() const; + + /** + Public key part of a PGP key + */ + PGPKey pgpPublicKey() const; + + /** + Private key part of a PGP key + */ + PGPKey pgpSecretKey() const; + + /** + Set the public key part of a PGP key + + \param pub the PGP public key + */ + void setPGPPublicKey(const PGPKey &pub); + + /** + Set the private key part of a PGP key + + \param sec the PGP secretkey + */ + void setPGPSecretKey(const PGPKey &sec); + + /** + The X.509 certificate chain (public part) for this key + */ + CertificateChain x509CertificateChain() const; + + /** + The X.509 private key part of this key + */ + PrivateKey x509PrivateKey() const; + + /** + Set the public key part of this X.509 key. + + \param c the Certificate chain containing the public keys + */ + void setX509CertificateChain(const CertificateChain &c); + + /** + Set the private key part of this X.509 key. + + \param k the private key + */ + void setX509PrivateKey(const PrivateKey &k); + + /** + Set the public and private part of this X.509 key with KeyBundle. + + \param kb the public and private key bundle + */ + void setX509KeyBundle(const KeyBundle &kb); + + /** + Test if this key contains a private key part + */ + bool havePrivate() const; + + /** + The name associated with this key + + For a PGP key, this is the primary user ID + + For an X.509 key, this is the Common Name + */ + QString name() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + A list of message keys +*/ +typedef QList SecureMessageKeyList; + +/** + \class SecureMessageSignature qca_securemessage.h QtCrypto + + SecureMessage signature + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureMessageSignature +{ +public: + /** + The result of identity verification + */ + enum IdentityResult + { + Valid, ///< indentity is verified, matches signature + InvalidSignature, ///< valid key provided, but signature failed + InvalidKey, ///< invalid key provided + NoKey ///< identity unknown + }; + + /** + Create an empty signature check object. + + User applications don't normally need to create signature checks. You normally + get the object back as a result of a SecureMessage operation. + */ + SecureMessageSignature(); + + /** + Create a signature check object + + User applications don't normally need to create signature checks. You normally + get the object back as a result of a SecureMessage operation. + + \param r the result of the check + \param v the Validity of the key validation check + \param key the key associated with the signature + \param ts the timestamp associated with the signature + */ + SecureMessageSignature(IdentityResult r, Validity v, const SecureMessageKey &key, const QDateTime &ts); + + /** + Standard copy constructor + + \param from the source signature object + */ + SecureMessageSignature(const SecureMessageSignature &from); + + ~SecureMessageSignature(); + + /** + Standard assignment operator + + \param from the source signature object + */ + SecureMessageSignature &operator=(const SecureMessageSignature &from); + + /** + get the results of the identity check on this signature + */ + IdentityResult identityResult() const; + + /** + get the results of the key validation check on this signature + */ + Validity keyValidity() const; + + /** + get the key associated with this signature + */ + SecureMessageKey key() const; + + /** + get the timestamp associated with this signature + */ + QDateTime timestamp() const; + +private: + class Private; + QSharedDataPointer d; +}; + +/** + A list of signatures +*/ +typedef QList SecureMessageSignatureList; + +/** + \class SecureMessage qca_securemessage.h QtCrypto + + Class representing a secure message + + SecureMessage presents a unified interface for working with both + OpenPGP and CMS (S/MIME) messages. Prepare the object by calling + setFormat(), setRecipient(), and setSigner() as necessary, and then + begin the operation by calling an appropriate 'start' function, such + as startSign(). + + Here is an example of how to perform a Clearsign operation using PGP: + + \code +// first make the SecureMessageKey +PGPKey myPGPKey = getSecretKeyFromSomewhere(); +SecureMessageKey key; +key.setPGPSecretKey(myPGPKey); + +// our data to sign +QByteArray plain = "Hello, world"; + +// let's do it +OpenPGP pgp; +SecureMessage msg(&pgp); +msg.setSigner(key); +msg.startSign(SecureMessage::Clearsign); +msg.update(plain); +msg.end(); +msg.waitForFinished(-1); + +if(msg.success()) +{ + QByteArray result = msg.read(); + // result now contains the clearsign text data +} +else +{ + // error + ... +} + \endcode + + Performing a CMS sign operation is similar. Simply set up the + SecureMessageKey with a Certificate instead of a PGPKey, and operate on a + CMS object instead of an OpenPGP object. + + \sa SecureMessageKey + \sa SecureMessageSignature + \sa OpenPGP + \sa CMS + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureMessage : public QObject, public Algorithm +{ + Q_OBJECT +public: + /** + The type of secure message + */ + enum Type + { + OpenPGP, ///< a Pretty Good Privacy message + CMS ///< a Cryptographic Message Syntax message + }; + + /** + The type of message signature + */ + enum SignMode + { + Message, ///< the message includes the signature + Clearsign, ///< the message is clear signed + Detached ///< the signature is detached + }; + + /** + Formats for secure messages + */ + enum Format + { + Binary, ///< DER/binary + Ascii ///< PEM/ascii-armored + }; + + /** + Errors for secure messages + */ + enum Error + { + ErrorPassphrase, ///< passphrase was either wrong or not provided + ErrorFormat, ///< input format was bad + ErrorSignerExpired, ///< signing key is expired + ErrorSignerInvalid, ///< signing key is invalid in some way + ErrorEncryptExpired, ///< encrypting key is expired + ErrorEncryptUntrusted, ///< encrypting key is untrusted + ErrorEncryptInvalid, ///< encrypting key is invalid in some way + ErrorNeedCard, ///< pgp card is missing + ErrorCertKeyMismatch, ///< certificate and private key don't match + ErrorUnknown, ///< other error + ErrorSignerRevoked, ///< signing key is revoked + ErrorSignatureExpired, ///< signature is expired + ErrorEncryptRevoked ///< encrypting key is revoked + }; + + /** + Create a new secure message + + This constructor uses an existing + SecureMessageSystem object (for example, an OpenPGP + or CMS object) to generate a specific kind of + secure message. + + \param system a pre-existing and configured SecureMessageSystem + object + */ + SecureMessage(SecureMessageSystem *system); + ~SecureMessage() override; + + /** + The Type of secure message + */ + Type type() const; + + /** + Test if the message type supports multiple + (parallel) signatures. + + \return true if the secure message support multiple + parallel signatures + + \note PGP cannot do this - it is primarily a CMS + feature + */ + bool canSignMultiple() const; + + /** + True if the SecureMessageSystem can clearsign + messages. + + \note CMS cannot clearsign - this is normally only + available for PGP + */ + bool canClearsign() const; + + /** + True if the SecureMessageSystem can both sign and + encrypt (in the same operation). + + \note CMS cannot do an integrated sign/encrypt - + this is normally only available for PGP. You can do + separate signing and encrypting operations on the + same message with CMS though. + */ + bool canSignAndEncrypt() const; + + /** + Reset the object state to that of original construction. + Now a new operation can be performed immediately. + */ + void reset(); + + /** + Returns true if bundling of the signer certificate chain is + enabled + */ + bool bundleSignerEnabled() const; + + /** + Returns true if inclusion of S/MIME attributes is enabled + */ + bool smimeAttributesEnabled() const; + + /** + Return the format type set for this message + */ + Format format() const; + + /** + Return the recipient(s) set for this message with setRecipient() or + setRecipients() + */ + SecureMessageKeyList recipientKeys() const; + + /** + Return the signer(s) set for this message with setSigner() or + setSigners() + */ + SecureMessageKeyList signerKeys() const; + + /** + For CMS only, this will bundle the signer certificate chain + into the message. This allows a message to be verified + on its own, without the need to have obtained the signer's + certificate in advance. Email clients using S/MIME often + bundle the signer, greatly simplifying key management. + + This behavior is enabled by default. + + \param b whether to bundle (if true) or not (false) + */ + void setBundleSignerEnabled(bool b); + + /** + For CMS only, this will put extra attributes into the + message related to S/MIME, such as the preferred + type of algorithm to use in replies. The attributes + used are decided by the provider. + + This behavior is enabled by default. + + \param b whether to embed extra attribues (if true) or not (false) + */ + void setSMIMEAttributesEnabled(bool b); + + /** + Set the Format used for messages + + The default is Binary. + + \param f whether to use Binary or Ascii + */ + void setFormat(Format f); + + /** + Set the recipient for an encrypted message + + \param key the recipient's key + + \sa setRecipients + */ + void setRecipient(const SecureMessageKey &key); + + /** + Set the list of recipients for an encrypted message. + + For a list with one item, this has the same effect as setRecipient. + + \param keys the recipients' key + + \sa setRecipient + */ + void setRecipients(const SecureMessageKeyList &keys); + + /** + Set the signer for a signed message. + + This is used for both creating signed messages as well as for + verifying CMS messages that have no signer bundled. + + \param key the key associated with the signer + + \sa setSigners + */ + void setSigner(const SecureMessageKey &key); + + /** + Set the list of signers for a signed message. + + This is used for both creating signed messages as well as for + verifying CMS messages that have no signer bundled. + + For a list with one item, this has the same effect as setSigner. + + \param keys the key associated with the signer + + \sa setSigner + */ + void setSigners(const SecureMessageKeyList &keys); + + /** + Start an encryption operation + + You will normally use this with some code along + these lines: + \code +encryptingObj.startEncrypt(); +encryptingObj.update(message); +// perhaps some more update()s +encryptingObj.end(); + \endcode + + Each update() may (or may not) result in some + encrypted data, as indicated by the readyRead() + signal being emitted. Alternatively, you can wait + until the whole message is available (using either + waitForFinished(), or use the finished() + signal. The encrypted message can then be read + using the read() method. + */ + void startEncrypt(); + + /** + Start an decryption operation + + You will normally use this with some code along + these lines: + \code +decryptingObj.startEncrypt(); +decryptingObj.update(message); +// perhaps some more update()s +decryptingObj.end(); + \endcode + + Each update() may (or may not) result in some + decrypted data, as indicated by the readyRead() + signal being emitted. Alternatively, you can wait + until the whole message is available (using either + waitForFinished(), or the finished() + signal). The decrypted message can then be read + using the read() method. + + \note If decrypted result is also signed (not for + CMS), then the signature will be verified during + this operation. + */ + void startDecrypt(); + + /** + Start a signing operation + + You will normally use this with some code along + these lines: + \code +signingObj.startSign(QCA::SecureMessage::Detached) +signingObj.update(message); +// perhaps some more update()s +signingObj.end(); + \endcode + + For Detached signatures, you won't get any results + until the whole process is done - you either + waitForFinished(), or use the finished() signal, to + figure out when you can get the signature (using + the signature() method, not using read()). For + other formats, you can use the readyRead() signal + to determine when there may be part of a signed + message to read(). + + \param m the mode that will be used to generate the + signature + */ + void startSign(SignMode m = Message); + + /** + Start a verification operation + + \param detachedSig the detached signature to + verify. Do not pass a signature for other signature + types. + */ + void startVerify(const QByteArray &detachedSig = QByteArray()); + + /** + Start a combined signing and encrypting + operation. You use this in the same way as + startEncrypt(). + + \note This may not be possible (e.g. CMS + cannot do this) - see canSignAndEncrypt() for a + suitable test. + */ + void startSignAndEncrypt(); + + /** + Process a message (or the next part of a message) + in the current operation. You need to have already + set up the message (startEncrypt(), startDecrypt(), + startSign(), startSignAndEncrypt() and + startVerify()) before calling this method. + + \param in the data to process + */ + void update(const QByteArray &in); + + /** + Read the available data. + + \note For detached signatures, you don't get + anything back using this method. Use signature() to + get the detached signature(). + */ + QByteArray read(); + + /** + The number of bytes available to be read. + */ + int bytesAvailable() const; + + /** + Complete an operation. + + You need to call this method after you have + processed the message (which you pass in as the + argument to update(). + + \note the results of the operation are not + available as soon as this method returns. You need + to wait for the finished() signal, or use + waitForFinished(). + */ + void end(); + + /** + Block until the operation (encryption, decryption, + signing or verifying) completes. + + \param msecs the number of milliseconds to wait for + the operation to complete. Pass -1 to wait + indefinitely. + + \note You should not use this in GUI + applications where the blocking behaviour looks + like a hung application. Instead, connect the + finished() signal to a slot that handles the + results. + + \note This synchronous operation may require event handling, and so + it must not be called from the same thread as an EventHandler. + */ + bool waitForFinished(int msecs = 30000); + + /** + Indicates whether or not the operation was successful + or failed. If this function returns false, then + the reason for failure can be obtained with errorCode(). + + \sa errorCode + \sa diagnosticText + */ + bool success() const; + + /** + Returns the failure code. + + \sa success + \sa diagnosticText + */ + Error errorCode() const; + + /** + The signature for the message. This is only used + for Detached signatures. For other message types, + you get the message and signature together using + read(). + */ + QByteArray signature() const; + + /** + The name of the hash used for the signature process + */ + QString hashName() const; + + /** + Test if the message was signed. + + This is true for OpenPGP if the decrypted message + was also signed. + + \return true if the message was signed. + */ + bool wasSigned() const; + + /** + Verify that the message signature is correct. + + \return true if the signature is valid for the + message, otherwise return false + */ + bool verifySuccess() const; + + /** + Information on the signer for the message + */ + SecureMessageSignature signer() const; + + /** + Information on the signers for the message. + + This is only meaningful if the message type supports + multiple signatures (see canSignMultiple() for a + suitable test). + */ + SecureMessageSignatureList signers() const; + + /** + Returns a log of technical information about the operation, + which may be useful for presenting to the user in an + advanced error dialog. + */ + QString diagnosticText() const; + +Q_SIGNALS: + /** + This signal is emitted when there is some data to + read. Typically you connect this signal to a slot + that does a read() of the available data. + + \note This signal does not mean that the processing + of a message is necessarily complete - see + finished(). + */ + void readyRead(); + + /** + This signal is emitted when data has been accepted + by the message processor. + + \param bytes the number of bytes written + */ + void bytesWritten(int bytes); + + /** + This signal is emitted when the message is fully + processed. + */ + void finished(); + +private: + Q_DISABLE_COPY(SecureMessage) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class SecureMessageSystem qca_securemessage.h QtCrypto + + Abstract superclass for secure messaging systems + + \sa SecureMessage + \sa SecureMessageKey + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureMessageSystem : public QObject, public Algorithm +{ + Q_OBJECT +public: + ~SecureMessageSystem() override; + +protected: + /** + Protected constructor for SecureMessageSystem + classes. You are meant to be using a subclass (such + as OpenPGP or CMS) - you only need to worry about + this class if you are creating a whole new + SecureMessageSystem type. + + \param parent the parent object for this object + \param type the name of the Type of + SecureMessageSystem to create + \param provider the provider to use, if a specific + provider is required. + */ + SecureMessageSystem(QObject *parent, const QString &type, const QString &provider); + +private: + Q_DISABLE_COPY(SecureMessageSystem) +}; + +/** + \class OpenPGP qca_securemessage.h QtCrypto + + Pretty Good Privacy messaging system + + \sa SecureMessage + \sa SecureMessageKey + + \ingroup UserAPI + +*/ +class QCA_EXPORT OpenPGP : public SecureMessageSystem +{ + Q_OBJECT +public: + /** + Standard constructor + + \param parent the parent object for this object + \param provider the provider to use, if a specific + provider is required + */ + explicit OpenPGP(QObject *parent = nullptr, const QString &provider = QString()); + ~OpenPGP() override; + +private: + Q_DISABLE_COPY(OpenPGP) + + class Private; + Private *d; +}; + +/** + \class CMS qca_securemessage.h QtCrypto + + Cryptographic Message Syntax messaging system + + Cryptographic Message Syntax (%CMS) "is used to digitally + sign, digest, authenticate, or encrypt arbitrary message + content. The %CMS describes an encapsulation syntax for + data protection. It supports digital signatures and + encryption. The syntax allows multiple encapsulations; one + encapsulation envelope can be nested inside another. + Likewise, one party can digitally sign some previously + encapsulated data. It also allows arbitrary attributes, + such as signing time, to be signed along with the message + content, and provides for other attributes such as + countersignatures to be associated with a signature." (from + RFC3852 + "Cryptographic Message Syntax") + + \sa SecureMessage + \sa SecureMessageKey + + \ingroup UserAPI + +*/ +class QCA_EXPORT CMS : public SecureMessageSystem +{ + Q_OBJECT +public: + /** + Standard constructor + + \param parent the parent object for this object + \param provider the provider to use, if a specific + provider is required + */ + explicit CMS(QObject *parent = nullptr, const QString &provider = QString()); + ~CMS() override; + + /** + Return the trusted certificates set for this object + */ + CertificateCollection trustedCertificates() const; + + /** + Return the untrusted certificates set for this object + */ + CertificateCollection untrustedCertificates() const; + + /** + Return the private keys set for this object + */ + SecureMessageKeyList privateKeys() const; + + /** + Set the trusted certificates to use for the + messages built using this CMS object. + + \param trusted the collection of trusted + certificates to use + */ + void setTrustedCertificates(const CertificateCollection &trusted); + + /** + Set the untrusted certificates to use for the + messages built using this CMS object. + + This function is useful when verifying messages that don't + contain the certificates (or intermediate signers) within + the CMS blob. In order to verify such messages, you'll + have to pass the possible signer certs with this function. + + \param untrusted the collection of untrusted + certificates to use + */ + void setUntrustedCertificates(const CertificateCollection &untrusted); + + /** + Set the private keys to use for the messages built + using this CMS object. + + Keys are required for decrypting and signing (not + for encrypting or verifying). + + \param keys the collection of keys to use + */ + void setPrivateKeys(const SecureMessageKeyList &keys); + +private: + Q_DISABLE_COPY(CMS) + + class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_support.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_support.h new file mode 100644 index 0000000000..b16a545808 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_support.h @@ -0,0 +1,1122 @@ +/* + * qca_support.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2005 Justin Karneges + * Copyright (C) 2004,2005, 2007 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_support.h + + Header file for "support" classes used in %QCA + + The classes in this header do not have any cryptographic + content - they are used in %QCA, and are included for convenience. + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_SUPPORT_H +#define QCA_SUPPORT_H + +#include "qca_export.h" +#include "qca_tools.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QCA { + +/** + Convenience method to determine the return type of a method + + This function identifies the return type of a specified + method. This function can be used as shown: + \code +class TestClass : public QObject +{ + Q_OBJECT + // ... +public slots: + QString qstringMethod() { return QString(); }; + bool boolMethod( const QString & ) { return true; }; +}; + +QByteArray myTypeName; + +TestClass testClass; +QList argsList; // empty list, since no args + +myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "qstringMethod" ), argsList ); +// myTypeName is "QString" + +myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "boolMethod" ), argsList ); +// myTypeName is "", because there is no method called "boolMethod" that has no arguments + +argsList << "QString"; // now we have one argument +myTypeName = QCA::methodReturnType( testClass.metaObject(), QByteArray( "boolMethod" ), argsList ); +// myTypeName is "bool" + \endcode + + The return type name of a method returning void is an empty string, not "void" + + \note This function is not normally required for use with + %QCA. It is provided for use in your code, if required. + + \param obj the QMetaObject for the object + \param method the name of the method (without the arguments or brackets) + \param argTypes the list of argument types of the method + + \return the name of the type that this method will return with the specified + argument types. + + \sa QMetaType for more information on the Qt meta type system. + + \relates SyncThread +*/ + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +QCA_EXPORT int methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList &argTypes); +#else +QCA_EXPORT QByteArray methodReturnType(const QMetaObject *obj, + const QByteArray &method, + const QList argTypes); +#endif + +/** + Convenience method to invoke a method by name, using a variant + list of arguments. + + This function can be used as shown: + \code +class TestClass : public QObject +{ + Q_OBJECT + // ... +public slots: + QString qstringMethod() { return QString( "the result" ); }; + bool boolMethod( const QString & ) { return true; }; +}; + +TestClass *testClass = new TestClass; +QVariantList args; + +QVariant stringRes; +// calls testClass->qstringMethod() with no arguments ( since args is an empty list) +bool ret = QCA::invokeMethodWithVariants( testClass, QByteArray( "qstringMethod" ), args, &stringRes ); +// ret is true (since call succeeded), stringRes.toString() is a string - "the result" + +QVariant boolResult; +QString someString( "not important" ); +args << someString; +// calls testClass->boolMethod( someString ), returning result in boolResult +ret = QCA::invokeMethodWithVariants( testClass1, QByteArray( "boolMethod" ), args, &boolResult ); +// ret is true (since call succeeded), boolResult.toBool() is true. + \endcode + + \param obj the object to call the method on + \param method the name of the method (without the arguments or brackets) + \param args the list of arguments to use in the method call + \param ret the return value of the method (unchanged if the call fails) + \param type the type of connection to use + + \return true if the call succeeded, otherwise false + + \relates SyncThread +*/ +QCA_EXPORT bool invokeMethodWithVariants(QObject *obj, + const QByteArray &method, + const QVariantList &args, + QVariant *ret, + Qt::ConnectionType type = Qt::AutoConnection); + +/** + \class SyncThread qca_support.h QtCrypto + + Convenience class to run a thread and interact with it synchronously + + SyncThread makes it easy to perform the common practice of starting a + thread, running some objects in that thread, and then interacting with + those objects safely. Often, there is no need to directly use threading + primitives (e.g. QMutex), resulting in very clean multi-threaded code. + + \note The following is an excerpt from + http://delta.affinix.com/2006/11/13/synchronized-threads-part-3/ + + ---
+ With SyncThread, you can start, stop, and call a method in another thread + while the main thread sleeps. The only requirement is that the methods be + declared as slots. + + Below is a contrived example, where we have an object in another thread + that increments a counter over a some interval, using the Qt event loop, + and provides a method to inspect the value. + + First, the Counter object: + +\code +class Counter : public QObject +{ + Q_OBJECT +private: + int x; + QTimer timer; + +public: + Counter() : timer(this) + { + x = 0; + connect(&timer, &QTimer::timeout, this, &Counter::t_timeout); + } + +public slots: + void start(int seconds) + { + timer.setInterval(seconds * 1000); + timer.start(); + } + + int value() const + { + return x; + } + +private Q_SLOTS: + void t_timeout() + { + ++x; + } +}; +\endcode + + Looks like a typical object, no surprises. + + Now to wrap Counter with SyncThread. We went over how to do this in the + first article, and it is very straightforward: + +\code +class CounterThread : public SyncThread +{ + Q_OBJECT +public: + Counter *counter; + + CounterThread(QObject *parent) : SyncThread(parent) + { + counter = 0; + } + + ~CounterThread() + { + // SyncThread will stop the thread on destruct, but since our + // atStop() function makes references to CounterThread's + // members, we need to shutdown here, before CounterThread + // destructs. + stop(); + } + +protected: + virtual void atStart() + { + counter = new Counter; + } + + virtual void atStop() + { + delete counter; + } +}; +\endcode + + We can then use it like this: + +\code +CounterThread *thread = new CounterThread; + +// after this call, the thread is started and the Counter is ready +thread->start(); + +// let's start the counter with a 1 second interval +thread->call(thread->counter, "start", QVariantList() << 1); +... + +// after some time passes, let's check on the value +int x = thread->call(thread->counter, "value").toInt(); + +// we're done with this thing +delete thread; +\endcode + + Even without the call() function, SyncThread is still very useful + for preparing objects in another thread, which you can then + QObject::connect() to and use signals and slots like normal. + + \ingroup UserAPI +*/ +class QCA_EXPORT SyncThread : public QThread +{ + Q_OBJECT +public: + /** + Standard constructor + + \param parent the parent object for this parent. + */ + SyncThread(QObject *parent = nullptr); + + /** + Calls stop() and then destructs + + \note Subclasses should call stop() in their own destructor + */ + ~SyncThread() override; + + /** + Starts the thread, begins the event loop the thread, and then + calls atStart() in the thread. This function will block until + atStart() has returned. + */ + void start(); + + /** + Stops the event loop of the thread, calls atStop() in the thread, + and instructs the thread to finish. This function will block + until the thread has finished. + */ + void stop(); + + /** + Calls a slot of an object in the thread. This function will block + until the slot has returned. + + It is possible for the call to fail, for example if the method + does not exist. + + The arguments and return value of the call use QVariant. If the + method has no return value (returns void), then the returned + QVariant will be null. + + \param obj the object to call the method on + \param method the name of the method (without the arguments or + brackets) + \param args the list of arguments to use in the method call + \param ok if not 0, true is stored here if the call succeeds, + otherwise false is stored here. + */ + QVariant + call(QObject *obj, const QByteArray &method, const QVariantList &args = QVariantList(), bool *ok = nullptr); + +protected: + /** + Reimplement this to perform your initialization + */ + virtual void atStart() = 0; + + /** + Reimplement this to perform your deinitialization + */ + virtual void atEnd() = 0; + + /** + Starts the event loop and calls atStart and atStop as necessary + */ + void run() override; + +private: + Q_DISABLE_COPY(SyncThread) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class Synchronizer qca_support.h QtCrypto + + Enable synchronization between two threads. +*/ +class QCA_EXPORT Synchronizer : public QObject +{ + Q_OBJECT +public: + /** + Standard constructor + + \param parent the parent object to this object + */ + Synchronizer(QObject *parent); + ~Synchronizer() override; + + /** + Call to pause execution in this thread. This function + will block until conditionMet() is called. + + \param msecs the time to wait before proceeding. The default + timeout value (-1) indicates to wait indefinitely. + */ + bool waitForCondition(int msecs = -1); + + /** + Call to continue execution in the paused thread. + */ + void conditionMet(); + +private: + Q_DISABLE_COPY(Synchronizer) + + class Private; + Private *d; +}; + +/** + \class DirWatch qca_support.h QtCrypto + + Support class to monitor a directory for activity. + + %DirWatch monitors a specified file for any changes. When + the directory changes, the changed() signal is emitted. + + \note QFileSystemWatcher has very similar functionality + to this class. You should evaluate this class and + QFileSystemWatcher to determine which better suits your + application needs. + + \ingroup UserAPI +*/ +class QCA_EXPORT DirWatch : public QObject +{ + Q_OBJECT +public: + /** + Standard constructor + + \param dir the name of the directory to watch. If not + set in the constructor, you can set it using setDirName() + \param parent the parent object for this object + */ + explicit DirWatch(const QString &dir = QString(), QObject *parent = nullptr); + ~DirWatch() override; + + /** + The name of the directory that is being monitored + */ + QString dirName() const; + + /** + Change the directory being monitored + + \param dir the name of the directory to monitor + */ + void setDirName(const QString &dir); + +Q_SIGNALS: + /** + The changed signal is emitted when the directory is + changed (e.g.\ modified by addition or deletion of a + file within the directory, or the deletion of the + directory) + */ + void changed(); + +private: + Q_DISABLE_COPY(DirWatch) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class FileWatch qca_support.h QtCrypto + + Support class to monitor a file for activity + + %FileWatch monitors a specified file for any changes. When + the file changes, the changed() signal is emitted. + + \note QFileSystemWatcher has very similar functionality + to this class. You should evaluate this class and + QFileSystemWatcher to determine which better suits your + application needs. + + \ingroup UserAPI +*/ +class QCA_EXPORT FileWatch : public QObject +{ + Q_OBJECT +public: + /** + Standard constructor + + \param file the name of the file to watch. If not + in this object, you can set it using setFileName() + \param parent the parent object for this object + */ + explicit FileWatch(const QString &file = QString(), QObject *parent = nullptr); + ~FileWatch() override; + + /** + The name of the file that is being monitored + */ + QString fileName() const; + + /** + Change the file being monitored + + \param file the name of the file to monitor + */ + void setFileName(const QString &file); + +Q_SIGNALS: + /** + The changed signal is emitted when the file is + changed (e.g. modified, deleted) + */ + void changed(); + +private: + Q_DISABLE_COPY(FileWatch) + + class Private; + friend class Private; + Private *d; +}; + +class ConsolePrivate; +class ConsoleReferencePrivate; +class ConsoleReference; + +/** + \class Console qca_support.h QtCrypto + + %QCA %Console system + + %QCA provides an API for asynchronous, event-based access to + the console and stdin/stdout, as these facilities are + otherwise not portable. The primary use of this system within + %QCA is for passphrase prompting in command-line applications, + using the tty console type. + + How it works: Create a %Console object for the type of console + desired, and then use ConsoleReference to act on the console. + Only one ConsoleReference may operate on a %Console at a time. + + A %Console object takes over either the physical console (Console::Tty + type) or stdin/stdout (Console::Stdio type). Only one of each type + may be created at a time. + + Whenever code is written that needs a tty or stdio object, the + code should first call one of the static methods (ttyInstance() + or stdioInstance()) to see if a console object for the desired + type exists already. If the object exists, use it. If it does + not exist, the rule is that the relevant code should create the + object, use the object, and then destroy the object when the + operation is completed. + + By following the above rule, you can write code that utilizes + a console without the application having to create some master + console object for you. Of course, if the application has + created a console then it will be used. + + The reason why there is a master console object is that it + is not guaranteed that all I/O will survive creation and + destruction of a console object. If you are using the Stdio + Type, then you probably want a long-lived console object. It + is possible to capture unprocessed I/O by calling + bytesLeftToRead or bytesLeftToWrite. However, it is not + expected that general console-needing code will call these + functions when utilizing a temporary console. Thus, an + application developer would need to create his own console + object, invoke the console-needing code, and then do his own + extraction of the unprocessed I/O if necessary. Another reason + to extract unprocessed I/O is if you need to switch from + %Console back to standard functions (e.g. fgets() ). + + \ingroup UserAPI +*/ +class QCA_EXPORT Console : public QObject +{ + Q_OBJECT +public: + /** + The type of console object + */ + enum Type + { + Tty, ///< physical console + Stdio ///< stdin/stdout + }; + /** + The type of I/O to use with the console object. + */ + enum ChannelMode + { + Read, ///< Read only (equivalent to stdin) + ReadWrite ///< Read/write (equivalent to stdin and stdout) + }; + + /** + The nature of the console operation + */ + enum TerminalMode + { + Default, ///< use default terminal settings + Interactive ///< char-by-char input, no echo + }; + + /** + Standard constructor + + Note that library code should not create a new Console object + without checking whether there is already a Console object of + the required Type. See the main documentation for Console for the + rationale for this. + + \param type the Type of Console object to create + \param cmode the ChannelMode (I/O type) to use + \param tmode the TerminalMode to use + \param parent the parent object for this object + + \sa ttyInstance() and stdioInstance for static methods that allow + you to test whether there is already a Console object of the + required Type, and if there is, obtain a reference to that object. + */ + Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent = nullptr); + ~Console() override; + + /** + The Type of this Console object + */ + Type type() const; + + /** + The ChannelMode of this Console object + */ + ChannelMode channelMode() const; + + /** + The TerminalMode of this Console object + */ + TerminalMode terminalMode() const; + + /** + Test whether standard input is redirected. + + \sa type() and channelMode() + */ + static bool isStdinRedirected(); + + /** + Test whether standard output is redirected. + + \sa type() and channelMode() + */ + static bool isStdoutRedirected(); + + /** + The current terminal-type console object + + \return null if there is no current Console + of this type, otherwise the Console to use + */ + static Console *ttyInstance(); + + /** + The current stdio-type console object + + \return null if there is no current Console + of this type, otherwise the Console to use + */ + static Console *stdioInstance(); + + /** + Release the Console + + This allows access to buffers containing any remaining data + */ + void release(); + + /** + Obtain remaining data from the Console, awaiting + a read operation + */ + QByteArray bytesLeftToRead(); + + /** + Obtain remaining data from the Console, awaiting + a write operation + */ + QByteArray bytesLeftToWrite(); + +private: + Q_DISABLE_COPY(Console) + + friend class ConsolePrivate; + ConsolePrivate *d; + + friend class ConsoleReference; +}; + +/** + \class ConsoleReference qca_support.h QtCrypto + + Manager for a Console + + \note Only one %ConsoleReference object can be active at a time + + \ingroup UserAPI +*/ +class QCA_EXPORT ConsoleReference : public QObject +{ + Q_OBJECT +public: + /** + The security setting to use for the Console being managed. + */ + enum SecurityMode + { + SecurityDisabled, + SecurityEnabled + }; + + /** + Standard constructor + + \param parent the parent object for this object + */ + ConsoleReference(QObject *parent = nullptr); + ~ConsoleReference() override; + + /** + Set the Console object to be managed, and start processing. + + You typically want to use Console::ttyInstance() or + Console::stdioInstance() to obtain the required Console + reference. + + \param console reference to the Console to be managed + \param mode the SecurityMode to use for this Console. + + \sa QCA::Console for more information on how to handle the + console aspects of your application or library code. + */ + bool start(Console *console, SecurityMode mode = SecurityDisabled); + + /** + Stop processing, and release the Console + */ + void stop(); + + /** + The Console object managed by this object + + \sa start() to set the Console to be managed + */ + Console *console() const; + + /** + The security mode setting for the Console object + managed by this object. + + \sa start() to set the SecurityMode + */ + SecurityMode securityMode() const; + + /** + Read data from the Console. + + \param bytes the number of bytes to read. The default + is to read all available bytes + + \sa readSecure() for a method suitable for reading + sensitive data. + */ + QByteArray read(int bytes = -1); + + /** + Write data to the Console. + + \param a the array of data to write to the Console + + \sa writeSecure() for a method suitable for writing + sensitive data. + */ + void write(const QByteArray &a); + + /** + Read secure data from the Console + + \param bytes the number of bytes to read. The default + is to read all available bytes + + \sa read() which is suitable for non-sensitive data + */ + SecureArray readSecure(int bytes = -1); + + /** + Write secure data to the Console + + \param a the array of data to write to the Console + + \sa write() which is suitable for non-sensitive data + */ + void writeSecure(const SecureArray &a); + + /** + Close the write channel + + You only need to call this if writing is enabled + on the Console being managed. + */ + void closeOutput(); + + /** + The number of bytes available to read from the + Console being managed. + */ + int bytesAvailable() const; + + /** + The number of bytes remaining to be written + to the Console being managed + */ + int bytesToWrite() const; + +Q_SIGNALS: + /** + Emitted when there are bytes available to read from + the Console being managed + */ + void readyRead(); + + /** + Emitted when bytes are written to the Console + + \param bytes the number of bytes that were written + + \sa bytesAvailable() + */ + void bytesWritten(int bytes); + + /** + Emitted when the console input is closed + */ + void inputClosed(); + + /** + Emitted when the console output is closed + */ + void outputClosed(); + +private: + Q_DISABLE_COPY(ConsoleReference) + + friend class ConsoleReferencePrivate; + ConsoleReferencePrivate *d; + + friend class Console; +}; + +/** + \class ConsolePrompt qca_support.h QtCrypto + + Console prompt handler. + + This class provides a convenient way to get user input in a secure way, +as shown below: +\code +QCA::ConsolePrompt prompt; +prompt.getHidden("Passphrase"); +prompt.waitForFinished(); +QCA:SecureArray pass = prompt.result(); +\endcode + + \note It is not necessary to use waitForFinished(), because you can + just connect the finished() signal to a suitable method, however + command line (console) applications often require waitForFinished(). + + \ingroup UserAPI +*/ +class QCA_EXPORT ConsolePrompt : public QObject +{ + Q_OBJECT +public: + /** + Standard constructor + + \param parent the parent object for this object + */ + ConsolePrompt(QObject *parent = nullptr); + ~ConsolePrompt() override; + + /** + Allow the user to enter data without it being echo'd to + the terminal. This is particularly useful for entry + of passwords, passphrases and PINs. + + \param promptStr the prompt to display to the user + + \sa result() for how to get the input back. + */ + void getHidden(const QString &promptStr); + + /** + Obtain one character from the user + + \sa resultChar() for how to get the input back. + */ + void getChar(); + + /** + Block waiting for user input. + + You may wish to use the finished() signal to + avoid blocking. + */ + void waitForFinished(); + + /** + Obtain the result of the user input. + + This method is usually called to obtain data + from the user that was requested by the getHidden() + call. + */ + SecureArray result() const; + + /** + Obtain the result of the user input. + + This method is usually called to obtain data + from the user that was requested by the getChar() + call. + */ + QChar resultChar() const; + +Q_SIGNALS: + /** + Emitted when the user input activity has been + completed. + + This corresponds to the provision of a string + for getHidden() or a single character for getChar(). + + \sa waitForFinished + */ + void finished(); + +private: + Q_DISABLE_COPY(ConsolePrompt) + + class Private; + friend class Private; + Private *d; +}; + +class AbstractLogDevice; + +/** + \class Logger qca_support.h QtCrypto + + A simple logging system + + This class provides a simple but flexible approach to logging information + that may be used for debugging or system operation diagnostics. + + There is a single %Logger for each application that uses %QCA. You do not + need to create this %Logger yourself - %QCA automatically creates it on + startup. You can get access to the %Logger using the global QCA::logger() + method. + + By default the Logger just accepts all messages (binary and text). If you + want to get access to those messages, you need to subclass + AbstractLogDevice, and register your subclass (using registerLogDevice()). + You can then take whatever action is appropriate (e.g. show to the user + using the GUI, log to a file or send to standard error). + + \ingroup UserAPI +*/ +class QCA_EXPORT Logger : public QObject +{ + Q_OBJECT +public: + /** + The severity of the message + + This information may be used by the log device to determine + what the appropriate action is. + */ + enum Severity + { + Quiet = 0, ///< Quiet: turn of logging + Emergency = 1, ///< Emergency: system is unusable + Alert = 2, ///< Alert: action must be taken immediately + Critical = 3, ///< Critical: critical conditions + Error = 4, ///< Error: error conditions + Warning = 5, ///< Warning: warning conditions + Notice = 6, ///< Notice: normal but significant condition + Information = 7, ///< Informational: informational messages + Debug = 8 ///< Debug: debug-level messages + }; + + /** + Get the current logging level + + \return Current level + */ + inline Severity level() const + { + return m_logLevel; + } + + /** + Set the current logging level + + \param level new logging level + + Only severities less or equal than the log level one will be logged + */ + void setLevel(Severity level); + + /** + Log a message to all available log devices + + \param message the text to log + */ + void logTextMessage(const QString &message, Severity = Information); + + /** + Log a binary blob to all available log devices + + \param blob the information to log + + \note how this is handled is quite logger specific. For + example, it might be logged as a binary, or it might be + encoded in some way + */ + void logBinaryMessage(const QByteArray &blob, Severity = Information); + + /** + Add an AbstractLogDevice subclass to the existing list of loggers + + \param logger the LogDevice to add + */ + void registerLogDevice(AbstractLogDevice *logger); + + /** + Remove an AbstractLogDevice subclass from the existing list of loggers + + \param loggerName the name of the LogDevice to remove + + \note If there are several log devices with the same name, all will be removed. + */ + void unregisterLogDevice(const QString &loggerName); + + /** + Get a list of the names of all registered log devices + */ + QStringList currentLogDevices() const; + +private: + Q_DISABLE_COPY(Logger) + + friend class Global; + + /** + Create a new message logger + */ + Logger(); + + ~Logger() override; + + QStringList m_loggerNames; + QList m_loggers; + Severity m_logLevel; +}; + +/** + \class AbstractLogDevice qca_support.h QtCrypto + + An abstract log device + + \ingroup UserAPI +*/ +class QCA_EXPORT AbstractLogDevice : public QObject +{ + Q_OBJECT +public: + /** + The name of this log device + */ + QString name() const; + + /** + Log a message + + The default implementation does nothing - you should + override this method in your subclass to do whatever + logging is required + + \param message the message to log + \param severity the severity level of the message + */ + virtual void logTextMessage(const QString &message, Logger::Severity severity); + + /** + Log a binary blob + + The default implementation does nothing - you should + override this method in your subclass to do whatever + logging is required + + \param blob the message (as a byte array) to log + \param severity the severity level of the message + */ + virtual void logBinaryMessage(const QByteArray &blob, Logger::Severity severity); + +protected: + /** + Create a new message logger + + \param name the name of this log device + \param parent the parent for this logger + */ + explicit AbstractLogDevice(const QString &name, QObject *parent = nullptr); + + ~AbstractLogDevice() override = 0; + +private: + Q_DISABLE_COPY(AbstractLogDevice) + + class Private; + Private *d; + + QString m_name; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_textfilter.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_textfilter.h new file mode 100644 index 0000000000..2ffd8c38c6 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_textfilter.h @@ -0,0 +1,327 @@ +/* + * qca_textfilter.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2005 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_textfilter.h + + Header file for text encoding/decoding classes + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_TEXTFILTER_H +#define QCA_TEXTFILTER_H + +#include "qca_core.h" + +namespace QCA { + +/** + \class TextFilter qca_textfilter.h QtCrypto + + Superclass for text based filtering algorithms + + This differs from Filter in that it has the concept + of an algorithm that works in two directions, and + supports operations on QString arguments. + + \ingroup UserAPI +*/ +class QCA_EXPORT TextFilter : public Filter +{ +public: + /** + Standard constructor + + \param dir the Direction that this TextFilter + should use. + */ + TextFilter(Direction dir); + + /** + Reset the TextFilter + + \param dir the Direction that this TextFilter + should use. + */ + void setup(Direction dir); + + /** + The direction the TextFilter is set up to use + */ + Direction direction() const; + + /** + Process an array in the "forward" direction, + returning an array + + This method runs in the forward direction, so + for something like a Base64 encoding, it takes + the "native" array, and returns that array + encoded in base64. + + \param a the array to encode + */ + MemoryRegion encode(const MemoryRegion &a); + + /** + Process an array in the "reverse" direction, + returning an array + + This method runs in the reverse direction, so + for something like a Base64 encoding, it takes + a Base64 encoded array, and returns the "native" + representation. + + \param a the array to decode + */ + MemoryRegion decode(const MemoryRegion &a); + + /** + Process an array in the "forward" direction, + returning a QString + + This is equivalent to encode(), except + that it returns a QString, rather than a + byte array. + + \param a the array to encode + */ + QString arrayToString(const MemoryRegion &a); + + /** + Process an string in the "reverse" direction, + returning a byte array + + This is equivalent to decode(), except + that it takes a QString, rather than a + byte array. + + \param s the array to decode + */ + MemoryRegion stringToArray(const QString &s); + + /** + Process a string in the "forward" direction, + returning a string + + This is equivalent to encode(), except + that it takes and returns a QString, rather than + byte arrays. + + \param s the string to encode + */ + QString encodeString(const QString &s); + + /** + Process a string in the "reverse" direction, + returning a string + + This is equivalent to decode(), except + that it takes and returns a QString, rather than + byte arrays. + + \param s the string to decode + */ + QString decodeString(const QString &s); + +protected: + /** + Internal state variable for the Direction + that the filter operates in + */ + Direction _dir; +}; + +/** + \class Hex qca_textfilter.h QtCrypto + + Hexadecimal encoding / decoding + + \ingroup UserAPI +*/ +class QCA_EXPORT Hex : public TextFilter +{ +public: + /** + Standard constructor + + \param dir the Direction that should be used. + + \note The direction can be changed using + the setup() call. + */ + Hex(Direction dir = Encode); + + /** + Reset the internal state. + + This is useful to reuse an existing Hex object + */ + void clear() override; + + /** + Process more data, returning the corresponding + encoded or decoded (depending on the Direction + set in the constructor or setup() call) representation. + + If you find yourself with code that only calls + this method once, you might be better off using + encode() or decode(). Similarly, if the data is + really a string, you might be better off using + arrayToString(), encodeString(), stringToArray() + or decodeString(). + + \param a the array containing data to process + */ + MemoryRegion update(const MemoryRegion &a) override; + + /** + Complete the algorithm + + \return any remaining output. Because of the way + hexadecimal encoding works, this will return a + zero length array - any output will have been returned + from the update() call. + */ + MemoryRegion final() override; + + /** + Test if an update() or final() call succeeded. + + \return true if the previous call succeeded + */ + bool ok() const override; + +private: + Q_DISABLE_COPY(Hex) + + uchar val; + bool partial; + bool _ok; +}; + +/** + \class Base64 qca_textfilter.h QtCrypto + + %Base64 encoding / decoding + + \ingroup UserAPI +*/ +class QCA_EXPORT Base64 : public TextFilter +{ +public: + /** + Standard constructor + + \param dir the Direction that should be used. + + \note The direction can be changed using + the setup() call. + */ + Base64(Direction dir = Encode); + + /** + Returns true if line breaks are enabled + */ + bool lineBreaksEnabled() const; + + /** + Returns the line break column + */ + int lineBreaksColumn() const; + + /** + Sets line break mode. If enabled, linebreaks will be + added to encoded output or accepted in encoded input. + If disabled, linebreaks in encoded input will cause + a failure to decode. The default is disabled. + + \param b whether to enable line breaks (true) or disable line breaks (false) + */ + void setLineBreaksEnabled(bool b); + + /** + Sets the column that linebreaks should be inserted at + when encoding. + + \param column the column number that line breaks should be inserted at. + */ + void setLineBreaksColumn(int column); + + /** + Reset the internal state. This is useful to + reuse an existing Base64 object + */ + void clear() override; + + /** + Process more data, returning the corresponding + encoded or decoded (depending on the Direction + set in the constructor or setup() call) representation. + + If you find yourself with code that only calls + this method once, you might be better off using + encode() or decode(). Similarly, if the data is + really a string, you might be better off using + arrayToString(), encodeString(), stringToArray() + or decodeString(). + + \param a the array containing data to process + */ + MemoryRegion update(const MemoryRegion &a) override; + + /** + Complete the algorithm + + \return any remaining output. Because of the way + Base64 encoding works, you will get either an + empty array, or an array containing one or two + "=" (equals, 0x3D) characters. + */ + MemoryRegion final() override; + + /** + Test if an update() or final() call succeeded. + + \return true if the previous call succeeded + */ + bool ok() const override; + +private: + Q_DISABLE_COPY(Base64) + + QByteArray partial; + bool _ok; + int col; + bool _lb_enabled; + int _lb_column; + + class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_tools.h b/local/recipes/libs/qca/source/include/QtCrypto/qca_tools.h new file mode 100644 index 0000000000..66f6d052f1 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_tools.h @@ -0,0 +1,850 @@ +/* + * qca_tools.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_tools.h + + Header file for "tool" classes used in %QCA + + These classes differ from those in qca_support.h, in that they have + some cryptographic relationship, and require secure memory. + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_TOOLS_H +#define QCA_TOOLS_H + +#include "qca_export.h" +#include +#include +#include + +class QString; +class QByteArray; +class QTextStream; + +/** + Allocate a block of memory from the secure memory pool. + + This is intended to be used when working with C libraries. + + \param bytes the number of bytes to allocate +*/ +QCA_EXPORT void *qca_secure_alloc(int bytes); + +/** + Free (de-allocate) a block of memory that has been previously + allocated from the secure memory pool. + + This is intended to be used when working with C libraries. + + \param p pointer to the block of memory to be free'd +*/ +QCA_EXPORT void qca_secure_free(void *p); + +/** + Resize (re-allocate) a block of memory that has been previously + allocated from the secure memory pool. + + \param p pointer to the block of memory to be resized. + \param bytes the new size that is required. +*/ +QCA_EXPORT void *qca_secure_realloc(void *p, int bytes); + +namespace QCA { + +/** + \class MemoryRegion qca_tools.h QtCrypto + + Array of bytes that may be optionally secured + + This class is mostly unusable on its own. Either use it as a SecureArray + subclass or call toByteArray() to convert to QByteArray. + + Note that this class is implicitly shared (that is, copy on write). + + \ingroup UserAPI +*/ +class QCA_EXPORT MemoryRegion +{ +public: + MemoryRegion(); + + /** + Constructs a new Memory Region from a null terminated + character array + + \param str pointer to the array of data to copy + */ + MemoryRegion(const char *str); + + /** + Constructs a new MemoryRegion from the data in a + byte array + + \param from the QByteArray to copy from + */ + MemoryRegion(const QByteArray &from); + + /** + Standard copy constructor + + \param from the MemoryRegion to copy from + */ + MemoryRegion(const MemoryRegion &from); + ~MemoryRegion(); + + /** + Standard assignment operator + + \param from the MemoryRegion to copy from + */ + MemoryRegion &operator=(const MemoryRegion &from); + + /** + Standard assignment operator + + \param from the QByteArray to copy from + */ + MemoryRegion &operator=(const QByteArray &from); + + /** + Test if the MemoryRegion is null (i.e. was created + as a null array, and hasn't been resized). + + This is probably not what you are trying to do. If + you are trying to determine whether there are any + bytes in the array, use isEmpty() instead. + */ + bool isNull() const; + + /** + Test if the MemoryRegion is using secure memory, or not. + + In this context, memory is secure if it will not be paged + out to disk. + + \return true if the memory region is secure + */ + bool isSecure() const; + + /** + Convert this memory region to a byte array. + + \note For secure data, this will make it insecure + + \sa data() and constData() for other ways to convert + to an "accessible" format. + */ + QByteArray toByteArray() const; + + /** + Returns true if the size of the memory region is zero. + */ + bool isEmpty() const; + + /** + Returns the number of bytes in the memory region. + */ + int size() const; + + /** + Convert the contents of the memory region to + a C-compatible character array. This consists + of size() bytes, followed by a null terminator. + + \sa toByteArray for an alternative approach. + \sa constData, which is equivalent to this method, but avoids + the possibility that the compiler picks the wrong version. + */ + const char *data() const; + + /** + Convert the contents of the memory region to + a C-compatible character array. This consists + of size() bytes, followed by a null terminator. + + \sa toByteArray for an alternative approach. + \sa data which is equivalent to this method + */ + const char *constData() const; + + /** + Obtain the value of the memory location at the specified + position. + + \param index the offset into the memory region. + + \note The contents of a memory region are between + 0 and size()-1. The content at position size() is + always a null terminator. + */ + const char &at(int index) const; + +protected: + /** + Create a memory region, optionally using secure + storage. + + \param secure if this is true, the memory region + will use secure storage. + + \note This will create a memory region without + any content (i.e. both isNull() and isEmpty() will + return true. + */ + MemoryRegion(bool secure); + + /** + Create a memory region, optionally using secure + storage. + + \param size the number of bytes in the memory + region. + \param secure if this is true, the memory region + will use secure storage. + */ + MemoryRegion(int size, bool secure); + + /** + Create a memory region, optionally using secure + storage. + + This constructor variant allows you to + initialize the memory region from an existing + array. + + \param from the byte array to copy from. + \param secure if this is true, the memory region + will use secure storage. + */ + MemoryRegion(const QByteArray &from, bool secure); + + /** + Convert the contents of the memory region to + a C-compatible character array. This consists + of size() bytes, followed by a null terminator. + */ + char *data(); + + /** + Obtain the value of the memory location at the specified + position. + + \param index the offset into the memory region. + + \note The contents of a memory region are between + 0 and size()-1. The content at position size() is + always a null terminator. + */ + char &at(int index); + + /** + Resize the memory region to the specified size. + + \param size the new size of the region. + */ + bool resize(int size); + + /** + Modify the memory region to match a specified + byte array. This resizes the memory region + as required to match the byte array size. + + \param from the byte array to copy from. + \param secure if this is true, the memory region + will use secure storage. + */ + void set(const QByteArray &from, bool secure); + + /** + Convert the memory region to use the specified + memory type. + + This may involve copying data from secure to + insecure storage, or from insecure to secure + storage. + + \param secure if true, use secure memory; otherwise + use insecure memory. + */ + void setSecure(bool secure); + +private: + bool _secure; + class Private; + QSharedDataPointer d; +}; + +/** + \class SecureArray qca_tools.h QtCrypto + + Secure array of bytes + + The %SecureArray provides an array of memory from a pool that is, + at least partly, secure. In this sense, secure means that the contents + of the memory should not be made available to other applications. By + comparison, a QByteArray or QString may be held in pages that might be + swapped to disk or free'd without being cleared first. + + Note that this class is implicitly shared (that is, copy on write). + + \ingroup UserAPI +*/ +class QCA_EXPORT SecureArray : public MemoryRegion +{ +public: + /** + Construct a secure byte array, zero length + */ + SecureArray(); + + /** + Construct a secure byte array of the specified length + + \param size the number of bytes in the array + \param ch the value every byte should be set to + */ + explicit SecureArray(int size, char ch = 0); + + /** + Construct a secure byte array from a string + + Note that this copies, rather than references the source array. + + \param str the source of the data (as a null terminated string). + */ + SecureArray(const char *str); + + /** + Construct a secure byte array from a QByteArray + + Note that this copies, rather than references the source array. + + \param a the source of the data. + + \sa operator=() + */ + SecureArray(const QByteArray &a); + + /** + Construct a secure byte array from a MemoryRegion + + Note that this copies, rather than references the source array + + \param a the source of the data. + + \sa operator=() + */ + SecureArray(const MemoryRegion &a); + + /** + Construct a (shallow) copy of another secure byte array + + \param from the source of the data and length. + */ + SecureArray(const SecureArray &from); + + ~SecureArray(); + + /** + Creates a reference, rather than a deep copy. + + \param from the array to reference + */ + SecureArray &operator=(const SecureArray &from); + + /** + Creates a copy, rather than references + + \param a the array to copy from + */ + SecureArray &operator=(const QByteArray &a); + + /** + Clears the contents of the array and makes it empty + */ + void clear(); + + /** + Returns a reference to the byte at the index position + + \param index the zero-based offset to obtain + */ + char &operator[](int index); + + /** + Returns a reference to the byte at the index position + + \param index the zero-based offset to obtain + */ + const char &operator[](int index) const; + + /** + Pointer to the data in the secure array + + You can use this for memcpy and similar functions. If you are trying + to obtain data at a particular offset, you might be better off using + at() or operator[] + */ + char *data(); + + /** + Pointer to the data in the secure array + + You can use this for memcpy and similar functions. If you are trying + to obtain data at a particular offset, you might be better off using + at() or operator[] + */ + const char *data() const; + + /** + Pointer to the data in the secure array + + You can use this for memcpy and similar functions. If you are trying + to obtain data at a particular offset, you might be better off using + at() or operator[] + */ + const char *constData() const; + + /** + Returns a reference to the byte at the index position + + \param index the zero-based offset to obtain + */ + char &at(int index); + + /** + Returns a reference to the byte at the index position + + \param index the zero-based offset to obtain + */ + const char &at(int index) const; + + /** + Returns the number of bytes in the array + */ + int size() const; + + /** + Test if the array contains any bytes. + + This is equivalent to testing (size() != 0). Note that if + the array is allocated, isEmpty() is false (even if no data + has been added) + + \return true if the array has zero length, otherwise false + */ + bool isEmpty() const; + + /** + Change the length of this array + If the new length is less than the old length, the extra information + is (safely) discarded. If the new length is equal to or greater than + the old length, the existing data is copied into the array. + + \param size the new length + */ + bool resize(int size); + + /** + Fill the data array with a specified character + + \param fillChar the character to use as the fill + \param fillToPosition the number of characters to fill + to. If not specified (or -1), fills array to + current length. + + \note This function does not extend the array - if + you ask for fill beyond the current length, only + the current length will be used. + \note The number of characters is 1 based, so if + you ask for fill('x', 10), it will fill from + */ + void fill(char fillChar, int fillToPosition = -1); + + /** + Copy the contents of the secure array out to a + standard QByteArray. Note that this performs a deep copy + of the data. + */ + QByteArray toByteArray() const; + + /** + Append a secure byte array to the end of this array + + \param a the array to append to this array + */ + SecureArray &append(const SecureArray &a); + + /** + Equality operator. Returns true if both arrays have the same + data (and the same length, of course). + + \param other the MemoryRegion to compare to + */ + bool operator==(const MemoryRegion &other) const; + + /** + Inequality operator. Returns true if both arrays have different + length, or the same length but different data. + + \param other the MemoryRegion to compare to + */ + inline bool operator!=(const MemoryRegion &other) const + { + return !(*this == other); + } + + /** + Append a secure byte array to the end of this array + + \param a the array to append to this array + */ + SecureArray &operator+=(const SecureArray &a); + +protected: + /** + Assign the contents of a provided byte array to this + object. + + \param from the byte array to copy + */ + void set(const SecureArray &from); + + /** + Assign the contents of a provided byte array to this + object. + + \param from the byte array to copy + */ + void set(const QByteArray &from); +}; + +/** + Returns an array that is the result of concatenating a and b + + \param a the string to put at the start of the result + \param b the string to put at the end of the result +*/ +QCA_EXPORT const SecureArray operator+(const SecureArray &a, const SecureArray &b); + +/** + \class BigInteger qca_tools.h QtCrypto + + Arbitrary precision integer + + BigInteger provides arbitrary precision integers. + \code +if ( BigInteger("3499543804349") == + BigInteger("38493290803248") + BigInteger( 343 ) ) +{ + // do something +} + \endcode + + \ingroup UserAPI +*/ +class QCA_EXPORT BigInteger +{ +public: + /** + Constructor. Creates a new BigInteger, initialised to zero. + */ + BigInteger(); + + /** + \overload + + \param n an alternative integer initialisation value. + */ + BigInteger(int n); + + /** + \overload + + \param c an alternative initialisation value, encoded as a character array + + \code +BigInteger b ( "9890343" ); + \endcode + */ + BigInteger(const char *c); + + /** + \overload + + \param s an alternative initialisation value, encoded as a string + */ + BigInteger(const QString &s); + + /** + \overload + + \param a an alternative initialisation value, encoded as SecureArray + */ + BigInteger(const QCA::SecureArray &a); + + /** + \overload + + \param from an alternative initialisation value, encoded as a %BigInteger + */ + BigInteger(const BigInteger &from); + + ~BigInteger(); + + /** + Assignment operator + + \param from the BigInteger to copy from + + \code +BigInteger a; // a is zero +BigInteger b( 500 ); +a = b; // a is now 500 + \endcode + */ + BigInteger &operator=(const BigInteger &from); + + /** + \overload + + \param s the QString containing an integer representation + + \sa bool fromString(const QString &s) + + \note it is the application's responsibility to make sure + that the QString represents a valid integer (ie it only + contains numbers and an optional minus sign at the start) + */ + BigInteger &operator=(const QString &s); + + /** + Increment in place operator + + \param b the amount to increment by + + \code +BigInteger a; // a is zero +BigInteger b( 500 ); +a += b; // a is now 500 +a += b; // a is now 1000 + \endcode + */ + BigInteger &operator+=(const BigInteger &b); + + /** + Decrement in place operator + + \param b the amount to decrement by + + \code +BigInteger a; // a is zero +BigInteger b( 500 ); +a -= b; // a is now -500 +a -= b; // a is now -1000 + \endcode + */ + BigInteger &operator-=(const BigInteger &b); + + /** + Multiply in place operator + + \param b the amount to multiply by + */ + BigInteger &operator*=(const BigInteger &b); + + /** + Divide in place operator + + \param b the amount to divide by + */ + BigInteger &operator/=(const BigInteger &b); + + /** + Modulo in place operator + + \param b the amount to divide by + */ + BigInteger &operator%=(const BigInteger &b); + + /** + Output %BigInteger as a byte array, useful for storage or + transmission. The format is a binary integer in sign-extended + network-byte-order. + + \sa void fromArray(const SecureArray &a); + */ + QCA::SecureArray toArray() const; + + /** + Assign from an array. The input is expected to be a binary integer + in sign-extended network-byte-order. + + \param a a SecureArray that represents an integer + + \sa BigInteger(const SecureArray &a); + \sa SecureArray toArray() const; + */ + void fromArray(const QCA::SecureArray &a); + + /** + Convert %BigInteger to a QString + + \code +QString aString; +BigInteger aBiggishInteger( 5878990 ); +aString = aBiggishInteger.toString(); // aString is now "5878990" + \endcode + */ + QString toString() const; + + /** + Assign from a QString + + \param s a QString that represents an integer + + \note it is the application's responsibility to make sure + that the QString represents a valid integer (ie it only + contains numbers and an optional minus sign at the start) + + \sa BigInteger(const QString &s) + \sa BigInteger & operator=(const QString &s) + */ + bool fromString(const QString &s); + + /** + Compare this value with another %BigInteger + + Normally it is more readable to use one of the operator overloads, + so you don't need to use this method directly. + + \param n the BigInteger to compare with + + \return zero if the values are the same, negative if the argument + is less than the value of this BigInteger, and positive if the + argument value is greater than this BigInteger + + \code +BigInteger a( "400" ); +BigInteger b( "-400" ); +BigInteger c( " 200 " ); +int result; +result = a.compare( b ); // return positive 400 > -400 +result = a.compare( c ); // return positive, 400 > 200 +result = b.compare( c ); // return negative, -400 < 200 + \endcode + */ + int compare(const BigInteger &n) const; + + /** + Equality operator. Returns true if the two BigInteger values + are the same, including having the same sign. + + \param other the BigInteger to compare to + */ + inline bool operator==(const BigInteger &other) const + { + return (compare(other) == 0); + } + + /** + Inequality operator. Returns true if the two BigInteger values + are different in magnitude, sign or both. + + \param other the BigInteger to compare to + */ + inline bool operator!=(const BigInteger &other) const + { + return !(*this == other); + } + + /** + Less than or equal operator. Returns true if the BigInteger value + on the left hand side is equal to or less than the BigInteger + value on the right hand side. + + \param other the BigInteger to compare to + */ + inline bool operator<=(const BigInteger &other) const + { + return (compare(other) <= 0); + } + + /** + Greater than or equal operator. Returns true if the BigInteger + value on the left hand side is equal to or greater than the + BigInteger value on the right hand side. + + \param other the BigInteger to compare to + */ + inline bool operator>=(const BigInteger &other) const + { + return (compare(other) >= 0); + } + + /** + Less than operator. Returns true if the BigInteger value + on the left hand side is less than the BigInteger value + on the right hand side. + + \param other the BigInteger to compare to + */ + inline bool operator<(const BigInteger &other) const + { + return (compare(other) < 0); + } + + /** + Greater than operator. Returns true if the BigInteger value + on the left hand side is greater than the BigInteger value + on the right hand side. + + \param other the BigInteger to compare to + */ + inline bool operator>(const BigInteger &other) const + { + return (compare(other) > 0); + } + +private: + class Private; + QSharedDataPointer d; +}; + +/** + Stream operator + + \param stream the stream to write to + \param b the integer to write to the stream + + \relates BigInteger +*/ +QCA_EXPORT QTextStream &operator<<(QTextStream &stream, const BigInteger &b); + +} + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qca_version.h.in b/local/recipes/libs/qca/source/include/QtCrypto/qca_version.h.in new file mode 100644 index 0000000000..15d5f306c5 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qca_version.h.in @@ -0,0 +1,81 @@ +/* + * qca_version.h - Qt Cryptographic Architecture + * Copyright (C) 2014 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qca_version.h + + Header file with %QCA version + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCA_VERSION_H +#define QCA_VERSION_H + +/** + The major part of current %QCA version. +*/ + +#define QCA_MAJOR_VERSION @QCA_LIB_MAJOR_VERSION@ + +/** + The minor part of current %QCA version. +*/ + +#define QCA_MINOR_VERSION @QCA_LIB_MINOR_VERSION@ + +/** + The patch part of current %QCA version. +*/ + +#define QCA_PATCH_VERSION @QCA_LIB_PATCH_VERSION@ + +/** + The current version of %QCA as string. + */ + +#define QCA_VERSION_STR "@QCA_LIB_VERSION_STRING@" + +/** + Can be used like #if (QCA_VERSION >= %QCA_VERSION_CHECK(2, 0, 3)) + + \param major part of the version + \param minor part of the version + \param patch part of the version +*/ + +#define QCA_VERSION_CHECK(major, minor, patch) \ + ((major << 16) | (minor << 8) | (patch)) + +/** + The current version of %QCA + + This provides you a compile time check of the %QCA version. + + \sa qcaVersion for a runtime check. +*/ + +#define QCA_VERSION \ + QCA_VERSION_CHECK(@QCA_LIB_MAJOR_VERSION@, @QCA_LIB_MINOR_VERSION@, @QCA_LIB_PATCH_VERSION@) + +#endif // QCA_VERSION_H diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qcaprovider.h b/local/recipes/libs/qca/source/include/QtCrypto/qcaprovider.h new file mode 100644 index 0000000000..bd6ac265d8 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qcaprovider.h @@ -0,0 +1,3158 @@ +/* + * qcaprovider.h - QCA Plugin API + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qcaprovider.h + + Header file for provider implementation classes (plugins) + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QCAPROVIDER_H +#define QCAPROVIDER_H + +#include "qca_basic.h" +#include "qca_cert.h" +#include "qca_core.h" +#include "qca_keystore.h" +#include "qca_publickey.h" +#include "qca_securelayer.h" +#include "qca_securemessage.h" + +#include + +#ifndef DOXYGEN_NO_PROVIDER_API + +/** + \defgroup ProviderAPI QCA provider API + + This group of classes is not normally needed + by application writers, but can be used to extend QCA if + required +*/ + +/** + \class QCAPlugin qcaprovider.h QtCrypto + + Provider plugin base class + + QCA loads cryptographic provider plugins with QPluginLoader. The QObject + obtained when loading the plugin must implement the QCAPlugin interface. + This is done by inheriting QCAPlugin, and including + Q_INTERFACES(QCAPlugin) in your class declaration. + + For example: +\code +class MyPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_INTERFACES(QCAPlugin) +public: + virtual Provider *createProvider() { ... } +}; +\endcode + + There is only one function to reimplement, called createProvider(). This + function should return a newly allocated Provider instance. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT QCAPlugin +{ +public: + /** + Destructs the object + */ + virtual ~QCAPlugin() + { + } + + /** + Returns a newly allocated Provider instance. + */ + virtual QCA::Provider *createProvider() = 0; +}; + +Q_DECLARE_INTERFACE(QCAPlugin, "com.affinix.qca.Plugin/1.0") + +namespace QCA { + +/** + \class InfoContext qcaprovider.h QtCrypto + + Extended provider information + + \note This class is part of the provider plugin interface and should not + be used directly by applications. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT InfoContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + InfoContext(Provider *p) + : BasicContext(p, QStringLiteral("info")) + { + } + + /** + The hash algorithms supported by the provider + */ + virtual QStringList supportedHashTypes() const; + + /** + The cipher algorithms supported by the provider + */ + virtual QStringList supportedCipherTypes() const; + + /** + The mac algorithms supported by the provider + */ + virtual QStringList supportedMACTypes() const; +}; + +/** + \class RandomContext qcaprovider.h QtCrypto + + Random provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Random instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT RandomContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + RandomContext(Provider *p) + : BasicContext(p, QStringLiteral("random")) + { + } + + /** + Return an array of random bytes + + \param size the number of random bytes to return + */ + virtual SecureArray nextBytes(int size) = 0; +}; + +/** + \class HashContext qcaprovider.h QtCrypto + + Hash provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Hash instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT HashContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the name of the type of hash provided by this context + */ + HashContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Reset the object to its initial state + */ + virtual void clear() = 0; + + /** + Process a chunk of data + + \param a the input data to process + */ + virtual void update(const MemoryRegion &a) = 0; + + /** + Return the computed hash + */ + virtual MemoryRegion final() = 0; +}; + +/** + \class CipherContext qcaprovider.h QtCrypto + + Cipher provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Cipher instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CipherContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the name of the type of cipher provided by this context + + \note type includes the name of the cipher (e.g. "aes256"), the operating + mode (e.g. "cbc" or "ofb") and the padding type (e.g. "pkcs7") if any. + */ + CipherContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Set up the object for encrypt/decrypt + + \param dir the direction for the cipher (encryption/decryption) + \param key the symmetric key to use for the cipher + \param iv the initialization vector to use for the cipher (not used in ECB mode) + \param tag the AuthTag to use (only for GCM and CCM modes) + */ + virtual void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag) = 0; + + /** + Returns the KeyLength for this cipher + */ + virtual KeyLength keyLength() const = 0; + + /** + Returns the block size for this cipher + */ + virtual int blockSize() const = 0; + + /** + Returns the authentication tag for this cipher + */ + virtual AuthTag tag() const = 0; + + /** + Process a chunk of data. Returns true if successful. + + \param in the input data to process + \param out pointer to an array that should store the result + */ + virtual bool update(const SecureArray &in, SecureArray *out) = 0; + + /** + Finish the cipher processing. Returns true if successful. + + \param out pointer to an array that should store the result + */ + virtual bool final(SecureArray *out) = 0; +}; + +/** + \class MACContext qcaprovider.h QtCrypto + + Message authentication code provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want + MessageAuthenticationCode instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT MACContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + \param p the provider associated with this context + \param type the name of the type of MAC algorithm provided by this context + */ + MACContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Set up the object for hashing + + \param key the key to use with the MAC. + */ + virtual void setup(const SymmetricKey &key) = 0; + + /** + Returns the KeyLength for this MAC algorithm + */ + virtual KeyLength keyLength() const = 0; + + /** + Process a chunk of data + + \param in the input data to process + */ + virtual void update(const MemoryRegion &in) = 0; + + /** + Compute the result after processing all data + + \param out pointer to an array that should store the result + */ + virtual void final(MemoryRegion *out) = 0; + +protected: + /** + Returns a KeyLength that supports any length + */ + KeyLength anyKeyLength() const + { + // this is used instead of a default implementation to make sure that + // provider authors think about it, at least a bit. + // See Meyers, Effective C++, Effective C++ (2nd Ed), Item 36 + return KeyLength(0, INT_MAX, 1); + } +}; + +/** + \class KDFContext qcaprovider.h QtCrypto + + Key derivation function provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want KeyDerivationFunction + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT KDFContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the name of the KDF provided by this context (including algorithm) + */ + KDFContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Create a key and return it + + \param secret the secret part (typically password) + \param salt the salt / initialization vector + \param keyLength the length of the key to be produced + \param iterationCount the number of iterations of the derivation algorithm + */ + virtual SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) = 0; + + /** + Create a key and return it + + \param secret the secret part (typically password) + \param salt the salt / initialization vector + \param keyLength the length of the key to be produced + \param msecInterval the maximum time to compute the key, in milliseconds + \param iterationCount a pointer to store the number of iterations of the derivation algorithm + */ + virtual SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) = 0; +}; + +/** + \class HKDFContext qcaprovider.h QtCrypto + + HKDF provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want HKDF instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT HKDFContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the name of the HKDF provided by this context (including algorithm) + */ + HKDFContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Create a key and return it + + \param secret the secret part (typically password) + \param salt the salt / initialization vector + \param info the info / initialization vector + \param keyLength the length of the key to be produced + */ + virtual SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + const InitializationVector &info, + unsigned int keyLength) = 0; +}; + +/** + \class DLGroupContext qcaprovider.h QtCrypto + + Discrete logarithm provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want DLGroup instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT DLGroupContext : public Provider::Context +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + DLGroupContext(Provider *p) + : Provider::Context(p, QStringLiteral("dlgroup")) + { + } + + /** + The DLGroupSets supported by this object + */ + virtual QList supportedGroupSets() const = 0; + + /** + Returns true if there is a result to obtain + */ + virtual bool isNull() const = 0; + + /** + Attempt to create P, Q, and G values from the specified group set + + If \a block is true, then this function blocks until completion. + Otherwise, this function returns immediately and finished() is + emitted when the operation completes. + + If an error occurs during generation, then the operation will + complete and isNull() will return true. + + \param set the group set to generate the key from + \param block whether to block (true) or not (false) + */ + virtual void fetchGroup(DLGroupSet set, bool block) = 0; + + /** + Obtain the result of the operation. Ensure isNull() returns false + before calling this function. + + \param p the P value + \param q the Q value + \param g the G value + */ + virtual void getResult(BigInteger *p, BigInteger *q, BigInteger *g) const = 0; + +Q_SIGNALS: + /** + Emitted when the fetchGroup() operation completes in non-blocking + mode. + */ + void finished(); +}; + +/** + \class PKeyBase qcaprovider.h QtCrypto + + Public key implementation provider base + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want PKey, PublicKey, or + PrivateKey instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT PKeyBase : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + \param type type of key provided by this context + */ + PKeyBase(Provider *p, const QString &type); + + /** + Returns true if this object is not valid. This is the default + state, and the object may also become this state if a conversion + or generation function fails. + */ + virtual bool isNull() const = 0; + + /** + Returns the type of public key + */ + virtual PKey::Type type() const = 0; + + /** + Returns true if this is a private key, otherwise false + */ + virtual bool isPrivate() const = 0; + + /** + Returns true if the components of this key are accessible and + whether it can be serialized into an output format. Private keys + from a smart card device will often not be exportable. + */ + virtual bool canExport() const = 0; + + /** + If the key is a private key, this function will convert it into a + public key (all private key data includes the public data as well, + which is why this is possible). If the key is already a public + key, then this function has no effect. + */ + virtual void convertToPublic() = 0; + + /** + Returns the number of bits in the key + */ + virtual int bits() const = 0; + + /** + Returns the maximum number of bytes that can be encrypted by this + key + + \param alg the algorithm to be used for encryption + */ + virtual int maximumEncryptSize(EncryptionAlgorithm alg) const; + + /** + Encrypt data + + \param in the input data to encrypt + \param alg the encryption algorithm to use + */ + virtual SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg); + + /** + Decrypt data + + \param in the input data to decrypt + \param out pointer to an array to store the plaintext result + \param alg the encryption algorithm used to generate the input + data + */ + virtual bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg); + + /** + Begin a signing operation + + \param alg the signature algorithm to use + \param format the signature format to use + */ + virtual void startSign(SignatureAlgorithm alg, SignatureFormat format); + + /** + Begin a verify operation + + \param alg the signature algorithm used by the input signature + \param format the signature format used by the input signature + */ + virtual void startVerify(SignatureAlgorithm alg, SignatureFormat format); + + /** + Process the plaintext input data for either signing or verifying, + whichever operation is active. + + \param in the input data to process + */ + virtual void update(const MemoryRegion &in); + + /** + Complete a signing operation, and return the signature value + + If there is an error signing, an empty array is returned. + */ + virtual QByteArray endSign(); + + /** + Complete a verify operation, and return true if successful + + If there is an error verifying, this function returns false. + + \param sig the signature to verify with the input data + */ + virtual bool endVerify(const QByteArray &sig); + + /** + Compute a symmetric key based on this private key and some other + public key + + Essentially for Diffie-Hellman only. + + \param theirs the other side (public key) to be used for key generation. + */ + virtual SymmetricKey deriveKey(const PKeyBase &theirs); + +Q_SIGNALS: + /** + Emitted when an asynchronous operation completes on this key. + Such operations will be documented that they emit this signal. + */ + void finished(); +}; + +/** + \class RSAContext qcaprovider.h QtCrypto + + RSA provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want RSAPublicKey or + RSAPrivateKey instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT RSAContext : public PKeyBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + RSAContext(Provider *p) + : PKeyBase(p, QStringLiteral("rsa")) + { + } + + /** + Generate an RSA private key + + If \a block is true, then this function blocks until completion. + Otherwise, this function returns immediately and finished() is + emitted when the operation completes. + + If an error occurs during generation, then the operation will + complete and isNull() will return true. + + \param bits the length of the key to generate, in bits + \param exp the exponent to use for generation + \param block whether to use blocking mode + */ + virtual void createPrivate(int bits, int exp, bool block) = 0; + + /** + Create an RSA private key based on the five components + + \param n the N parameter + \param e the public exponent + \param p the P parameter + \param q the Q parameter + \param d the D parameter + */ + virtual void createPrivate(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d) = 0; + + /** + Create an RSA public key based on the two public components + + \param n the N parameter + \param e the public exponent + */ + virtual void createPublic(const BigInteger &n, const BigInteger &e) = 0; + + /** + Returns the public N component of this RSA key + */ + virtual BigInteger n() const = 0; + + /** + Returns the public E component of this RSA key + */ + virtual BigInteger e() const = 0; + + /** + Returns the private P component of this RSA key + */ + virtual BigInteger p() const = 0; + + /** + Returns the private Q component of this RSA key + */ + virtual BigInteger q() const = 0; + + /** + Returns the private D component of this RSA key + */ + virtual BigInteger d() const = 0; +}; + +/** + \class DSAContext qcaprovider.h QtCrypto + + DSA provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want DSAPublicKey or + DSAPrivateKey instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT DSAContext : public PKeyBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + DSAContext(Provider *p) + : PKeyBase(p, QStringLiteral("dsa")) + { + } + + /** + Generate a DSA private key + + If \a block is true, then this function blocks until completion. + Otherwise, this function returns immediately and finished() is + emitted when the operation completes. + + If an error occurs during generation, then the operation will + complete and isNull() will return true. + + \param domain the domain values to use for generation + \param block whether to use blocking mode + */ + virtual void createPrivate(const DLGroup &domain, bool block) = 0; + + /** + Create a DSA private key based on its numeric components + + \param domain the domain values to use for generation + \param y the public Y component + \param x the private X component + */ + virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) = 0; + + /** + Create a DSA public key based on its numeric components + + \param domain the domain values to use for generation + \param y the public Y component + */ + virtual void createPublic(const DLGroup &domain, const BigInteger &y) = 0; + + /** + Returns the public domain component of this DSA key + */ + virtual DLGroup domain() const = 0; + + /** + Returns the public Y component of this DSA key + */ + virtual BigInteger y() const = 0; + + /** + Returns the private X component of this DSA key + */ + virtual BigInteger x() const = 0; +}; + +/** + \class DHContext qcaprovider.h QtCrypto + + Diffie-Hellman provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want DHPublicKey or + DHPrivateKey instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT DHContext : public PKeyBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + DHContext(Provider *p) + : PKeyBase(p, QStringLiteral("dh")) + { + } + + /** + Generate a Diffie-Hellman private key + + If \a block is true, then this function blocks until completion. + Otherwise, this function returns immediately and finished() is + emitted when the operation completes. + + If an error occurs during generation, then the operation will + complete and isNull() will return true. + + \param domain the domain values to use for generation + \param block whether to use blocking mode + */ + virtual void createPrivate(const DLGroup &domain, bool block) = 0; + + /** + Create a Diffie-Hellman private key based on its numeric + components + + \param domain the domain values to use for generation + \param y the public Y component + \param x the private X component + */ + virtual void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) = 0; + + /** + Create a Diffie-Hellman public key based on its numeric + components + + \param domain the domain values to use for generation + \param y the public Y component + */ + virtual void createPublic(const DLGroup &domain, const BigInteger &y) = 0; + + /** + Returns the public domain component of this Diffie-Hellman key + */ + virtual DLGroup domain() const = 0; + + /** + Returns the public Y component of this Diffie-Hellman key + */ + virtual BigInteger y() const = 0; + + /** + Returns the private X component of this Diffie-Hellman key + */ + virtual BigInteger x() const = 0; +}; + +/** + \class PKeyContext qcaprovider.h QtCrypto + + Public key container provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want PKey, PublicKey, or + PrivateKey instead. + + This object "holds" a public key object. By default it contains no key + (key() returns 0), but you can put a key into it with setKey(), or you + can call an import function such as publicFromDER(). + + \ingroup ProviderAPI +*/ +class QCA_EXPORT PKeyContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + PKeyContext(Provider *p) + : BasicContext(p, QStringLiteral("pkey")) + { + } + + /** + Returns a list of supported public key types + */ + virtual QList supportedTypes() const = 0; + + /** + Returns a list of public key types that can be serialized and + deserialized into DER and PEM format + */ + virtual QList supportedIOTypes() const = 0; + + /** + Returns a list of password-based encryption algorithms that are + supported for private key serialization and deserialization + */ + virtual QList supportedPBEAlgorithms() const = 0; + + /** + Returns the key held by this object, or 0 if there is no key + */ + virtual PKeyBase *key() = 0; + + /** + Returns the key held by this object, or 0 if there is no key + */ + virtual const PKeyBase *key() const = 0; + + /** + Sets the key for this object. If this object already had a key, + then the old one is destructed. This object takes ownership of + the key. + + \param key the key to be set for this object + */ + virtual void setKey(PKeyBase *key) = 0; + + /** + Attempt to import a key from another provider. Returns true if + successful, otherwise false. + + Generally this function is used if the specified key's provider + does not support serialization, but your provider does. The call + to this function would then be followed by an export function, + such as publicToDER(). + + \param key the key to be imported + */ + virtual bool importKey(const PKeyBase *key) = 0; + + /** + Convert a public key to DER format, and return the value + + Returns an empty array on error. + */ + virtual QByteArray publicToDER() const; + + /** + Convert a public key to PEM format, and return the value + + Returns an empty string on error. + */ + virtual QString publicToPEM() const; + + /** + Read DER-formatted input and convert it into a public key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param a the input data + */ + virtual ConvertResult publicFromDER(const QByteArray &a); + + /** + Read PEM-formatted input and convert it into a public key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param s the input data + */ + virtual ConvertResult publicFromPEM(const QString &s); + + /** + Convert a private key to DER format, and return the value + + Returns an empty array on error. + + \param passphrase the passphrase to encode the result with, or an + empty array if no encryption is desired + \param pbe the encryption algorithm to use, if applicable + */ + virtual SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const; + + /** + Convert a private key to PEM format, and return the value + + Returns an empty string on error. + + \param passphrase the passphrase to encode the result with, or an + empty array if no encryption is desired + \param pbe the encryption algorithm to use, if applicable + */ + virtual QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const; + + /** + Read DER-formatted input and convert it into a private key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param a the input data + \param passphrase the passphrase needed to decrypt, if applicable + */ + virtual ConvertResult privateFromDER(const SecureArray &a, const SecureArray &passphrase); + + /** + Read PEM-formatted input and convert it into a private key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param s the input data + \param passphrase the passphrase needed to decrypt, if applicable + */ + virtual ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase); +}; + +/** + \class CertBase qcaprovider.h QtCrypto + + X.509 certificate and certificate request provider base + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Certificate, + CertificateRequest, or CRL instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CertBase : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the type of certificate-like object provided by this context + */ + CertBase(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Convert this object to DER format, and return the value + + Returns an empty array on error. + */ + virtual QByteArray toDER() const = 0; + + /** + Convert this object to PEM format, and return the value + + Returns an empty string on error. + */ + virtual QString toPEM() const = 0; + + /** + Read DER-formatted input and convert it into this object + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param a the input data + */ + virtual ConvertResult fromDER(const QByteArray &a) = 0; + + /** + Read PEM-formatted input and convert it into this object + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param s the input data + */ + virtual ConvertResult fromPEM(const QString &s) = 0; +}; + +/** + \class CertContextProps qcaprovider.h QtCrypto + + X.509 certificate or certificate request properties + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Certificate or + CertificateRequest instead. + + Some fields are only for certificates or only for certificate requests, + and these fields are noted. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CertContextProps +{ +public: + /** + The X.509 certificate version, usually 3 + + This field is for certificates only. + */ + int version; + + /** + The time the certificate becomes valid (often the time of create) + + This field is for certificates only. + */ + QDateTime start; + + /** + The time the certificate expires + + This field is for certificates only. + */ + QDateTime end; + + /** + The subject information + */ + CertificateInfoOrdered subject; + + /** + The issuer information + + This field is for certificates only. + */ + CertificateInfoOrdered issuer; + + /** + The constraints + */ + Constraints constraints; + + /** + The policies + */ + QStringList policies; + + /** + A list of URIs for CRLs + + This field is for certificates only. + */ + QStringList crlLocations; + + /** + A list of URIs for issuer certificates + + This field is for certificates only. + */ + QStringList issuerLocations; + + /** + A list of URIs for OCSP services + + This field is for certificates only. + */ + QStringList ocspLocations; + + /** + The certificate serial number + + This field is for certificates only. + */ + BigInteger serial; + + /** + True if the certificate is a CA or the certificate request is + requesting to be a CA, otherwise false + */ + bool isCA; + + /** + True if the certificate is self-signed + + This field is for certificates only. + */ + bool isSelfSigned; + + /** + The path limit + */ + int pathLimit; + + /** + The signature data + */ + QByteArray sig; + + /** + The signature algorithm used to create the signature + */ + SignatureAlgorithm sigalgo; + + /** + The subject id + + This field is for certificates only. + */ + QByteArray subjectId; + + /** + The issuer id + + This field is for certificates only. + */ + QByteArray issuerId; + + /** + The SPKAC challenge value + + This field is for certificate requests only. + */ + QString challenge; + + /** + The format used for the certificate request + + This field is for certificate requests only. + */ + CertificateRequestFormat format; +}; + +/** + \class CRLContextProps qcaprovider.h QtCrypto + + X.509 certificate revocation list properties + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want CRL instead. + + For efficiency and simplicity, the members are directly accessed. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CRLContextProps +{ +public: + /** + The issuer information of the CRL + */ + CertificateInfoOrdered issuer; + + /** + The CRL number, which increases at each update + */ + int number; + + /** + The time this CRL was created + */ + QDateTime thisUpdate; + + /** + The time this CRL expires, and the next CRL should be fetched + */ + QDateTime nextUpdate; + + /** + The revoked entries + */ + QList revoked; + + /** + The signature data of the CRL + */ + QByteArray sig; + + /** + The signature algorithm used by the issuer to sign the CRL + */ + SignatureAlgorithm sigalgo; + + /** + The issuer id + */ + QByteArray issuerId; +}; + +class CRLContext; + +/** + \class CertContext qcaprovider.h QtCrypto + + X.509 certificate provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want Certificate instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CertContext : public CertBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + CertContext(Provider *p) + : CertBase(p, QStringLiteral("cert")) + { + } + + /** + Create a self-signed certificate based on the given options and + private key. Returns true if successful, otherwise false. + + If successful, this object becomes the self-signed certificate. + If unsuccessful, this object is considered to be in an + uninitialized state. + + \param opts the options to set on the certificate + \param priv the key to be used to sign the certificate + */ + virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) = 0; + + /** + Returns a pointer to the properties of this certificate + */ + virtual const CertContextProps *props() const = 0; + + /** + Returns true if this certificate is equal to another certificate, + otherwise false + + \param other the certificate to compare with + */ + virtual bool compare(const CertContext *other) const = 0; + + /** + Returns a copy of this certificate's public key. The caller is + responsible for deleting it. + */ + virtual PKeyContext *subjectPublicKey() const = 0; + + /** + Returns true if this certificate is an issuer of another + certificate, otherwise false + + \param other the issued certificate to check + */ + virtual bool isIssuerOf(const CertContext *other) const = 0; + + /** + Validate this certificate + + This function is blocking. + + \param trusted list of trusted certificates + \param untrusted list of untrusted certificates (can be empty) + \param crls list of CRLs (can be empty) + \param u the desired usage for this certificate + \param vf validation options + */ + virtual Validity validate(const QList &trusted, + const QList &untrusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const = 0; + + /** + Validate a certificate chain. This function makes no use of the + certificate represented by this object, and it can be used even + if this object is in an uninitialized state. + + This function is blocking. + + \param chain list of certificates in the chain, starting with the + user certificate. It is not necessary for the chain to contain + the final root certificate. + \param trusted list of trusted certificates + \param crls list of CRLs (can be empty) + \param u the desired usage for the user certificate in the chain + \param vf validation options + */ + virtual Validity validate_chain(const QList &chain, + const QList &trusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const = 0; +}; + +/** + \class CSRContext qcaprovider.h QtCrypto + + X.509 certificate request provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want CertificateRequest + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CSRContext : public CertBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + CSRContext(Provider *p) + : CertBase(p, QStringLiteral("csr")) + { + } + + /** + Returns true if the provider of this object supports the specified + format, otherwise false + + \param f the format to test for support for. + */ + virtual bool canUseFormat(CertificateRequestFormat f) const = 0; + + /** + Create a certificate request based on the given options and + private key. Returns true if successful, otherwise false. + + If successful, this object becomes the certificate request. + If unsuccessful, this object is considered to be in an + uninitialized state. + + \param opts the options to set on the certificate + \param priv the key to be used to sign the certificate + */ + virtual bool createRequest(const CertificateOptions &opts, const PKeyContext &priv) = 0; + + /** + Returns a pointer to the properties of this certificate request + */ + virtual const CertContextProps *props() const = 0; + + /** + Returns true if this certificate request is equal to another + certificate request, otherwise false + + \param other the certificate request to compare with + */ + virtual bool compare(const CSRContext *other) const = 0; + + /** + Returns a copy of this certificate request's public key. The + caller is responsible for deleting it. + */ + virtual PKeyContext *subjectPublicKey() const = 0; + + /** + Convert this certificate request to Netscape SPKAC format, and + return the value + + Returns an empty string on error. + */ + virtual QString toSPKAC() const = 0; + + /** + Read Netscape SPKAC input and convert it into a certificate + request + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param s the input data + */ + virtual ConvertResult fromSPKAC(const QString &s) = 0; +}; + +/** + \class CRLContext qcaprovider.h QtCrypto + + X.509 certificate revocation list provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want CRL instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CRLContext : public CertBase +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + CRLContext(Provider *p) + : CertBase(p, QStringLiteral("crl")) + { + } + + /** + Returns a pointer to the properties of this CRL + */ + virtual const CRLContextProps *props() const = 0; + + /** + Returns true if this CRL is equal to another CRL, otherwise false + + \param other the CRL to compare with + */ + virtual bool compare(const CRLContext *other) const = 0; +}; + +/** + \class CertCollectionContext qcaprovider.h QtCrypto + + X.509 certificate collection provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want CertificateCollection + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CertCollectionContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + */ + CertCollectionContext(Provider *p) + : BasicContext(p, QStringLiteral("certcollection")) + { + } + + /** + Create PKCS#7 DER output based on the input certificates and CRLs + + Returns an empty array on error. + + \param certs list of certificates to store in the output + \param crls list of CRLs to store in the output + */ + virtual QByteArray toPKCS7(const QList &certs, const QList &crls) const = 0; + + /** + Read PKCS#7 DER input and convert it into a list of certificates + and CRLs + + The caller is responsible for deleting the returned items. + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param a the input data + \param certs the destination list for the certificates + \param crls the destination list for the CRLs + */ + virtual ConvertResult + fromPKCS7(const QByteArray &a, QList *certs, QList *crls) const = 0; +}; + +/** + \class CAContext qcaprovider.h QtCrypto + + X.509 certificate authority provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want CertificateAuthority + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT CAContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + CAContext(Provider *p) + : BasicContext(p, QStringLiteral("ca")) + { + } + + /** + Prepare the object for usage + + This must be called before any CA operations are performed. + + \param cert the certificate of the CA + \param priv the private key of the CA + */ + virtual void setup(const CertContext &cert, const PKeyContext &priv) = 0; + + /** + Returns a copy of the CA's certificate. The caller is responsible + for deleting it. + */ + virtual CertContext *certificate() const = 0; + + /** + Issue a certificate based on a certificate request, and return + the certificate. The caller is responsible for deleting it. + + \param req the certificate request + \param notValidAfter the expiration date + */ + virtual CertContext *signRequest(const CSRContext &req, const QDateTime ¬ValidAfter) const = 0; + + /** + Issue a certificate based on a public key and options, and return + the certificate. The caller is responsible for deleting it. + + \param pub the public key of the certificate + \param opts the options to use for generation + */ + virtual CertContext *createCertificate(const PKeyContext &pub, const CertificateOptions &opts) const = 0; + + /** + Create a new CRL and return it. The caller is responsible for + deleting it. + + The CRL has no entries in it. + + \param nextUpdate the expiration date of the CRL + */ + virtual CRLContext *createCRL(const QDateTime &nextUpdate) const = 0; + + /** + Update an existing CRL, by examining an old one and creating a new + one based on it. The new CRL is returned, and the caller is + responsible for deleting it. + + \param crl an existing CRL issued by this CA + \param entries the list of revoked entries + \param nextUpdate the expiration date of the new CRL + */ + virtual CRLContext * + updateCRL(const CRLContext &crl, const QList &entries, const QDateTime &nextUpdate) const = 0; +}; + +/** + \class PKCS12Context qcaprovider.h QtCrypto + + PKCS#12 provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want KeyBundle instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT PKCS12Context : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + PKCS12Context(Provider *p) + : BasicContext(p, QStringLiteral("pkcs12")) + { + } + + /** + Create PKCS#12 DER output based on a set of input items + + Returns an empty array on error. + + \param name the friendly name of the data + \param chain the certificate chain to store + \param priv the private key to store + \param passphrase the passphrase to encrypt the PKCS#12 data with + */ + virtual QByteArray toPKCS12(const QString &name, + const QList &chain, + const PKeyContext &priv, + const SecureArray &passphrase) const = 0; + + /** + Read PKCS#12 DER input and convert it into a set of output items + + The caller is responsible for deleting the returned items. + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param in the input data + \param passphrase the passphrase needed to decrypt the input data + \param name the destination string for the friendly name + \param chain the destination list for the certificate chain + \param priv address of a pointer to accept the private key + */ + virtual ConvertResult fromPKCS12(const QByteArray &in, + const SecureArray &passphrase, + QString *name, + QList *chain, + PKeyContext **priv) const = 0; +}; + +/** + \class PGPKeyContextProps qcaprovider.h QtCrypto + + OpenPGP key properties + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want PGPKey instead. + + For efficiency and simplicity, the members are directly accessed. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT PGPKeyContextProps +{ +public: + /** + The key id + */ + QString keyId; + + /** + List of user id strings for the key, the first one being the + primary user id + */ + QStringList userIds; + + /** + True if this key is a secret key, otherwise false + */ + bool isSecret; + + /** + The time the key was created + */ + QDateTime creationDate; + + /** + The time the key expires + */ + QDateTime expirationDate; + + /** + The hex fingerprint of the key + + The format is all lowercase with no spaces. + */ + QString fingerprint; + + /** + True if this key is in a keyring (and thus usable), otherwise + false + */ + bool inKeyring; + + /** + True if this key is trusted (e.g. signed by the keyring owner or + via some web-of-trust), otherwise false + */ + bool isTrusted; +}; + +/** + \class PGPKeyContext qcaprovider.h QtCrypto + + OpenPGP key provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want PGPKey instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT PGPKeyContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + PGPKeyContext(Provider *p) + : BasicContext(p, QStringLiteral("pgpkey")) + { + } + + /** + Returns a pointer to the properties of this key + */ + virtual const PGPKeyContextProps *props() const = 0; + + /** + Convert the key to binary format, and return the value + */ + virtual QByteArray toBinary() const = 0; + + /** + Convert the key to ascii-armored format, and return the value + */ + virtual QString toAscii() const = 0; + + /** + Read binary input and convert it into a key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param a the input data + */ + virtual ConvertResult fromBinary(const QByteArray &a) = 0; + + /** + Read ascii-armored input and convert it into a key + + Returns QCA::ConvertGood if successful, otherwise some error + value. + + \param s the input data + */ + virtual ConvertResult fromAscii(const QString &s) = 0; +}; + +/** + \class KeyStoreEntryContext qcaprovider.h QtCrypto + + KeyStoreEntry provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want KeyStoreEntry + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT KeyStoreEntryContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + KeyStoreEntryContext(Provider *p) + : BasicContext(p, QStringLiteral("keystoreentry")) + { + } + + /** + Returns the entry type + */ + virtual KeyStoreEntry::Type type() const = 0; + + /** + Returns the entry id + + This id must be unique among all other entries in the same store. + */ + virtual QString id() const = 0; + + /** + Returns the name of this entry + */ + virtual QString name() const = 0; + + /** + Returns the id of the store that contains this entry + */ + virtual QString storeId() const = 0; + + /** + Returns the name of the store that contains this entry + */ + virtual QString storeName() const = 0; + + /** + Returns true if the private key of this entry is present for use + */ + virtual bool isAvailable() const; + + /** + Serialize the information about this entry + + This allows the entry object to be restored later, even if the + store that contains it is not present. + + \sa KeyStoreListContext::entryPassive() + */ + virtual QString serialize() const = 0; + + /** + If this entry is of type KeyStoreEntry::TypeKeyBundle, this + function returns the KeyBundle of the entry + */ + virtual KeyBundle keyBundle() const; + + /** + If this entry is of type KeyStoreEntry::TypeCertificate, this + function returns the Certificate of the entry + */ + virtual Certificate certificate() const; + + /** + If this entry is of type KeyStoreEntry::TypeCRL, this function + returns the CRL of the entry + */ + virtual CRL crl() const; + + /** + If this entry is of type KeyStoreEntry::TypePGPSecretKey, this + function returns the secret PGPKey of the entry + */ + virtual PGPKey pgpSecretKey() const; + + /** + If this entry is of type KeyStoreEntry::TypePGPPublicKey or + KeyStoreEntry::TypePGPSecretKey, this function returns the public + PGPKey of the entry + */ + virtual PGPKey pgpPublicKey() const; + + /** + Attempt to ensure the private key of this entry is usable and + accessible, potentially prompting the user and/or performing a + login to a token device. Returns true if the entry is now + accessible, or false if the entry cannot be made accessible. + + This function is blocking. + */ + virtual bool ensureAccess(); +}; + +/** + \class KeyStoreListContext qcaprovider.h QtCrypto + + KeyStore provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want KeyStore instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT KeyStoreListContext : public Provider::Context +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + KeyStoreListContext(Provider *p) + : Provider::Context(p, QStringLiteral("keystorelist")) + { + } + + /** + Starts the keystore provider + */ + virtual void start(); + + /** + Enables or disables update events + + The updated() and storeUpdated() signals might not be emitted if + updates are not enabled. + + \param enabled whether update notifications are enabled (true) or disabled (false) + */ + virtual void setUpdatesEnabled(bool enabled); + + /** + Returns a list of integer context ids, each representing a + keystore instance + + If a keystore becomes unavailable and then later becomes + available again (for example, if a smart card is removed and + then the same one is inserted again), the integer context id + must be different than last time. + */ + virtual QList keyStores() = 0; + + /** + Returns the type of the specified store, or -1 if the integer + context id is invalid + + \param id the id for the store context + */ + virtual KeyStore::Type type(int id) const = 0; + + /** + Returns the string id of the store, or an empty string if the + integer context id is invalid + + The string id of the store should be unique to a single store, and + it should persist between availability/unavailability. For + example, a smart card that is removed and inserted again should + have the same string id (despite having a new integer context id). + + \param id the id for the store context + */ + virtual QString storeId(int id) const = 0; + + /** + Returns the friendly name of the store, or an empty string if the + integer context id is invalid + + \param id the id for the store context + */ + virtual QString name(int id) const = 0; + + /** + Returns true if the store is read-only + + If the integer context id is invalid, this function should return + true. + + \param id the id for the store context + */ + virtual bool isReadOnly(int id) const; + + /** + Returns the types supported by the store, or an empty list if the + integer context id is invalid + + This function should return all supported types, even if the store + doesn't actually contain entries for all of the types. + + \param id the id for the store context + */ + virtual QList entryTypes(int id) const = 0; + + /** + Returns the entries of the store, or an empty list if the integer + context id is invalid + + The caller is responsible for deleting the returned entry objects. + + \param id the id for the store context + */ + virtual QList entryList(int id) = 0; + + /** + Returns a single entry in the store, if the entry id is already + known. If the entry does not exist, the function returns 0. + + The caller is responsible for deleting the returned entry object. + + \param id the id for the store context + \param entryId the entry to retrieve + */ + virtual KeyStoreEntryContext *entry(int id, const QString &entryId); + + /** + Returns a single entry, created from the serialization string of + a previous entry (using KeyStoreEntryContext::serialize()). If + the serialization string cannot be parsed by this provider, or the + entry cannot otherwise be created, the function returns 0. + + The caller is responsible for deleting the returned entry object. + + This function must be thread-safe. + + \param serialized the serialized data to create the entry from + */ + virtual KeyStoreEntryContext *entryPassive(const QString &serialized); + + /** + Write a KeyBundle to the store + + Returns the entry id of the new item, or an empty string if there + was an error writing the item. + + \param id the id for the store context + \param kb the key bundle to add to the store + */ + virtual QString writeEntry(int id, const KeyBundle &kb); + + /** + Write a Certificate to the store + + Returns the entry id of the new item, or an empty string if there + was an error writing the item. + + \param id the id for the store context + \param cert the certificate to add to the store + */ + virtual QString writeEntry(int id, const Certificate &cert); + + /** + Write a CRL to the store + + Returns the entry id of the new item, or an empty string if there + was an error writing the item. + + \param id the id for the store context + \param crl the revocation list to add to the store + */ + virtual QString writeEntry(int id, const CRL &crl); + + /** + Write a PGPKey to the store + + Returns the entry id of the new item, or an empty string if there + was an error writing the item. + + \param id the id for the store context + \param key the PGP key to add to the store + */ + virtual QString writeEntry(int id, const PGPKey &key); + + /** + Remove an entry from the store + + Returns true if the entry is successfully removed, otherwise + false. + + \param id the id for the store context + \param entryId the entry to remove from the store + */ + virtual bool removeEntry(int id, const QString &entryId); + +Q_SIGNALS: + /** + Emit this when the provider is busy looking for keystores. The + provider goes into a busy state when it has reason to believe + there are keystores present, but it still needs to check or query + some devices to see for sure. + + For example, if a smart card is inserted, then the provider may + immediately go into a busy state upon detecting the insert. + However, it may take some seconds before the smart card + information can be queried and reported by the provider. Once + the card is queried successfully, the provider would leave the + busy state and report the new keystore. + + When this object is first started with start(), it is assumed to + be in the busy state, so there is no need to emit this signal at + the beginning. + */ + void busyStart(); + + /** + Emit this to leave the busy state + + When this object is first started with start(), it is assumed to + be in the busy state. You must emit busyEnd() at some point, or + QCA will never ask you about keystores. + */ + void busyEnd(); + + /** + Indicates the list of keystores has changed, and that QCA should + call keyStores() to obtain the latest list + */ + void updated(); + + /** + Emitted when there is diagnostic text to report + + \param str the diagnostic text + */ + void diagnosticText(const QString &str); + + /** + Indicates that the entry list of a keystore has changed (entries + added, removed, or modified) + + \param id the id of the key store that has changed + */ + void storeUpdated(int id); +}; + +/** + \class TLSSessionContext qcaprovider.h QtCrypto + + TLS "session" provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want TLSSession instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT TLSSessionContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the Provider associated with this context + */ + TLSSessionContext(Provider *p) + : BasicContext(p, QStringLiteral("tlssession")) + { + } +}; + +/** + \class TLSContext qcaprovider.h QtCrypto + + TLS provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want TLS instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT TLSContext : public Provider::Context +{ + Q_OBJECT +public: + /** + \class QCA::TLSContext::SessionInfo qcaprovider.h QtCrypto + + Information about an active TLS connection + + For efficiency and simplicity, the members are directly accessed. + + \ingroup ProviderAPI + */ + class SessionInfo + { + public: + /** + True if the TLS connection is compressed, otherwise false + */ + bool isCompressed; + + /** + The TLS protocol version being used for this connection + */ + TLS::Version version; + + /** + The cipher suite being used for this connection + + \sa TLSContext::supportedCipherSuites() + */ + QString cipherSuite; + + /** + The bit size of the cipher used for this connection + */ + int cipherBits; + + /** + The maximum bit size possible of the cipher used for this + connection + */ + int cipherMaxBits; + + /** + Pointer to the id of this TLS session, for use with + resuming + */ + TLSSessionContext *id; + }; + + /** + Result of a TLS operation + */ + enum Result + { + Success, ///< Operation completed + Error, ///< Operation failed + Continue ///< More data needed to complete operation + }; + + /** + Standard constructor + + \param p the Provider associated with this context + \param type the name of the type of feature that supported by this context + */ + TLSContext(Provider *p, const QString &type) + : Provider::Context(p, type) + { + } + + /** + Reset the object to its initial state + */ + virtual void reset() = 0; + + /** + Returns a list of supported cipher suites for the specified + SSL/TLS version. The cipher suites are specified as strings, for + example: "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA" (without quotes). + + \param version the version of TLS to search for + */ + virtual QStringList supportedCipherSuites(const TLS::Version &version) const = 0; + + /** + Returns true if the provider supports compression + */ + virtual bool canCompress() const = 0; + + /** + Returns true if the provider supports server name indication + */ + virtual bool canSetHostName() const = 0; + + /** + Returns the maximum SSF supported by this provider + */ + virtual int maxSSF() const = 0; + + /** + Configure a new session + + This function will be called before any other configuration + functions. + + \param serverMode whether to operate as a server (true) or client (false) + \param hostName the hostname to use + \param compress whether to compress (true) or not (false) + */ + virtual void setup(bool serverMode, const QString &hostName, bool compress) = 0; + + /** + Set the constraints of the session using SSF values + + This function will be called before start(). + + \param minSSF the minimum strength factor that is acceptable + \param maxSSF the maximum strength factor that is acceptable + */ + virtual void setConstraints(int minSSF, int maxSSF) = 0; + + /** + \overload + + Set the constraints of the session using a cipher suite list + + This function will be called before start(). + + \param cipherSuiteList the list of cipher suites that may be used for + this session. + + \sa supportedCipherSuites + */ + virtual void setConstraints(const QStringList &cipherSuiteList) = 0; + + /** + Set the list of trusted certificates + + This function may be called at any time. + + \param trusted the trusted certificates and CRLs to be used. + */ + virtual void setTrustedCertificates(const CertificateCollection &trusted) = 0; + + /** + Set the list of acceptable issuers + + This function may be called at any time. + + This function is for server mode only. + + \param issuerList the list of issuers that may be used + */ + virtual void setIssuerList(const QList &issuerList) = 0; + + /** + Set the local certificate + + This function may be called at any time. + + \param cert the certificate and associated trust chain + \param key the private key for the local certificate + */ + virtual void setCertificate(const CertificateChain &cert, const PrivateKey &key) = 0; + + /** + Set the TLS session id, for session resuming + + This function will be called before start(). + + \param id the session identification + */ + virtual void setSessionId(const TLSSessionContext &id) = 0; + + /** + Sets the session to the shutdown state. + + The actual shutdown operation will happen at a future call to + update(). + + This function is for normal TLS only (not DTLS). + */ + virtual void shutdown() = 0; + + /** + Set the maximum transmission unit size + + This function is for DTLS only. + + \param size the maximum number of bytes in a datagram + */ + virtual void setMTU(int size); + + /** + Begins the session, starting with the handshake + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, the result() function will return Success if the + TLS session is able to begin, or Error if there is a failure to + initialize the TLS subsystem. If successful, the session is now + in the handshake state, and update() will be called repeatedly + until the session ends. + */ + virtual void start() = 0; + + /** + Performs one iteration of the TLS session processing + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + If the session is in a handshake state, result() and to_net() will + be valid. If result() is Success, then the session is now in the + connected state. + + If the session is in a shutdown state, result() and to_net() will + be valid. If result() is Success, then the session has ended. + + If the session is in a connected state, result(), to_net(), + encoded(), to_app(), and eof() are valid. The result() function + will return Success or Error. Note that eof() does not apply + to DTLS. + + For DTLS, this function operates with single packets. Many + update() operations must be performed repeatedly to exchange + multiple packets. + + \param from_net the data from the "other side" of the connection + \param from_app the data from the application of the protocol + */ + virtual void update(const QByteArray &from_net, const QByteArray &from_app) = 0; + + /** + Waits for a start() or update() operation to complete. In this + case, the resultsReady() signal is not emitted. Returns true if + the operation completed or false if this function times out. + + This function is blocking. + + \param msecs number of milliseconds to wait (-1 to wait forever) + */ + virtual bool waitForResultsReady(int msecs) = 0; + + /** + Returns the result code of an operation + */ + virtual Result result() const = 0; + + /** + Returns data that should be sent across the network + */ + virtual QByteArray to_net() = 0; + + /** + Returns the number of bytes of plaintext data that is encoded + inside of to_net() + */ + virtual int encoded() const = 0; + + /** + Returns data that is decoded from the network and should be + processed by the application + */ + virtual QByteArray to_app() = 0; + + /** + Returns true if the peer has closed the stream + */ + virtual bool eof() const = 0; + + /** + Returns true if the TLS client hello has been received + + This is only valid if a handshake is in progress or + completed. + */ + virtual bool clientHelloReceived() const = 0; + + /** + Returns true if the TLS server hello has been received + + This is only valid if a handshake is in progress or completed. + */ + virtual bool serverHelloReceived() const = 0; + + /** + Returns the host name sent by the client using server name + indication (server mode only) + + This is only valid if a handshake is in progress or completed. + */ + virtual QString hostName() const = 0; + + /** + Returns true if the peer is requesting a certificate + + This is only valid if a handshake is in progress or completed. + */ + virtual bool certificateRequested() const = 0; + + /** + Returns the issuer list sent by the server (client mode only) + + This is only valid if a handshake is in progress or completed. + */ + virtual QList issuerList() const = 0; + + /** + Returns the QCA::Validity of the peer certificate + + This is only valid if a handshake is completed. + */ + virtual Validity peerCertificateValidity() const = 0; + + /** + Returns the peer certificate chain + + This is only valid if a handshake is completed. + */ + virtual CertificateChain peerCertificateChain() const = 0; + + /** + Returns information about the active TLS session + + This is only valid if a handshake is completed. + */ + virtual SessionInfo sessionInfo() const = 0; + + /** + Returns any unprocessed network input data + + This is only valid after a successful shutdown. + */ + virtual QByteArray unprocessed() = 0; + +Q_SIGNALS: + /** + Emit this when a start() or update() operation has completed. + */ + void resultsReady(); + + /** + Emit this to force the application to call update(), even with + empty arguments. + */ + void dtlsTimeout(); +}; + +/** + \class SASLContext qcaprovider.h QtCrypto + + SASL provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want SASL instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT SASLContext : public Provider::Context +{ + Q_OBJECT +public: + /** + \class QCA::SASLContext::HostPort qcaprovider.h QtCrypto + + Convenience class to hold an IP address and an associated port + + For efficiency and simplicity, the members are directly accessed. + + \ingroup ProviderAPI + */ + class HostPort + { + public: + /** + The IP address + */ + QString addr; + + /** + The port + */ + quint16 port; + }; + + /** + Result of a SASL operation + */ + enum Result + { + Success, ///< Operation completed + Error, ///< Operation failed + Params, ///< Parameters are needed to complete authentication + AuthCheck, ///< Client login can be inspected (server only) + Continue ///< More steps needed to complete authentication + }; + + /** + Standard constructor + + \param p the Provider associated with this context + */ + SASLContext(Provider *p) + : Provider::Context(p, QStringLiteral("sasl")) + { + } + + /** + Reset the object to its initial state + */ + virtual void reset() = 0; + + /** + Configure a new session + + This function will be called before any other configuration + functions. + + \param service the name of the network service being provided by + this application, which can be used by the SASL system for policy + control. Examples: "imap", "xmpp" + \param host the hostname that the application is interacting with + or as + \param local pointer to a HostPort representing the local end of a + network socket, or 0 if this information is unknown or not + available + \param remote pointer to a HostPort representing the peer end of a + network socket, or 0 if this information is unknown or not + available + \param ext_id the id to be used for SASL EXTERNAL (client only) + \param ext_ssf the SSF of the external authentication channel + (client only) + */ + virtual void setup(const QString &service, + const QString &host, + const HostPort *local, + const HostPort *remote, + const QString &ext_id, + int ext_ssf) = 0; + + /** + Set the constraints of the session using SSF values + + This function will be called before startClient() or + startServer(). + + \param f the flags to use + \param minSSF the minimum strength factor that is acceptable + \param maxSSF the maximum strength factor that is acceptable + */ + virtual void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) = 0; + + /** + Begins the session in client mode, starting with the + authentication + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result(), mech(), haveClientInit(), and stepData() + will be valid. If result() is Success, then the session is now in + the connected state. + + \param mechlist the list of mechanisms + \param allowClientSendFirst whether the client sends first (true) or the server + sends first (false) + */ + virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) = 0; + + /** + Begins the session in server mode, starting with the + authentication + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result() and mechlist() will be valid. The + result() function will return Success or Error. If the result is + Success, then serverFirstStep() will be called next. + + \param realm the realm to authenticate in + \param disableServerSendLast whether the client sends first (true) + or the server sends first (false) + */ + virtual void startServer(const QString &realm, bool disableServerSendLast) = 0; + + /** + Finishes server startup + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result() and stepData() will be valid. If result() + is Success, then the session is now in the connected state. + + \param mech the mechanism to use + \param clientInit initial data from the client, or 0 if there is + no such data + */ + virtual void serverFirstStep(const QString &mech, const QByteArray *clientInit) = 0; + + /** + Perform another step of the SASL authentication + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result() and stepData() will be valid. + + \param from_net the data from the "other side" of the protocol + to be used for the next step. + */ + virtual void nextStep(const QByteArray &from_net) = 0; + + /** + Attempt the most recent operation again. This is used if the + result() of an operation is Params or AuthCheck. + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result() and stepData() will be valid. + */ + virtual void tryAgain() = 0; + + /** + Performs one iteration of the SASL security layer processing + + This function returns immediately, and completion is signaled with + the resultsReady() signal. + + On completion, result(), to_net(), encoded(), and to_app() will be + valid. The result() function will return Success or Error. + + \param from_net the data from the "other side" of the protocol + \param from_app the data from the application of the protocol + */ + virtual void update(const QByteArray &from_net, const QByteArray &from_app) = 0; + + /** + Waits for a startClient(), startServer(), serverFirstStep(), + nextStep(), tryAgain(), or update() operation to complete. In + this case, the resultsReady() signal is not emitted. Returns true + if the operation completed or false if this function times out. + + This function is blocking. + + \param msecs number of milliseconds to wait (-1 to wait forever) + */ + virtual bool waitForResultsReady(int msecs) = 0; + + /** + Returns the result code of an operation + */ + virtual Result result() const = 0; + + /** + Returns the mechanism list (server mode only) + */ + virtual QStringList mechlist() const = 0; + + /** + Returns the mechanism selected + */ + virtual QString mech() const = 0; + + /** + Returns true if the client has initialization data + */ + virtual bool haveClientInit() const = 0; + + /** + Returns an authentication payload for to be transmitted over the + network + */ + virtual QByteArray stepData() const = 0; + + /** + Returns data that should be sent across the network (for the + security layer) + */ + virtual QByteArray to_net() = 0; + + /** + Returns the number of bytes of plaintext data that is encoded + inside of to_net() + */ + virtual int encoded() const = 0; + + /** + Returns data that is decoded from the network and should be + processed by the application + */ + virtual QByteArray to_app() = 0; + + /** + Returns the SSF of the active SASL session + + This is only valid after authentication success. + */ + virtual int ssf() const = 0; + + /** + Returns the reason for failure, if the authentication was not + successful. + + This is only valid after authentication failure. + */ + virtual SASL::AuthCondition authCondition() const = 0; + + /** + Returns the needed/optional client parameters + + This is only valid after receiving the Params result code. + */ + virtual SASL::Params clientParams() const = 0; + + /** + Set some of the client parameters (pass 0 to not set a field) + + \param user the user name + \param authzid the authorization name / role + \param pass the password + \param realm the realm to authenticate in + */ + virtual void + setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) = 0; + + /** + Returns the realm list (client mode only) + + This is only valid after receiving the Params result code and + SASL::Params::canSendRealm is set to true. + */ + virtual QStringList realmlist() const = 0; + + /** + Returns the username attempting to authenticate (server mode only) + + This is only valid after receiving the AuthCheck result code. + */ + virtual QString username() const = 0; + + /** + Returns the authzid attempting to authorize (server mode only) + + This is only valid after receiving the AuthCheck result code. + */ + virtual QString authzid() const = 0; + +Q_SIGNALS: + /** + Emit this when a startClient(), startServer(), serverFirstStep(), + nextStep(), tryAgain(), or update() operation has completed. + */ + void resultsReady(); +}; + +/** + \class MessageContext qcaprovider.h QtCrypto + + SecureMessage provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want SecureMessage + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT MessageContext : public Provider::Context +{ + Q_OBJECT +public: + /** + The type of operation being performed + */ + enum Operation + { + Encrypt, ///< Encrypt operation + Decrypt, ///< Decrypt (or Decrypt and Verify) operation + Sign, ///< Sign operation + Verify, ///< Verify operation + SignAndEncrypt ///< Sign and Encrypt operation + }; + + /** + Standard constructor + + \param p the Provider associated with this context + \param type the name of the type of secure message to be created + */ + MessageContext(Provider *p, const QString &type) + : Provider::Context(p, type) + { + } + + /** + Returns true if the provider supports multiple signers for + signature creation or signature verification + */ + virtual bool canSignMultiple() const = 0; + + /** + The type of secure message (e.g. PGP or CMS) + */ + virtual SecureMessage::Type type() const = 0; + + /** + Reset the object to its initial state + */ + virtual void reset() = 0; + + /** + Configure a new encrypting operation + + \param keys the keys to be used for encryption. + */ + virtual void setupEncrypt(const SecureMessageKeyList &keys) = 0; + + /** + Configure a new signing operation + + \param keys the keys to use for signing + \param m the mode to sign in + \param bundleSigner whether to bundle the signing keys (true) or not (false) + \param smime whether to use smime format (true) or not (false) + */ + virtual void + setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime) = 0; + + /** + Configure a new verify operation + + \param detachedSig the detached signature to use (if applicable) for verification + */ + virtual void setupVerify(const QByteArray &detachedSig) = 0; + + /** + Begins the secure message operation + + This function returns immediately. + + If there is input data, update() will be called (potentially + repeatedly) afterwards. Emit updated() if there is data to + read, if input data has been accepted, or if the operation has + finished. + + \param f the format of the message to be produced + \param op the operation to be performed + */ + virtual void start(SecureMessage::Format f, Operation op) = 0; + + /** + Provide input to the message operation + + \param in the data to use for the message operation + */ + virtual void update(const QByteArray &in) = 0; + + /** + Extract output from the message operation + */ + virtual QByteArray read() = 0; + + /** + Returns the number of input bytes accepted since the last call to + update() + */ + virtual int written() = 0; + + /** + Indicates the end of input + */ + virtual void end() = 0; + + /** + Returns true if the operation has finished, otherwise false + */ + virtual bool finished() const = 0; + + /** + Waits for the secure message operation to complete. In this case, + the updated() signal is not emitted. Returns true if the + operation completed or false if this function times out. + + This function is blocking. + + \param msecs number of milliseconds to wait (-1 to wait forever) + */ + virtual bool waitForFinished(int msecs) = 0; + + /** + Returns true if the operation was successful + + This is only valid if the operation has finished. + */ + virtual bool success() const = 0; + + /** + Returns the reason for failure, if the operation was not + successful + + This is only valid if the operation has finished. + */ + virtual SecureMessage::Error errorCode() const = 0; + + /** + Returns the signature, in the case of a detached signature + operation + + This is only valid if the operation has finished. + */ + virtual QByteArray signature() const = 0; + + /** + Returns the name of the hash used to generate the signature, in + the case of a signature operation + + This is only valid if the operation has finished. + */ + virtual QString hashName() const = 0; + + /** + Returns a list of signatures, in the case of a verify or decrypt + and verify operation + + This is only valid if the operation has finished. + */ + virtual SecureMessageSignatureList signers() const = 0; + + /** + Returns any diagnostic text for the operation, potentially useful + to show the user in the event the operation is unsuccessful. For + example, this could be the stderr output of gpg. + + This is only valid if the operation has finished. + */ + virtual QString diagnosticText() const; + +Q_SIGNALS: + /** + Emitted when there is data to read, if input data has been + accepted, or if the operation has finished + */ + void updated(); +}; + +/** + \class SMSContext qcaprovider.h QtCrypto + + SecureMessageSystem provider + + \note This class is part of the provider plugin interface and should not + be used directly by applications. You probably want SecureMessageSystem + instead. + + \ingroup ProviderAPI +*/ +class QCA_EXPORT SMSContext : public BasicContext +{ + Q_OBJECT +public: + /** + Standard constructor + + \param p the provider associated with this context + \param type the name of the type of secure message system + */ + SMSContext(Provider *p, const QString &type) + : BasicContext(p, type) + { + } + + /** + Set the trusted certificates and for this secure message system, + to be used for validation + + The collection may also contain CRLs. + + This function is only valid for CMS. + + \param trusted a set of trusted certificates and CRLs. + */ + virtual void setTrustedCertificates(const CertificateCollection &trusted); + + /** + Set the untrusted certificates and CRLs for this secure message + system, to be used for validation + + This function is only valid for CMS. + + \param untrusted a set of untrusted certificates and CRLs. + */ + virtual void setUntrustedCertificates(const CertificateCollection &untrusted); + + /** + Set the private keys for this secure message system, to be used + for decryption + + This function is only valid for CMS. + + \param keys the keys to be used for decryption + */ + virtual void setPrivateKeys(const QList &keys); + + /** + Create a new message object for this system. The caller is + responsible for deleting it. + */ + virtual MessageContext *createMessage() = 0; +}; + +} +#endif + +#endif diff --git a/local/recipes/libs/qca/source/include/QtCrypto/qpipe.h b/local/recipes/libs/qca/source/include/QtCrypto/qpipe.h new file mode 100644 index 0000000000..4852acf236 --- /dev/null +++ b/local/recipes/libs/qca/source/include/QtCrypto/qpipe.h @@ -0,0 +1,538 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +/** + \file qpipe.h + + Header file for the QPipe FIFO class + + \note You should not use this header directly from an + application. You should just use \#include \ + instead. +*/ + +#ifndef QPIPE_H +#define QPIPE_H + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#ifndef QPIPE_NO_SECURE +#define QPIPE_SECURE +#endif + +#ifdef QPIPE_SECURE +#include "QtCrypto" +#else +#define QCA_EXPORT +#endif + +// defs adapted qprocess_p.h +#ifdef Q_OS_WIN +#include +typedef HANDLE Q_PIPE_ID; +#define INVALID_Q_PIPE_ID INVALID_HANDLE_VALUE +#else +typedef int Q_PIPE_ID; +#define INVALID_Q_PIPE_ID -1 +#endif + +#endif + +// Note: for Windows console, I/O must be in UTF-8. Reads are guaranteed to +// to completely decode (no partial characters). Likewise, writes must +// not contain partial characters. + +namespace QCA { + +/** + \class QPipeDevice qpipe.h QtCrypto + + Unbuffered direct pipe. + + This class is not usually required except for very low level operations. + You should use QPipe and QPipeEnd for most applications. + + \ingroup UserAPI +*/ +class QCA_EXPORT QPipeDevice : public QObject +{ + Q_OBJECT +public: + /** + The type of device +*/ + enum Type + { + Read, ///< The pipe end can be read from + Write ///< The pipe end can be written to + }; + + /** + Standard constructor + + \param parent the parent object to this object + */ + QPipeDevice(QObject *parent = nullptr); + ~QPipeDevice() override; + + /** + The Type of the pipe device (that is, read or write) + */ + Type type() const; + + /** + Test whether this object corresponds to a valid pipe + */ + bool isValid() const; + + /** + The low level identification for this pipe. + + On Windows, this is a HANDLE. On Unix, this is a file descriptor (i.e. integer). + + Code using this method should be carefully tested for portability. + + \sa idAsInt + */ + Q_PIPE_ID id() const; + + /** + The low level identification for this pipe, returned as an integer. + + Code using this method should be carefully tested for portability. + + \sa id(). + */ + int idAsInt() const; + + /** + Take over an existing pipe id, closing the old pipe if any. + + \param id the identification of the pipe end to take over. + \param t the type of pipe end (read or write). + */ + void take(Q_PIPE_ID id, Type t); + + /** + Enable the pipe for reading or writing (depending on Type) + */ + void enable(); + + /** + Close the pipe end. + */ + void close(); + + /** + Release the pipe end, but do not close it. + */ + void release(); + + /** + Set the pipe end to be inheritable + + \note On Windows, this operation changes the pipe end id value. + + \param enabled whether the pipe is inheritable (true) or not (false) + */ + bool setInheritable(bool enabled); + + /** + Obtain the number of bytes available to be read. + */ + int bytesAvailable() const; + + /** + Read from the pipe end + + \param data where to put the data that has been read + \param maxsize the maximum number of bytes to be read. + + \return the actual number of bytes read, 0 on end-of-file, or -1 on error. + */ + int read(char *data, int maxsize); + + /** + Write to the pipe end. + + \param data the source of the data to be written + \param size the number of bytes in the data to be written + + \note the data source must remain valid + + \return the number of bytes written, or -1 on error. + */ + int write(const char *data, int size); + + /** + The result of a write operation + + \param written if not null, this will be set to the number of + bytes written in the last operation. + + \return 0 on success (all data written), or -1 on error + */ + int writeResult(int *written) const; + +Q_SIGNALS: + /** + Emitted when the pipe end can be read from or written to (depending on its Type). + */ + void notify(); + +private: + Q_DISABLE_COPY(QPipeDevice) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class QPipeEnd qpipe.h QtCrypto + + A buffered higher-level pipe end + + This is either the read end or write end of a QPipe. + + \ingroup UserAPI +*/ +class QCA_EXPORT QPipeEnd : public QObject +{ + Q_OBJECT +public: + /** + The type of error + */ + enum Error + { + ErrorEOF, ///< End of file error + ErrorBroken ///< Broken pipe error + }; + + /** + Standard constructor + + \param parent the parent object for this object + */ + QPipeEnd(QObject *parent = nullptr); + + ~QPipeEnd() override; + + /** + Reset the pipe end to an inactive state + */ + void reset(); + + /** + The type of pipe end (either read or write) + */ + QPipeDevice::Type type() const; + + /** + Determine whether the pipe end is valid. + + \note This does not mean the pipe is ready to be used - you + may need to call enable() first + */ + bool isValid() const; + + /** + Pipe identification + */ + Q_PIPE_ID id() const; + + /** + Pipe identification + */ + int idAsInt() const; + + /** + Take over an existing pipe handle + + \param id the pipe handle + \param t the type of the pipe (read or write) + */ + void take(Q_PIPE_ID id, QPipeDevice::Type t); + +#ifdef QPIPE_SECURE + /** + Sets whether the pipe uses secure memory for read/write + + Enabling this may reduce performance, and it should only be used if + sensitive data is being transmitted (such as a passphrase). + + \param secure whether the pipe uses secure memory (true) or not (false). + */ + void setSecurityEnabled(bool secure); +#endif + + /** + Enable the endpoint for the pipe + + When an endpoint is created, it is not + able to be used until it is enabled. + */ + void enable(); + + /** + Close the end of the pipe + + \sa closed() + */ + void close(); + + /** + Let go of the active pipe handle, but don't close it + + Use this before destructing QPipeEnd, if you don't want the pipe + to automatically close. + */ + void release(); + + /** + Sets whether the pipe should be inheritable to child processes + + Returns true if inheritability was successfully changed, otherwise + false. + + \param enabled whether the pipe is inheritable (true) or not (false). + */ + bool setInheritable(bool enabled); + + /** + Clear the contents of the pipe, and invalidate the pipe + */ + void finalize(); + + /** + Clear the contents of the pipe, and release the pipe + */ + void finalizeAndRelease(); + + /** + Determine how many bytes are available to be read. + + This only makes sense at the read end of the pipe + + \sa readyRead() for a signal that can be used to determine + when there are bytes available to read. + */ + int bytesAvailable() const; + + /** + Returns the number of bytes pending to write + + This only makes sense at the write end of the pipe + + \sa bytesWritten() for a signal that can be used to determine + when bytes have been written + */ + int bytesToWrite() const; + + /** + Read bytes from the pipe. + + You can only call this on the read end of the pipe + + If the pipe is using secure memory, you should use readSecure() + + \param bytes the number of bytes to read (-1 for all + content). + */ + QByteArray read(int bytes = -1); + + /** + Write bytes to the pipe. + + You can only call this on the write end of the pipe. + + If the pipe is using secure memory, you should use writeSecure(). + + \param a the array to write to the pipe + */ + void write(const QByteArray &a); + +#ifdef QPIPE_SECURE + /** + Read bytes from the pipe. + + You can only call this on the read end of the pipe + + If the pipe is using insecure memory, you should use read() + + \param bytes the number of bytes to read (-1 for all + content). + */ + SecureArray readSecure(int bytes = -1); + + /** + Write bytes to the pipe. + + You can only call this on the write end of the pipe. + + If the pipe is using insecure memory, you should use write(). + + \param a the array to write to the pipe + */ + void writeSecure(const SecureArray &a); +#endif + + /** + Returns any unsent bytes queued for writing + + If the pipe is using secure memory, you should use + takeBytesToWriteSecure(). + */ + QByteArray takeBytesToWrite(); + +#ifdef QPIPE_SECURE + /** + Returns any unsent bytes queued for writing + + If the pipe is using insecure memory, you should use + takeBytesToWrite(). + */ + SecureArray takeBytesToWriteSecure(); +#endif + +Q_SIGNALS: + /** + Emitted when there are bytes available to be read + from the read end of the pipe. + + \sa bytesAvailable() + */ + void readyRead(); + + /** + Emitted when bytes have been written to the + write end of the pipe. + + \param bytes the number of bytes written + */ + void bytesWritten(int bytes); + + /** + Emitted when this end of the pipe is closed as a result of calling + close() + + If this is the write end of the pipe and there is data still + pending to write, this signal will be emitted once all of the data + has been written. + + To be notified if the other end of the pipe has been closed, see + error(). + */ + void closed(); + + /** + Emitted when the pipe encounters an error trying to read or write, + or if the other end of the pipe has been closed + + \param e the reason for error + */ + void error(QCA::QPipeEnd::Error e); + +private: + Q_DISABLE_COPY(QPipeEnd) + + class Private; + friend class Private; + Private *d; +}; + +/** + \class QPipe qpipe.h QtCrypto + + A FIFO buffer (named pipe) abstraction + + This class creates a full buffer, consisting of two ends + (QPipeEnd). You can obtain each end (after calling create()) using + readEnd() and writeEnd(), however you must call enable() on each end + before using the pipe. + + By default, the pipe ends are not inheritable by child processes. On + Windows, the pipe is created with inheritability disabled. On Unix, the + FD_CLOEXEC flag is set on each end's file descriptor. + + \ingroup UserAPI +*/ +class QCA_EXPORT QPipe +{ +public: + /** + Standard constructor + + \note You must call create() before using the pipe ends. + + \param parent the parent object for this object + */ + QPipe(QObject *parent = nullptr); + + ~QPipe(); + + /** + Reset the pipe. + + At this point, the readEnd() and writeEnd() calls + will no longer be valid. + */ + void reset(); + +#ifdef QPIPE_SECURE + /** + Create the pipe + + \param secure whether to use secure memory (true) or not (false) + */ + bool create(bool secure = false); +#else + /** + Create the pipe + */ + bool create(); +#endif + + /** + The read end of the pipe. + */ + QPipeEnd &readEnd() + { + return i; + } + + /** + The write end of the pipe. + */ + QPipeEnd &writeEnd() + { + return o; + } + +private: + Q_DISABLE_COPY(QPipe) + + QPipeEnd i, o; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/man/qcatool.1 b/local/recipes/libs/qca/source/man/qcatool.1 new file mode 100644 index 0000000000..550942b6a7 --- /dev/null +++ b/local/recipes/libs/qca/source/man/qcatool.1 @@ -0,0 +1,191 @@ +.TH QCATOOL "1" "August 2007" "qcatool 1.0.0" "Qt Cryptographic Architecture (QCA)" + +.SH NAME +qcatool \- command line tool for the Qt Cryptographic Architecture + +.SH DESCRIPTION +qcatool is a command line tool for performing various cryptographic +operations with the Qt Cryptographic Architecture (QCA). qcatool can +also be used for testing and debugging QCA. + +.SH USAGE +qcatool has a range of options and commands. You only ever get to +use one command, but you may use several, one or no options. + +.SH OPTIONS +As noted above, these are all optional, and may be combined. +.PP +.TP +\fB\-\-pass\fR=PASSWORD +Specify the password to use. This is probably a bad idea except for +testing, because anyone can read the arguments to a command line +application. +.TP +\fB\-\-newpass\fR=PASSWORD +Specify the new password to use for password change +with the \fBkey changepass\fR and \fBkeybundle changepass\fR commands. +This is probably a bad idea except for +testing, because anyone can read the arguments to a command line +application. +.TP +\fB\-\-nonroots\fR=CERTIFICATES +Specify additional certificates, not trusted, but which may be used +in the trust path if appropriate trust can be established. +.TP +\fB\-\-roots\fR=CERTIFICATES +Specify additional certificates which can be used as trusted (root) +certificates. +.TP +\fB\-\-nosys\fR +Disable use of the standard root certificates that are provided by +the operating system. +.TP +\fB\-\-noprompt\fR +Disable prompting for passwords/passphrases. If you do not provide +the passphrase on the command line (with \fB\-\-pass\fR or \fB\-\-newpass\fR) +this will cause qcatool to abort the command if a password/passphrase is +required. +.TP +\fB\-\-ordered\fR +If outputting certificate information fields (Distinguished Name and Subject Alternative Name), show them in same the order that they are present in the certificate rather than in a friendly sorted order. +.TP +\fB\-\-debug\fR +Enable additional output to aid debugging. +.TP +\fB\-\-log-file=FILENAME\fR +Log to the specified file. +.TP +\fB\-\-log-level=LEVEL\fR +Log at the specified level. The log level can be between 0 (none) +and 8 (most). +.TP +\fB\-\-nobundle\fR +When S/MIME signing, do not bundle the signer's certificate chain inside the signature. This results in a smaller signature output, but requires the recipient to have all of the necessary certificates in order to verify it. + +.SH COMMANDS +.TP +\fBhelp\fR, \fB\-\-help\fR, \fB\-h\fR +Output usage (help) information. +.TP +\fBversion\fR, \fB\-\-version\fR, \fB\-v\fR +Output version information. +.TP +\fBplugins\fR +List available plugins. Use the \fB\-\-debug\fR option to get +more information on plugins which are found and which ones actually +loaded. +.TP +\fBconfig save \fI[provider]\fR +Save provider configuration. Use this to have the provider's default configuration written to persistent storage, which you can then edit by hand. +.TP +\fBconfig edit \fI[provider]\fR +Edit provider configuration. The changes are written to persistent storage. +.TP +\fBkey make rsa|dsa [bits]\fR +Create a key pair +.TP +\fBkey changepass [K] +Add/change/remove passphrase of a key +.TP +\fBcert makereq [K]\fR +Create certificate request (CSR) +.TP +\fBcert makeself [K]\fR +Create self-signed certificate +.TP +\fBcert makereqadv [K]\fR +Advanced version of 'makereq' +.TP +\fBcert makeselfadv [K]\fR +Advanced version of 'makeself' +.TP +\fBcert validate [C]\fR +Validate certificate +.TP +\fBkeybundle make [K] [C]\fR +Create a keybundle +.TP +\fBkeybundle extract [X]\fR +Extract certificate(s) and key +.TP +\fBkeybundle changepass [X]\fR +Change passphrase of a keybundle +.TP +\fBkeystore list-stores\fR +List all available keystores +.TP +\fBkeystore list [storeName]\fR +List content of a keystore +.TP +\fBkeystore monitor\fR +Monitor for keystore availability +.TP +\fBkeystore export [E]\fR +Export a keystore entry's content +.TP +\fBkeystore exportref [E]\fR +Export a keystore entry reference +.TP +\fBkeystore addkb [storeName] [cert.p12]\fR +Add a keybundle into a keystore +.TP +\fBkeystore addpgp [storeName] [key.asc]\fR +Add a PGP key into a keystore +.TP +\fBkeystore remove [E]\fR +Remove an object from a keystore +.TP +\fBshow cert [C]\fR +Examine a certificate +.TP +\fBshow req [req.pem]\fR +Examine a certificate request (CSR) +.TP +\fBshow crl [crl.pem]\fR +Examine a certificate revocation list +.TP +\fBshow kb [X]\fR +Examine a keybundle +.TP +\fBshow pgp [P|S]\fR +Examine a PGP key +.TP +\fBmessage sign pgp|pgpdetach|smime [X|S]\fR +Sign a message +.TP +\fBmessage encrypt pgp|smime [C|P]\fR +Encrypt a message +.TP +\fBmessage signencrypt [S] [P]\fR +PGP sign & encrypt a message +.TP +\fBmessage verify pgp|smime\fR +Verify a message +.TP +\fBmessage decrypt pgp|smime ((X) ...)\fR +Decrypt a message (S/MIME needs X) +.TP +\fBmessage exportcerts\fR +Export certs from S/MIME message + +.SH ARGUMENTS +The arguments to the commands are as follows. + +K = private key. + +C = certificate. + +X = key bundle. + +P = PGP public key. + +S = PGP secret key. + +E = generic entry. + +These must be identified by either a filename or a keystore reference ("store:obj"). + +.SH AUTHOR +qcatool was written by Justin Karneges as part of QCA. This manual page +was written by Brad Hards. + diff --git a/local/recipes/libs/qca/source/metainfo.yaml b/local/recipes/libs/qca/source/metainfo.yaml new file mode 100644 index 0000000000..04b0eb0565 --- /dev/null +++ b/local/recipes/libs/qca/source/metainfo.yaml @@ -0,0 +1,40 @@ +maintainer: sitter +fancyname: QCA +description: QCA (Qt Cryptographic Architecture) provides a straightforward and cross-platform crypto API +platforms: + - name: Linux + - name: FreeBSD + - name: Windows +# - name: MacOSX +# - name: Android +release: true +public_lib: true +public_source_dirs: + - include/QtCrypto + - examples +public_doc_dir: + - docs +public_example_dirs: + - examples/aes-cmac + - examples/base64test + - examples/certtest + - examples/ciphertest + - examples/cms + - examples/cmssigner + - examples/eventhandlerdemo + - examples/hashtest + - examples/hextest + - examples/keyloader + - examples/mactest + - examples/md5crypt + - examples/providertest + - examples/publickeyexample + - examples/randomtest + - examples/rsatest + - examples/saslclient + - examples/saslserver + - examples/ssltest + - examples/sslservtest + - examples/tlssocket +irc: kde-devel +mailinglist: kde-core-devel diff --git a/local/recipes/libs/qca/source/plugins/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/CMakeLists.txt new file mode 100644 index 0000000000..6d354dcf58 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/CMakeLists.txt @@ -0,0 +1,68 @@ +# Use the same path for shared and static plugins +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME}/crypto") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME}/crypto") + +set(PLUGINS "botan;cyrus-sasl;gcrypt;gnupg;logger;nss;ossl;pkcs11;softstore" CACHE INTERNAL "") + +# Initialize WITH_${PLUGIN}_PLUGIN cache variables +foreach(PLUGIN IN LISTS PLUGINS) + set(WITH_${PLUGIN}_PLUGIN "" CACHE STRING "Build ${PLUGIN} plugin") + string(TOLOWER "${WITH_${PLUGIN}_PLUGIN}" WITH_${PLUGIN}_PLUGIN) +endforeach(PLUGIN IN LISTS PLUGINS) + +string(REGEX MATCH "^none|all|auto$" NOT_PLUGIN_LIST "${BUILD_PLUGINS}") + +if(NOT_PLUGIN_LIST) + # BUILD_PLUGINS has "none", "all" or "auto" value + foreach(PLUGIN IN LISTS PLUGINS) + # If not defined by user use BUILD_PLUGINS value + # to decide build or not build the plugin + if("${WITH_${PLUGIN}_PLUGIN}" STREQUAL "") + if("${BUILD_PLUGINS}" STREQUAL "all") + set(WITH_${PLUGIN}_PLUGIN "yes") + elseif("${BUILD_PLUGINS}" STREQUAL "auto") + set(WITH_${PLUGIN}_PLUGIN "auto") + else() + set(WITH_${PLUGIN}_PLUGIN "no") + endif() + elseif(NOT WITH_${PLUGIN}_PLUGIN) + set(WITH_${PLUGIN}_PLUGIN "no") + elseif("${WITH_${PLUGIN}_PLUGIN}" STREQUAL "auto") + set(WITH_${PLUGIN}_PLUGIN "auto") + else() + set(WITH_${PLUGIN}_PLUGIN "yes") + endif() + + # Build plugin if yes or auto + if(WITH_${PLUGIN}_PLUGIN) + add_subdirectory("qca-${PLUGIN}") + else() + disable_plugin(${PLUGIN}) + endif() + endforeach(PLUGIN IN LISTS PLUGINS) +else() + # BUILD_PLUGINS has list plugins to builds + foreach(PLUGIN IN LISTS PLUGINS) + list(FIND BUILD_PLUGINS "${PLUGIN}" PLUGIN_INDEX) + if(PLUGIN_INDEX GREATER -1) + set(WITH_${PLUGIN}_PLUGIN "yes") + add_subdirectory("qca-${PLUGIN}") + else() + disable_plugin(${PLUGIN}) + endif() + endforeach(PLUGIN IN LISTS PLUGINS) +endif() + +message("") +message("Plugins:") +foreach(PLUGIN IN LISTS PLUGINS) + message(" qca-${PLUGIN} ${WITH_${PLUGIN}_PLUGIN_INTERNAL}") +endforeach(PLUGIN IN LISTS PLUGINS) + +# Currently disabled +# +# IF (WIN32) +# MESSAGE(STATUS "WinCrypto plugin enabled") +# ADD_SUBDIRECTORY(qca-wincrypto) +# ENDIF (WIN32) + diff --git a/local/recipes/libs/qca/source/plugins/qca-botan/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-botan/CMakeLists.txt new file mode 100644 index 0000000000..a8ae3ec963 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-botan/CMakeLists.txt @@ -0,0 +1,40 @@ +find_package(PkgConfig REQUIRED) + +pkg_check_modules(BOTAN IMPORTED_TARGET botan-2) +if(NOT BOTAN_FOUND) + pkg_check_modules(BOTAN IMPORTED_TARGET botan-3) + if(BOTAN_FOUND) + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + endif() +endif() + +if(WITH_botan_PLUGIN STREQUAL "yes" AND NOT BOTAN_FOUND) + message(FATAL_ERROR "botan requested and not found") +endif() + +if(BOTAN_FOUND) + enable_plugin("botan") + + set(QCA_BOTAN_SOURCES qca-botan.cpp) + add_library(qca-botan ${PLUGIN_TYPE} ${QCA_BOTAN_SOURCES}) + + if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-botan PROPERTY SUFFIX ".dylib") + endif() + + target_link_libraries(qca-botan Qt${QT_MAJOR_VERSION}::Core ${QCA_LIB_NAME} PkgConfig::BOTAN) + + if(NOT DEVELOPER_MODE) + install(TARGETS qca-botan + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-botan ${QCA_CRYPTO_INSTALL_DIR}) + endif() + +else() + disable_plugin("botan") +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-botan/COPYING b/local/recipes/libs/qca/source/plugins/qca-botan/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-botan/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-botan/README b/local/recipes/libs/qca/source/plugins/qca-botan/README new file mode 100644 index 0000000000..46751d9a5c --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-botan/README @@ -0,0 +1,16 @@ +QCA Botan plugin +------------------ +Author: Brad Hards + +This plugin provides features based on Botan. It implements: +* TBA + + +Requirements: + Botan 1.4.1 or later + +Installation procedure: + ./configure + make + su -c "make install" + diff --git a/local/recipes/libs/qca/source/plugins/qca-botan/qca-botan.cpp b/local/recipes/libs/qca/source/plugins/qca-botan/qca-botan.cpp new file mode 100644 index 0000000000..049c8b48cf --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-botan/qca-botan.cpp @@ -0,0 +1,762 @@ +/* + * Copyright (C) 2004 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//----------------------------------------------------------- +class botanRandomContext : public QCA::RandomContext +{ + Q_OBJECT +public: + botanRandomContext(QCA::Provider *p) + : RandomContext(p) + { + } + + Context *clone() const override + { + return new botanRandomContext(*this); + } + + QCA::SecureArray nextBytes(int size) override + { + QCA::SecureArray buf(size); + Botan::AutoSeeded_RNG rng; + rng.randomize(reinterpret_cast(buf.data()), buf.size()); + return buf; + } +}; + +static QString qcaHashToBotanHash(const QString &type) +{ + if (type == QLatin1String("md2")) + return QStringLiteral("MD2"); + else if (type == QLatin1String("md4")) + return QStringLiteral("MD4"); + else if (type == QLatin1String("md5")) + return QStringLiteral("MD5"); + else if (type == QLatin1String("sha1")) + return QStringLiteral("SHA-1"); + else if (type == QLatin1String("sha256")) + return QStringLiteral("SHA-256"); + else if (type == QLatin1String("sha384")) + return QStringLiteral("SHA-384"); + else if (type == QLatin1String("sha512")) + return QStringLiteral("SHA-512"); + else if (type == QLatin1String("ripemd160")) + return QStringLiteral("RIPEMD-160"); + + return {}; +} + +//----------------------------------------------------------- +class BotanHashContext : public QCA::HashContext +{ + Q_OBJECT +public: + BotanHashContext(QCA::Provider *p, const QString &type) + : QCA::HashContext(p, type) + { + const QString hashName = qcaHashToBotanHash(type); + m_hashObj = Botan::HashFunction::create(hashName.toStdString()).release(); + } + + ~BotanHashContext() override + { + delete m_hashObj; + } + + bool isOk() const + { + return m_hashObj; + } + + Context *clone() const override + { + return new BotanHashContext(provider(), type()); + } + + void clear() override + { + m_hashObj->clear(); + } + + void update(const QCA::MemoryRegion &a) override + { + m_hashObj->update((const Botan::byte *)a.data(), a.size()); + } + + QCA::MemoryRegion final() override + { + QCA::SecureArray a(m_hashObj->output_length()); + m_hashObj->final((Botan::byte *)a.data()); + return a; + } + +private: + Botan::HashFunction *m_hashObj; +}; + +static QString qcaHmacToBotanHmac(const QString &type) +{ + if (type == QLatin1String("hmac(md5)")) + return QStringLiteral("HMAC(MD5)"); + else if (type == QLatin1String("hmac(sha1)")) + return QStringLiteral("HMAC(SHA-1)"); + else if (type == QLatin1String("hmac(sha224)")) + return QStringLiteral("HMAC(SHA-224)"); + else if (type == QLatin1String("hmac(sha256)")) + return QStringLiteral("HMAC(SHA-256)"); + else if (type == QLatin1String("hmac(sha384)")) + return QStringLiteral("HMAC(SHA-384)"); + else if (type == QLatin1String("hmac(sha512)")) + return QStringLiteral("HMAC(SHA-512)"); + else if (type == QLatin1String("hmac(ripemd160)")) + return QStringLiteral("HMAC(RIPEMD-160)"); + + return {}; +} + +//----------------------------------------------------------- +class BotanHMACContext : public QCA::MACContext +{ + Q_OBJECT +public: + BotanHMACContext(QCA::Provider *p, const QString &type) + : QCA::MACContext(p, type) + , m_hashObj(Botan::MessageAuthenticationCode::create(qcaHmacToBotanHmac(type).toStdString())) + { + if (nullptr == m_hashObj) { + std::cout << "null context object " << qcaHmacToBotanHmac(type).toStdString() << std::endl; + } + } + + ~BotanHMACContext() override + { + } + + void setup(const QCA::SymmetricKey &key) override + { + // this often gets called with an empty key, because that is the default + // in the QCA MessageAuthenticationCode constructor. Botan doesn't like + // that happening. + if (key.size() > 0) { + m_hashObj->set_key((const Botan::byte *)key.data(), key.size()); + } + } + + Context *clone() const override + { + return new BotanHMACContext(provider(), type()); + } + + void clear() + { + m_hashObj->clear(); + } + + QCA::KeyLength keyLength() const override + { + return anyKeyLength(); + } + + void update(const QCA::MemoryRegion &a) override + { + m_hashObj->update((const Botan::byte *)a.data(), a.size()); + } + + void final(QCA::MemoryRegion *out) override + { + QCA::SecureArray sa(m_hashObj->output_length(), 0); + m_hashObj->final((Botan::byte *)sa.data()); + *out = sa; + } + +protected: + std::unique_ptr m_hashObj; +}; + +static QString qcaPbkdfToBotanPbkdf(const QString &pbkdf) +{ + if (pbkdf == QLatin1String("pbkdf1(sha1)")) + return QStringLiteral("PBKDF1(SHA-1)"); + else if (pbkdf == QLatin1String("pbkdf1(md2)")) + return QStringLiteral("PBKDF1(MD2)"); + else if (pbkdf == QLatin1String("pbkdf2(sha1)")) + return QStringLiteral("PBKDF2(SHA-1)"); + + return {}; +} + +//----------------------------------------------------------- +class BotanPBKDFContext : public QCA::KDFContext +{ + Q_OBJECT +public: + BotanPBKDFContext(QCA::Provider *p, const QString &type) + : QCA::KDFContext(p, type) + { + try { + const QString kdfName = qcaPbkdfToBotanPbkdf(type); + m_s2k = Botan::get_s2k(kdfName.toStdString()); + } catch (Botan::Exception &e) { + m_s2k = nullptr; + } + } + + ~BotanPBKDFContext() override + { + delete m_s2k; + } + + bool isOk() const + { + return m_s2k; + } + + Context *clone() const override + { + return new BotanPBKDFContext(provider(), type()); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) override + { + if (!m_s2k) + return {}; + + const std::string secretString(secret.data(), secret.size()); + const Botan::OctetString key = + m_s2k->derive_key(keyLength, secretString, (const Botan::byte *)salt.data(), salt.size(), iterationCount); + const QCA::SecureArray retval(QByteArray((const char *)key.begin(), key.length())); + return QCA::SymmetricKey(retval); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) override + { + Q_ASSERT(iterationCount != nullptr); + Botan::OctetString key; + QElapsedTimer timer; + const std::string secretString(secret.data(), secret.size()); + + *iterationCount = 0; + timer.start(); + while (timer.elapsed() < msecInterval) { + key = m_s2k->derive_key(keyLength, secretString, (const Botan::byte *)salt.data(), salt.size(), 1); + ++(*iterationCount); + } + return makeKey(secret, salt, keyLength, *iterationCount); + } + +protected: + Botan::S2K *m_s2k; +}; + +static QString qcaHkdfToBotanHkdf(const QString &type) +{ + if (type == QLatin1String("hkdf(sha256)")) + return QStringLiteral("HKDF(SHA-256)"); + + return {}; +} + +//----------------------------------------------------------- +class BotanHKDFContext : public QCA::HKDFContext +{ + Q_OBJECT +public: + BotanHKDFContext(QCA::Provider *p, const QString &type) + : QCA::HKDFContext(p, type) + , m_hkdf(Botan::KDF::create(qcaHkdfToBotanHkdf(type).toStdString())) + { + } + + ~BotanHKDFContext() override + { + } + + Context *clone() const override + { + return new BotanHKDFContext(provider(), type()); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + const QCA::InitializationVector &info, + unsigned int keyLength) override + { + Botan::secure_vector key(keyLength); + m_hkdf->kdf(key.data(), + keyLength, + reinterpret_cast(secret.data()), + secret.size(), + reinterpret_cast(salt.data()), + salt.size(), + reinterpret_cast(info.data()), + info.size()); + QCA::SecureArray retval(QByteArray::fromRawData(reinterpret_cast(key.data()), key.size())); + return QCA::SymmetricKey(retval); + } + +protected: + std::unique_ptr m_hkdf; +}; + +static void +qcaCipherToBotanCipher(const QString &type, std::string *algoName, std::string *algoMode, std::string *algoPadding) +{ + if (type == QLatin1String("aes128-ecb")) { + *algoName = "AES-128"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes128-cbc")) { + *algoName = "AES-128"; + *algoMode = "CBC"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes128-cfb")) { + *algoName = "AES-128"; + *algoMode = "CFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes128-ofb")) { + *algoName = "AES-128"; + *algoMode = "OFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes192-ecb")) { + *algoName = "AES-192"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes192-cbc")) { + *algoName = "AES-192"; + *algoMode = "CBC"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes192-cfb")) { + *algoName = "AES-192"; + *algoMode = "CFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes192-ofb")) { + *algoName = "AES-192"; + *algoMode = "OFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes256-ecb")) { + *algoName = "AES-256"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes256-cbc")) { + *algoName = "AES-256"; + *algoMode = "CBC"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes256-cfb")) { + *algoName = "AES-256"; + *algoMode = "CFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("aes256-ofb")) { + *algoName = "AES-256"; + *algoMode = "OFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("blowfish-ecb")) { + *algoName = "Blowfish"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("blowfish-cbc")) { + *algoName = "Blowfish"; + *algoMode = "CBC"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("blowfish-cbc-pkcs7")) { + *algoName = "Blowfish"; + *algoMode = "CBC"; + *algoPadding = "PKCS7"; + } else if (type == QLatin1String("blowfish-cfb")) { + *algoName = "Blowfish"; + *algoMode = "CFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("blowfish-ofb")) { + *algoName = "Blowfish"; + *algoMode = "OFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("des-ecb")) { + *algoName = "DES"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("des-ecb-pkcs7")) { + *algoName = "DES"; + *algoMode = "ECB"; + *algoPadding = "PKCS7"; + } else if (type == QLatin1String("des-cbc")) { + *algoName = "DES"; + *algoMode = "CBC"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("des-cbc-pkcs7")) { + *algoName = "DES"; + *algoMode = "CBC"; + *algoPadding = "PKCS7"; + } else if (type == QLatin1String("des-cfb")) { + *algoName = "DES"; + *algoMode = "CFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("des-ofb")) { + *algoName = "DES"; + *algoMode = "OFB"; + *algoPadding = "NoPadding"; + } else if (type == QLatin1String("tripledes-ecb")) { + *algoName = "TripleDES"; + *algoMode = "ECB"; + *algoPadding = "NoPadding"; + } +} + +static std::string qcaCipherToBotanCipher(const QString &qcaCipher) +{ + std::string algoName, algoMode, algoPadding; + qcaCipherToBotanCipher(qcaCipher, &algoName, &algoMode, &algoPadding); + return algoName + '/' + algoMode + '/' + algoPadding; // NOLINT(performance-inefficient-string-concatenation) +} + +#if BOTAN_VERSION_MAJOR == 2 +#define BOTAN_CIPHER_DIR_ENCRYPTION Botan::ENCRYPTION +#define BOTAN_CIPHER_DIR_DECRYPTION Botan::DECRYPTION +#elif BOTAN_VERSION_MAJOR == 3 +#define BOTAN_CIPHER_DIR_ENCRYPTION Botan::Cipher_Dir::Encryption +#define BOTAN_CIPHER_DIR_DECRYPTION Botan::Cipher_Dir::Decryption +#endif + +//----------------------------------------------------------- +class BotanCipherContext : public QCA::CipherContext +{ + Q_OBJECT +public: + BotanCipherContext(QCA::Provider *p, const QString &type) + : QCA::CipherContext(p, type) + { + qcaCipherToBotanCipher(type, &m_algoName, &m_algoMode, &m_algoPadding); + } + + void setup(QCA::Direction dir, + const QCA::SymmetricKey &key, + const QCA::InitializationVector &iv, + const QCA::AuthTag &tag) override + { + Q_UNUSED(tag); + try { + m_dir = dir; + const Botan::SymmetricKey keyCopy((Botan::byte *)key.data(), key.size()); + + if (iv.size() == 0) { + if (QCA::Encode == dir) { + m_crypter = new Botan::Pipe(Botan::get_cipher( + m_algoName + '/' + m_algoMode + '/' + m_algoPadding, keyCopy, BOTAN_CIPHER_DIR_ENCRYPTION)); + } else { + m_crypter = new Botan::Pipe(Botan::get_cipher( + m_algoName + '/' + m_algoMode + '/' + m_algoPadding, keyCopy, BOTAN_CIPHER_DIR_DECRYPTION)); + } + } else { + const Botan::InitializationVector ivCopy((Botan::byte *)iv.data(), iv.size()); + if (QCA::Encode == dir) { + m_crypter = new Botan::Pipe(Botan::get_cipher(m_algoName + '/' + m_algoMode + '/' + m_algoPadding, + keyCopy, + ivCopy, + BOTAN_CIPHER_DIR_ENCRYPTION)); + } else { + m_crypter = new Botan::Pipe(Botan::get_cipher(m_algoName + '/' + m_algoMode + '/' + m_algoPadding, + keyCopy, + ivCopy, + BOTAN_CIPHER_DIR_DECRYPTION)); + } + } + m_crypter->start_msg(); + } catch (Botan::Exception &e) { + m_crypter = nullptr; + std::cout << "caught: " << e.what() << std::endl; + } + } + + Context *clone() const override + { + return new BotanCipherContext(*this); + } + + int blockSize() const override + { + if (const std::unique_ptr bc = Botan::BlockCipher::create(m_algoName)) + return bc->block_size(); + + throw Botan::Algorithm_Not_Found(m_algoName); + } + + QCA::AuthTag tag() const override + { + // For future implementation + return QCA::AuthTag(); + } + + bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override + { + if (!m_crypter) + return false; + m_crypter->write((Botan::byte *)in.data(), in.size()); + QCA::SecureArray result(m_crypter->remaining()); + // Perhaps bytes_read is redundant and can be dropped + const size_t bytes_read = m_crypter->read((Botan::byte *)result.data(), result.size()); + result.resize(bytes_read); + *out = result; + return true; + } + + bool final(QCA::SecureArray *out) override + { + m_crypter->end_msg(); + QCA::SecureArray result(m_crypter->remaining()); + // Perhaps bytes_read is redundant and can be dropped + const size_t bytes_read = m_crypter->read((Botan::byte *)result.data(), result.size()); + result.resize(bytes_read); + *out = result; + return true; + } + + QCA::KeyLength keyLength() const override + { + Botan::Key_Length_Specification kls(0); + if (const std::unique_ptr bc = Botan::BlockCipher::create(m_algoName)) + kls = bc->key_spec(); + else if (const std::unique_ptr sc = Botan::StreamCipher::create(m_algoName)) + kls = sc->key_spec(); + else if (const std::unique_ptr mac = + Botan::MessageAuthenticationCode::create(m_algoName)) + kls = mac->key_spec(); + return QCA::KeyLength(kls.minimum_keylength(), kls.maximum_keylength(), kls.keylength_multiple()); + } + + ~BotanCipherContext() override + { + delete m_crypter; + } + +protected: + QCA::Direction m_dir; + std::string m_algoName; + std::string m_algoMode; + std::string m_algoPadding; + Botan::Keyed_Filter *m_cipher; + Botan::Pipe *m_crypter; +}; + +//========================================================== +class botanProvider : public QCA::Provider +{ +public: + void init() override + { + } + + ~botanProvider() override + { + // We should be cleaning up there, but + // this causes the unit tests to segfault + // delete m_init; + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("qca-botan"); + } + + const QStringList &pbkdfTypes() const + { + static QStringList list; + if (list.isEmpty()) { + static const QStringList allTypes = { + QStringLiteral("pbkdf1(sha1)"), QStringLiteral("pbkdf1(md2)"), QStringLiteral("pbkdf2(sha1)")}; + for (const QString &type : allTypes) { + std::unique_ptr pbkdf(new BotanPBKDFContext(nullptr, type)); + if (pbkdf->isOk()) + list += type; + } + } + return list; + } + + const QStringList &hashTypes() const + { + static QStringList supported; + if (supported.isEmpty()) { + QStringList list; + list += QStringLiteral("md2"); + list += QStringLiteral("md4"); + list += QStringLiteral("md5"); + list += QStringLiteral("sha1"); + list += QStringLiteral("sha256"); + list += QStringLiteral("sha384"); + list += QStringLiteral("sha512"); + list += QStringLiteral("ripemd160"); + + for (const QString &hash : std::as_const(list)) { + std::unique_ptr hashContext(new BotanHashContext(nullptr, hash)); + if (hashContext->isOk()) { + supported << hash; + } + } + } + return supported; + } + + const QStringList &cipherTypes() const + { + static QStringList supported; + if (supported.isEmpty()) { + QStringList list; + list += QStringLiteral("aes128-ecb"); + list += QStringLiteral("aes128-cbc"); + list += QStringLiteral("aes128-cfb"); + list += QStringLiteral("aes128-ofb"); + list += QStringLiteral("aes192-ecb"); + list += QStringLiteral("aes192-cbc"); + list += QStringLiteral("aes192-cfb"); + list += QStringLiteral("aes192-ofb"); + list += QStringLiteral("aes256-ecb"); + list += QStringLiteral("aes256-cbc"); + list += QStringLiteral("aes256-cfb"); + list += QStringLiteral("aes256-ofb"); + list += QStringLiteral("des-ecb"); + list += QStringLiteral("des-ecb-pkcs7"); + list += QStringLiteral("des-cbc"); + list += QStringLiteral("des-cbc-pkcs7"); + list += QStringLiteral("des-cfb"); + list += QStringLiteral("des-ofb"); + list += QStringLiteral("tripledes-ecb"); + list += QStringLiteral("blowfish-ecb"); + list += QStringLiteral("blowfish-cbc"); + list += QStringLiteral("blowfish-cbc-pkcs7"); + list += QStringLiteral("blowfish-cfb"); + list += QStringLiteral("blowfish-ofb"); + + for (const QString &cipher : std::as_const(list)) { + const std::string bothanCipher = qcaCipherToBotanCipher(cipher); + try { + std::unique_ptr enc( + Botan::get_cipher(bothanCipher, BOTAN_CIPHER_DIR_ENCRYPTION)); + std::unique_ptr dec( + Botan::get_cipher(bothanCipher, BOTAN_CIPHER_DIR_DECRYPTION)); + supported += cipher; + } catch (Botan::Exception &e) { + } + } + } + return supported; + } + + const QStringList &hmacTypes() const + { + static QStringList list; + if (list.isEmpty()) { + list += QStringLiteral("hmac(md5)"); + list += QStringLiteral("hmac(sha1)"); + // HMAC with SHA2 doesn't appear to work correctly in Botan. + list += QStringLiteral("hmac(sha224)"); + list += QStringLiteral("hmac(sha256)"); + list += QStringLiteral("hmac(sha384)"); + list += QStringLiteral("hmac(sha512)"); + list += QStringLiteral("hmac(ripemd160)"); + } + return list; + } + + QStringList hkdfTypes() const + { + static QStringList list; + if (list.isEmpty()) { + list += QStringLiteral("hkdf(sha256)"); + } + return list; + } + + QStringList features() const override + { + static QStringList list; + if (list.isEmpty()) { + list += QStringLiteral("random"); + list += hmacTypes(); + list += pbkdfTypes(); + list += hkdfTypes(); + list += cipherTypes(); + list += hashTypes(); + } + return list; + } + + Context *createContext(const QString &type) override + { + if (type == QLatin1String("random")) + return new botanRandomContext(this); + else if (hashTypes().contains(type)) + return new BotanHashContext(this, type); + else if (hmacTypes().contains(type)) + return new BotanHMACContext(this, type); + else if (pbkdfTypes().contains(type)) + return new BotanPBKDFContext(this, type); + else if (hkdfTypes().contains(type)) + return new BotanHKDFContext(this, type); + else if (cipherTypes().contains(type)) + return new BotanCipherContext(this, type); + else + return nullptr; + } + +private: +}; + +class botanPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + QCA::Provider *createProvider() override + { + return new botanProvider; + } +}; + +#include "qca-botan.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-botan/qcextra b/local/recipes/libs/qca/source/plugins/qca-botan/qcextra new file mode 100755 index 0000000000..fef4f18bcd --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-botan/qcextra @@ -0,0 +1,9 @@ +#!/bin/sh + +cat >extra.pri < + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/README b/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/README new file mode 100644 index 0000000000..a1b8144c8a --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/README @@ -0,0 +1,29 @@ +QCA Cyrus SASL plugin version 2.0.0 +----------------------------------- +Date: October 11th, 2007 +Website: http://delta.affinix.com/qca/ +Mailing List: Delta Project + +Author: Justin Karneges + +This plugin provides features based on Cyrus SASL version 2. + +Requirements: + Cyrus SASL 2.x (libsasl2) + +Installing +---------- + +For Unix/Linux/Mac: + + ./configure + make + make install + +For Windows: + + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + diff --git a/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/qca-cyrus-sasl.cpp b/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/qca-cyrus-sasl.cpp new file mode 100644 index 0000000000..3314011f90 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-cyrus-sasl/qca-cyrus-sasl.cpp @@ -0,0 +1,1000 @@ +/* + * qca-sasl.cpp - SASL plugin for QCA + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2006 Michail Pishchagin + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include +#include + +extern "C" { +#include +} + +#include +#include +#include + +#define SASL_BUFSIZE 8192 +#define SASL_APP "qca" + +using namespace QCA; + +namespace saslQCAPlugin { + +class saslProvider : public Provider +{ +public: + saslProvider(); + void init() override; + ~saslProvider() override; + int qcaVersion() const override; + QString name() const override; + QString credit() const override; + QStringList features() const override; + Context *createContext(const QString &type) override; + + bool client_init; + bool server_init; + QString appname; +}; + +//---------------------------------------------------------------------------- +// SASLParams +//---------------------------------------------------------------------------- + +class SASLParams +{ +public: + class SParams + { + public: + bool user, authzid, pass, realm; + }; + + SASLParams() + { + reset(); + } + + void reset() + { + resetNeed(); + resetHave(); + foreach (char *result, results) + delete result; + results.clear(); + } + + void resetNeed() + { + need.user = false; + need.authzid = false; + need.pass = false; + need.realm = false; + } + + void resetHave() + { + have.user = false; + have.authzid = false; + have.pass = false; + have.realm = false; + } + + void setUsername(const QString &s) + { + have.user = true; + user = s; + } + + void setAuthzid(const QString &s) + { + have.authzid = true; + authzid = s; + } + + void setPassword(const SecureArray &s) + { + have.pass = true; + pass = QString::fromUtf8(s.toByteArray()); + } + + void setRealm(const QString &s) + { + have.realm = true; + realm = s; + } + + void applyInteract(sasl_interact_t *needp) + { + for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) { + if (needp[n].id == SASL_CB_AUTHNAME) + need.user = true; // yes, I know these + if (needp[n].id == SASL_CB_USER) + need.authzid = true; // look backwards + if (needp[n].id == SASL_CB_PASS) + need.pass = true; + if (needp[n].id == SASL_CB_GETREALM) + need.realm = true; + } + } + + void extractHave(sasl_interact_t *needp) + { + for (int n = 0; needp[n].id != SASL_CB_LIST_END; ++n) { + if (needp[n].id == SASL_CB_AUTHNAME && have.user) + setValue(&needp[n], user); + if (needp[n].id == SASL_CB_USER && have.authzid) + setValue(&needp[n], authzid); + if (needp[n].id == SASL_CB_PASS && have.pass) + setValue(&needp[n], pass); + if (needp[n].id == SASL_CB_GETREALM && have.realm) + setValue(&needp[n], realm); + } + } + + bool missingAny() const + { + if ((need.user && !have.user) /*|| (need.authzid && !have.authzid)*/ || + (need.pass && !have.pass) /*|| (need.realm && !have.realm)*/) + return true; + return false; + } + + SParams missing() const + { + SParams np = need; + if (have.user) + np.user = false; + if (have.authzid) + np.authzid = false; + if (have.pass) + np.pass = false; + if (have.realm) + np.realm = false; + return np; + } + + void setValue(sasl_interact_t *i, const QString &s) + { + if (i->result) + return; + const QByteArray cs = s.toUtf8(); + const int len = cs.length(); + char *p = new char[len + 1]; + memcpy(p, cs.data(), len); + p[len] = 0; + i->result = p; + i->len = len; + + // record this + results.append(p); + } + + QList results; + SParams need; + SParams have; + QString user, authzid, pass, realm; +}; + +static QByteArray makeByteArray(const void *in, unsigned int len) +{ + QByteArray buf(len, 0); + memcpy(buf.data(), in, len); + return buf; +} + +static QString addrString(const SASLContext::HostPort &hp) +{ + return (hp.addr + QLatin1Char(';') + QString::number(hp.port)); +} + +//---------------------------------------------------------------------------- +// saslContext +//---------------------------------------------------------------------------- + +class saslContext : public SASLContext +{ + Q_OBJECT + saslProvider *g; + + // core props + QString service, host; + QString localAddr, remoteAddr; + + // security props + int secflags; + int ssf_min, ssf_max; + QString ext_authid; + int ext_ssf; + + sasl_conn_t *con; + sasl_interact_t *need; + int maxoutbuf; + sasl_callback_t *callbacks; + + // state + bool servermode; + int step; + bool in_sendFirst; + QByteArray in_buf; + QString in_mech; + bool in_useClientInit; + QByteArray in_clientInit; + QString out_mech; + // bool out_useClientInit; + // QByteArray out_clientInit; + QByteArray out_buf; + + SASLParams params; + QString sc_username, sc_authzid; + bool ca_flag, ca_done, ca_skip; + int last_r; + + int result_ssf; + Result result_result; + bool result_haveClientInit; + QStringList result_mechlist; + SASL::AuthCondition result_authCondition; + QByteArray result_to_net; + QByteArray result_plain; + int result_encoded; + +private: + void resetState() + { + if (con) { + sasl_dispose(&con); + con = nullptr; + } + need = nullptr; + if (callbacks) { + delete callbacks; + callbacks = nullptr; + } + + localAddr = QLatin1String(""); + remoteAddr = QLatin1String(""); + maxoutbuf = 128; + sc_username = QLatin1String(""); + sc_authzid = QLatin1String(""); + + result_authCondition = SASL::AuthFail; + result_haveClientInit = false; + result_mechlist.clear(); + result_plain.clear(); + result_plain.clear(); + result_plain.clear(); + result_ssf = 0; + } + + void resetParams() + { + params.reset(); + secflags = 0; + ssf_min = 0; + ssf_max = 0; + ext_authid = QLatin1String(""); + ext_ssf = 0; + } + + bool setsecprops() + { + sasl_security_properties_t secprops; + secprops.min_ssf = ssf_min; + secprops.max_ssf = ssf_max; + secprops.maxbufsize = SASL_BUFSIZE; + secprops.property_names = nullptr; + secprops.property_values = nullptr; + secprops.security_flags = secflags; + int r = sasl_setprop(con, SASL_SEC_PROPS, &secprops); + if (r != SASL_OK) + return false; + + if (!ext_authid.isEmpty()) { + const QByteArray ext_authidBA = ext_authid.toLatin1(); + const char *authid = ext_authidBA.data(); + sasl_ssf_t ssf = ext_ssf; + r = sasl_setprop(con, SASL_SSF_EXTERNAL, &ssf); + if (r != SASL_OK) + return false; + r = sasl_setprop(con, SASL_AUTH_EXTERNAL, authid); + if (r != SASL_OK) + return false; + } + + return true; + } + + void setAuthCondition(int r) + { + // qDebug() << "authcondition: " << r; + SASL::AuthCondition x; + switch (r) { + // common + case SASL_NOMECH: + x = SASL::NoMechanism; + break; + case SASL_BADPROT: + x = SASL::BadProtocol; + break; + + // client + case SASL_BADSERV: + x = SASL::BadServer; + break; + + // server + case SASL_BADAUTH: + x = SASL::BadAuth; + break; + case SASL_NOAUTHZ: + x = SASL::NoAuthzid; + break; + case SASL_TOOWEAK: + x = SASL::TooWeak; + break; + case SASL_ENCRYPT: + x = SASL::NeedEncrypt; + break; + case SASL_EXPIRED: + x = SASL::Expired; + break; + case SASL_DISABLED: + x = SASL::Disabled; + break; + case SASL_NOUSER: + x = SASL::NoUser; + break; + case SASL_UNAVAIL: + x = SASL::RemoteUnavailable; + break; + + default: + x = SASL::AuthFail; + break; + } + result_authCondition = x; + } + + void getssfparams() + { + const void *maybe_sff; + if (SASL_OK == sasl_getprop(con, SASL_SSF, &maybe_sff)) + result_ssf = *(const int *)maybe_sff; + + const void *maybe_maxoutbuf; + if (SASL_OK == sasl_getprop(con, SASL_MAXOUTBUF, &maybe_maxoutbuf)) + maxoutbuf = *(const int *)maybe_maxoutbuf; + } + + static int scb_checkauth(sasl_conn_t *, + void *context, + const char *requested_user, + unsigned, + const char *auth_identity, + unsigned, + const char *, + unsigned, + struct propctx *) + { + saslContext *that = (saslContext *)context; + that->sc_username = QString::fromLatin1(auth_identity); // yeah yeah, it looks + that->sc_authzid = QString::fromLatin1(requested_user); // backwards, but it is right + that->ca_flag = true; + return SASL_OK; + } + + void clientTryAgain() + { + result_haveClientInit = false; + + if (step == 0) { + const char *clientout, *m; + unsigned int clientoutlen; + + need = nullptr; + const QString list = result_mechlist.join(QStringLiteral(" ")); + int r; + while (true) { + if (need) + params.extractHave(need); + if (in_sendFirst) + r = sasl_client_start(con, list.toLatin1().data(), &need, &clientout, &clientoutlen, &m); + else + r = sasl_client_start(con, list.toLatin1().data(), &need, nullptr, nullptr, &m); + if (r != SASL_INTERACT) + break; + + params.applyInteract(need); + if (params.missingAny()) { + out_mech = QString::fromLatin1(m); + result_result = Params; + return; + } + } + if (r != SASL_OK && r != SASL_CONTINUE) { + setAuthCondition(r); + result_result = Error; + return; + } + + out_mech = QString::fromLatin1(m); + if (in_sendFirst && clientout) { + out_buf = makeByteArray(clientout, clientoutlen); + result_haveClientInit = true; + } + + ++step; + + if (r == SASL_OK) { + getssfparams(); + result_result = Success; + return; + } + result_result = Continue; + return; + } else { + const char *clientout; + unsigned int clientoutlen; + int r; + while (true) { + if (need) + params.extractHave(need); + // printf("sasl_client_step(con, {%s}, %d, &need, &clientout, &clientoutlen);\n", in_buf.data(), + // in_buf.size()); + r = sasl_client_step(con, in_buf.data(), in_buf.size(), &need, &clientout, &clientoutlen); + // printf("returned: %d\n", r); + if (r != SASL_INTERACT) + break; + + params.applyInteract(need); + if (params.missingAny()) { + result_result = Params; + return; + } + } + if (r != SASL_OK && r != SASL_CONTINUE) { + setAuthCondition(r); + result_result = Error; + return; + } + out_buf = makeByteArray(clientout, clientoutlen); + if (r == SASL_OK) { + getssfparams(); + result_result = Success; + return; + } + result_result = Continue; + return; + } + } + + void serverTryAgain() + { + if (step == 0) { + if (!ca_skip) { + const char *clientin = nullptr; + unsigned int clientinlen = 0; + if (in_useClientInit) { + clientin = in_clientInit.data(); + clientinlen = in_clientInit.size(); + } + const char *serverout; + unsigned int serveroutlen; + ca_flag = false; + const int r = + sasl_server_start(con, in_mech.toLatin1().data(), clientin, clientinlen, &serverout, &serveroutlen); + if (r != SASL_OK && r != SASL_CONTINUE) { + setAuthCondition(r); + result_result = Error; + return; + } + out_buf = makeByteArray(serverout, serveroutlen); + last_r = r; + if (ca_flag && !ca_done) { + ca_done = true; + ca_skip = true; + result_result = AuthCheck; + return; + } + } + ca_skip = false; + ++step; + + if (last_r == SASL_OK) { + getssfparams(); + result_result = Success; + return; + } + result_result = Continue; + return; + } else { + if (!ca_skip) { + const char *serverout; + unsigned int serveroutlen; + const int r = sasl_server_step(con, in_buf.data(), in_buf.size(), &serverout, &serveroutlen); + if (r != SASL_OK && r != SASL_CONTINUE) { + setAuthCondition(r); + result_result = Error; + return; + } + if (r == SASL_OK) + out_buf.resize(0); + else + out_buf = makeByteArray(serverout, serveroutlen); + last_r = r; + if (ca_flag && !ca_done) { + ca_done = true; + ca_skip = true; + result_result = AuthCheck; + return; + } + } + ca_skip = false; + if (last_r == SASL_OK) { + getssfparams(); + result_result = Success; + return; + } + result_result = Continue; + return; + } + } + + bool sasl_endecode(const QByteArray &in, QByteArray *out, bool enc) + { + // no security + if (result_ssf == 0) { + *out = in; + return true; + } + + int at = 0; + out->resize(0); + while (true) { + int size = in.size() - at; + if (size == 0) + break; + if (size > maxoutbuf) + size = maxoutbuf; + const char *outbuf; + unsigned len; + int r; + if (enc) + r = sasl_encode(con, in.data() + at, size, &outbuf, &len); + else + r = sasl_decode(con, in.data() + at, size, &outbuf, &len); + if (r != SASL_OK) + return false; + const int oldsize = out->size(); + out->resize(oldsize + len); + memcpy(out->data() + oldsize, outbuf, len); + at += size; + } + return true; + } + + void doResultsReady() + { + QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); + } + +public: + saslContext(saslProvider *_g) + : SASLContext(_g) + { + result_result = Success; + g = _g; + con = nullptr; + callbacks = nullptr; + + reset(); + } + + ~saslContext() override + { + reset(); + } + + Provider::Context *clone() const override + { + return nullptr; + } + + Result result() const override + { + return result_result; + } + + void reset() override + { + resetState(); + resetParams(); + } + + void setup(const QString &_service, + const QString &_host, + const HostPort *local, + const HostPort *remote, + const QString &ext_id, + int _ext_ssf) override + { + service = _service; + host = _host; + localAddr = local ? addrString(*local) : QLatin1String(""); + remoteAddr = remote ? addrString(*remote) : QLatin1String(""); + ext_authid = ext_id; + ext_ssf = _ext_ssf; + } + + int ssf() const override + { + return result_ssf; + } + + void startClient(const QStringList &mechlist, bool allowClientSendFirst) override + { + resetState(); + + in_sendFirst = allowClientSendFirst; + + if (!g->client_init) { + sasl_client_init(nullptr); + g->client_init = true; + } + + callbacks = new sasl_callback_t[5]; + + callbacks[0].id = SASL_CB_GETREALM; + callbacks[0].proc = nullptr; + callbacks[0].context = nullptr; + + callbacks[1].id = SASL_CB_USER; + callbacks[1].proc = nullptr; + callbacks[1].context = nullptr; + + callbacks[2].id = SASL_CB_AUTHNAME; + callbacks[2].proc = nullptr; + callbacks[2].context = nullptr; + + callbacks[3].id = SASL_CB_PASS; + callbacks[3].proc = nullptr; + callbacks[3].context = nullptr; + + callbacks[4].id = SASL_CB_LIST_END; + callbacks[4].proc = nullptr; + callbacks[4].context = nullptr; + + result_result = Error; + + const int r = sasl_client_new(service.toLatin1().data(), + host.toLatin1().data(), + localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(), + remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(), + callbacks, + 0, + &con); + if (r != SASL_OK) { + setAuthCondition(r); + doResultsReady(); + return; + } + + if (!setsecprops()) { + doResultsReady(); + return; + } + + result_mechlist = mechlist; + servermode = false; + step = 0; + result_result = Success; + clientTryAgain(); + doResultsReady(); + return; + } + + // TODO: make use of disableServerSendLast + void startServer(const QString &realm, bool disableServerSendLast) override + { + Q_UNUSED(disableServerSendLast); + resetState(); + + g->appname = QStringLiteral(SASL_APP); + if (!g->server_init) { + sasl_server_init(nullptr, QFile::encodeName(g->appname).constData()); + g->server_init = true; + } + + callbacks = new sasl_callback_t[2]; + + callbacks[0].id = SASL_CB_PROXY_POLICY; + callbacks[0].proc = (int (*)())scb_checkauth; + callbacks[0].context = this; + + callbacks[1].id = SASL_CB_LIST_END; + callbacks[1].proc = nullptr; + callbacks[1].context = nullptr; + + result_result = Error; + + int r = sasl_server_new(service.toLatin1().data(), + host.toLatin1().data(), + !realm.isEmpty() ? realm.toLatin1().data() : nullptr, + localAddr.isEmpty() ? nullptr : localAddr.toLatin1().data(), + remoteAddr.isEmpty() ? nullptr : remoteAddr.toLatin1().data(), + callbacks, + 0, + &con); + if (r != SASL_OK) { + setAuthCondition(r); + doResultsReady(); + return; + } + + if (!setsecprops()) { + doResultsReady(); + return; + } + + const char *ml; + r = sasl_listmech(con, nullptr, nullptr, " ", nullptr, &ml, nullptr, nullptr); + if (r != SASL_OK) + return; + result_mechlist = QString::fromUtf8(ml).split(QLatin1Char(' ')); + + servermode = true; + step = 0; + ca_done = false; + ca_skip = false; + result_result = Success; + doResultsReady(); + return; + } + + void serverFirstStep(const QString &mech, const QByteArray *clientInit) override + { + in_mech = mech; + if (clientInit) { + in_useClientInit = true; + in_clientInit = *clientInit; + } else + in_useClientInit = false; + serverTryAgain(); + doResultsReady(); + } + + SASL::Params clientParams() const override + { + const SASLParams::SParams sparams = params.missing(); + return SASL::Params(sparams.user, sparams.authzid, sparams.pass, sparams.realm); + } + + void + setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) override + { + if (user) + params.setUsername(*user); + if (authzid) + params.setAuthzid(*authzid); + if (pass) + params.setPassword(*pass); + if (realm) + params.setRealm(*realm); + } + + QString username() const override + { + return sc_username; + } + + QString authzid() const override + { + return sc_authzid; + } + + void nextStep(const QByteArray &from_net) override + { + in_buf = from_net; + tryAgain(); + } + + void tryAgain() override + { + if (servermode) + serverTryAgain(); + else + clientTryAgain(); + doResultsReady(); + } + + QString mech() const override + { + if (servermode) + return in_mech; + else + return out_mech; + } + + QStringList mechlist() const override + { + return result_mechlist; + } + + QStringList realmlist() const override + { + // TODO + return QStringList(); + } + + void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) override + { + int sf = 0; + if (!(f & SASL::AllowPlain)) + sf |= SASL_SEC_NOPLAINTEXT; + // if( !(f & SASL::AllowActiveVulnerable) ) // TODO + // sf |= SASL_SEC_NOACTIVE; + // if( !(f & SASL::AllowDictVulnerable) ) // TODO + // sf |= SASL_SEC_NODICTIONARY; + if (!(f & SASL::AllowAnonymous)) + sf |= SASL_SEC_NOANONYMOUS; + if (f & SASL::RequireForwardSecrecy) + sf |= SASL_SEC_FORWARD_SECRECY; + if (f & SASL::RequirePassCredentials) + sf |= SASL_SEC_PASS_CREDENTIALS; + if (f & SASL::RequireMutualAuth) + sf |= SASL_SEC_MUTUAL_AUTH; + + secflags = sf; + ssf_min = minSSF; + ssf_max = maxSSF; + } + + bool waitForResultsReady(int msecs) override + { + // TODO: for now, all operations block anyway + Q_UNUSED(msecs); + return true; + } + + void update(const QByteArray &from_net, const QByteArray &from_app) override + { + bool ok = true; + if (!from_app.isEmpty()) + ok = sasl_endecode(from_app, &result_to_net, true); + if (ok && !from_net.isEmpty()) + ok = sasl_endecode(from_net, &result_plain, false); + result_result = ok ? Success : Error; + result_encoded = from_app.size(); + + // printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), + // from_app.size(), result_plain.size()); + + doResultsReady(); + } + + bool haveClientInit() const override + { + return result_haveClientInit; + } + + QByteArray stepData() const override + { + return out_buf; + } + + QByteArray to_net() override + { + const QByteArray a = result_to_net; + result_to_net.clear(); + return a; + } + + int encoded() const override + { + return result_encoded; + } + + QByteArray to_app() override + { + const QByteArray a = result_plain; + result_plain.clear(); + return a; + } + + SASL::AuthCondition authCondition() const override + { + return result_authCondition; + } +}; + +//---------------------------------------------------------------------------- +// saslProvider +//---------------------------------------------------------------------------- +saslProvider::saslProvider() +{ + client_init = false; + server_init = false; +} + +void saslProvider::init() +{ +} + +saslProvider::~saslProvider() +{ + if (client_init || server_init) + sasl_done(); +} + +int saslProvider::qcaVersion() const +{ + return QCA_VERSION; +} + +QString saslProvider::name() const +{ + return QStringLiteral("qca-cyrus-sasl"); +} + +QString saslProvider::credit() const +{ + return QString(); // TODO +} + +QStringList saslProvider::features() const +{ + QStringList list; + list += QStringLiteral("sasl"); + + return list; +} + +Provider::Context *saslProvider::createContext(const QString &type) +{ + if (type == QLatin1String("sasl")) + return new saslContext(this); + + return nullptr; +} + +} // namespace saslQCAPlugin + +using namespace saslQCAPlugin; + +//---------------------------------------------------------------------------- +// saslPlugin +//---------------------------------------------------------------------------- + +class saslPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + Provider *createProvider() override + { + return new saslProvider; + } +}; + +#include "qca-cyrus-sasl.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-gcrypt/CMakeLists.txt new file mode 100644 index 0000000000..7ccf5f9eb7 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/CMakeLists.txt @@ -0,0 +1,46 @@ +find_package(PkgConfig REQUIRED) + +if(WITH_gcrypt_PLUGIN STREQUAL "yes") + pkg_check_modules(LIBGCRYPT REQUIRED IMPORTED_TARGET libgcrypt) +else() + pkg_check_modules(LIBGCRYPT IMPORTED_TARGET libgcrypt) +endif() + +if(LIBGCRYPT_FOUND) + include(CheckTypeSize) + + set(remember_includes ${CMAKE_EXTRA_INCLUDE_FILES}) + set(remember_defines ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_EXTRA_INCLUDE_FILES gcrypt.h) + set(CMAKE_REQUIRED_FLAGS ${LIBGCRYPT_CFLAGS}) + check_type_size(gcry_error_t GCRY_ERROR_T) + set(CMAKE_REQUIRED_FLAGS ${remember_defines}) + set(CMAKE_EXTRA_INCLUDE_FILES ${remember_includes}) + if(HAVE_GCRY_ERROR_T) + enable_plugin("gcrypt") + + set(QCA_GCRYPT_SOURCES qca-gcrypt.cpp) + add_definitions(${LIBGCRYPT_CFLAGS}) + add_library(qca-gcrypt ${PLUGIN_TYPE} ${QCA_GCRYPT_SOURCES}) + + if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-gcrypt PROPERTY SUFFIX ".dylib") + endif() + + target_link_libraries(qca-gcrypt Qt${QT_MAJOR_VERSION}::Core ${QCA_LIB_NAME} PkgConfig::LIBGCRYPT) + + if(NOT DEVELOPER_MODE) + install(TARGETS qca-gcrypt + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-gcrypt ${QCA_CRYPTO_INSTALL_DIR}) + endif() + else() + message(STATUS "libgcrypt seems to be too old") + disable_plugin("gcrypt") + endif() +else() + disable_plugin("gcrypt") +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/COPYING b/local/recipes/libs/qca/source/plugins/qca-gcrypt/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/README b/local/recipes/libs/qca/source/plugins/qca-gcrypt/README new file mode 100644 index 0000000000..943dd19a1b --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/README @@ -0,0 +1,17 @@ +QCA libgcrypt plugin +------------------ +Author: Brad Hards + +This plugin provides features based on libgcrypt. It implements: +* Hashing - SHA1, SHA256, SHA384, SHA512 +* Symmetric encryption - AES128 + + +Requirements: + libgcrypt 1.2.0 or later + +Installation procedure: + ./configure + make + su -c "make install" + diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/TODO b/local/recipes/libs/qca/source/plugins/qca-gcrypt/TODO new file mode 100644 index 0000000000..e9d4d40e59 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/TODO @@ -0,0 +1,8 @@ +Configuration: +* Add check for libgcrypt support for SHA224 + +Implementation: +* Cipher is incomplete - it can't handle cases where + data is not provided in blocksize chunks. Needs buffering + and padding to be added. + diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/hkdf.c b/local/recipes/libs/qca/source/plugins/qca-gcrypt/hkdf.c new file mode 100644 index 0000000000..965f9048ac --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/hkdf.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 Collabora Ltd. + * Copyright (C) 2018 Alexander Volkov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Author: Stef Walter + */ + +#include + +static gcry_error_t gcry_hkdf(int algo, + const char *input, + size_t n_input, + const char *salt, + size_t n_salt, + const char *info, + size_t n_info, + char *output, + size_t n_output) +{ + void *alloc = nullptr; + void *buffer = nullptr; + gcry_md_hd_t md1, md2; + unsigned int hash_len; + int i; + size_t step, n_buffer; + char *at; + gcry_error_t gcry; + + hash_len = gcry_md_get_algo_dlen(algo); + if (hash_len == 0) { + return GPG_ERR_UNSUPPORTED_ALGORITHM; + } + + if (n_output > 255 * hash_len) { + return GPG_ERR_TOO_LARGE; + } + + /* Buffer we need to for intermediate stuff */ + buffer = gcry_malloc_secure(hash_len); + if (!buffer) { + return GPG_ERR_ENOMEM; + } + n_buffer = 0; + + /* Salt defaults to hash_len zeros */ + if (!salt) { + alloc = gcry_calloc_secure(hash_len, 1); + if (!alloc) { + return GPG_ERR_ENOMEM; + } + salt = (const char *)alloc; + n_salt = hash_len; + } + + /* Step 1: Extract */ + gcry = gcry_md_open(&md1, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); + if (gcry != GPG_ERR_NO_ERROR) { + goto done; + } + gcry = gcry_md_setkey(md1, salt, n_salt); + if (gcry != GPG_ERR_NO_ERROR) { + gcry_md_close(md1); + goto done; + } + gcry_md_write(md1, input, n_input); + + /* Step 2: Expand */ + gcry = gcry_md_open(&md2, algo, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); + if (gcry != GPG_ERR_NO_ERROR) { + gcry_md_close(md1); + goto done; + } + gcry = gcry_md_setkey(md2, gcry_md_read(md1, algo), hash_len); + if (gcry != GPG_ERR_NO_ERROR) { + gcry_md_close(md2); + gcry_md_close(md1); + goto done; + } + gcry_md_close(md1); + + at = output; + for (i = 1; i < 256; ++i) { + gcry_md_reset(md2); + gcry_md_write(md2, buffer, n_buffer); + gcry_md_write(md2, info, n_info); + gcry_md_putc(md2, i); + + n_buffer = hash_len; + memcpy(buffer, gcry_md_read(md2, algo), n_buffer); + + step = n_buffer < n_output ? n_buffer : n_output; + memcpy(at, buffer, step); + n_output -= step; + at += step; + + if (!n_output) + break; + } + gcry_md_close(md2); + +done: + gcry_free(alloc); + gcry_free(buffer); + return gcry; +} diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/pkcs5.c b/local/recipes/libs/qca/source/plugins/qca-gcrypt/pkcs5.c new file mode 100644 index 0000000000..3f2d74566f --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/pkcs5.c @@ -0,0 +1,195 @@ +/* pkcs5.c Partial Password-Based Cryptography (PKCS#5) implementation + * Copyright (C) 2002 Free Software Foundation, Inc. + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "gcrypt.h" + +/* + * 5.2 PBKDF2 + * + * PBKDF2 applies a pseudorandom function (see Appendix B.1 for an + * example) to derive keys. The length of the derived key is essentially + * unbounded. (However, the maximum effective search space for the + * derived key may be limited by the structure of the underlying + * pseudorandom function. See Appendix B.1 for further discussion.) + * PBKDF2 is recommended for new applications. + * + * PBKDF2 (P, S, c, dkLen) + * + * Options: PRF underlying pseudorandom function (hLen + * denotes the length in octets of the + * pseudorandom function output) + * + * Input: P password, an octet string + * S salt, an octet string + * c iteration count, a positive integer + * dkLen intended length in octets of the derived + * key, a positive integer, at most + * (2^32 - 1) * hLen + * + * Output: DK derived key, a dkLen-octet string + */ + +static gcry_error_t gcry_pbkdf2(int PRF, + const char *P, + size_t Plen, + const char *S, + size_t Slen, + unsigned int c, + unsigned int dkLen, + char *DK) +{ + gcry_md_hd_t prf; + gcry_error_t rc; + char *U; + unsigned int u; + unsigned int hLen; + unsigned int l; + unsigned int r; + unsigned char *p; + unsigned int i; + unsigned int k; + + hLen = gcry_md_get_algo_dlen(PRF); + if (hLen == 0) + return GPG_ERR_UNSUPPORTED_ALGORITHM; + + if (c == 0) + return GPG_ERR_INV_ARG; + + if (dkLen == 0) + return GPG_ERR_TOO_SHORT; + + /* + * + * Steps: + * + * 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and + * stop. + */ + + if (dkLen > 4294967295U) + return GPG_ERR_TOO_LARGE; + + /* + * 2. Let l be the number of hLen-octet blocks in the derived key, + * rounding up, and let r be the number of octets in the last + * block: + * + * l = CEIL (dkLen / hLen) , + * r = dkLen - (l - 1) * hLen . + * + * Here, CEIL (x) is the "ceiling" function, i.e. the smallest + * integer greater than, or equal to, x. + */ + + l = dkLen / hLen; + if (dkLen % hLen) + l++; + r = dkLen - (l - 1) * hLen; + + /* + * 3. For each block of the derived key apply the function F defined + * below to the password P, the salt S, the iteration count c, and + * the block index to compute the block: + * + * T_1 = F (P, S, c, 1) , + * T_2 = F (P, S, c, 2) , + * ... + * T_l = F (P, S, c, l) , + * + * where the function F is defined as the exclusive-or sum of the + * first c iterates of the underlying pseudorandom function PRF + * applied to the password P and the concatenation of the salt S + * and the block index i: + * + * F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c + * + * where + * + * U_1 = PRF (P, S || INT (i)) , + * U_2 = PRF (P, U_1) , + * ... + * U_c = PRF (P, U_{c-1}) . + * + * Here, INT (i) is a four-octet encoding of the integer i, most + * significant octet first. + * + * 4. Concatenate the blocks and extract the first dkLen octets to + * produce a derived key DK: + * + * DK = T_1 || T_2 || ... || T_l<0..r-1> + * + * 5. Output the derived key DK. + * + * Note. The construction of the function F follows a "belt-and- + * suspenders" approach. The iterates U_i are computed recursively to + * remove a degree of parallelism from an opponent; they are exclusive- + * ored together to reduce concerns about the recursion degenerating + * into a small set of values. + * + */ + rc = gcry_md_open(&prf, PRF, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); + if (rc != GPG_ERR_NO_ERROR) + return rc; + + U = (char *)gcry_malloc(hLen); + if (!U) { + rc = GPG_ERR_ENOMEM; + goto done; + } + + for (i = 1; i <= l; i++) { + memset(DK + (i - 1) * hLen, 0, i == l ? r : hLen); + + for (u = 1; u <= c; u++) { + gcry_md_reset(prf); + + rc = gcry_md_setkey(prf, P, Plen); + if (rc != GPG_ERR_NO_ERROR) { + goto done; + } + if (u == 1) { + char tmp[4]; + gcry_md_write(prf, S, Slen); + tmp[0] = (i & 0xff000000) >> 24; + tmp[1] = (i & 0x00ff0000) >> 16; + tmp[2] = (i & 0x0000ff00) >> 8; + tmp[3] = (i & 0x000000ff) >> 0; + gcry_md_write(prf, tmp, 4); + } else + gcry_md_write(prf, U, hLen); + + p = gcry_md_read(prf, PRF); + if (p == nullptr) { + rc = GPG_ERR_CONFIGURATION; + goto done; + } + + memcpy(U, p, hLen); + for (k = 0; k < (i == l ? r : hLen); k++) + DK[(i - 1) * hLen + k] ^= U[k]; + } + } + + rc = GPG_ERR_NO_ERROR; +done: + gcry_md_close(prf); + gcry_free(U); + return rc; +} diff --git a/local/recipes/libs/qca/source/plugins/qca-gcrypt/qca-gcrypt.cpp b/local/recipes/libs/qca/source/plugins/qca-gcrypt/qca-gcrypt.cpp new file mode 100644 index 0000000000..dcb4ce853a --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gcrypt/qca-gcrypt.cpp @@ -0,0 +1,749 @@ +/* + * Copyright (C) 2004 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ +#include + +#include + +#include + +#include +#include +#include + +namespace gcryptQCAPlugin { + +#include "hkdf.c" +#include "pkcs5.c" + +void check_error(const char *label, gcry_error_t err) +{ + // we ignore the case where it is not an error, and + // we also don't flag weak keys. + if ((GPG_ERR_NO_ERROR != err) && (GPG_ERR_WEAK_KEY != gpg_err_code(err))) { + std::cout << "Failure (" << label << "): "; + std::cout << gcry_strsource(err) << "/"; + std::cout << gcry_strerror(err) << std::endl; + } +} + +class gcryHashContext : public QCA::HashContext +{ + Q_OBJECT +public: + gcryHashContext(int hashAlgorithm, QCA::Provider *p, const QString &type) + : QCA::HashContext(p, type) + { + m_hashAlgorithm = hashAlgorithm; + err = gcry_md_open(&context, m_hashAlgorithm, 0); + if (GPG_ERR_NO_ERROR != err) { + std::cout << "Failure: "; + std::cout << gcry_strsource(err) << "/"; + std::cout << gcry_strerror(err) << std::endl; + } + } + + ~gcryHashContext() override + { + gcry_md_close(context); + } + + Context *clone() const override + { + return new gcryHashContext(m_hashAlgorithm, provider(), type()); + } + + void clear() override + { + gcry_md_reset(context); + } + + void update(const QCA::MemoryRegion &a) override + { + gcry_md_write(context, a.data(), a.size()); + } + + QCA::MemoryRegion final() override + { + unsigned char *md; + QCA::SecureArray a(gcry_md_get_algo_dlen(m_hashAlgorithm)); + md = gcry_md_read(context, m_hashAlgorithm); + memcpy(a.data(), md, a.size()); + return a; + } + +protected: + gcry_md_hd_t context; + gcry_error_t err; + int m_hashAlgorithm; +}; + +class gcryHMACContext : public QCA::MACContext +{ + Q_OBJECT +public: + gcryHMACContext(int hashAlgorithm, QCA::Provider *p, const QString &type) + : QCA::MACContext(p, type) + { + m_hashAlgorithm = hashAlgorithm; + err = gcry_md_open(&context, m_hashAlgorithm, GCRY_MD_FLAG_HMAC); + if (GPG_ERR_NO_ERROR != err) { + std::cout << "Failure: "; + std::cout << gcry_strsource(err) << "/"; + std::cout << gcry_strerror(err) << std::endl; + } + } + + ~gcryHMACContext() override + { + gcry_md_close(context); + } + + void setup(const QCA::SymmetricKey &key) override + { + gcry_md_setkey(context, key.data(), key.size()); + } + + Context *clone() const override + { + return new gcryHMACContext(m_hashAlgorithm, provider(), type()); + } + + void clear() + { + gcry_md_reset(context); + } + + QCA::KeyLength keyLength() const override + { + return anyKeyLength(); + } + + void update(const QCA::MemoryRegion &a) override + { + gcry_md_write(context, a.data(), a.size()); + } + + void final(QCA::MemoryRegion *out) override + { + QCA::SecureArray sa(gcry_md_get_algo_dlen(m_hashAlgorithm), 0); + unsigned char *md; + md = gcry_md_read(context, m_hashAlgorithm); + memcpy(sa.data(), md, sa.size()); + *out = sa; + } + +protected: + gcry_md_hd_t context; + gcry_error_t err; + int m_hashAlgorithm; +}; + +class gcryCipherContext : public QCA::CipherContext +{ + Q_OBJECT +public: + gcryCipherContext(int algorithm, int mode, bool pad, QCA::Provider *p, const QString &type) + : QCA::CipherContext(p, type) + { + m_cryptoAlgorithm = algorithm; + m_mode = mode; + m_pad = pad; + } + + void setup(QCA::Direction dir, + const QCA::SymmetricKey &key, + const QCA::InitializationVector &iv, + const QCA::AuthTag &tag) override + { + Q_UNUSED(tag); + m_direction = dir; + err = gcry_cipher_open(&context, m_cryptoAlgorithm, m_mode, 0); + check_error("gcry_cipher_open", err); + if ((GCRY_CIPHER_3DES == m_cryptoAlgorithm) && (key.size() == 16)) { + // this is triple DES with two keys, and gcrypt wants three + QCA::SymmetricKey keyCopy(key); + QCA::SecureArray thirdKey(key); + thirdKey.resize(8); + keyCopy += thirdKey; + err = gcry_cipher_setkey(context, keyCopy.data(), keyCopy.size()); + } else { + err = gcry_cipher_setkey(context, key.data(), key.size()); + } + check_error("gcry_cipher_setkey", err); + err = gcry_cipher_setiv(context, iv.data(), iv.size()); + check_error("gcry_cipher_setiv", err); + } + + Context *clone() const override + { + return new gcryCipherContext(*this); + } + + int blockSize() const override + { + size_t blockSize; + gcry_cipher_algo_info(m_cryptoAlgorithm, GCRYCTL_GET_BLKLEN, nullptr, &blockSize); + return blockSize; + } + + QCA::AuthTag tag() const override + { + // For future implementation + return QCA::AuthTag(); + } + + bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override + { + QCA::SecureArray result(in.size()); + if (QCA::Encode == m_direction) { + err = gcry_cipher_encrypt( + context, (unsigned char *)result.data(), result.size(), (unsigned char *)in.data(), in.size()); + } else { + err = gcry_cipher_decrypt( + context, (unsigned char *)result.data(), result.size(), (unsigned char *)in.data(), in.size()); + } + check_error("update cipher encrypt/decrypt", err); + result.resize(in.size()); + *out = result; + return true; + } + + bool final(QCA::SecureArray *out) override + { + QCA::SecureArray result; + if (m_pad) { + result.resize(blockSize()); + if (QCA::Encode == m_direction) { + err = gcry_cipher_encrypt(context, (unsigned char *)result.data(), result.size(), nullptr, 0); + } else { + err = gcry_cipher_decrypt(context, (unsigned char *)result.data(), result.size(), nullptr, 0); + } + check_error("final cipher encrypt/decrypt", err); + } else { + // just return null + } + *out = result; + return true; + } + + QCA::KeyLength keyLength() const override + { + switch (m_cryptoAlgorithm) { + case GCRY_CIPHER_DES: + return QCA::KeyLength(8, 8, 1); + case GCRY_CIPHER_AES128: + return QCA::KeyLength(16, 16, 1); + case GCRY_CIPHER_AES192: + return QCA::KeyLength(24, 24, 1); + case GCRY_CIPHER_3DES: + // we do two and three key versions + return QCA::KeyLength(16, 24, 8); + case GCRY_CIPHER_AES256: + return QCA::KeyLength(32, 32, 1); + case GCRY_CIPHER_BLOWFISH: + // Don't know - TODO + return QCA::KeyLength(1, 32, 1); + default: + return QCA::KeyLength(0, 1, 1); + } + } + +protected: + gcry_cipher_hd_t context; + gcry_error_t err; + int m_cryptoAlgorithm; + QCA::Direction m_direction; + int m_mode; + bool m_pad; +}; + +class pbkdf1Context : public QCA::KDFContext +{ + Q_OBJECT +public: + pbkdf1Context(int algorithm, QCA::Provider *p, const QString &type) + : QCA::KDFContext(p, type) + { + m_hashAlgorithm = algorithm; + err = gcry_md_open(&context, m_hashAlgorithm, 0); + if (GPG_ERR_NO_ERROR != err) { + std::cout << "Failure: "; + std::cout << gcry_strsource(err) << "/"; + std::cout << gcry_strerror(err) << std::endl; + } + } + + ~pbkdf1Context() override + { + gcry_md_close(context); + } + + Context *clone() const override + { + return new pbkdf1Context(m_hashAlgorithm, provider(), type()); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) override + { + /* from RFC2898: + Steps: + + 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output + "derived key too long" and stop. + */ + if (keyLength > gcry_md_get_algo_dlen(m_hashAlgorithm)) { + std::cout << "derived key too long" << std::endl; + return QCA::SymmetricKey(); + } + + /* + 2. Apply the underlying hash function Hash for c iterations to the + concatenation of the password P and the salt S, then extract + the first dkLen octets to produce a derived key DK: + + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + DK = Tc<0..dkLen-1> + */ + // calculate T_1 + gcry_md_write(context, secret.data(), secret.size()); + gcry_md_write(context, salt.data(), salt.size()); + unsigned char *md; + md = gcry_md_read(context, m_hashAlgorithm); + QCA::SecureArray a(gcry_md_get_algo_dlen(m_hashAlgorithm)); + memcpy(a.data(), md, a.size()); + + // calculate T_2 up to T_c + for (unsigned int i = 2; i <= iterationCount; ++i) { + gcry_md_reset(context); + gcry_md_write(context, a.data(), a.size()); + md = gcry_md_read(context, m_hashAlgorithm); + memcpy(a.data(), md, a.size()); + } + + // shrink a to become DK, of the required length + a.resize(keyLength); + + /* + 3. Output the derived key DK. + */ + return a; + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) override + { + Q_ASSERT(iterationCount != nullptr); + QElapsedTimer timer; + + /* + from RFC2898: + Steps: + + 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output + "derived key too long" and stop. + */ + if (keyLength > gcry_md_get_algo_dlen(m_hashAlgorithm)) { + std::cout << "derived key too long" << std::endl; + return QCA::SymmetricKey(); + } + + /* + 2. Apply the underlying hash function Hash for M milliseconds + to the concatenation of the password P and the salt S, incrementing c, + then extract the first dkLen octets to produce a derived key DK: + + time from 0 to M + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + when time = 0: stop, + DK = Tc<0..dkLen-1> + */ + // calculate T_1 + gcry_md_write(context, secret.data(), secret.size()); + gcry_md_write(context, salt.data(), salt.size()); + unsigned char *md; + md = gcry_md_read(context, m_hashAlgorithm); + QCA::SecureArray a(gcry_md_get_algo_dlen(m_hashAlgorithm)); + memcpy(a.data(), md, a.size()); + + // calculate T_2 up to T_c + *iterationCount = 2 - 1; // <- Have to remove 1, unless it computes one + timer.start(); // ^ time more than the base function + // ^ with the same iterationCount + while (timer.elapsed() < msecInterval) { + gcry_md_reset(context); + gcry_md_write(context, a.data(), a.size()); + md = gcry_md_read(context, m_hashAlgorithm); + memcpy(a.data(), md, a.size()); + ++(*iterationCount); + } + + // shrink a to become DK, of the required length + a.resize(keyLength); + + /* + 3. Output the derived key DK. + */ + return a; + } + +protected: + gcry_md_hd_t context; + gcry_error_t err; + int m_hashAlgorithm; +}; + +class pbkdf2Context : public QCA::KDFContext +{ + Q_OBJECT +public: + pbkdf2Context(int algorithm, QCA::Provider *p, const QString &type) + : QCA::KDFContext(p, type) + { + m_algorithm = algorithm; + } + + Context *clone() const override + { + return new pbkdf2Context(*this); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) override + { + QCA::SymmetricKey result(keyLength); + gcry_error_t retval = gcry_pbkdf2(m_algorithm, + secret.data(), + secret.size(), + salt.data(), + salt.size(), + iterationCount, + keyLength, + result.data()); + if (retval == GPG_ERR_NO_ERROR) { + return result; + } else { + // std::cout << "got: " << retval << std::endl; + return QCA::SymmetricKey(); + } + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) override + { + Q_ASSERT(iterationCount != nullptr); + QCA::SymmetricKey result(keyLength); + QElapsedTimer timer; + + *iterationCount = 0; + timer.start(); + + while (timer.elapsed() < msecInterval) { + gcry_pbkdf2( + m_algorithm, secret.data(), secret.size(), salt.data(), salt.size(), 1, keyLength, result.data()); + ++(*iterationCount); + } + + return makeKey(secret, salt, keyLength, *iterationCount); + } + +protected: + int m_algorithm; +}; + +class hkdfContext : public QCA::HKDFContext +{ + Q_OBJECT +public: + hkdfContext(int algorithm, QCA::Provider *p, const QString &type) + : QCA::HKDFContext(p, type) + { + m_algorithm = algorithm; + } + + Context *clone() const override + { + return new hkdfContext(*this); + } + + QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, + const QCA::InitializationVector &salt, + const QCA::InitializationVector &info, + unsigned int keyLength) override + { + QCA::SymmetricKey result(keyLength); + gcry_error_t retval = gcry_hkdf(m_algorithm, + secret.data(), + secret.size(), + salt.data(), + salt.size(), + info.data(), + info.size(), + result.data(), + result.size()); + if (retval == GPG_ERR_NO_ERROR) { + return result; + } else { + return QCA::SymmetricKey(); + } + } + +protected: + int m_algorithm; +}; + +} + +extern "C" { + +static void *qca_func_malloc(size_t n) +{ + return qca_secure_alloc(n); +} + +static void *qca_func_secure_malloc(size_t n) +{ + return qca_secure_alloc(n); +} + +static void *qca_func_realloc(void *oldBlock, size_t newBlockSize) +{ + return qca_secure_realloc(oldBlock, newBlockSize); +} + +static void qca_func_free(void *mem) +{ + qca_secure_free(mem); +} + +int qca_func_secure_check(const void *) +{ + return (int)QCA::haveSecureMemory(); +} +} // extern "C" + +class gcryptProvider : public QCA::Provider +{ +public: + void init() override + { + if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { /* No other library has already initialized libgcrypt. */ + + if (!gcry_check_version(GCRYPT_VERSION)) { + std::cout << "libgcrypt is too old (need " << GCRYPT_VERSION; + std::cout << ", have " << gcry_check_version(nullptr) << ")" << std::endl; + } + gcry_set_allocation_handler( + qca_func_malloc, qca_func_secure_malloc, qca_func_secure_check, qca_func_realloc, qca_func_free); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED); + } + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("qca-gcrypt"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("sha1"); + list += QStringLiteral("md4"); + list += QStringLiteral("md5"); + list += QStringLiteral("ripemd160"); +#ifdef GCRY_MD_SHA224 + list += QStringLiteral("sha224"); +#endif + list += QStringLiteral("sha256"); + list += QStringLiteral("sha384"); + list += QStringLiteral("sha512"); + list += QStringLiteral("hmac(md5)"); + list += QStringLiteral("hmac(sha1)"); +#ifdef GCRY_MD_SHA224 + list += QStringLiteral("hmac(sha224)"); +#endif + list += QStringLiteral("hmac(sha256)"); + if (!(nullptr == gcry_check_version("1.3.0"))) { + // 1.2 and earlier have broken implementation + list += QStringLiteral("hmac(sha384)"); + list += QStringLiteral("hmac(sha512)"); + } + list += QStringLiteral("hmac(ripemd160)"); + list += QStringLiteral("aes128-ecb"); + list += QStringLiteral("aes128-cfb"); + list += QStringLiteral("aes128-cbc"); + list += QStringLiteral("aes192-ecb"); + list += QStringLiteral("aes192-cfb"); + list += QStringLiteral("aes192-cbc"); + list += QStringLiteral("aes256-ecb"); + list += QStringLiteral("aes256-cfb"); + list += QStringLiteral("aes256-cbc"); + list += QStringLiteral("blowfish-ecb"); + list += QStringLiteral("blowfish-cbc"); + list += QStringLiteral("blowfish-cfb"); + list += QStringLiteral("tripledes-ecb"); + // list += QStringLiteral("des-ecb"); + list += QStringLiteral("des-cbc"); + list += QStringLiteral("des-cfb"); + if (!(nullptr == gcry_check_version("1.3.0"))) { + // 1.2 branch and earlier doesn't support OFB mode + list += QStringLiteral("aes128-ofb"); + list += QStringLiteral("aes192-ofb"); + list += QStringLiteral("aes256-ofb"); + list += QStringLiteral("des-ofb"); + list += QStringLiteral("tripledes-ofb"); + list += QStringLiteral("blowfish-ofb"); + } + list += QStringLiteral("pbkdf1(sha1)"); + list += QStringLiteral("pbkdf2(sha1)"); + list += QStringLiteral("hkdf(sha256)"); + return list; + } + + Context *createContext(const QString &type) override + { + // std::cout << "type: " << qPrintable(type) << std::endl; + if (type == QLatin1String("sha1")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_SHA1, this, type); + else if (type == QLatin1String("md4")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_MD4, this, type); + else if (type == QLatin1String("md5")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_MD5, this, type); + else if (type == QLatin1String("ripemd160")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_RMD160, this, type); +#ifdef GCRY_MD_SHA224 + else if (type == QLatin1String("sha224")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_SHA224, this, type); +#endif + else if (type == QLatin1String("sha256")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_SHA256, this, type); + else if (type == QLatin1String("sha384")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_SHA384, this, type); + else if (type == QLatin1String("sha512")) + return new gcryptQCAPlugin::gcryHashContext(GCRY_MD_SHA512, this, type); + else if (type == QLatin1String("hmac(md5)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_MD5, this, type); + else if (type == QLatin1String("hmac(sha1)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_SHA1, this, type); +#ifdef GCRY_MD_SHA224 + else if (type == QLatin1String("hmac(sha224)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_SHA224, this, type); +#endif + else if (type == QLatin1String("hmac(sha256)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_SHA256, this, type); + else if (type == QLatin1String("hmac(sha384)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_SHA384, this, type); + else if (type == QLatin1String("hmac(sha512)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_SHA512, this, type); + else if (type == QLatin1String("hmac(ripemd160)")) + return new gcryptQCAPlugin::gcryHMACContext(GCRY_MD_RMD160, this, type); + else if (type == QLatin1String("aes128-ecb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("aes128-cfb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB, false, this, type); + else if (type == QLatin1String("aes128-ofb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("aes128-cbc")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, false, this, type); + else if (type == QLatin1String("aes192-ecb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("aes192-cfb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, false, this, type); + else if (type == QLatin1String("aes192-ofb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("aes192-cbc")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, false, this, type); + else if (type == QLatin1String("aes256-ecb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("aes256-cfb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, false, this, type); + else if (type == QLatin1String("aes256-ofb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("aes256-cbc")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, false, this, type); + else if (type == QLatin1String("blowfish-ecb")) + return new gcryptQCAPlugin::gcryCipherContext( + GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("blowfish-cbc")) + return new gcryptQCAPlugin::gcryCipherContext( + GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, false, this, type); + else if (type == QLatin1String("blowfish-cfb")) + return new gcryptQCAPlugin::gcryCipherContext( + GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, false, this, type); + else if (type == QLatin1String("blowfish-ofb")) + return new gcryptQCAPlugin::gcryCipherContext( + GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("tripledes-ecb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("tripledes-ofb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("des-ecb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, false, this, type); + else if (type == QLatin1String("des-cbc")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, false, this, type); + else if (type == QLatin1String("des-cfb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB, false, this, type); + else if (type == QLatin1String("des-ofb")) + return new gcryptQCAPlugin::gcryCipherContext(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB, false, this, type); + else if (type == QLatin1String("pbkdf1(sha1)")) + return new gcryptQCAPlugin::pbkdf1Context(GCRY_MD_SHA1, this, type); + else if (type == QLatin1String("pbkdf2(sha1)")) + return new gcryptQCAPlugin::pbkdf2Context(GCRY_MD_SHA1, this, type); + else if (type == QLatin1String("hkdf(sha256)")) + return new gcryptQCAPlugin::hkdfContext(GCRY_MD_SHA256, this, type); + else + return nullptr; + } +}; + +class gcryptPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + QCA::Provider *createProvider() override + { + return new gcryptProvider; + } +}; + +#include "qca-gcrypt.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-gnupg/CMakeLists.txt new file mode 100644 index 0000000000..d75f1ab465 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/CMakeLists.txt @@ -0,0 +1,58 @@ +# QCA GnuPG + +enable_plugin("gnupg") + +set(QCA_GNUPG_SOURCES + qca-gnupg.cpp + gpgop.cpp + utils.cpp + gpgproc/sprocess.cpp + mypgpkeycontext.cpp + mykeystoreentry.cpp + myopenpgpcontext.cpp + mykeystorelist.cpp + mymessagecontext.cpp + ringwatch.cpp + lineconverter.cpp + gpgaction.cpp + gpgproc/gpgproc.cpp +) + +set(QCA_GNUPG_HEADERS + gpgaction.h + ringwatch.h + gpgop.h + gpgop_p.h + lineconverter.h + mypgpkeycontext.h + mykeystoreentry.h + mykeystorelist.h + gpgproc/gpgproc_p.h + gpgproc/sprocess.h + gpgproc/gpgproc.h + utils.h + mymessagecontext.h + myopenpgpcontext.h +) + +add_library(qca-gnupg ${PLUGIN_TYPE} ${QCA_GNUPG_SOURCES} ${EXTRA_GNUPG_SOURCES} ${QCA_GNUPG_HEADERS}) + +if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-gnupg PROPERTY SUFFIX ".dylib") +endif() + +include_directories(gpgproc) +target_link_libraries(qca-gnupg Qt${QT_MAJOR_VERSION}::Core ${QCA_LIB_NAME}) + +if (WIN32) + target_link_libraries(qca-gnupg advapi32) +endif() + +if(NOT DEVELOPER_MODE) + install(TARGETS qca-gnupg DESTINATION + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-gnupg ${QCA_CRYPTO_INSTALL_DIR}) +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/COPYING b/local/recipes/libs/qca/source/plugins/qca-gnupg/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/README b/local/recipes/libs/qca/source/plugins/qca-gnupg/README new file mode 100644 index 0000000000..d350efa639 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/README @@ -0,0 +1,29 @@ +QCA GnuPG plugin version 2.0.0 +------------------------------ +Date: October 11th, 2007 +Website: http://delta.affinix.com/qca/ +Mailing List: Delta Project + +Author: Justin Karneges + +This plugin provides features based on GnuPG. + +Requirements: + GnuPG 1.x or 2.x (runtime dependency only) + +Installing +---------- + +For Unix/Linux/Mac: + + ./configure + make + make install + +For Windows: + + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/TODO b/local/recipes/libs/qca/source/plugins/qca-gnupg/TODO new file mode 100644 index 0000000000..dd99cb9249 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/TODO @@ -0,0 +1 @@ +don't write stdin to signing until status channel says it is okay diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.cpp new file mode 100644 index 0000000000..dc3c6b3ad4 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.cpp @@ -0,0 +1,848 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +// #define GPGOP_DEBUG + +#include "gpgaction.h" + +#ifdef GPGOP_DEBUG +#include "stdio.h" +#endif + +namespace gpgQCAPlugin { + +static QDateTime getTimestamp(const QString &s) +{ + if (s.isEmpty()) + return QDateTime(); + + if (s.contains(QLatin1Char('T'))) { + return QDateTime::fromString(s, Qt::ISODate); + } else { + return QDateTime::fromSecsSinceEpoch(s.toInt()); + } +} + +static QByteArray getCString(const QByteArray &a) +{ + QByteArray out; + + // convert the "backslash" C-string syntax + for (int n = 0; n < a.size(); ++n) { + if (a[n] == '\\' && n + 1 < a.size()) { + ++n; + unsigned char c = (unsigned char)a[n]; + if (c == '\\') { + out += '\\'; + } else if (c == 'x' && n + 2 < a.size()) { + ++n; + const QByteArray hex = a.mid(n, 2); + ++n; // only skip one, loop will skip the next + + bool ok; + uint val = hex.toInt(&ok, 16); + if (ok) { + out += (unsigned char)val; + } else { + out += "\\x"; + out += hex; + } + } + } else { + out += a[n]; + } + } + + return out; +} + +static bool stringToKeyList(const QString &outstr, GpgOp::KeyList *_keylist, QString *_keyring) +{ + GpgOp::KeyList keyList; + const QStringList lines = outstr.split(QLatin1Char('\n')); + + if (lines.count() < 1) + return false; + + QStringList::ConstIterator it = lines.constBegin(); + + // first line is keyring file + QString keyring = *(it++); + + // if the second line isn't a divider, we are dealing + // with a new version of gnupg that doesn't give us + // the keyring file on gpg --list-keys --with-colons + if (it == lines.constEnd() || (*it).isEmpty() || (*it).at(0) != QLatin1Char('-')) { + // first line wasn't the keyring name... + keyring.clear(); + // ...so read the first line again + it--; + } else { + // this was the divider line - skip it + it++; + } + + for (; it != lines.constEnd(); ++it) { + const QStringList f = (*it).split(QLatin1Char(':')); + if (f.count() < 1) + continue; + const QString &type = f[0]; + + bool key = false; // key or not + bool primary = false; // primary key or sub key + // bool sec = false; // private key or not + + if (type == QLatin1String("pub")) { + key = true; + primary = true; + } else if (type == QLatin1String("sec")) { + key = true; + primary = true; + // sec = true; + } else if (type == QLatin1String("sub")) { + key = true; + } else if (type == QLatin1String("ssb")) { + key = true; + // sec = true; + } + + if (key) { + if (primary) { + keyList += GpgOp::Key(); + + const QString &trust = f[1]; + if (trust == QLatin1String("f") || trust == QLatin1String("u")) + keyList.last().isTrusted = true; + } + + const int key_type = f[3].toInt(); + const QString &caps = f[11]; + + GpgOp::KeyItem item; + item.bits = f[2].toInt(); + if (key_type == 1) + item.type = GpgOp::KeyItem::RSA; + else if (key_type == 16) + item.type = GpgOp::KeyItem::ElGamal; + else if (key_type == 17) + item.type = GpgOp::KeyItem::DSA; + else + item.type = GpgOp::KeyItem::Unknown; + item.id = f[4]; + item.creationDate = getTimestamp(f[5]); + item.expirationDate = getTimestamp(f[6]); + if (caps.contains(QLatin1Char('e'))) + item.caps |= GpgOp::KeyItem::Encrypt; + if (caps.contains(QLatin1Char('s'))) + item.caps |= GpgOp::KeyItem::Sign; + if (caps.contains(QLatin1Char('c'))) + item.caps |= GpgOp::KeyItem::Certify; + if (caps.contains(QLatin1Char('a'))) + item.caps |= GpgOp::KeyItem::Auth; + + keyList.last().keyItems += item; + } else if (type == QLatin1String("uid")) { + const QByteArray uid = getCString(f[9].toUtf8()); + keyList.last().userIds.append(QString::fromUtf8(uid)); + } else if (type == QLatin1String("fpr")) { + const QString &s = f[9]; + keyList.last().keyItems.last().fingerprint = s; + } + } + + if (_keylist) + *_keylist = keyList; + if (_keyring) + *_keyring = keyring; + + return true; +} + +static bool findKeyringFilename(const QString &outstr, QString *_keyring) +{ + const QStringList lines = outstr.split(QLatin1Char('\n')); + if (lines.count() < 1) + return false; + + *_keyring = lines[0]; + return true; +} + +GpgAction::GpgAction(QObject *parent) + : QObject(parent) + , proc(this) + , dtextTimer(this) + , utf8Output(false) +{ + dtextTimer.setSingleShot(true); + + connect(&proc, &GPGProc::error, this, &GpgAction::proc_error); + connect(&proc, &GPGProc::finished, this, &GpgAction::proc_finished); + connect(&proc, &GPGProc::readyReadStdout, this, &GpgAction::proc_readyReadStdout); + connect(&proc, &GPGProc::readyReadStderr, this, &GpgAction::proc_readyReadStderr); + connect(&proc, &GPGProc::readyReadStatusLines, this, &GpgAction::proc_readyReadStatusLines); + connect(&proc, &GPGProc::bytesWrittenStdin, this, &GpgAction::proc_bytesWrittenStdin); + connect(&proc, &GPGProc::bytesWrittenAux, this, &GpgAction::proc_bytesWrittenAux); + connect(&proc, &GPGProc::bytesWrittenCommand, this, &GpgAction::proc_bytesWrittenCommand); + connect(&proc, &GPGProc::debug, this, &GpgAction::proc_debug); + connect(&dtextTimer, &QCA::SafeTimer::timeout, this, &GpgAction::t_dtext); + + reset(); +} + +GpgAction::~GpgAction() +{ + reset(); +} + +void GpgAction::reset() +{ + collectOutput = true; + allowInput = false; + readConv.setup(LineConverter::Read); + writeConv.setup(LineConverter::Write); + readText = false; + writeText = false; + useAux = false; + passphraseKeyId = QString(); + signing = false; + decryptGood = false; + signGood = false; + curError = GpgOp::ErrorUnknown; + badPassphrase = false; + need_submitPassphrase = false; + need_cardOkay = false; + diagnosticText = QString(); + dtextTimer.stop(); + + output = Output(); + + proc.reset(); +} + +void GpgAction::start() +{ + reset(); + + QStringList args; + bool extra = false; + + if (input.opt_ascii) + args += QStringLiteral("--armor"); + + if (input.opt_noagent) + args += QStringLiteral("--no-use-agent"); + + if (input.opt_alwaystrust) + args += QStringLiteral("--always-trust"); + + if (!input.opt_pubfile.isEmpty() && !input.opt_secfile.isEmpty()) { + args += QStringLiteral("--no-default-keyring"); + args += QStringLiteral("--keyring"); + args += input.opt_pubfile; + args += QStringLiteral("--secret-keyring"); + args += input.opt_secfile; + } + + switch (input.op) { + case GpgOp::Check: + { + args += QStringLiteral("--version"); + readText = true; + break; + } + case GpgOp::SecretKeyringFile: + { +#ifndef Q_OS_WIN + args += QStringLiteral("--display-charset=utf-8"); +#endif + args += QStringLiteral("--list-secret-keys"); + readText = true; + break; + } + case GpgOp::PublicKeyringFile: + { +#ifndef Q_OS_WIN + args += QStringLiteral("--display-charset=utf-8"); +#endif + args += QStringLiteral("--list-public-keys"); + readText = true; + break; + } + case GpgOp::SecretKeys: + { + args += QStringLiteral("--fixed-list-mode"); + args += QStringLiteral("--with-colons"); + args += QStringLiteral("--with-fingerprint"); + args += QStringLiteral("--with-fingerprint"); + args += QStringLiteral("--list-secret-keys"); + utf8Output = true; + readText = true; + break; + } + case GpgOp::PublicKeys: + { + args += QStringLiteral("--fixed-list-mode"); + args += QStringLiteral("--with-colons"); + args += QStringLiteral("--with-fingerprint"); + args += QStringLiteral("--with-fingerprint"); + args += QStringLiteral("--list-public-keys"); + utf8Output = true; + readText = true; + break; + } + case GpgOp::Encrypt: + { + args += QStringLiteral("--encrypt"); + + // recipients + for (QStringList::ConstIterator it = input.recip_ids.constBegin(); it != input.recip_ids.constEnd(); ++it) { + args += QStringLiteral("--recipient"); + args += QStringLiteral("0x") + *it; + } + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + readText = true; + break; + } + case GpgOp::Decrypt: + { + args += QStringLiteral("--decrypt"); + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + writeText = true; + break; + } + case GpgOp::Sign: + { + args += QStringLiteral("--default-key"); + args += QStringLiteral("0x") + input.signer_id; + args += QStringLiteral("--sign"); + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + readText = true; + signing = true; + break; + } + case GpgOp::SignAndEncrypt: + { + args += QStringLiteral("--default-key"); + args += QStringLiteral("0x") + input.signer_id; + args += QStringLiteral("--sign"); + args += QStringLiteral("--encrypt"); + + // recipients + for (QStringList::ConstIterator it = input.recip_ids.constBegin(); it != input.recip_ids.constEnd(); ++it) { + args += QStringLiteral("--recipient"); + args += QStringLiteral("0x") + *it; + } + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + readText = true; + signing = true; + break; + } + case GpgOp::SignClearsign: + { + args += QStringLiteral("--default-key"); + args += QStringLiteral("0x") + input.signer_id; + args += QStringLiteral("--clearsign"); + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + readText = true; + signing = true; + break; + } + case GpgOp::SignDetached: + { + args += QStringLiteral("--default-key"); + args += QStringLiteral("0x") + input.signer_id; + args += QStringLiteral("--detach-sign"); + extra = true; + collectOutput = false; + allowInput = true; + if (input.opt_ascii) + readText = true; + signing = true; + break; + } + case GpgOp::Verify: + { + args += QStringLiteral("--verify"); + args += QStringLiteral("-"); // krazy:exclude=doublequote_chars + extra = true; + allowInput = true; + if (input.opt_ascii) + writeText = true; + break; + } + case GpgOp::VerifyDetached: + { + args += QStringLiteral("--verify"); + args += QStringLiteral("-"); // krazy:exclude=doublequote_chars + args += QStringLiteral("-&?"); + extra = true; + allowInput = true; + useAux = true; + break; + } + case GpgOp::Import: + { + args += QStringLiteral("--import"); + readText = true; + if (input.opt_ascii) + writeText = true; + break; + } + case GpgOp::Export: + { + args += QStringLiteral("--export"); + args += QStringLiteral("0x") + input.export_key_id; + collectOutput = false; + if (input.opt_ascii) + readText = true; + break; + } + case GpgOp::DeleteKey: + { + args += QStringLiteral("--batch"); + args += QStringLiteral("--delete-key"); + args += QStringLiteral("0x") + input.delete_key_fingerprint; + break; + } + } + +#ifdef GPG_PROFILE + timer.start(); + printf("<< launch >>\n"); +#endif + proc.start(input.bin, args, extra ? GPGProc::ExtendedMode : GPGProc::NormalMode); + + // detached sig + if (input.op == GpgOp::VerifyDetached) { + QByteArray a = input.sig; + if (input.opt_ascii) { + LineConverter conv; + conv.setup(LineConverter::Write); + a = conv.process(a); + } + proc.writeStdin(a); + proc.closeStdin(); + } + + // import + if (input.op == GpgOp::Import) { + QByteArray a = input.inkey; + if (writeText) { + LineConverter conv; + conv.setup(LineConverter::Write); + a = conv.process(a); + } + proc.writeStdin(a); + proc.closeStdin(); + } +} + +#ifdef QPIPE_SECURE +void GpgAction::submitPassphrase(const QCA::SecureArray &a) +#else +void GpgAction::submitPassphrase(const QByteArray &a) +#endif +{ + if (!need_submitPassphrase) + return; + + need_submitPassphrase = false; + +#ifdef QPIPE_SECURE + QCA::SecureArray b; +#else + QByteArray b; +#endif + // filter out newlines, since that's the delimiter used + // to indicate a submitted passphrase + b.resize(a.size()); + int at = 0; + for (int n = 0; n < a.size(); ++n) { + if (a[n] != '\n') + b[at++] = a[n]; + } + b.resize(at); + + // append newline + b.resize(b.size() + 1); + b[b.size() - 1] = '\n'; + proc.writeCommand(b); +} + +QByteArray GpgAction::read() +{ + if (collectOutput) + return QByteArray(); + + QByteArray a = proc.readStdout(); + if (readText) + a = readConv.update(a); + if (!proc.isActive()) + a += readConv.final(); + return a; +} + +void GpgAction::write(const QByteArray &in) +{ + if (!allowInput) + return; + + QByteArray a = in; + if (writeText) + a = writeConv.update(in); + + if (useAux) + proc.writeAux(a); + else + proc.writeStdin(a); +} + +void GpgAction::endWrite() +{ + if (!allowInput) + return; + + if (useAux) + proc.closeAux(); + else + proc.closeStdin(); +} + +void GpgAction::cardOkay() +{ + if (need_cardOkay) { + need_cardOkay = false; + submitCommand("\n"); + } +} + +QString GpgAction::readDiagnosticText() +{ + QString s = diagnosticText; + diagnosticText = QString(); + return s; +} + +void GpgAction::submitCommand(const QByteArray &a) +{ + proc.writeCommand(a); +} + +// since str is taken as a value, it is ok to use the same variable for 'rest' +QString GpgAction::nextArg(QString str, QString *rest) +{ + int n = str.indexOf(QLatin1Char(' ')); + if (n == -1) { + if (rest) + *rest = QString(); + return str; + } else { + if (rest) + *rest = str.mid(n + 1); + return str.mid(0, n); + } +} + +void GpgAction::processStatusLine(const QString &line) +{ + appendDiagnosticText(QStringLiteral("{") + line + QStringLiteral("}")); + ensureDTextEmit(); + + if (!proc.isActive()) + return; + + QString s, rest; + s = nextArg(line, &rest); + + if (s == QLatin1String("NODATA")) { + // only set this if it'll make it better + if (curError == GpgOp::ErrorUnknown) + curError = GpgOp::ErrorFormat; + } else if (s == QLatin1String("UNEXPECTED")) { + if (curError == GpgOp::ErrorUnknown) + curError = GpgOp::ErrorFormat; + } else if (s == QLatin1String("EXPKEYSIG")) { + curError = GpgOp::ErrorSignerExpired; + } else if (s == QLatin1String("REVKEYSIG")) { + curError = GpgOp::ErrorSignerRevoked; + } else if (s == QLatin1String("EXPSIG")) { + curError = GpgOp::ErrorSignatureExpired; + } else if (s == QLatin1String("INV_RECP")) { + const int r = nextArg(rest).toInt(); + + if (curError == GpgOp::ErrorUnknown) { + if (r == 10) + curError = GpgOp::ErrorEncryptUntrusted; + else if (r == 4) + curError = GpgOp::ErrorEncryptRevoked; + else if (r == 5) + curError = GpgOp::ErrorEncryptExpired; + else + // due to GnuPG bug #1650 + // + // encrypting to expired and revoked keys will + // not specify any reason for failing, + // defaulting to this + curError = GpgOp::ErrorEncryptInvalid; + } + } else if (s == QLatin1String("NO_SECKEY")) { + output.encryptedToId = nextArg(rest); + + if (curError == GpgOp::ErrorUnknown) + curError = GpgOp::ErrorDecryptNoKey; + } else if (s == QLatin1String("DECRYPTION_OKAY")) { + decryptGood = true; + + // message could be encrypted with several keys + if (curError == GpgOp::ErrorDecryptNoKey) + curError = GpgOp::ErrorUnknown; + } else if (s == QLatin1String("SIG_CREATED")) { + signGood = true; + } else if (s == QLatin1String("USERID_HINT")) { + passphraseKeyId = nextArg(rest); + } else if (s == QLatin1String("GET_HIDDEN")) { + QString arg = nextArg(rest); + if (arg == QLatin1String("passphrase.enter") || arg == QLatin1String("passphrase.pin.ask")) { + need_submitPassphrase = true; + + // for signal-safety, emit later + QMetaObject::invokeMethod(this, "needPassphrase", Qt::QueuedConnection, Q_ARG(QString, passphraseKeyId)); + } + } else if (s == QLatin1String("GET_LINE")) { + QString arg = nextArg(rest); + if (arg == QLatin1String("cardctrl.insert_card.okay")) { + need_cardOkay = true; + + QMetaObject::invokeMethod(this, "needCard", Qt::QueuedConnection); + } + } else if (s == QLatin1String("GET_BOOL")) { + QString arg = nextArg(rest); + if (arg == QLatin1String("untrusted_key.override")) + submitCommand("no\n"); + } else if (s == QLatin1String("GOOD_PASSPHRASE")) { + badPassphrase = false; + } else if (s == QLatin1String("BAD_PASSPHRASE")) { + badPassphrase = true; + } else if (s == QLatin1String("GOODSIG")) { + output.wasSigned = true; + output.signerId = nextArg(rest); + output.verifyResult = GpgOp::VerifyGood; + } else if (s == QLatin1String("BADSIG")) { + output.wasSigned = true; + output.signerId = nextArg(rest); + output.verifyResult = GpgOp::VerifyBad; + } else if (s == QLatin1String("ERRSIG")) { + output.wasSigned = true; + const QStringList list = rest.split(QLatin1Char(' '), Qt::SkipEmptyParts); + output.signerId = list[0]; + output.timestamp = getTimestamp(list[4]); + output.verifyResult = GpgOp::VerifyNoKey; + } else if (s == QLatin1String("VALIDSIG")) { + const QStringList list = rest.split(QLatin1Char(' '), Qt::SkipEmptyParts); + output.timestamp = getTimestamp(list[2]); + } +} + +void GpgAction::processResult(int code) +{ +#ifdef GPG_PROFILE + printf("<< launch: %d >>\n", timer.elapsed()); +#endif + + // put stdout and stderr into QStrings + + QString outstr; + QString errstr; + +#ifdef Q_OS_WIN + if (!utf8Output) { + outstr = QString::fromLocal8Bit(buf_stdout); + errstr = QString::fromLocal8Bit(buf_stderr); + } else { +#endif + outstr = QString::fromUtf8(buf_stdout); + errstr = QString::fromUtf8(buf_stderr); +#ifdef Q_OS_WIN + } +#endif + + if (collectOutput) + appendDiagnosticText(QStringLiteral("stdout: [%1]").arg(outstr)); + appendDiagnosticText(QStringLiteral("stderr: [%1]").arg(errstr)); + ensureDTextEmit(); + + if (badPassphrase) { + output.errorCode = GpgOp::ErrorPassphrase; + } else if (curError != GpgOp::ErrorUnknown) { + output.errorCode = curError; + } else if (code == 0) { + if (input.op == GpgOp::Check) { + const QStringList strList = outstr.split(QStringLiteral("\n")); + foreach (const QString &str, strList) { + if (!str.startsWith(QLatin1String("Home: "))) + continue; + + output.homeDir = str.section(QLatin1Char(' '), 1); + break; + } + output.success = true; + } else if (input.op == GpgOp::SecretKeyringFile || input.op == GpgOp::PublicKeyringFile) { + if (findKeyringFilename(outstr, &output.keyringFile)) + output.success = true; + } else if (input.op == GpgOp::SecretKeys || input.op == GpgOp::PublicKeys) { + if (stringToKeyList(outstr, &output.keys, &output.keyringFile)) + output.success = true; + } else + output.success = true; + } else { + // decrypt and sign success based on status only. + // this is mainly because gpg uses fatal return + // values if there is trouble with gpg-agent, even + // though the operation otherwise works. + + if (input.op == GpgOp::Decrypt && decryptGood) + output.success = true; + if (signing && signGood) + output.success = true; + + // gpg will indicate failure for bad sigs, but we don't + // consider this to be operation failure. + + bool signedMakesItGood = false; + if (input.op == GpgOp::Verify || input.op == GpgOp::VerifyDetached) + signedMakesItGood = true; + + if (signedMakesItGood && output.wasSigned) + output.success = true; + } + + emit finished(); +} + +void GpgAction::ensureDTextEmit() +{ + if (!dtextTimer.isActive()) + dtextTimer.start(); +} + +void GpgAction::t_dtext() +{ + emit readyReadDiagnosticText(); +} + +void GpgAction::proc_error(gpgQCAPlugin::GPGProc::Error e) +{ + QString str; + if (e == GPGProc::FailedToStart) + str = QStringLiteral("FailedToStart"); + else if (e == GPGProc::UnexpectedExit) + str = QStringLiteral("UnexpectedExit"); + else if (e == GPGProc::ErrorWrite) + str = QStringLiteral("ErrorWrite"); + + appendDiagnosticText(QStringLiteral("GPG Process Error: %1").arg(str)); + ensureDTextEmit(); + + output.errorCode = GpgOp::ErrorProcess; + emit finished(); +} + +void GpgAction::proc_finished(int exitCode) +{ + appendDiagnosticText(QStringLiteral("GPG Process Finished: exitStatus=%1").arg(exitCode)); + ensureDTextEmit(); + + processResult(exitCode); +} + +void GpgAction::proc_readyReadStdout() +{ + if (collectOutput) { + QByteArray a = proc.readStdout(); + if (readText) + a = readConv.update(a); + buf_stdout.append(a); + } else + emit readyRead(); +} + +void GpgAction::proc_readyReadStderr() +{ + buf_stderr.append(proc.readStderr()); +} + +void GpgAction::proc_readyReadStatusLines() +{ + const QStringList lines = proc.readStatusLines(); + for (int n = 0; n < lines.count(); ++n) + processStatusLine(lines[n]); +} + +void GpgAction::proc_bytesWrittenStdin(int bytes) +{ + if (!useAux) { + int actual = writeConv.writtenToActual(bytes); + emit bytesWritten(actual); + } +} + +void GpgAction::proc_bytesWrittenAux(int bytes) +{ + if (useAux) { + int actual = writeConv.writtenToActual(bytes); + emit bytesWritten(actual); + } +} + +void GpgAction::proc_bytesWrittenCommand(int) +{ + // don't care about this +} + +void GpgAction::proc_debug(const QString &str) +{ + appendDiagnosticText(QStringLiteral("GPGProc: ") + str); + ensureDTextEmit(); +} + +void GpgAction::appendDiagnosticText(const QString &line) +{ +#ifdef GPGOP_DEBUG + printf("%s\n", qPrintable(line)); +#endif + diagnosticText += line; +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.h new file mode 100644 index 0000000000..6b0779374d --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgaction.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#pragma once + +#include "gpgop.h" +#include "gpgproc.h" +#include "lineconverter.h" +#include "qca_safetimer.h" +#include +#include +#include + +#ifdef GPG_PROFILE +#include +#endif + +namespace gpgQCAPlugin { + +class GpgAction : public QObject +{ + Q_OBJECT +public: + struct Input + { + QString bin; + GpgOp::Type op; + bool opt_ascii, opt_noagent, opt_alwaystrust; + QString opt_pubfile, opt_secfile; + QStringList recip_ids; + QString signer_id; + QByteArray sig; + QByteArray inkey; + QString export_key_id; + QString delete_key_fingerprint; + + Input() + : opt_ascii(false) + , opt_noagent(false) + , opt_alwaystrust(false) + { + } + }; + + struct Output + { + bool success; + GpgOp::Error errorCode; + GpgOp::KeyList keys; + QString keyringFile; + QString encryptedToId; + bool wasSigned; + QString signerId; + QDateTime timestamp; + GpgOp::VerifyResult verifyResult; + QString homeDir; + + Output() + : success(false) + , errorCode(GpgOp::ErrorUnknown) + , wasSigned(false) + { + } + }; + + Input input; + Output output; + + GpgAction(QObject *parent = nullptr); + ~GpgAction() override; + void reset(); + void start(); +#ifdef QPIPE_SECURE + void submitPassphrase(const QCA::SecureArray &a); +#else + void submitPassphrase(const QByteArray &a); +#endif + +public Q_SLOTS: + QByteArray read(); + void write(const QByteArray &in); + void endWrite(); + void cardOkay(); + QString readDiagnosticText(); + +Q_SIGNALS: + void readyRead(); + void bytesWritten(int bytes); + void finished(); + void needPassphrase(const QString &keyId); + void needCard(); + void readyReadDiagnosticText(); + +private: + void submitCommand(const QByteArray &a); + + // since str is taken as a value, it is ok to use the same variable for 'rest' + QString nextArg(QString str, QString *rest = nullptr); + void processStatusLine(const QString &line); + void processResult(int code); + void ensureDTextEmit(); + + GPGProc proc; + bool collectOutput, allowInput; + LineConverter readConv, writeConv; + bool readText, writeText; + QByteArray buf_stdout, buf_stderr; + bool useAux; + QString passphraseKeyId; + bool signing, decryptGood, signGood; + GpgOp::Error curError; + bool badPassphrase; + bool need_submitPassphrase, need_cardOkay; + QString diagnosticText; + QCA::SafeTimer dtextTimer; + bool utf8Output; + +#ifdef GPG_PROFILE + QTime timer; +#endif + +private Q_SLOTS: + void t_dtext(); + void proc_error(gpgQCAPlugin::GPGProc::Error e); + void proc_finished(int exitCode); + void proc_readyReadStdout(); + void proc_readyReadStderr(); + void proc_readyReadStatusLines(); + void proc_bytesWrittenStdin(int bytes); + void proc_bytesWrittenAux(int bytes); + void proc_bytesWrittenCommand(int); + void proc_debug(const QString &str); + void appendDiagnosticText(const QString &line); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.cpp new file mode 100644 index 0000000000..07e4a544c0 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.cpp @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "gpgop.h" +#include "gpgaction.h" +#include "gpgop_p.h" + +namespace gpgQCAPlugin { + +//---------------------------------------------------------------------------- +// GpgOp +//---------------------------------------------------------------------------- +GpgOp::Private::Private(GpgOp *_q) + : QObject(_q) + , sync(_q) + , q(_q) + , act(nullptr) + , waiting(false) +{ + reset(ResetAll); +} + +GpgOp::Private::~Private() +{ + reset(ResetAll); +} + +void GpgOp::Private::reset(ResetMode mode) +{ + if (act) { + act->disconnect(this); + act->setParent(nullptr); + act->deleteLater(); + + act = nullptr; + } + + if (mode >= ResetSessionAndData) { + output = GpgAction::Output(); + result.clear(); + diagnosticText = QString(); + eventList.clear(); + } + + if (mode >= ResetAll) { + opt_ascii = false; + opt_noagent = false; + opt_alwaystrust = false; + opt_pubfile = QString(); + opt_secfile = QString(); + } +} + +void GpgOp::Private::make_act(GpgOp::Type _op) +{ + reset(ResetSessionAndData); + + op = _op; + + act = new GpgAction(this); + + connect(act, &GpgAction::readyRead, this, &GpgOp::Private::act_readyRead); + connect(act, &GpgAction::bytesWritten, this, &GpgOp::Private::act_bytesWritten); + connect(act, &GpgAction::needPassphrase, this, &GpgOp::Private::act_needPassphrase); + connect(act, &GpgAction::needCard, this, &GpgOp::Private::act_needCard); + connect(act, &GpgAction::finished, this, &GpgOp::Private::act_finished); + connect(act, &GpgAction::readyReadDiagnosticText, this, &GpgOp::Private::act_readyReadDiagnosticText); + + act->input.bin = bin; + act->input.op = op; + act->input.opt_ascii = opt_ascii; + act->input.opt_noagent = opt_noagent; + act->input.opt_alwaystrust = opt_alwaystrust; + act->input.opt_pubfile = opt_pubfile; + act->input.opt_secfile = opt_secfile; +} + +void GpgOp::Private::eventReady(const GpgOp::Event &e) +{ + eventList += e; + sync.conditionMet(); +} + +void GpgOp::Private::eventReady(GpgOp::Event::Type type) +{ + GpgOp::Event e; + e.type = type; + eventReady(e); +} + +void GpgOp::Private::eventReady(GpgOp::Event::Type type, int written) +{ + GpgOp::Event e; + e.type = type; + e.written = written; + eventReady(e); +} + +void GpgOp::Private::eventReady(GpgOp::Event::Type type, const QString &keyId) +{ + GpgOp::Event e; + e.type = type; + e.keyId = keyId; + eventReady(e); +} + +void GpgOp::Private::act_readyRead() +{ + if (waiting) + eventReady(GpgOp::Event::ReadyRead); + else + emit q->readyRead(); +} + +void GpgOp::Private::act_bytesWritten(int bytes) +{ + if (waiting) + eventReady(GpgOp::Event::BytesWritten, bytes); + else + emit q->bytesWritten(bytes); +} + +void GpgOp::Private::act_needPassphrase(const QString &keyId) +{ + if (waiting) + eventReady(GpgOp::Event::NeedPassphrase, keyId); + else + emit q->needPassphrase(keyId); +} + +void GpgOp::Private::act_needCard() +{ + if (waiting) + eventReady(GpgOp::Event::NeedCard); + else + emit q->needCard(); +} + +void GpgOp::Private::act_readyReadDiagnosticText() +{ + const QString s = act->readDiagnosticText(); + // printf("dtext ready: [%s]\n", qPrintable(s)); + diagnosticText += s; + + if (waiting) + eventReady(GpgOp::Event::ReadyReadDiagnosticText); + else + emit q->readyReadDiagnosticText(); +} + +void GpgOp::Private::act_finished() +{ +#ifdef GPG_PROFILE + if (op == GpgOp::Encrypt) + printf("<< doEncrypt: %d >>\n", timer.elapsed()); +#endif + + result = act->read(); + diagnosticText += act->readDiagnosticText(); + output = act->output; + + QMap errmap; + errmap[GpgOp::ErrorProcess] = QStringLiteral("ErrorProcess"); + errmap[GpgOp::ErrorPassphrase] = QStringLiteral("ErrorPassphrase"); + errmap[GpgOp::ErrorFormat] = QStringLiteral("ErrorFormat"); + errmap[GpgOp::ErrorSignerExpired] = QStringLiteral("ErrorSignerExpired"); + errmap[GpgOp::ErrorEncryptExpired] = QStringLiteral("ErrorEncryptExpired"); + errmap[GpgOp::ErrorEncryptUntrusted] = QStringLiteral("ErrorEncryptUntrusted"); + errmap[GpgOp::ErrorEncryptInvalid] = QStringLiteral("ErrorEncryptInvalid"); + errmap[GpgOp::ErrorDecryptNoKey] = QStringLiteral("ErrorDecryptNoKey"); + errmap[GpgOp::ErrorUnknown] = QStringLiteral("ErrorUnknown"); + if (output.success) + diagnosticText += QStringLiteral("GpgAction success\n"); + else + diagnosticText += QStringLiteral("GpgAction error: %1\n").arg(errmap[output.errorCode]); + + if (output.wasSigned) { + QString s; + if (output.verifyResult == GpgOp::VerifyGood) + s = QStringLiteral("VerifyGood"); + else if (output.verifyResult == GpgOp::VerifyBad) + s = QStringLiteral("VerifyBad"); + else + s = QStringLiteral("VerifyNoKey"); + diagnosticText += QStringLiteral("wasSigned: verifyResult: %1\n").arg(s); + } + + // printf("diagnosticText:\n%s", qPrintable(diagnosticText)); + + reset(ResetSession); + + if (waiting) + eventReady(GpgOp::Event::Finished); + else + emit q->finished(); +} + +GpgOp::GpgOp(const QString &bin, QObject *parent) + : QObject(parent) +{ + d = new Private(this); + d->bin = bin; +} + +GpgOp::~GpgOp() +{ + delete d; +} + +void GpgOp::reset() +{ + d->reset(ResetAll); +} + +bool GpgOp::isActive() const +{ + return (d->act ? true : false); +} + +GpgOp::Type GpgOp::op() const +{ + return d->op; +} + +void GpgOp::setAsciiFormat(bool b) +{ + d->opt_ascii = b; +} + +void GpgOp::setDisableAgent(bool b) +{ + d->opt_noagent = b; +} + +void GpgOp::setAlwaysTrust(bool b) +{ + d->opt_alwaystrust = b; +} + +void GpgOp::setKeyrings(const QString &pubfile, const QString &secfile) +{ + d->opt_pubfile = pubfile; + d->opt_secfile = secfile; +} + +void GpgOp::doCheck() +{ + d->make_act(Check); + d->act->start(); +} + +void GpgOp::doSecretKeyringFile() +{ + d->make_act(SecretKeyringFile); + d->act->start(); +} + +void GpgOp::doPublicKeyringFile() +{ + d->make_act(PublicKeyringFile); + d->act->start(); +} + +void GpgOp::doSecretKeys() +{ + d->make_act(SecretKeys); + d->act->start(); +} + +void GpgOp::doPublicKeys() +{ + d->make_act(PublicKeys); + d->act->start(); +} + +void GpgOp::doEncrypt(const QStringList &recip_ids) +{ +#ifdef GPG_PROFILE + d->timer.start(); + printf("<< doEncrypt >>\n"); +#endif + + d->make_act(Encrypt); + d->act->input.recip_ids = recip_ids; + d->act->start(); +} + +void GpgOp::doDecrypt() +{ + d->make_act(Decrypt); + d->act->start(); +} + +void GpgOp::doSign(const QString &signer_id) +{ + d->make_act(Sign); + d->act->input.signer_id = signer_id; + d->act->start(); +} + +void GpgOp::doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids) +{ + d->make_act(SignAndEncrypt); + d->act->input.signer_id = signer_id; + d->act->input.recip_ids = recip_ids; + d->act->start(); +} + +void GpgOp::doSignClearsign(const QString &signer_id) +{ + d->make_act(SignClearsign); + d->act->input.signer_id = signer_id; + d->act->start(); +} + +void GpgOp::doSignDetached(const QString &signer_id) +{ + d->make_act(SignDetached); + d->act->input.signer_id = signer_id; + d->act->start(); +} + +void GpgOp::doVerify() +{ + d->make_act(Verify); + d->act->start(); +} + +void GpgOp::doVerifyDetached(const QByteArray &sig) +{ + d->make_act(VerifyDetached); + d->act->input.sig = sig; + d->act->start(); +} + +void GpgOp::doImport(const QByteArray &in) +{ + d->make_act(Import); + d->act->input.inkey = in; + d->act->start(); +} + +void GpgOp::doExport(const QString &key_id) +{ + d->make_act(Export); + d->act->input.export_key_id = key_id; + d->act->start(); +} + +void GpgOp::doDeleteKey(const QString &key_fingerprint) +{ + d->make_act(DeleteKey); + d->act->input.delete_key_fingerprint = key_fingerprint; + d->act->start(); +} + +#ifdef QPIPE_SECURE +void GpgOp::submitPassphrase(const QCA::SecureArray &a) +#else +void GpgOp::submitPassphrase(const QByteArray &a) +#endif +{ + d->act->submitPassphrase(a); +} + +void GpgOp::cardOkay() +{ + d->act->cardOkay(); +} + +QByteArray GpgOp::read() +{ + if (d->act) { + return d->act->read(); + } else { + const QByteArray a = d->result; + d->result.clear(); + return a; + } +} + +void GpgOp::write(const QByteArray &in) +{ + d->act->write(in); +} + +void GpgOp::endWrite() +{ + d->act->endWrite(); +} + +QString GpgOp::readDiagnosticText() +{ + QString s = d->diagnosticText; + d->diagnosticText = QString(); + return s; +} + +GpgOp::Event GpgOp::waitForEvent(int msecs) +{ + if (!d->eventList.isEmpty()) + return d->eventList.takeFirst(); + + if (!d->act) + return GpgOp::Event(); + + d->waiting = true; + d->sync.waitForCondition(msecs); + d->waiting = false; + if (!d->eventList.isEmpty()) + return d->eventList.takeFirst(); + else + return GpgOp::Event(); +} + +bool GpgOp::success() const +{ + return d->output.success; +} + +GpgOp::Error GpgOp::errorCode() const +{ + return d->output.errorCode; +} + +GpgOp::KeyList GpgOp::keys() const +{ + return d->output.keys; +} + +QString GpgOp::keyringFile() const +{ + return d->output.keyringFile; +} + +QString GpgOp::homeDir() const +{ + return d->output.homeDir; +} + +QString GpgOp::encryptedToId() const +{ + return d->output.encryptedToId; +} + +bool GpgOp::wasSigned() const +{ + return d->output.wasSigned; +} + +QString GpgOp::signerId() const +{ + return d->output.signerId; +} + +QDateTime GpgOp::timestamp() const +{ + return d->output.timestamp; +} + +GpgOp::VerifyResult GpgOp::verifyResult() const +{ + return d->output.verifyResult; +} + +} diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.h new file mode 100644 index 0000000000..57ddf229c7 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef GPGOP_H +#define GPGOP_H + +#include "qpipe.h" +#include + +namespace gpgQCAPlugin { + +class GpgOp : public QObject +{ + Q_OBJECT +public: + enum Type + { + Check, // --version + SecretKeyringFile, // --list-secret-keys + PublicKeyringFile, // --list-public-keys + SecretKeys, // --fixed-list-mode --with-colons --list-secret-keys + PublicKeys, // --fixed-list-mode --with-colons --list-public-keys + Encrypt, // --encrypt + Decrypt, // --decrypt + Sign, // --sign + SignAndEncrypt, // --sign --encrypt + SignClearsign, // --clearsign + SignDetached, // --detach-sign + Verify, // --verify + VerifyDetached, // --verify + Import, // --import + Export, // --export + DeleteKey // --delete-key + }; + + enum VerifyResult + { + VerifyGood, // good sig + VerifyBad, // bad sig + VerifyNoKey // we don't have signer's public key + }; + + enum Error + { + ErrorProcess, // startup, process, or ipc error + ErrorPassphrase, // passphrase was either wrong or not provided + ErrorFormat, // input format was bad + ErrorSignerExpired, // signing key is expired + ErrorEncryptExpired, // encrypting key is expired + ErrorEncryptUntrusted, // encrypting key is untrusted + ErrorEncryptInvalid, // encrypting key is invalid in some way + ErrorDecryptNoKey, // missing decrypt key + ErrorUnknown, // other error + ErrorSignerRevoked, // signing key is revoked + ErrorSignatureExpired, // signature is expired + ErrorEncryptRevoked // encrypting key is revoked + }; + + class Event + { + public: + enum Type + { + None, + ReadyRead, + BytesWritten, + Finished, + NeedPassphrase, + NeedCard, + ReadyReadDiagnosticText + }; + + Type type; + int written; // BytesWritten + QString keyId; // NeedPassphrase + + Event() + : type(None) + , written(0) + { + } + }; + + class KeyItem + { + public: + enum Type + { + RSA, + DSA, + ElGamal, + Unknown + }; + + enum Caps + { + Encrypt = 0x01, + Sign = 0x02, + Certify = 0x04, + Auth = 0x08 + }; + + QString id; + Type type; + int bits; + QDateTime creationDate; + QDateTime expirationDate; + int caps; // flags OR'd together + QString fingerprint; + + KeyItem() + : type(Unknown) + , bits(0) + , caps(0) + { + } + }; + + class Key + { + public: + QList keyItems; // first item is primary + QStringList userIds; + bool isTrusted; + + Key() + : isTrusted(false) + { + } + }; + typedef QList KeyList; + + explicit GpgOp(const QString &bin, QObject *parent = nullptr); + ~GpgOp() override; + + void reset(); + + bool isActive() const; + Type op() const; + + void setAsciiFormat(bool b); + void setDisableAgent(bool b); + void setAlwaysTrust(bool b); + void setKeyrings(const QString &pubfile, const QString &secfile); // for keylists and import + + void doCheck(); + void doSecretKeyringFile(); + void doPublicKeyringFile(); + void doSecretKeys(); + void doPublicKeys(); + void doEncrypt(const QStringList &recip_ids); + void doDecrypt(); + void doSign(const QString &signer_id); + void doSignAndEncrypt(const QString &signer_id, const QStringList &recip_ids); + void doSignClearsign(const QString &signer_id); + void doSignDetached(const QString &signer_id); + void doVerify(); + void doVerifyDetached(const QByteArray &sig); + void doImport(const QByteArray &in); + void doExport(const QString &key_id); + void doDeleteKey(const QString &key_fingerprint); + +#ifdef QPIPE_SECURE + void submitPassphrase(const QCA::SecureArray &a); +#else + void submitPassphrase(const QByteArray &a); +#endif + void cardOkay(); + + // for encrypt, decrypt, sign, verify, export + QByteArray read(); + void write(const QByteArray &in); + void endWrite(); + + QString readDiagnosticText(); + + // for synchronous operation + Event waitForEvent(int msecs = -1); + + // results + bool success() const; + Error errorCode() const; + KeyList keys() const; // Keys + QString keyringFile() const; // KeyringFile + QString homeDir() const; // GnuPG home directory + QString encryptedToId() const; // Decrypt (for ErrorDecryptNoKey) + bool wasSigned() const; // Decrypt + QString signerId() const; // Verify + QDateTime timestamp() const; // Verify + VerifyResult verifyResult() const; // Verify + +Q_SIGNALS: + void readyRead(); + void bytesWritten(int bytes); + void finished(); + void needPassphrase(const QString &keyId); + void needCard(); + void readyReadDiagnosticText(); + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop_p.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop_p.h new file mode 100644 index 0000000000..0e740e9c61 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgop_p.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#pragma once + +#include "gpgaction.h" +#include "gpgop.h" +#include "gpgproc_p.h" +#include + +namespace gpgQCAPlugin { + +class GpgOp::Private : public QObject +{ + Q_OBJECT +public: + QCA::Synchronizer sync; + GpgOp *q; + GpgAction *act; + QString bin; + GpgOp::Type op; + GpgAction::Output output; + QByteArray result; + QString diagnosticText; + QList eventList; + bool waiting; + + bool opt_ascii, opt_noagent, opt_alwaystrust; + QString opt_pubfile, opt_secfile; + +#ifdef GPG_PROFILE + QTime timer; +#endif + + Private(GpgOp *_q); + ~Private() override; + void reset(ResetMode mode); + void make_act(GpgOp::Type _op); + void eventReady(const GpgOp::Event &e); + void eventReady(GpgOp::Event::Type type); + void eventReady(GpgOp::Event::Type type, int written); + void eventReady(GpgOp::Event::Type type, const QString &keyId); + +public Q_SLOTS: + void act_readyRead(); + void act_bytesWritten(int bytes); + void act_needPassphrase(const QString &keyId); + void act_needCard(); + void act_readyReadDiagnosticText(); + void act_finished(); +}; + +} // namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/README b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/README new file mode 100644 index 0000000000..a077a9c66f --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/README @@ -0,0 +1,8 @@ +GPGProc launches a single instance of GPG and provides a friendly API to +work with all six possible pipe channels. Theoretically, it should be +possible to build any GPG front end with it, even though qca-gnupg uses it +for only a handful of operations. If you are writing a Qt-based GPG front +end, please use this class. + +GPGProc works on both Windows and Unix platforms. + diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.cpp new file mode 100644 index 0000000000..9b8367ee92 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.cpp @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "gpgproc_p.h" + +#ifdef Q_OS_MAC +#define QT_PIPE_HACK +#endif + +using namespace QCA; + +namespace gpgQCAPlugin { + +void releaseAndDeleteLater(QObject *owner, QObject *obj) +{ + obj->disconnect(owner); + obj->setParent(nullptr); + obj->deleteLater(); +} + +GPGProc::Private::Private(GPGProc *_q) + : QObject(_q) + , q(_q) + , pipeAux(this) + , pipeCommand(this) + , pipeStatus(this) + , startTrigger(this) + , doneTrigger(this) +{ + qRegisterMetaType("gpgQCAPlugin::GPGProc::Error"); + + proc = nullptr; + proc_relay = nullptr; + startTrigger.setSingleShot(true); + doneTrigger.setSingleShot(true); + + connect(&pipeAux.writeEnd(), &QCA::QPipeEnd::bytesWritten, this, &GPGProc::Private::aux_written); + connect(&pipeAux.writeEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::aux_error); + connect(&pipeCommand.writeEnd(), &QCA::QPipeEnd::bytesWritten, this, &GPGProc::Private::command_written); + connect(&pipeCommand.writeEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::command_error); + connect(&pipeStatus.readEnd(), &QCA::QPipeEnd::readyRead, this, &GPGProc::Private::status_read); + connect(&pipeStatus.readEnd(), &QCA::QPipeEnd::error, this, &GPGProc::Private::status_error); + connect(&startTrigger, &QCA::SafeTimer::timeout, this, &GPGProc::Private::doStart); + connect(&doneTrigger, &QCA::SafeTimer::timeout, this, &GPGProc::Private::doTryDone); + + reset(ResetSessionAndData); +} + +GPGProc::Private::~Private() +{ + reset(ResetSession); +} + +void GPGProc::Private::closePipes() +{ +#ifdef QT_PIPE_HACK + pipeAux.readEnd().reset(); + pipeCommand.readEnd().reset(); + pipeStatus.writeEnd().reset(); +#endif + + pipeAux.reset(); + pipeCommand.reset(); + pipeStatus.reset(); +} + +void GPGProc::Private::reset(ResetMode mode) +{ +#ifndef QT_PIPE_HACK + closePipes(); +#endif + + if (proc) { + proc->disconnect(this); + + if (proc->state() != QProcess::NotRunning) { + // Before try to correct end proccess + // Terminate if failed + proc->close(); + bool finished = proc->waitForFinished(5000); + if (!finished) + proc->terminate(); + } + + proc->setParent(nullptr); + releaseAndDeleteLater(this, proc_relay); + proc_relay = nullptr; + delete proc; // should be safe to do thanks to relay + proc = nullptr; + } + +#ifdef QT_PIPE_HACK + closePipes(); +#endif + + startTrigger.stop(); + doneTrigger.stop(); + + pre_stdin.clear(); + pre_aux.clear(); + pre_command.clear(); + pre_stdin_close = false; + pre_aux_close = false; + pre_command_close = false; + + need_status = false; + fin_process = false; + fin_status = false; + + if (mode >= ResetSessionAndData) { + statusBuf.clear(); + statusLines.clear(); + leftover_stdout.clear(); + leftover_stderr.clear(); + error = GPGProc::FailedToStart; + exitCode = -1; + } +} + +bool GPGProc::Private::setupPipes(bool makeAux) +{ + if (makeAux && !pipeAux.create()) { + closePipes(); + emit q->debug(QStringLiteral("Error creating pipeAux")); + return false; + } + +#ifdef QPIPE_SECURE + if (!pipeCommand.create(true)) // secure +#else + if (!pipeCommand.create()) +#endif + { + closePipes(); + emit q->debug(QStringLiteral("Error creating pipeCommand")); + return false; + } + + if (!pipeStatus.create()) { + closePipes(); + emit q->debug(QStringLiteral("Error creating pipeStatus")); + return false; + } + + return true; +} + +void GPGProc::Private::setupArguments() +{ + QStringList fullargs; + fullargs += QStringLiteral("--no-tty"); + fullargs += QStringLiteral("--pinentry-mode"); + fullargs += QStringLiteral("loopback"); + + if (mode == ExtendedMode) { + fullargs += QStringLiteral("--enable-special-filenames"); + + fullargs += QStringLiteral("--status-fd"); + fullargs += QString::number(pipeStatus.writeEnd().idAsInt()); + + fullargs += QStringLiteral("--command-fd"); + fullargs += QString::number(pipeCommand.readEnd().idAsInt()); + } + + for (int n = 0; n < args.count(); ++n) { + QString a = args[n]; + if (mode == ExtendedMode && a == QLatin1String("-&?")) + fullargs += QStringLiteral("-&") + QString::number(pipeAux.readEnd().idAsInt()); + else + fullargs += a; + } + + QString fullcmd = fullargs.join(QStringLiteral(" ")); + emit q->debug(QStringLiteral("Running: [") + bin + QLatin1Char(' ') + fullcmd + QLatin1Char(']')); + + args = fullargs; +} + +void GPGProc::Private::doStart() +{ +#ifdef Q_OS_WIN + // Note: for unix, inheritability is set in SProcess + if (pipeAux.readEnd().isValid()) + pipeAux.readEnd().setInheritable(true); + if (pipeCommand.readEnd().isValid()) + pipeCommand.readEnd().setInheritable(true); + if (pipeStatus.writeEnd().isValid()) + pipeStatus.writeEnd().setInheritable(true); +#endif + + setupArguments(); + + proc->start(bin, args); + proc->waitForStarted(); + + pipeAux.readEnd().close(); + pipeCommand.readEnd().close(); + pipeStatus.writeEnd().close(); +} + +void GPGProc::Private::aux_written(int x) +{ + emit q->bytesWrittenAux(x); +} + +void GPGProc::Private::aux_error(QCA::QPipeEnd::Error) +{ + emit q->debug(QStringLiteral("Aux: Pipe error")); + reset(ResetSession); + emit q->error(GPGProc::ErrorWrite); +} + +void GPGProc::Private::command_written(int x) +{ + emit q->bytesWrittenCommand(x); +} + +void GPGProc::Private::command_error(QCA::QPipeEnd::Error) +{ + emit q->debug(QStringLiteral("Command: Pipe error")); + reset(ResetSession); + emit q->error(GPGProc::ErrorWrite); +} + +void GPGProc::Private::status_read() +{ + if (readAndProcessStatusData()) + emit q->readyReadStatusLines(); +} + +void GPGProc::Private::status_error(QCA::QPipeEnd::Error e) +{ + if (e == QPipeEnd::ErrorEOF) + emit q->debug(QStringLiteral("Status: Closed (EOF)")); + else + emit q->debug(QStringLiteral("Status: Closed (gone)")); + + fin_status = true; + doTryDone(); +} + +void GPGProc::Private::proc_started() +{ + emit q->debug(QStringLiteral("Process started")); + + // Note: we don't close these here anymore. instead we + // do it just after calling proc->start(). + // close these, we don't need them + /*pipeAux.readEnd().close(); + pipeCommand.readEnd().close(); + pipeStatus.writeEnd().close();*/ + + // do the pre* stuff + if (!pre_stdin.isEmpty()) { + proc->write(pre_stdin); + pre_stdin.clear(); + } + if (!pre_aux.isEmpty()) { + pipeAux.writeEnd().write(pre_aux); + pre_aux.clear(); + } + if (!pre_command.isEmpty()) { +#ifdef QPIPE_SECURE + pipeCommand.writeEnd().writeSecure(pre_command); +#else + pipeCommand.writeEnd().write(pre_command); +#endif + pre_command.clear(); + } + + if (pre_stdin_close) { + proc->waitForBytesWritten(); + proc->closeWriteChannel(); + } + + if (pre_aux_close) + pipeAux.writeEnd().close(); + if (pre_command_close) + pipeCommand.writeEnd().close(); +} + +void GPGProc::Private::proc_readyReadStandardOutput() +{ + emit q->readyReadStdout(); +} + +void GPGProc::Private::proc_readyReadStandardError() +{ + emit q->readyReadStderr(); +} + +void GPGProc::Private::proc_bytesWritten(qint64 lx) +{ + int x = (int)lx; + emit q->bytesWrittenStdin(x); +} + +void GPGProc::Private::proc_finished(int x) +{ + emit q->debug(QStringLiteral("Process finished: %1").arg(x)); + exitCode = x; + + fin_process = true; + fin_process_success = true; + + if (need_status && !fin_status) { + pipeStatus.readEnd().finalize(); + fin_status = true; + if (readAndProcessStatusData()) { + doneTrigger.start(); + emit q->readyReadStatusLines(); + return; + } + } + + doTryDone(); +} + +void GPGProc::Private::proc_error(QProcess::ProcessError x) +{ + QMap errmap; + errmap[QProcess::FailedToStart] = QStringLiteral("FailedToStart"); + errmap[QProcess::Crashed] = QStringLiteral("Crashed"); + errmap[QProcess::Timedout] = QStringLiteral("Timedout"); + errmap[QProcess::WriteError] = QStringLiteral("WriteError"); + errmap[QProcess::ReadError] = QStringLiteral("ReadError"); + errmap[QProcess::UnknownError] = QStringLiteral("UnknownError"); + + emit q->debug(QStringLiteral("Process error: %1").arg(errmap[x])); + + if (x == QProcess::FailedToStart) + error = GPGProc::FailedToStart; + else if (x == QProcess::WriteError) + error = GPGProc::ErrorWrite; + else + error = GPGProc::UnexpectedExit; + + fin_process = true; + fin_process_success = false; + +#ifdef QT_PIPE_HACK + // If the process fails to start, then the ends of the pipes + // intended for the child process are still open. Some Mac + // users experience a lockup if we close our ends of the pipes + // when the child's ends are still open. If we ensure the + // child's ends are closed, we prevent this lockup. I have no + // idea why the problem even happens or why this fix should + // work. + pipeAux.readEnd().reset(); + pipeCommand.readEnd().reset(); + pipeStatus.writeEnd().reset(); +#endif + + if (need_status && !fin_status) { + pipeStatus.readEnd().finalize(); + fin_status = true; + if (readAndProcessStatusData()) { + doneTrigger.start(); + emit q->readyReadStatusLines(); + return; + } + } + + doTryDone(); +} + +void GPGProc::Private::doTryDone() +{ + if (!fin_process) + return; + + if (need_status && !fin_status) + return; + + emit q->debug(QStringLiteral("Done")); + + // get leftover data + proc->setReadChannel(QProcess::StandardOutput); + leftover_stdout = proc->readAll(); + + proc->setReadChannel(QProcess::StandardError); + leftover_stderr = proc->readAll(); + + reset(ResetSession); + if (fin_process_success) + emit q->finished(exitCode); + else + emit q->error(error); +} + +bool GPGProc::Private::readAndProcessStatusData() +{ + const QByteArray buf = pipeStatus.readEnd().read(); + if (buf.isEmpty()) + return false; + + return processStatusData(buf); +} + +// return true if there are newly parsed lines available +bool GPGProc::Private::processStatusData(const QByteArray &buf) +{ + statusBuf.append(buf); + + // extract all lines + QStringList list; + while (true) { + int n = statusBuf.indexOf('\n'); + if (n == -1) + break; + + // extract the string from statusbuf + ++n; + char *p = (char *)statusBuf.data(); + QByteArray cs(p, n); + const int newsize = statusBuf.size() - n; + memmove(p, p + n, newsize); + statusBuf.resize(newsize); + + // convert to string without newline + QString str = QString::fromUtf8(cs); + str.truncate(str.length() - 1); + + // ensure it has a proper header + if (str.left(9) != QLatin1String("[GNUPG:] ")) + continue; + + // take it off + str = str.mid(9); + + // add to the list + list += str; + } + + if (list.isEmpty()) + return false; + + statusLines += list; + return true; +} + +GPGProc::GPGProc(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +GPGProc::~GPGProc() +{ + delete d; +} + +void GPGProc::reset() +{ + d->reset(ResetAll); +} + +bool GPGProc::isActive() const +{ + return (d->proc ? true : false); +} + +void GPGProc::start(const QString &bin, const QStringList &args, Mode mode) +{ + if (isActive()) + d->reset(ResetSessionAndData); + + if (mode == ExtendedMode) { + if (!d->setupPipes(args.contains(QStringLiteral("-&?")))) { + d->error = FailedToStart; + + // emit later + QMetaObject::invokeMethod( + this, "error", Qt::QueuedConnection, Q_ARG(gpgQCAPlugin::GPGProc::Error, d->error)); + return; + } + + d->need_status = true; + + emit debug(QStringLiteral("Pipe setup complete")); + } + + d->proc = new SProcess(d); + +#ifdef Q_OS_UNIX + QList plist; + if (d->pipeAux.readEnd().isValid()) + plist += d->pipeAux.readEnd().id(); + if (d->pipeCommand.readEnd().isValid()) + plist += d->pipeCommand.readEnd().id(); + if (d->pipeStatus.writeEnd().isValid()) + plist += d->pipeStatus.writeEnd().id(); + d->proc->setInheritPipeList(plist); +#endif + + // enable the pipes we want + if (d->pipeAux.writeEnd().isValid()) + d->pipeAux.writeEnd().enable(); + if (d->pipeCommand.writeEnd().isValid()) + d->pipeCommand.writeEnd().enable(); + if (d->pipeStatus.readEnd().isValid()) + d->pipeStatus.readEnd().enable(); + + d->proc_relay = new QProcessSignalRelay(d->proc, d); + connect(d->proc_relay, &QProcessSignalRelay::started, d, &GPGProc::Private::proc_started); + connect(d->proc_relay, + &QProcessSignalRelay::readyReadStandardOutput, + d, + &GPGProc::Private::proc_readyReadStandardOutput); + connect( + d->proc_relay, &QProcessSignalRelay::readyReadStandardError, d, &GPGProc::Private::proc_readyReadStandardError); + connect(d->proc_relay, &QProcessSignalRelay::bytesWritten, d, &GPGProc::Private::proc_bytesWritten); + connect(d->proc_relay, &QProcessSignalRelay::finished, d, &GPGProc::Private::proc_finished); + connect(d->proc_relay, &QProcessSignalRelay::error, d, &GPGProc::Private::proc_error); + + d->bin = bin; + d->args = args; + d->mode = mode; + d->startTrigger.start(); +} + +QByteArray GPGProc::readStdout() +{ + if (d->proc) { + d->proc->setReadChannel(QProcess::StandardOutput); + return d->proc->readAll(); + } else { + const QByteArray a = d->leftover_stdout; + d->leftover_stdout.clear(); + return a; + } +} + +QByteArray GPGProc::readStderr() +{ + if (d->proc) { + d->proc->setReadChannel(QProcess::StandardError); + return d->proc->readAll(); + } else { + const QByteArray a = d->leftover_stderr; + d->leftover_stderr.clear(); + return a; + } +} + +QStringList GPGProc::readStatusLines() +{ + const QStringList out = d->statusLines; + d->statusLines.clear(); + return out; +} + +void GPGProc::writeStdin(const QByteArray &a) +{ + if (!d->proc || a.isEmpty()) + return; + + if (d->proc->state() == QProcess::Running) + d->proc->write(a); + else + d->pre_stdin += a; +} + +void GPGProc::writeAux(const QByteArray &a) +{ + if (!d->proc || a.isEmpty()) + return; + + if (d->proc->state() == QProcess::Running) + d->pipeAux.writeEnd().write(a); + else + d->pre_aux += a; +} + +#ifdef QPIPE_SECURE +void GPGProc::writeCommand(const SecureArray &a) +#else +void GPGProc::writeCommand(const QByteArray &a) +#endif +{ + if (!d->proc || a.isEmpty()) + return; + + if (d->proc->state() == QProcess::Running) +#ifdef QPIPE_SECURE + d->pipeCommand.writeEnd().writeSecure(a); +#else + d->pipeCommand.writeEnd().write(a); +#endif + else + d->pre_command += a; +} + +void GPGProc::closeStdin() +{ + if (!d->proc) + return; + + if (d->proc->state() == QProcess::Running) { + d->proc->waitForBytesWritten(); + d->proc->closeWriteChannel(); + } else { + d->pre_stdin_close = true; + } +} + +void GPGProc::closeAux() +{ + if (!d->proc) + return; + + if (d->proc->state() == QProcess::Running) + d->pipeAux.writeEnd().close(); + else + d->pre_aux_close = true; +} + +void GPGProc::closeCommand() +{ + if (!d->proc) + return; + + if (d->proc->state() == QProcess::Running) + d->pipeCommand.writeEnd().close(); + else + d->pre_command_close = true; +} + +} diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.h new file mode 100644 index 0000000000..e9de4b43bb --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef GPGPROC_H +#define GPGPROC_H + +#include "qpipe.h" + +namespace gpgQCAPlugin { + +// GPGProc - executes gpg and provides access to all 6 channels. NormalMode +// enables stdout, stderr, and stdin. ExtendedMode has those 3 plus status +// aux, and command. The aux channel is connected to the '-&?' argument. +// The debug() signal, as well as stderr, can be used for diagnostic text. +class GPGProc : public QObject +{ + Q_OBJECT +public: + enum Error + { + FailedToStart, + UnexpectedExit, + ErrorWrite + }; + enum Mode + { + NormalMode, + ExtendedMode + }; + GPGProc(QObject *parent = nullptr); + ~GPGProc() override; + + void reset(); + + bool isActive() const; + void start(const QString &bin, const QStringList &args, Mode m = ExtendedMode); + + QByteArray readStdout(); + QByteArray readStderr(); + QStringList readStatusLines(); + void writeStdin(const QByteArray &a); + void writeAux(const QByteArray &a); +#ifdef QPIPE_SECURE + void writeCommand(const QCA::SecureArray &a); +#else + void writeCommand(const QByteArray &a); +#endif + void closeStdin(); + void closeAux(); + void closeCommand(); + +Q_SIGNALS: + void error(gpgQCAPlugin::GPGProc::Error error); + void finished(int exitCode); + void readyReadStdout(); + void readyReadStderr(); + void readyReadStatusLines(); + void bytesWrittenStdin(int bytes); + void bytesWrittenAux(int bytes); + void bytesWrittenCommand(int bytes); + void debug(const QString &str); // not signal-safe + +private: + class Private; + friend class Private; + Private *d; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc_p.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc_p.h new file mode 100644 index 0000000000..8064449ea0 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/gpgproc_p.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#pragma once + +#include "gpgproc.h" +#include "qpipe.h" +#include "sprocess.h" +#include + +namespace gpgQCAPlugin { + +class QProcessSignalRelay : public QObject +{ + Q_OBJECT +public: + QProcessSignalRelay(QProcess *proc, QObject *parent = nullptr) + : QObject(parent) + { + qRegisterMetaType("QProcess::ProcessError"); + connect(proc, &QProcess::started, this, &QProcessSignalRelay::proc_started, Qt::QueuedConnection); + connect(proc, + &QProcess::readyReadStandardOutput, + this, + &QProcessSignalRelay::proc_readyReadStandardOutput, + Qt::QueuedConnection); + connect(proc, + &QProcess::readyReadStandardError, + this, + &QProcessSignalRelay::proc_readyReadStandardError, + Qt::QueuedConnection); + connect(proc, &QProcess::bytesWritten, this, &QProcessSignalRelay::proc_bytesWritten, Qt::QueuedConnection); + connect(proc, + QOverload::of(&QProcess::finished), + this, + &QProcessSignalRelay::proc_finished, + Qt::QueuedConnection); + connect(proc, &QProcess::errorOccurred, this, &QProcessSignalRelay::proc_error, Qt::QueuedConnection); + } + +Q_SIGNALS: + void started(); + void readyReadStandardOutput(); + void readyReadStandardError(); + void bytesWritten(qint64); + void finished(int); + void error(QProcess::ProcessError); + +public Q_SLOTS: + void proc_started() + { + emit started(); + } + + void proc_readyReadStandardOutput() + { + emit readyReadStandardOutput(); + } + + void proc_readyReadStandardError() + { + emit readyReadStandardError(); + } + + void proc_bytesWritten(qint64 x) + { + emit bytesWritten(x); + } + + void proc_finished(int x) + { + emit finished(x); + } + + void proc_error(QProcess::ProcessError x) + { + emit error(x); + } +}; + +enum ResetMode +{ + ResetSession = 0, + ResetSessionAndData = 1, + ResetAll = 2 +}; + +class GPGProc::Private : public QObject +{ + Q_OBJECT +public: + GPGProc *q; + QString bin; + QStringList args; + GPGProc::Mode mode; + SProcess *proc; + QProcessSignalRelay *proc_relay; + QCA::QPipe pipeAux, pipeCommand, pipeStatus; + QByteArray statusBuf; + QStringList statusLines; + GPGProc::Error error; + int exitCode; + QCA::SafeTimer startTrigger, doneTrigger; + + QByteArray pre_stdin, pre_aux; +#ifdef QPIPE_SECURE + QCA::SecureArray pre_command; +#else + QByteArray pre_command; +#endif + bool pre_stdin_close, pre_aux_close, pre_command_close; + + bool need_status, fin_process, fin_process_success, fin_status; + QByteArray leftover_stdout; + QByteArray leftover_stderr; + + Private(GPGProc *_q); + ~Private() override; + void closePipes(); + void reset(ResetMode mode); + bool setupPipes(bool makeAux); + void setupArguments(); + +public Q_SLOTS: + void doStart(); + void aux_written(int x); + void aux_error(QCA::QPipeEnd::Error); + void command_written(int x); + void command_error(QCA::QPipeEnd::Error); + void status_read(); + void status_error(QCA::QPipeEnd::Error e); + void proc_started(); + void proc_readyReadStandardOutput(); + void proc_readyReadStandardError(); + void proc_bytesWritten(qint64 lx); + void proc_finished(int x); + void proc_error(QProcess::ProcessError x); + void doTryDone(); + +private: + bool readAndProcessStatusData(); + // return true if there are newly parsed lines available + bool processStatusData(const QByteArray &buf); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.cpp new file mode 100644 index 0000000000..a1bbe73734 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "sprocess.h" + +#ifdef Q_OS_UNIX +#include +#include +#endif + +namespace gpgQCAPlugin { + +//---------------------------------------------------------------------------- +// SProcess +//---------------------------------------------------------------------------- +SProcess::SProcess(QObject *parent) + : QProcess(parent) +{ +#ifdef Q_OS_UNIX +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + setChildProcessModifier([this]() { + // set the pipes to be inheritable + for (int n = 0; n < pipeList.count(); ++n) + ::fcntl(pipeList[n], F_SETFD, (::fcntl(pipeList[n], F_GETFD) & ~FD_CLOEXEC)); + }); +#endif +#endif +} + +SProcess::~SProcess() +{ +} + +#ifdef Q_OS_UNIX +void SProcess::setInheritPipeList(const QList &list) +{ + pipeList = list; +} + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +void SProcess::setupChildProcess() +{ + // set the pipes to be inheritable + for (int n = 0; n < pipeList.count(); ++n) + ::fcntl(pipeList[n], F_SETFD, (::fcntl(pipeList[n], F_GETFD) & ~FD_CLOEXEC)); +} +#endif +#endif + +} diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.h new file mode 100644 index 0000000000..44c9d0fc28 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/gpgproc/sprocess.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef SPROCESS_H +#define SPROCESS_H + +#include + +namespace gpgQCAPlugin { + +class SProcess : public QProcess +{ + Q_OBJECT +public: + SProcess(QObject *parent = nullptr); + ~SProcess() override; + +#ifdef Q_OS_UNIX + void setInheritPipeList(const QList &); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +protected: + void setupChildProcess() override; +#endif + +private: + QList pipeList; +#endif +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.cpp new file mode 100644 index 0000000000..6e327a4083 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "lineconverter.h" + +namespace gpgQCAPlugin { + +void LineConverter::setup(LineConverter::Mode m) +{ + state = Normal; + mode = m; + prebytes = 0; + list.clear(); +} + +QByteArray LineConverter::update(const QByteArray &buf) +{ + if (mode == Read) { + // Convert buf to UNIX line ending style + // If buf ends with '\r' set state to Partival + + QByteArray out; + + if (state == Normal) { + out = buf; + } else { + out.resize(buf.size() + 1); + out[0] = '\r'; + memcpy(out.data() + 1, buf.data(), buf.size()); + } + + int n = 0; + while (true) { + n = out.indexOf('\r', n); + // not found + if (n == -1) { + break; + } + // found, not last character + if (n < (buf.size() - 1)) { + // found windows line ending "\r\n" + if (out[n + 1] == '\n') { + // clip out the '\r' + memmove(out.data() + n, out.data() + n + 1, out.size() - n - 1); + out.resize(out.size() - 1); + } + } + // found, last character + else { + state = Partial; + break; + } + ++n; + } + + return out; + } else { + // On Windows use DOS line ending style. + // On UNIX don't do any convertation. Return buf as is. +#ifdef Q_OS_WIN + QByteArray out; + int prev = 0; + int at = 0; + + while (1) { + int n = buf.indexOf('\n', at); + if (n == -1) + break; + + int chunksize = n - at; + const int oldsize = out.size(); + out.resize(oldsize + chunksize + 2); + memcpy(out.data() + oldsize, buf.data() + at, chunksize); + memcpy(out.data() + oldsize + chunksize, "\r\n", 2); + + list.append(prebytes + n + 1 - prev); + prebytes = 0; + prev = n; + + at = n + 1; + } + if (at < buf.size()) { + const int chunksize = buf.size() - at; + const int oldsize = out.size(); + out.resize(oldsize + chunksize); + memcpy(out.data() + oldsize, buf.data() + at, chunksize); + } + + prebytes += buf.size() - prev; + return out; +#else + return buf; +#endif + } +} + +QByteArray LineConverter::final() +{ + if (mode == Read) { + QByteArray out; + if (state == Partial) { + out.resize(1); + out[0] = '\n'; + } + return out; + } else { + return QByteArray(); + } +} + +QByteArray LineConverter::process(const QByteArray &buf) +{ + return update(buf) + final(); +} + +int LineConverter::writtenToActual(int bytes) +{ +#ifdef Q_OS_WIN + int n = 0; + int counter = bytes; + while (counter > 0) { + if (!list.isEmpty() && bytes >= list.first()) { + ++n; + counter -= list.takeFirst(); + } else { + if (list.isEmpty()) + prebytes -= counter; + else + list.first() -= counter; + + if (prebytes < 0) { + bytes += prebytes; + prebytes = 0; + } + + break; + } + } + return bytes - n; +#else + return bytes; +#endif +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.h new file mode 100644 index 0000000000..61a8368603 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/lineconverter.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#pragma once + +#include +#include + +namespace gpgQCAPlugin { + +class LineConverter +{ +public: + enum Mode + { + Read, + Write + }; + + void setup(Mode m); + QByteArray update(const QByteArray &buf); + QByteArray final(); + QByteArray process(const QByteArray &buf); + int writtenToActual(int bytes); + +private: + enum State + { + Normal, + Partial + }; + Mode mode; + State state; + int prebytes; + QList list; +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.cpp new file mode 100644 index 0000000000..da2405834e --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "mykeystoreentry.h" +#include "utils.h" + +using namespace QCA; + +namespace gpgQCAPlugin { + +MyKeyStoreEntry::MyKeyStoreEntry(const PGPKey &_pub, const PGPKey &_sec, Provider *p) + : KeyStoreEntryContext(p) +{ + pub = _pub; + sec = _sec; + if (!sec.isNull()) + item_type = KeyStoreEntry::TypePGPSecretKey; + else + item_type = KeyStoreEntry::TypePGPPublicKey; +} + +MyKeyStoreEntry::MyKeyStoreEntry(const MyKeyStoreEntry &from) + : KeyStoreEntryContext(from) +{ +} + +MyKeyStoreEntry::~MyKeyStoreEntry() +{ +} + +Provider::Context *MyKeyStoreEntry::clone() const +{ + return new MyKeyStoreEntry(*this); +} + +KeyStoreEntry::Type MyKeyStoreEntry::type() const +{ + return item_type; +} + +QString MyKeyStoreEntry::name() const +{ + return pub.primaryUserId(); +} + +QString MyKeyStoreEntry::id() const +{ + return pub.keyId(); +} + +QString MyKeyStoreEntry::storeId() const +{ + return _storeId; +} + +QString MyKeyStoreEntry::storeName() const +{ + return _storeName; +} + +PGPKey MyKeyStoreEntry::pgpSecretKey() const +{ + return sec; +} + +PGPKey MyKeyStoreEntry::pgpPublicKey() const +{ + return pub; +} + +QString MyKeyStoreEntry::serialize() const +{ + // we only serialize the key id. this means the keyring + // must be available to restore the data + QStringList out; + out += escape_string(QStringLiteral("qca-gnupg-1")); + out += escape_string(pub.keyId()); + return out.join(QStringLiteral(":")); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.h new file mode 100644 index 0000000000..ace0bf684b --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystoreentry.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "qcaprovider.h" + +namespace gpgQCAPlugin { + +class MyKeyStoreList; + +class MyKeyStoreEntry : public QCA::KeyStoreEntryContext +{ + Q_OBJECT +public: + QCA::KeyStoreEntry::Type item_type; + QCA::PGPKey pub, sec; + QString _storeId, _storeName; + + MyKeyStoreEntry(const QCA::PGPKey &_pub, const QCA::PGPKey &_sec, QCA::Provider *p); + MyKeyStoreEntry(const MyKeyStoreEntry &from); + ~MyKeyStoreEntry() override; + + // reimplemented Provider::Context + QCA::Provider::Context *clone() const override; + + // reimplemented KeyStoreEntryContext + QCA::KeyStoreEntry::Type type() const override; + QString name() const override; + QString id() const override; + QString storeId() const override; + QString storeName() const override; + QCA::PGPKey pgpSecretKey() const override; + QCA::PGPKey pgpPublicKey() const override; + QString serialize() const override; +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.cpp new file mode 100644 index 0000000000..725d813760 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.cpp @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "mykeystorelist.h" +#include "mypgpkeycontext.h" +#include "utils.h" +#include +#include + +using namespace QCA; + +namespace gpgQCAPlugin { + +Q_GLOBAL_STATIC(QMutex, ksl_mutex) + +static MyKeyStoreList *keyStoreList = nullptr; +MyKeyStoreList::MyKeyStoreList(Provider *p) + : KeyStoreListContext(p) + , initialized(false) + , gpg(find_bin(), this) + , pubdirty(false) + , secdirty(false) + , ringWatch(this) +{ + QMutexLocker locker(ksl_mutex()); + keyStoreList = this; + + connect(&gpg, &GpgOp::finished, this, &MyKeyStoreList::gpg_finished); + connect(&ringWatch, &RingWatch::changed, this, &MyKeyStoreList::ring_changed); +} + +MyKeyStoreList::~MyKeyStoreList() +{ + QMutexLocker locker(ksl_mutex()); + keyStoreList = nullptr; +} + +Provider::Context *MyKeyStoreList::clone() const +{ + return nullptr; +} + +QString MyKeyStoreList::name(int) const +{ + return QStringLiteral("GnuPG Keyring"); +} + +KeyStore::Type MyKeyStoreList::type(int) const +{ + return KeyStore::PGPKeyring; +} + +QString MyKeyStoreList::storeId(int) const +{ + return QStringLiteral("qca-gnupg"); +} + +QList MyKeyStoreList::keyStores() +{ + // we just support one fixed keyring, if any + QList list; + if (initialized) + list += 0; + return list; +} + +void MyKeyStoreList::start() +{ + // kick start our init procedure: + // ensure gpg is installed + // obtain keyring file names for monitoring + // cache initial keyrings + + init_step = 0; + gpg.doCheck(); +} + +bool MyKeyStoreList::isReadOnly(int) const +{ + return false; +} + +QList MyKeyStoreList::entryTypes(int) const +{ + QList list; + list += KeyStoreEntry::TypePGPSecretKey; + list += KeyStoreEntry::TypePGPPublicKey; + return list; +} + +QList MyKeyStoreList::entryList(int) +{ + QMutexLocker locker(&ringMutex); + + QList out; + + foreach (const GpgOp::Key &pkey, pubkeys) { + PGPKey pub, sec; + + const QString id = pkey.keyItems.first().id; + + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + // not secret, in keyring + kc->set(pkey, false, true, pkey.isTrusted); + pub.change(kc); + + // optional + sec = getSecKey(id, pkey.userIds); + + MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); + c->_storeId = storeId(0); + c->_storeName = name(0); + out.append(c); + } + + return out; +} + +KeyStoreEntryContext *MyKeyStoreList::entry(int, const QString &entryId) +{ + QMutexLocker locker(&ringMutex); + + PGPKey pub = getPubKey(entryId); + if (pub.isNull()) + return nullptr; + + // optional + const PGPKey sec = getSecKey(entryId, static_cast(pub.context())->_props.userIds); + + MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); + c->_storeId = storeId(0); + c->_storeName = name(0); + return c; +} + +KeyStoreEntryContext *MyKeyStoreList::entryPassive(const QString &serialized) +{ + QMutexLocker locker(&ringMutex); + + const QStringList parts = serialized.split(QLatin1Char(':')); + if (parts.count() < 2) + return nullptr; + if (unescape_string(parts[0]) != QLatin1String("qca-gnupg-1")) + return nullptr; + + QString entryId = unescape_string(parts[1]); + if (entryId.isEmpty()) + return nullptr; + + PGPKey pub = getPubKey(entryId); + if (pub.isNull()) + return nullptr; + + // optional + const PGPKey sec = getSecKey(entryId, static_cast(pub.context())->_props.userIds); + + MyKeyStoreEntry *c = new MyKeyStoreEntry(pub, sec, provider()); + c->_storeId = storeId(0); + c->_storeName = name(0); + return c; +} + +// TODO: cache should reflect this change immediately +QString MyKeyStoreList::writeEntry(int, const PGPKey &key) +{ + const MyPGPKeyContext *kc = static_cast(key.context()); + const QByteArray buf = kc->toBinary(); + + GpgOp gpg(find_bin()); + gpg.doImport(buf); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) + return QString(); + + return kc->_props.keyId; +} + +// TODO: cache should reflect this change immediately +bool MyKeyStoreList::removeEntry(int, const QString &entryId) +{ + ringMutex.lock(); + PGPKey pub = getPubKey(entryId); + ringMutex.unlock(); + + const MyPGPKeyContext *kc = static_cast(pub.context()); + QString fingerprint = kc->_props.fingerprint; + + GpgOp gpg(find_bin()); + gpg.doDeleteKey(fingerprint); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + return gpg.success(); +} + +MyKeyStoreList *MyKeyStoreList::instance() +{ + QMutexLocker locker(ksl_mutex()); + return keyStoreList; +} + +void MyKeyStoreList::ext_keyStoreLog(const QString &str) +{ + if (str.isEmpty()) + return; + + // FIXME: collect and emit in one pass + QMetaObject::invokeMethod(this, "diagnosticText", Qt::QueuedConnection, Q_ARG(QString, str)); +} + +PGPKey MyKeyStoreList::getPubKey(const QString &keyId) const +{ + int at = -1; + for (int n = 0; n < pubkeys.count(); ++n) { + if (pubkeys[n].keyItems.first().id == keyId) { + at = n; + break; + } + } + if (at == -1) + return PGPKey(); + + const GpgOp::Key &pkey = pubkeys[at]; + + PGPKey pub; + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + // not secret, in keyring + kc->set(pkey, false, true, pkey.isTrusted); + pub.change(kc); + + return pub; +} + +PGPKey MyKeyStoreList::getSecKey(const QString &keyId, const QStringList &userIdsOverride) const +{ + Q_UNUSED(userIdsOverride); + + int at = -1; + for (int n = 0; n < seckeys.count(); ++n) { + if (seckeys[n].keyItems.first().id == keyId) { + at = n; + break; + } + } + if (at == -1) + return PGPKey(); + + const GpgOp::Key &skey = seckeys[at]; + + PGPKey sec; + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + // secret, in keyring, trusted + kc->set(skey, true, true, true); + // kc->_props.userIds = userIdsOverride; + sec.change(kc); + + return sec; +} + +PGPKey MyKeyStoreList::publicKeyFromId(const QString &keyId) +{ + QMutexLocker locker(&ringMutex); + + int at = -1; + for (int n = 0; n < pubkeys.count(); ++n) { + const GpgOp::Key &pkey = pubkeys[n]; + for (int k = 0; k < pkey.keyItems.count(); ++k) { + const GpgOp::KeyItem &ki = pkey.keyItems[k]; + if (ki.id == keyId) { + at = n; + break; + } + } + if (at != -1) + break; + } + if (at == -1) + return PGPKey(); + + const GpgOp::Key &pkey = pubkeys[at]; + + PGPKey pub; + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + // not secret, in keyring + kc->set(pkey, false, true, pkey.isTrusted); + pub.change(kc); + + return pub; +} + +PGPKey MyKeyStoreList::secretKeyFromId(const QString &keyId) +{ + QMutexLocker locker(&ringMutex); + + int at = -1; + for (int n = 0; n < seckeys.count(); ++n) { + const GpgOp::Key &skey = seckeys[n]; + for (int k = 0; k < skey.keyItems.count(); ++k) { + const GpgOp::KeyItem &ki = skey.keyItems[k]; + if (ki.id == keyId) { + at = n; + break; + } + } + if (at != -1) + break; + } + if (at == -1) + return PGPKey(); + + const GpgOp::Key &skey = seckeys[at]; + + PGPKey sec; + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + // secret, in keyring, trusted + kc->set(skey, true, true, true); + sec.change(kc); + + return sec; +} + +void MyKeyStoreList::gpg_finished() +{ + gpg_keyStoreLog(gpg.readDiagnosticText()); + + if (!initialized) { + // any steps that fail during init, just give up completely + if (!gpg.success()) { + ringWatch.clear(); + emit busyEnd(); + return; + } + + // check + if (init_step == 0) { + // obtain keyring file names for monitoring + init_step = 1; + homeDir = gpg.homeDir(); + gpg.doSecretKeyringFile(); + } + // secret keyring filename + else if (init_step == 1) { + secring = QFileInfo(gpg.keyringFile()).canonicalFilePath(); + + if (secring.isEmpty()) { + secring = homeDir + QStringLiteral("/secring.gpg"); + } + ringWatch.add(secring); + + // obtain keyring file names for monitoring + init_step = 2; + gpg.doPublicKeyringFile(); + } + // public keyring filename + else if (init_step == 2) { + pubring = QFileInfo(gpg.keyringFile()).canonicalFilePath(); + if (pubring.isEmpty()) { + pubring = homeDir + QStringLiteral("/pubring.gpg"); + } + ringWatch.add(pubring); + + // cache initial keyrings + init_step = 3; + gpg.doSecretKeys(); + } else if (init_step == 3) { + ringMutex.lock(); + seckeys = gpg.keys(); + ringMutex.unlock(); + + // cache initial keyrings + init_step = 4; + gpg.doPublicKeys(); + } else if (init_step == 4) { + ringMutex.lock(); + pubkeys = gpg.keys(); + ringMutex.unlock(); + + initialized = true; + handleDirtyRings(); + emit busyEnd(); + } + } else { + if (!gpg.success()) + return; + + const GpgOp::Type op = gpg.op(); + if (op == GpgOp::SecretKeys) { + ringMutex.lock(); + seckeys = gpg.keys(); + ringMutex.unlock(); + + secdirty = false; + } else if (op == GpgOp::PublicKeys) { + ringMutex.lock(); + pubkeys = gpg.keys(); + ringMutex.unlock(); + + pubdirty = false; + } + + if (!secdirty && !pubdirty) { + emit storeUpdated(0); + return; + } + + handleDirtyRings(); + } +} + +void MyKeyStoreList::ring_changed(const QString &filePath) +{ + ext_keyStoreLog(QStringLiteral("ring_changed: [%1]\n").arg(filePath)); + + if (filePath == secring) + sec_changed(); + else if (filePath == pubring) + pub_changed(); +} + +void MyKeyStoreList::pub_changed() +{ + pubdirty = true; + handleDirtyRings(); +} + +void MyKeyStoreList::sec_changed() +{ + secdirty = true; + handleDirtyRings(); +} + +void MyKeyStoreList::handleDirtyRings() +{ + if (!initialized || gpg.isActive()) + return; + + if (secdirty) + gpg.doSecretKeys(); + else if (pubdirty) + gpg.doPublicKeys(); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.h new file mode 100644 index 0000000000..6886f01006 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mykeystorelist.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "gpgop.h" +#include "mykeystoreentry.h" +#include "qcaprovider.h" +#include "ringwatch.h" +#include + +namespace gpgQCAPlugin { + +class MyKeyStoreList : public QCA::KeyStoreListContext +{ + Q_OBJECT +public: + int init_step; + bool initialized; + GpgOp gpg; + GpgOp::KeyList pubkeys, seckeys; + QString pubring, secring, homeDir; + bool pubdirty, secdirty; + RingWatch ringWatch; + QMutex ringMutex; + + MyKeyStoreList(QCA::Provider *p); + ~MyKeyStoreList() override; + + // reimplemented Provider::Context + QCA::Provider::Context *clone() const override; + + // reimplemented KeyStoreListContext + QString name(int) const override; + QCA::KeyStore::Type type(int) const override; + QString storeId(int) const override; + QList keyStores() override; + + void start() override; + + bool isReadOnly(int) const override; + + QList entryTypes(int) const override; + QList entryList(int) override; + QCA::KeyStoreEntryContext *entry(int, const QString &entryId) override; + QCA::KeyStoreEntryContext *entryPassive(const QString &serialized) override; + QString writeEntry(int, const QCA::PGPKey &key) override; + bool removeEntry(int, const QString &entryId) override; + + static MyKeyStoreList *instance(); + void ext_keyStoreLog(const QString &str); + + QCA::PGPKey getPubKey(const QString &keyId) const; + QCA::PGPKey getSecKey(const QString &keyId, const QStringList &userIdsOverride) const; + QCA::PGPKey publicKeyFromId(const QString &keyId); + QCA::PGPKey secretKeyFromId(const QString &keyId); + +private Q_SLOTS: + void gpg_finished(); + void ring_changed(const QString &filePath); + +private: + void pub_changed(); + void sec_changed(); + void handleDirtyRings(); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.cpp new file mode 100644 index 0000000000..6e16fc621f --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.cpp @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "mymessagecontext.h" +#include "mykeystorelist.h" +#include "mypgpkeycontext.h" +#include "utils.h" + +using namespace QCA; + +namespace gpgQCAPlugin { + +MyMessageContext::MyMessageContext(MyOpenPGPContext *_sms, Provider *p) + : MessageContext(p, QStringLiteral("pgpmsg")) + , sms(_sms) + , op(Sign) + , signMode(SecureMessage::Detached) + , format(SecureMessage::Ascii) + , wrote(0) + , ok(false) + , wasSigned(false) + , op_err(GpgOp::ErrorUnknown) + , gpg(find_bin()) + , _finished(false) +{ + connect(&gpg, &GpgOp::readyRead, this, &MyMessageContext::gpg_readyRead); + connect(&gpg, &GpgOp::bytesWritten, this, &MyMessageContext::gpg_bytesWritten); + connect(&gpg, &GpgOp::finished, this, &MyMessageContext::gpg_finished); + connect(&gpg, &GpgOp::needPassphrase, this, &MyMessageContext::gpg_needPassphrase); + connect(&gpg, &GpgOp::needCard, this, &MyMessageContext::gpg_needCard); + connect(&gpg, &GpgOp::readyReadDiagnosticText, this, &MyMessageContext::gpg_readyReadDiagnosticText); + + connect(&asker, &QCA::PasswordAsker::responseReady, this, &MyMessageContext::asker_responseReady); + connect(&tokenAsker, &QCA::TokenAsker::responseReady, this, &MyMessageContext::tokenAsker_responseReady); +} + +Provider::Context *MyMessageContext::clone() const +{ + return nullptr; +} + +bool MyMessageContext::canSignMultiple() const +{ + return false; +} + +SecureMessage::Type MyMessageContext::type() const +{ + return SecureMessage::OpenPGP; +} + +void MyMessageContext::reset() +{ + wrote = 0; + ok = false; + wasSigned = false; +} + +void MyMessageContext::setupEncrypt(const SecureMessageKeyList &keys) +{ + recipIds.clear(); + for (int n = 0; n < keys.count(); ++n) + recipIds += keys[n].pgpPublicKey().keyId(); +} + +void MyMessageContext::setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool, bool) +{ + signerId = keys.first().pgpSecretKey().keyId(); + signMode = m; +} + +void MyMessageContext::setupVerify(const QByteArray &detachedSig) +{ + sig = detachedSig; +} + +void MyMessageContext::start(SecureMessage::Format f, Operation op) +{ + _finished = false; + format = f; + this->op = op; + + if (getProperty(QStringLiteral("pgp-always-trust")).toBool()) + gpg.setAlwaysTrust(true); + + if (format == SecureMessage::Ascii) + gpg.setAsciiFormat(true); + else + gpg.setAsciiFormat(false); + + if (op == Encrypt) { + gpg.doEncrypt(recipIds); + } else if (op == Decrypt) { + gpg.doDecrypt(); + } else if (op == Sign) { + if (signMode == SecureMessage::Message) { + gpg.doSign(signerId); + } else if (signMode == SecureMessage::Clearsign) { + gpg.doSignClearsign(signerId); + } else // SecureMessage::Detached + { + gpg.doSignDetached(signerId); + } + } else if (op == Verify) { + if (!sig.isEmpty()) + gpg.doVerifyDetached(sig); + else + gpg.doDecrypt(); + } else if (op == SignAndEncrypt) { + gpg.doSignAndEncrypt(signerId, recipIds); + } +} + +void MyMessageContext::update(const QByteArray &in) +{ + gpg.write(in); + // this->in.append(in); +} + +QByteArray MyMessageContext::read() +{ + const QByteArray a = out; + out.clear(); + return a; +} + +int MyMessageContext::written() +{ + int x = wrote; + wrote = 0; + return x; +} + +void MyMessageContext::end() +{ + gpg.endWrite(); +} + +void MyMessageContext::seterror() +{ + gpg.reset(); + _finished = true; + ok = false; + op_err = GpgOp::ErrorUnknown; +} + +void MyMessageContext::complete() +{ + _finished = true; + + dtext = gpg.readDiagnosticText(); + + ok = gpg.success(); + if (ok) { + if (op == Sign && signMode == SecureMessage::Detached) + sig = gpg.read(); + else + out = gpg.read(); + } + + if (ok) { + if (gpg.wasSigned()) { + const QString signerId = gpg.signerId(); + const QDateTime ts = gpg.timestamp(); + const GpgOp::VerifyResult vr = gpg.verifyResult(); + + SecureMessageSignature::IdentityResult ir; + Validity v; + if (vr == GpgOp::VerifyGood) { + ir = SecureMessageSignature::Valid; + v = ValidityGood; + } else if (vr == GpgOp::VerifyBad) { + ir = SecureMessageSignature::InvalidSignature; + v = ValidityGood; // good key, bad sig + } else // GpgOp::VerifyNoKey + { + ir = SecureMessageSignature::NoKey; + v = ErrorValidityUnknown; + } + + SecureMessageKey key; + PGPKey pub = publicKeyFromId(signerId); + if (pub.isNull()) { + MyPGPKeyContext *kc = new MyPGPKeyContext(provider()); + kc->_props.keyId = signerId; + pub.change(kc); + } + key.setPGPPublicKey(pub); + + signer = SecureMessageSignature(ir, v, key, ts); + wasSigned = true; + } + } else + op_err = gpg.errorCode(); +} + +bool MyMessageContext::finished() const +{ + return _finished; +} + +bool MyMessageContext::waitForFinished(int msecs) +{ + // FIXME + Q_UNUSED(msecs); + MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); + + while (true) { + // TODO: handle token prompt events + + GpgOp::Event e = gpg.waitForEvent(-1); + if (e.type == GpgOp::Event::NeedPassphrase) { + // TODO + + QString keyId; + PGPKey sec = secretKeyFromId(e.keyId); + if (!sec.isNull()) + keyId = sec.keyId(); + else + keyId = e.keyId; + QStringList out; + out += escape_string(QStringLiteral("qca-gnupg-1")); + out += escape_string(keyId); + QString serialized = out.join(QStringLiteral(":")); + + KeyStoreEntry kse; + KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); + if (c) + kse.change(c); + + asker.ask(Event::StylePassphrase, + KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), + kse, + nullptr); + asker.waitForResponse(); + + if (!asker.accepted()) { + seterror(); + return true; + } + + gpg.submitPassphrase(asker.password()); + } else if (e.type == GpgOp::Event::NeedCard) { + tokenAsker.ask(KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), + KeyStoreEntry(), + nullptr); + + if (!tokenAsker.accepted()) { + seterror(); + return true; + } + + gpg.cardOkay(); + } else if (e.type == GpgOp::Event::Finished) + break; + } + + complete(); + return true; +} + +bool MyMessageContext::success() const +{ + return ok; +} + +SecureMessage::Error MyMessageContext::errorCode() const +{ + SecureMessage::Error e = SecureMessage::ErrorUnknown; + if (op_err == GpgOp::ErrorProcess) + e = SecureMessage::ErrorUnknown; + else if (op_err == GpgOp::ErrorPassphrase) + e = SecureMessage::ErrorPassphrase; + else if (op_err == GpgOp::ErrorFormat) + e = SecureMessage::ErrorFormat; + else if (op_err == GpgOp::ErrorSignerExpired) + e = SecureMessage::ErrorSignerExpired; + else if (op_err == GpgOp::ErrorSignerRevoked) + e = SecureMessage::ErrorSignerRevoked; + else if (op_err == GpgOp::ErrorSignatureExpired) + e = SecureMessage::ErrorSignatureExpired; + else if (op_err == GpgOp::ErrorEncryptExpired) + e = SecureMessage::ErrorEncryptExpired; + else if (op_err == GpgOp::ErrorEncryptRevoked) + e = SecureMessage::ErrorEncryptRevoked; + else if (op_err == GpgOp::ErrorEncryptUntrusted) + e = SecureMessage::ErrorEncryptUntrusted; + else if (op_err == GpgOp::ErrorEncryptInvalid) + e = SecureMessage::ErrorEncryptInvalid; + else if (op_err == GpgOp::ErrorDecryptNoKey) + e = SecureMessage::ErrorUnknown; + else if (op_err == GpgOp::ErrorUnknown) + e = SecureMessage::ErrorUnknown; + return e; +} + +QByteArray MyMessageContext::signature() const +{ + return sig; +} + +QString MyMessageContext::hashName() const +{ + // TODO + return QStringLiteral("sha1"); +} + +SecureMessageSignatureList MyMessageContext::signers() const +{ + SecureMessageSignatureList list; + if (ok && wasSigned) + list += signer; + return list; +} + +QString MyMessageContext::diagnosticText() const +{ + return dtext; +} + +void MyMessageContext::gpg_readyRead() +{ + emit updated(); +} + +void MyMessageContext::gpg_bytesWritten(int bytes) +{ + wrote += bytes; +} + +void MyMessageContext::gpg_finished() +{ + complete(); + emit updated(); +} + +void MyMessageContext::gpg_needPassphrase(const QString &in_keyId) +{ + // FIXME: copied from above, clean up later + + QString keyId; + PGPKey sec = secretKeyFromId(in_keyId); + if (!sec.isNull()) + keyId = sec.keyId(); + else + keyId = in_keyId; + // emit keyStoreList->storeNeedPassphrase(0, 0, keyId); + QStringList out; + out += escape_string(QStringLiteral("qca-gnupg-1")); + out += escape_string(keyId); + QString serialized = out.join(QStringLiteral(":")); + + KeyStoreEntry kse; + MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); + KeyStoreEntryContext *c = keyStoreList->entryPassive(serialized); + if (c) + kse.change(c); + + asker.ask(Event::StylePassphrase, + KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), + kse, + nullptr); +} + +void MyMessageContext::gpg_needCard() +{ + MyKeyStoreList *keyStoreList = MyKeyStoreList::instance(); + tokenAsker.ask( + KeyStoreInfo(KeyStore::PGPKeyring, keyStoreList->storeId(0), keyStoreList->name(0)), KeyStoreEntry(), nullptr); +} + +void MyMessageContext::gpg_readyReadDiagnosticText() +{ + // TODO ? +} + +void MyMessageContext::asker_responseReady() +{ + if (!asker.accepted()) { + seterror(); + emit updated(); + return; + } + + const SecureArray a = asker.password(); + gpg.submitPassphrase(a); +} + +void MyMessageContext::tokenAsker_responseReady() +{ + if (!tokenAsker.accepted()) { + seterror(); + emit updated(); + return; + } + + gpg.cardOkay(); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.h new file mode 100644 index 0000000000..2cc3646524 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mymessagecontext.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "gpgop.h" +#include "qcaprovider.h" + +namespace gpgQCAPlugin { + +class MyOpenPGPContext; + +class MyMessageContext : public QCA::MessageContext +{ + Q_OBJECT +public: + MyOpenPGPContext *sms; + + QString signerId; + QStringList recipIds; + QCA::MessageContext::Operation op; + QCA::SecureMessage::SignMode signMode; + QCA::SecureMessage::Format format; + QByteArray in, out, sig; + int wrote; + bool ok, wasSigned; + GpgOp::Error op_err; + QCA::SecureMessageSignature signer; + GpgOp gpg; + bool _finished; + QString dtext; + + QCA::PasswordAsker asker; + QCA::TokenAsker tokenAsker; + + MyMessageContext(MyOpenPGPContext *_sms, QCA::Provider *p); + + // reimplemented Provider::Context + QCA::Provider::Context *clone() const override; + + // reimplemented MessageContext + bool canSignMultiple() const override; + QCA::SecureMessage::Type type() const override; + void reset() override; + void setupEncrypt(const QCA::SecureMessageKeyList &keys) override; + void setupSign(const QCA::SecureMessageKeyList &keys, QCA::SecureMessage::SignMode m, bool, bool) override; + void setupVerify(const QByteArray &detachedSig) override; + void start(QCA::SecureMessage::Format f, QCA::MessageContext::Operation op) override; + void update(const QByteArray &in) override; + QByteArray read() override; + int written() override; + void end() override; + bool finished() const override; + bool waitForFinished(int msecs) override; + bool success() const override; + QCA::SecureMessage::Error errorCode() const override; + QByteArray signature() const override; + QString hashName() const override; + QCA::SecureMessageSignatureList signers() const override; + QString diagnosticText() const override; + + void seterror(); + void complete(); + +private Q_SLOTS: + void gpg_readyRead(); + void gpg_bytesWritten(int bytes); + void gpg_finished(); + void gpg_needPassphrase(const QString &in_keyId); + void gpg_needCard(); + void gpg_readyReadDiagnosticText(); + void asker_responseReady(); + void tokenAsker_responseReady(); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.cpp new file mode 100644 index 0000000000..2cdfff9d77 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "myopenpgpcontext.h" +#include "mymessagecontext.h" + +using namespace QCA; + +namespace gpgQCAPlugin { + +MyOpenPGPContext::MyOpenPGPContext(QCA::Provider *p) + : SMSContext(p, QStringLiteral("openpgp")) +{ + // TODO +} + +Provider::Context *MyOpenPGPContext::clone() const +{ + return nullptr; +} + +MessageContext *MyOpenPGPContext::createMessage() +{ + return new MyMessageContext(this, provider()); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.h new file mode 100644 index 0000000000..1399842cca --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/myopenpgpcontext.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "qcaprovider.h" + +namespace gpgQCAPlugin { + +class MyOpenPGPContext : public QCA::SMSContext +{ + Q_OBJECT +public: + MyOpenPGPContext(QCA::Provider *p); + + // reimplemented Provider::Context + QCA::Provider::Context *clone() const override; + + // reimplemented SMSContext + QCA::MessageContext *createMessage() override; +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.cpp new file mode 100644 index 0000000000..bcb758a8fe --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.cpp @@ -0,0 +1,202 @@ +#include "mypgpkeycontext.h" +#include "gpgop.h" +#include "utils.h" +#include +#include + +using namespace QCA; + +namespace gpgQCAPlugin { + +MyPGPKeyContext::MyPGPKeyContext(Provider *p) + : PGPKeyContext(p) +{ + // zero out the props + _props.isSecret = false; + _props.inKeyring = true; + _props.isTrusted = false; +} + +Provider::Context *MyPGPKeyContext::clone() const +{ + return new MyPGPKeyContext(*this); +} + +const PGPKeyContextProps *MyPGPKeyContext::props() const +{ + return &_props; +} + +QByteArray MyPGPKeyContext::toBinary() const +{ + if (_props.inKeyring) { + GpgOp gpg(find_bin()); + gpg.setAsciiFormat(false); + gpg.doExport(_props.keyId); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) + return QByteArray(); + return gpg.read(); + } else + return cacheExportBinary; +} + +ConvertResult MyPGPKeyContext::fromBinary(const QByteArray &a) +{ + GpgOp::Key key; + bool sec = false; + + // temporary keyrings + QString pubname, secname; + + QTemporaryFile pubtmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg")); + if (!pubtmp.open()) + return ErrorDecode; + + QTemporaryFile sectmp(QDir::tempPath() + QLatin1String("/qca_gnupg_tmp.XXXXXX.gpg")); + if (!sectmp.open()) + return ErrorDecode; + + pubname = pubtmp.fileName(); + secname = sectmp.fileName(); + + // we turn off autoRemove so that we can close the files + // without them getting deleted + pubtmp.setAutoRemove(false); + sectmp.setAutoRemove(false); + pubtmp.close(); + sectmp.close(); + + // import key into temporary keyring + GpgOp gpg(find_bin()); + gpg.setKeyrings(pubname, secname); + gpg.doImport(a); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + // comment this out. apparently gpg will report failure for + // an import if there are trust issues, even though the + // key actually did get imported + /*if(!gpg.success()) + { + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + }*/ + + // now extract the key from gpg like normal + + // is it a public key? + gpg.doPublicKeys(); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) { + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + } + + const GpgOp::KeyList pubkeys = gpg.keys(); + if (!pubkeys.isEmpty()) { + key = pubkeys.first(); + } else { + // is it a secret key? + gpg.doSecretKeys(); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) { + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + } + + const GpgOp::KeyList seckeys = gpg.keys(); + if (!seckeys.isEmpty()) { + key = seckeys.first(); + sec = true; + } else { + // no keys found + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + } + } + + // export binary/ascii and cache + + gpg.setAsciiFormat(false); + gpg.doExport(key.keyItems.first().id); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) { + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + } + cacheExportBinary = gpg.read(); + + gpg.setAsciiFormat(true); + gpg.doExport(key.keyItems.first().id); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) { + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + return ErrorDecode; + } + cacheExportAscii = QString::fromLocal8Bit(gpg.read()); + + // all done + + cleanup_temp_keyring(pubname); + cleanup_temp_keyring(secname); + + set(key, sec, false, false); + return ConvertGood; +} + +QString MyPGPKeyContext::toAscii() const +{ + if (_props.inKeyring) { + GpgOp gpg(find_bin()); + gpg.setAsciiFormat(true); + gpg.doExport(_props.keyId); + gpg_waitForFinished(&gpg); + gpg_keyStoreLog(gpg.readDiagnosticText()); + if (!gpg.success()) + return QString(); + return QString::fromLocal8Bit(gpg.read()); + } else { + return cacheExportAscii; + } +} + +ConvertResult MyPGPKeyContext::fromAscii(const QString &s) +{ + // GnuPG does ascii/binary detection for imports, so for + // simplicity we consider an ascii import to just be a + // binary import that happens to be comprised of ascii + return fromBinary(s.toLocal8Bit()); +} + +void MyPGPKeyContext::set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted) +{ + const GpgOp::KeyItem &ki = i.keyItems.first(); + + _props.keyId = ki.id; + _props.userIds = i.userIds; + _props.isSecret = isSecret; + _props.creationDate = ki.creationDate; + _props.expirationDate = ki.expirationDate; + _props.fingerprint = ki.fingerprint.toLower(); + _props.inKeyring = inKeyring; + _props.isTrusted = isTrusted; +} + +void MyPGPKeyContext::cleanup_temp_keyring(const QString &name) +{ + QFile::remove(name); + QFile::remove(name + QLatin1Char('~')); // remove possible backup file +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.h new file mode 100644 index 0000000000..7dcbdbee52 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/mypgpkeycontext.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "gpgop.h" +#include "qcaprovider.h" +#include "ringwatch.h" + +namespace gpgQCAPlugin { + +class MyPGPKeyContext : public QCA::PGPKeyContext +{ + Q_OBJECT +public: + QCA::PGPKeyContextProps _props; + + // keys loaded externally (not from the keyring) need to have these + // values cached, since we can't extract them later + QByteArray cacheExportBinary; + QString cacheExportAscii; + + MyPGPKeyContext(QCA::Provider *p); + + // reimplemented Provider::Context + QCA::Provider::Context *clone() const override; + + // reimplemented PGPKeyContext + const QCA::PGPKeyContextProps *props() const override; + + QByteArray toBinary() const override; + QCA::ConvertResult fromBinary(const QByteArray &a) override; + + QString toAscii() const override; + QCA::ConvertResult fromAscii(const QString &s) override; + + void set(const GpgOp::Key &i, bool isSecret, bool inKeyring, bool isTrusted); + static void cleanup_temp_keyring(const QString &name); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/qca-gnupg.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/qca-gnupg.cpp new file mode 100644 index 0000000000..548e8f6bba --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/qca-gnupg.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "mykeystorelist.h" +#include "myopenpgpcontext.h" +#include "mypgpkeycontext.h" +#include "qcaprovider.h" +#include + +using namespace gpgQCAPlugin; + +class gnupgProvider : public QCA::Provider +{ +public: + void init() override + { + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("qca-gnupg"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("pgpkey"); + list += QStringLiteral("openpgp"); + list += QStringLiteral("keystorelist"); + return list; + } + + Context *createContext(const QString &type) override + { + if (type == QLatin1String("pgpkey")) + return new MyPGPKeyContext(this); + else if (type == QLatin1String("openpgp")) + return new MyOpenPGPContext(this); + else if (type == QLatin1String("keystorelist")) + return new MyKeyStoreList(this); + else + return nullptr; + } +}; + +class gnupgPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + QCA::Provider *createProvider() override + { + return new gnupgProvider; + } +}; + +#include "qca-gnupg.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.cpp new file mode 100644 index 0000000000..da3b5cca6d --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// since keyring files are often modified by creating a new copy and +// overwriting the original file, this messes up Qt's file watching +// capability since the original file goes away. to work around this +// problem, we'll watch the directories containing the keyring files +// instead of watching the actual files themselves. +// +// FIXME: qca 2.0.1 FileWatch has this logic already, so we can probably +// simplify this class. + +#include "ringwatch.h" +#include "qca_safetimer.h" +#include "qca_support.h" +#include + +using namespace QCA; + +namespace gpgQCAPlugin { + +RingWatch::RingWatch(QObject *parent) + : QObject(parent) +{ +} + +RingWatch::~RingWatch() +{ + clear(); +} + +void RingWatch::add(const QString &filePath) +{ + QFileInfo fi(filePath); + // Try to avoid symbolic links + QString path = fi.canonicalPath(); + if (path.isEmpty()) + path = fi.absolutePath(); + + // watching this path already? + DirWatch *dirWatch = nullptr; + foreach (const DirItem &di, dirs) { + if (di.dirWatch->dirName() == path) { + dirWatch = di.dirWatch; + break; + } + } + + // if not, make a watcher + if (!dirWatch) { + // printf("creating dirwatch for [%s]\n", qPrintable(path)); + + DirItem di; + di.dirWatch = new DirWatch(path, this); + connect(di.dirWatch, &DirWatch::changed, this, &RingWatch::dirChanged); + + di.changeTimer = new SafeTimer(this); + di.changeTimer->setSingleShot(true); + connect(di.changeTimer, &SafeTimer::timeout, this, &RingWatch::handleChanged); + + dirWatch = di.dirWatch; + dirs += di; + } + + FileItem i; + i.dirWatch = dirWatch; + i.fileName = fi.fileName(); + i.exists = fi.exists(); + if (i.exists) { + i.size = fi.size(); + i.lastModified = fi.lastModified(); + } + files += i; + + // printf("watching [%s] in [%s]\n", qPrintable(fi.fileName()), qPrintable(i.dirWatch->dirName())); +} + +void RingWatch::clear() +{ + files.clear(); + + foreach (const DirItem &di, dirs) { + delete di.changeTimer; + delete di.dirWatch; + } + + dirs.clear(); +} + +void RingWatch::dirChanged() +{ + DirWatch *dirWatch = (DirWatch *)sender(); + + int at = -1; + for (int n = 0; n < dirs.count(); ++n) { + if (dirs[n].dirWatch == dirWatch) { + at = n; + break; + } + } + if (at == -1) + return; + + // we get a ton of change notifications for the dir when + // something happens.. let's collect them and only + // report after 100ms + + if (!dirs[at].changeTimer->isActive()) + dirs[at].changeTimer->start(100); +} + +void RingWatch::handleChanged() +{ + SafeTimer *t = (SafeTimer *)sender(); + + int at = -1; + for (int n = 0; n < dirs.count(); ++n) { + if (dirs[n].changeTimer == t) { + at = n; + break; + } + } + if (at == -1) + return; + + DirWatch *dirWatch = dirs[at].dirWatch; + const QString dir = dirWatch->dirName(); + + // see which files changed + QStringList changeList; + for (int n = 0; n < files.count(); ++n) { + FileItem &i = files[n]; + QString filePath = dir + QLatin1Char('/') + i.fileName; + QFileInfo fi(filePath); + + // if the file didn't exist, and still doesn't, skip + if (!i.exists && !fi.exists()) + continue; + + // size/lastModified should only get checked here if + // the file existed and still exists + if (fi.exists() != i.exists || fi.size() != i.size || fi.lastModified() != i.lastModified) { + changeList += filePath; + + i.exists = fi.exists(); + if (i.exists) { + i.size = fi.size(); + i.lastModified = fi.lastModified(); + } + } + } + + foreach (const QString &s, changeList) + emit changed(s); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.h new file mode 100644 index 0000000000..6b56a6f361 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/ringwatch.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + +namespace QCA { + +class SafeTimer; +class DirWatch; + +} + +namespace gpgQCAPlugin { + +class RingWatch : public QObject +{ + Q_OBJECT +public: + class DirItem + { + public: + QCA::DirWatch *dirWatch; + QCA::SafeTimer *changeTimer; + }; + + class FileItem + { + public: + QCA::DirWatch *dirWatch; + QString fileName; + bool exists; + qint64 size; + QDateTime lastModified; + }; + + QList dirs; + QList files; + + RingWatch(QObject *parent = nullptr); + ~RingWatch() override; + + void add(const QString &filePath); + void clear(); + +Q_SIGNALS: + void changed(const QString &filePath); + +private Q_SLOTS: + void dirChanged(); + void handleChanged(); +}; + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.cpp b/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.cpp new file mode 100644 index 0000000000..d571822eff --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * Copyright (C) 2014 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "utils.h" +#include "mykeystorelist.h" +#include +#include +#include +#ifdef Q_OS_WIN +#include +#endif + +using namespace QCA; + +namespace gpgQCAPlugin { + +void gpg_waitForFinished(GpgOp *gpg) +{ + while (true) { + GpgOp::Event e = gpg->waitForEvent(-1); + if (e.type == GpgOp::Event::Finished) + break; + } +} + +void gpg_keyStoreLog(const QString &str) +{ + MyKeyStoreList *ksl = MyKeyStoreList::instance(); + if (ksl) + ksl->ext_keyStoreLog(str); +} + +inline bool check_bin(const QString &bin) +{ + QFileInfo fi(bin); + return fi.exists(); +} + +#ifdef Q_OS_WIN +static bool get_reg_key(HKEY root, const char *path, QString &value) +{ + HKEY hkey = 0; + + char szValue[256]; + DWORD dwLen = 256; + + bool res = false; + + if (RegOpenKeyExA(root, path, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { + if (RegQueryValueExA(hkey, "Install Directory", NULL, NULL, (LPBYTE)szValue, &dwLen) == ERROR_SUCCESS) { + value = QString::fromLocal8Bit(szValue); + res = true; + } + RegCloseKey(hkey); + } + return res; +} + +static QString find_reg_gpgProgram() +{ + const QStringList bins = {QStringLiteral("gpg.exe"), QStringLiteral("gpg2.exe")}; + + HKEY root; + root = HKEY_CURRENT_USER; + + const char *path = "Software\\GNU\\GnuPG"; + const char *path2 = "Software\\Wow6432Node\\GNU\\GnuPG"; + + QString dir; + // check list of possible places in registry + get_reg_key(HKEY_CURRENT_USER, path, dir) || get_reg_key(HKEY_CURRENT_USER, path2, dir) || + get_reg_key(HKEY_LOCAL_MACHINE, path, dir) || get_reg_key(HKEY_LOCAL_MACHINE, path2, dir); + + if (!dir.isEmpty()) { + foreach (const QString &bin, bins) { + if (check_bin(dir + QStringLiteral("\\") + bin)) { + return dir + QStringLiteral("\\") + bin; + } + } + } + return QString(); +} +#endif + +QString find_bin() +{ + // gpg and gpg2 has identical semantics + // so any from them can be used + QStringList bins; +#ifdef Q_OS_WIN + bins << QStringLiteral("gpg.exe") << QStringLiteral("gpg2.exe"); +#else + bins << QStringLiteral("gpg") << QStringLiteral("gpg2"); +#endif + + // Prefer bundled gpg + foreach (const QString &bin, bins) { + if (check_bin(QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin)) { + return QCoreApplication::applicationDirPath() + QLatin1Char('/') + bin; + } + } + +#ifdef Q_OS_WIN + // On Windows look up at registry + QString bin = find_reg_gpgProgram(); + if (!bin.isEmpty()) + return bin; +#endif + +#ifdef Q_OS_WIN + const QString pathSep = QStringLiteral(";"); +#else + const QString pathSep = QStringLiteral(":"); +#endif + + // Look up at PATH environment + QStringList paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSep, Qt::SkipEmptyParts); + +#ifdef Q_OS_MAC + // On Mac OS bundled always uses system default PATH + // so it need explicity add extra paths which can + // contain gpg + // Mac GPG and brew use /usr/local/bin + // MacPorts uses /opt/local/bin + paths << QStringLiteral("/usr/local/bin") << QStringLiteral("/opt/local/bin"); +#endif + paths.removeDuplicates(); + + foreach (const QString &path, paths) { + foreach (const QString &bin, bins) { + if (check_bin(path + QLatin1Char('/') + bin)) { + return path + QLatin1Char('/') + bin; + } + } + } + + // Return nothing if gpg not found + return QString(); +} + +QString escape_string(const QString &in) +{ + QString out; + for (const QChar &c : in) { + if (c == QLatin1Char('\\')) + out += QStringLiteral("\\\\"); + else if (c == QLatin1Char(':')) + out += QStringLiteral("\\c"); + else + out += c; + } + return out; +} + +QString unescape_string(const QString &in) +{ + QString out; + for (int n = 0; n < in.length(); ++n) { + if (in[n] == QLatin1Char('\\')) { + if (n + 1 < in.length()) { + if (in[n + 1] == QLatin1Char('\\')) + out += QLatin1Char('\\'); + else if (in[n + 1] == QLatin1Char('c')) + out += QLatin1Char(':'); + ++n; + } + } else + out += in[n]; + } + return out; +} + +PGPKey publicKeyFromId(const QString &id) +{ + MyKeyStoreList *ksl = MyKeyStoreList::instance(); + if (!ksl) + return PGPKey(); + + return ksl->publicKeyFromId(id); +} + +PGPKey secretKeyFromId(const QString &id) +{ + MyKeyStoreList *ksl = MyKeyStoreList::instance(); + if (!ksl) + return PGPKey(); + + return ksl->secretKeyFromId(id); +} + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.h b/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.h new file mode 100644 index 0000000000..3069838b89 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-gnupg/utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * Copyright (C) 2014 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "qca_cert.h" +#include + +namespace gpgQCAPlugin { + +class GpgOp; +void gpg_waitForFinished(GpgOp *gpg); +void gpg_keyStoreLog(const QString &str); +QString find_bin(); +QString escape_string(const QString &in); +QString unescape_string(const QString &in); +QCA::PGPKey publicKeyFromId(const QString &id); +QCA::PGPKey secretKeyFromId(const QString &id); + +} // end namespace gpgQCAPlugin diff --git a/local/recipes/libs/qca/source/plugins/qca-logger/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-logger/CMakeLists.txt new file mode 100644 index 0000000000..c9734c1599 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-logger/CMakeLists.txt @@ -0,0 +1,24 @@ +# qca-logger + +enable_plugin("logger") +set(QCA_LOGGER_SOURCES qca-logger.cpp) + +add_library(qca-logger ${PLUGIN_TYPE} ${QCA_LOGGER_SOURCES}) + +if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-logger PROPERTY SUFFIX ".dylib") +endif() + +add_definitions(${LOGGERH_DEFINITIONS}) +include_directories(${LOGGERH_INCLUDE_DIR}) +target_link_libraries(qca-logger Qt${QT_MAJOR_VERSION}::Core) +target_link_libraries(qca-logger ${QCA_LIB_NAME}) + +if(NOT DEVELOPER_MODE) + install(TARGETS qca-logger + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-logger ${QCA_CRYPTO_INSTALL_DIR}) +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-logger/COPYING b/local/recipes/libs/qca/source/plugins/qca-logger/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-logger/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-logger/README b/local/recipes/libs/qca/source/plugins/qca-logger/README new file mode 100644 index 0000000000..441afe38f7 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-logger/README @@ -0,0 +1,49 @@ +qca-logger 2.0.0 -- Logger Plug-in to QCA + +ABOUT + qca-logger provides simple logger writer for QCA framework. + +DEPENDENCIES + None. + +INSTALL + For Unix/Linux/Mac: + ./configure + make + make install + + For Windows: + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + +ENVIRONMENT + Configuration can be overridden by environment variables. + + Variables: + QCALOGGER_LEVEL + qca-logger log level. + + QCALOGGER_FILE + File to write to, if empty stderr will be used. + +CONFIGURATION + Configuration is stored at ~/.config/Affinix/QCA.conf, in order to + generate default configuration use: + + $ qcatool config save qca-logger + + Attributes: + enabled (Boolean) + Enable/disable the plugin. + + file (String) + File to write into, if empty stderr will be used. + + level (Integer) + Log level 0 least. + +AUTHORS + Alon Bar-Lev + diff --git a/local/recipes/libs/qca/source/plugins/qca-logger/qca-logger.cpp b/local/recipes/libs/qca/source/plugins/qca-logger/qca-logger.cpp new file mode 100644 index 0000000000..7847b2d139 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-logger/qca-logger.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2007 Alon Bar-Lev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include +#include +#include + +#include + +using namespace QCA; + +namespace loggerQCAPlugin { + +class StreamLogger : public QCA::AbstractLogDevice +{ + Q_OBJECT +public: + StreamLogger(QTextStream &stream) + : QCA::AbstractLogDevice(QStringLiteral("Stream logger")) + , _stream(stream) + { + QCA::logger()->registerLogDevice(this); + } + + ~StreamLogger() override + { + QCA::logger()->unregisterLogDevice(name()); + } + + void logTextMessage(const QString &message, enum QCA::Logger::Severity severity) override + { + _stream << now() << " " << severityName(severity) << " " << message << Qt::endl; + } + + void logBinaryMessage(const QByteArray &blob, enum QCA::Logger::Severity severity) override + { + Q_UNUSED(blob); + _stream << now() << " " << severityName(severity) << " " + << "Binary blob not implemented yet" << Qt::endl; + } + +private: + inline const char *severityName(enum QCA::Logger::Severity severity) + { + if (severity <= QCA::Logger::Debug) { + return s_severityNames[severity]; + } else { + return s_severityNames[QCA::Logger::Debug + 1]; + } + } + + inline QString now() + { + static const QString format = QStringLiteral("yyyy-MM-dd hh:mm:ss"); + return QDateTime::currentDateTime().toString(format); + } + +private: + static const char *s_severityNames[]; + QTextStream &_stream; +}; + +const char *StreamLogger::s_severityNames[] = {"Q", "M", "A", "C", "E", "W", "N", "I", "D", "U"}; + +} + +using namespace loggerQCAPlugin; + +class loggerProvider : public Provider +{ +private: + QFile _logFile; + QTextStream _logStream; + StreamLogger *_streamLogger; + bool _externalConfig; + +public: + loggerProvider() + { + _externalConfig = false; + _streamLogger = nullptr; + + const QByteArray level = qgetenv("QCALOGGER_LEVEL"); + const QByteArray file = qgetenv("QCALOGGER_FILE"); + + if (!level.isEmpty()) { + printf("XXXX %s %s\n", level.data(), file.data()); + _externalConfig = true; + createLogger(atoi(level.constData()), file.isEmpty() ? QString() : QString::fromUtf8(file)); + } + } + + ~loggerProvider() override + { + delete _streamLogger; + _streamLogger = nullptr; + } + +public: + int qcaVersion() const override + { + return QCA_VERSION; + } + + void init() override + { + } + + QString name() const override + { + return QStringLiteral("qca-logger"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("log"); + return list; + } + + Context *createContext(const QString &type) override + { + Q_UNUSED(type); + return nullptr; + } + + QVariantMap defaultConfig() const override + { + QVariantMap mytemplate; + + mytemplate[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/qca-logger#1.0"); + mytemplate[QStringLiteral("enabled")] = false; + mytemplate[QStringLiteral("file")] = QLatin1String(""); + mytemplate[QStringLiteral("level")] = (int)Logger::Quiet; + + return mytemplate; + } + + void configChanged(const QVariantMap &config) override + { + if (!_externalConfig) { + delete _streamLogger; + _streamLogger = nullptr; + + if (config[QStringLiteral("enabled")].toBool()) { + createLogger(config[QStringLiteral("level")].toInt(), config[QStringLiteral("file")].toString()); + } + } + } + +private: + void createLogger(const int level, const QString &file) + { + bool success = false; + if (file.isEmpty()) { + success = _logFile.open(stderr, QIODevice::WriteOnly | QIODevice::Text | QIODevice::Unbuffered); + } else { + _logFile.setFileName(file); + success = _logFile.open(QIODevice::Append | QIODevice::Text | QIODevice::Unbuffered); + } + + if (success) { + _logStream.setDevice(&_logFile); + logger()->setLevel((Logger::Severity)level); + _streamLogger = new StreamLogger(_logStream); + } + } +}; + +class loggerPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) + +public: + Provider *createProvider() override + { + return new loggerProvider; + } +}; + +#include "qca-logger.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-nss/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-nss/CMakeLists.txt new file mode 100644 index 0000000000..201f351c9d --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-nss/CMakeLists.txt @@ -0,0 +1,30 @@ +find_package(PkgConfig REQUIRED) +if(WITH_nss_PLUGIN STREQUAL "yes") + pkg_check_modules(NSS REQUIRED IMPORTED_TARGET nss) +else() + pkg_check_modules(NSS IMPORTED_TARGET nss) +endif() + +if(NSS_FOUND) + enable_plugin("nss") + + set(QCA_NSS_SOURCES qca-nss.cpp) + add_library(qca-nss ${PLUGIN_TYPE} ${QCA_NSS_SOURCES}) + target_link_libraries(qca-nss Qt${QT_MAJOR_VERSION}::Core ${QCA_LIB_NAME} PkgConfig::NSS) + + if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-nss PROPERTY SUFFIX ".dylib") + endif() + + if(NOT DEVELOPER_MODE) + install(TARGETS qca-nss + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-nss ${QCA_CRYPTO_INSTALL_DIR}) + endif() +else() + disable_plugin("nss") + set(WITH_nss_PLUGIN "no" PARENT_SCOPE) +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-nss/COPYING b/local/recipes/libs/qca/source/plugins/qca-nss/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-nss/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-nss/README b/local/recipes/libs/qca/source/plugins/qca-nss/README new file mode 100644 index 0000000000..40d3caa97b --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-nss/README @@ -0,0 +1,16 @@ +QCA Mozilla NSS plugin +---------------------- +Author: Brad Hards + +This plugin provides features based on Mozilla NSS. It implements: +* Hashing + + +Requirements: + Recent version of NSS. + +Installation procedure: + ./configure + make + su -c "make install" + diff --git a/local/recipes/libs/qca/source/plugins/qca-nss/qca-nss.cpp b/local/recipes/libs/qca/source/plugins/qca-nss/qca-nss.cpp new file mode 100644 index 0000000000..5e1dc1dec9 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-nss/qca-nss.cpp @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ +#include "hasht.h" +#include "nss.h" +#include "pk11func.h" + +#include + +#include +#include +#include + +//----------------------------------------------------------- +class nssHashContext : public QCA::HashContext +{ + Q_OBJECT +public: + nssHashContext(QCA::Provider *p, const QString &type) + : QCA::HashContext(p, type) + { + SECStatus s; + + NSS_NoDB_Init("."); + + m_status = 0; + + /* Get a slot to use for the crypto operations */ + m_slot = PK11_GetInternalKeySlot(); + if (!m_slot) { + qDebug() << "GetInternalKeySlot failed"; + m_status = 1; + return; + } + + if (QLatin1String("md2") == type) { + m_hashAlgo = SEC_OID_MD2; + } else if (QLatin1String("md5") == type) { + m_hashAlgo = SEC_OID_MD5; + } else if (QLatin1String("sha1") == type) { + m_hashAlgo = SEC_OID_SHA1; + } else if (QLatin1String("sha256") == type) { + m_hashAlgo = SEC_OID_SHA256; + } else if (QLatin1String("sha384") == type) { + m_hashAlgo = SEC_OID_SHA384; + } else if (QLatin1String("sha512") == type) { + m_hashAlgo = SEC_OID_SHA512; + } else { + qDebug() << "Unknown provider type: " << type; + return; /* this will probably cause a segfault... */ + } + + m_context = PK11_CreateDigestContext(m_hashAlgo); + if (!m_context) { + qDebug() << "CreateDigestContext failed"; + return; + } + + s = PK11_DigestBegin(m_context); + if (s != SECSuccess) { + qDebug() << "DigestBegin failed"; + return; + } + } + + ~nssHashContext() override + { + PK11_DestroyContext(m_context, PR_TRUE); + if (m_slot) + PK11_FreeSlot(m_slot); + } + + Context *clone() const override + { + return new nssHashContext(provider(), type()); + } + + void clear() override + { + SECStatus s; + + PK11_DestroyContext(m_context, PR_TRUE); + + m_context = PK11_CreateDigestContext(m_hashAlgo); + if (!m_context) { + qDebug() << "CreateDigestContext failed"; + return; + } + + s = PK11_DigestBegin(m_context); + if (s != SECSuccess) { + qDebug() << "DigestBegin failed"; + return; + } + } + + void update(const QCA::MemoryRegion &a) override + { + PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size()); + } + + QCA::MemoryRegion final() override + { + unsigned int len = 0; + QCA::SecureArray a(64); + PK11_DigestFinal(m_context, (unsigned char *)a.data(), &len, a.size()); + a.resize(len); + return a; + } + +private: + PK11SlotInfo *m_slot; + int m_status; + PK11Context *m_context; + SECOidTag m_hashAlgo; +}; + +//----------------------------------------------------------- +class nssHmacContext : public QCA::MACContext +{ + Q_OBJECT +public: + nssHmacContext(QCA::Provider *p, const QString &type) + : QCA::MACContext(p, type) + { + NSS_NoDB_Init("."); + + m_context = nullptr; + m_status = 0; + + /* Get a slot to use for the crypto operations */ + m_slot = PK11_GetInternalKeySlot(); + if (!m_slot) { + qDebug() << "GetInternalKeySlot failed"; + m_status = 1; + return; + } + + if (QLatin1String("hmac(md5)") == type) { + m_macAlgo = CKM_MD5_HMAC; + } else if (QLatin1String("hmac(sha1)") == type) { + m_macAlgo = CKM_SHA_1_HMAC; + } else if (QLatin1String("hmac(sha256)") == type) { + m_macAlgo = CKM_SHA256_HMAC; + } else if (QLatin1String("hmac(sha384)") == type) { + m_macAlgo = CKM_SHA384_HMAC; + } else if (QLatin1String("hmac(sha512)") == type) { + m_macAlgo = CKM_SHA512_HMAC; + } else if (QLatin1String("hmac(ripemd160)") == type) { + m_macAlgo = CKM_RIPEMD160_HMAC; + } else { + qDebug() << "Unknown provider type: " << type; + return; /* this will probably cause a segfault... */ + } + } + + ~nssHmacContext() override + { + if (m_context) + PK11_DestroyContext(m_context, PR_TRUE); + if (m_slot) + PK11_FreeSlot(m_slot); + } + + Context *clone() const override + { + return new nssHmacContext(provider(), type()); + } + + void clear() + { + PK11_DestroyContext(m_context, PR_TRUE); + + SECItem noParams; + noParams.data = nullptr; + noParams.len = 0; + + m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams); + if (!m_context) { + qDebug() << "CreateContextBySymKey failed"; + return; + } + + SECStatus s = PK11_DigestBegin(m_context); + if (s != SECSuccess) { + qDebug() << "DigestBegin failed"; + return; + } + } + + QCA::KeyLength keyLength() const override + { + return anyKeyLength(); + } + + void setup(const QCA::SymmetricKey &key) override + { + /* turn the raw key into a SECItem */ + SECItem keyItem; + keyItem.data = (unsigned char *)key.data(); + keyItem.len = key.size(); + + m_nssKey = PK11_ImportSymKey(m_slot, m_macAlgo, PK11_OriginUnwrap, CKA_SIGN, &keyItem, nullptr); + + SECItem noParams; + noParams.data = nullptr; + noParams.len = 0; + + m_context = PK11_CreateContextBySymKey(m_macAlgo, CKA_SIGN, m_nssKey, &noParams); + if (!m_context) { + qDebug() << "CreateContextBySymKey failed"; + return; + } + + SECStatus s = PK11_DigestBegin(m_context); + if (s != SECSuccess) { + qDebug() << "DigestBegin failed"; + return; + } + } + + void update(const QCA::MemoryRegion &a) override + { + PK11_DigestOp(m_context, (const unsigned char *)a.data(), a.size()); + } + + void final(QCA::MemoryRegion *out) override + { + // NSS doesn't appear to be able to tell us how big the digest will + // be for a given algorithm until after we finalise it, so we work + // around the problem a bit. + QCA::SecureArray sa(HASH_LENGTH_MAX, 0); // assume the biggest hash size we know + unsigned int len = 0; + PK11_DigestFinal(m_context, (unsigned char *)sa.data(), &len, sa.size()); + sa.resize(len); // and fix it up later + *out = sa; + } + +private: + PK11SlotInfo *m_slot; + int m_status; + PK11Context *m_context; + CK_MECHANISM_TYPE m_macAlgo; + PK11SymKey *m_nssKey; +}; + +//----------------------------------------------------------- +class nssCipherContext : public QCA::CipherContext +{ + Q_OBJECT +public: + nssCipherContext(QCA::Provider *p, const QString &type) + : QCA::CipherContext(p, type) + { + NSS_NoDB_Init("."); + + if (QLatin1String("aes128-ecb") == type) { + m_cipherMechanism = CKM_AES_ECB; + } else if (QLatin1String("aes128-cbc") == type) { + m_cipherMechanism = CKM_AES_CBC; + } else if (QLatin1String("des-ecb") == type) { + m_cipherMechanism = CKM_DES_ECB; + } else if (QLatin1String("des-cbc") == type) { + m_cipherMechanism = CKM_DES_CBC; + } else if (QLatin1String("des-cbc-pkcs7") == type) { + m_cipherMechanism = CKM_DES_CBC_PAD; + } else if (QLatin1String("tripledes-ecb") == type) { + m_cipherMechanism = CKM_DES3_ECB; + } else { + qDebug() << "Unknown provider type: " << type; + return; /* this will probably cause a segfault... */ + } + } + + ~nssCipherContext() override + { + } + + void setup(QCA::Direction dir, + const QCA::SymmetricKey &key, + const QCA::InitializationVector &iv, + const QCA::AuthTag &tag) override + { + Q_UNUSED(tag); + /* Get a slot to use for the crypto operations */ + m_slot = PK11_GetBestSlot(m_cipherMechanism, nullptr); + if (!m_slot) { + qDebug() << "GetBestSlot failed"; + return; + } + + /* turn the raw key into a SECItem */ + SECItem keyItem; + keyItem.data = (unsigned char *)key.data(); + keyItem.len = key.size(); + + if (QCA::Encode == dir) { + m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr); + } else { + // decryption + m_nssKey = PK11_ImportSymKey(m_slot, m_cipherMechanism, PK11_OriginUnwrap, CKA_DECRYPT, &keyItem, nullptr); + } + + SECItem ivItem; + ivItem.data = (unsigned char *)iv.data(); + ivItem.len = iv.size(); + + m_params = PK11_ParamFromIV(m_cipherMechanism, &ivItem); + + if (QCA::Encode == dir) { + m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_ENCRYPT, m_nssKey, m_params); + } else { + // decryption + m_context = PK11_CreateContextBySymKey(m_cipherMechanism, CKA_DECRYPT, m_nssKey, m_params); + } + + if (!m_context) { + qDebug() << "CreateContextBySymKey failed"; + return; + } + } + + QCA::Provider::Context *clone() const override + { + return new nssCipherContext(*this); + } + + int blockSize() const override + { + return PK11_GetBlockSize(m_cipherMechanism, m_params); + } + + QCA::AuthTag tag() const override + { + // For future implementation + return QCA::AuthTag(); + } + + bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override + { + out->resize(in.size() + blockSize()); + int resultLength; + + PK11_CipherOp( + m_context, (unsigned char *)out->data(), &resultLength, out->size(), (unsigned char *)in.data(), in.size()); + out->resize(resultLength); + + return true; + } + + bool final(QCA::SecureArray *out) override + { + out->resize(blockSize()); + unsigned int resultLength; + + PK11_DigestFinal(m_context, (unsigned char *)out->data(), &resultLength, out->size()); + out->resize(resultLength); + + return true; + } + + QCA::KeyLength keyLength() const override + { + int min = 0; + int max = 0; + int multiple = 0; + + switch (m_cipherMechanism) { + case CKM_AES_ECB: + case CKM_AES_CBC: + min = max = 16; + multiple = 1; + break; + + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_CBC_PAD: + min = max = 8; + multiple = 1; + break; + + case CKM_DES3_ECB: + min = 16; + max = 24; + multiple = 1; + break; + } + + return QCA::KeyLength(min, max, multiple); + } + +private: + PK11SymKey *m_nssKey; + CK_MECHANISM_TYPE m_cipherMechanism; + PK11SlotInfo *m_slot; + PK11Context *m_context; + SECItem *m_params; +}; + +//========================================================== +class nssProvider : public QCA::Provider +{ +public: + void init() override + { + } + + ~nssProvider() override + { + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("qca-nss"); + } + + QStringList features() const override + { + QStringList list; + + list += QStringLiteral("md2"); + list += QStringLiteral("md5"); + list += QStringLiteral("sha1"); + list += QStringLiteral("sha256"); + list += QStringLiteral("sha384"); + list += QStringLiteral("sha512"); + + list += QStringLiteral("hmac(md5)"); + list += QStringLiteral("hmac(sha1)"); + list += QStringLiteral("hmac(sha256)"); + list += QStringLiteral("hmac(sha384)"); + list += QStringLiteral("hmac(sha512)"); + // appears to not be implemented in NSS yet + // list += QStringLiteral("hmac(ripemd160)"); + + list += QStringLiteral("aes128-ecb"); + list += QStringLiteral("aes128-cbc"); + list += QStringLiteral("des-ecb"); + list += QStringLiteral("des-cbc"); + list += QStringLiteral("des-cbc-pkcs7"); + list += QStringLiteral("tripledes-ecb"); + + return list; + } + + Context *createContext(const QString &type) override + { + if (type == QLatin1String("md2")) + return new nssHashContext(this, type); + if (type == QLatin1String("md5")) + return new nssHashContext(this, type); + if (type == QLatin1String("sha1")) + return new nssHashContext(this, type); + if (type == QLatin1String("sha256")) + return new nssHashContext(this, type); + if (type == QLatin1String("sha384")) + return new nssHashContext(this, type); + if (type == QLatin1String("sha512")) + return new nssHashContext(this, type); + + if (type == QLatin1String("hmac(md5)")) + return new nssHmacContext(this, type); + if (type == QLatin1String("hmac(sha1)")) + return new nssHmacContext(this, type); + if (type == QLatin1String("hmac(sha256)")) + return new nssHmacContext(this, type); + if (type == QLatin1String("hmac(sha384)")) + return new nssHmacContext(this, type); + if (type == QLatin1String("hmac(sha512)")) + return new nssHmacContext(this, type); + if (type == QLatin1String("hmac(ripemd160)")) + return new nssHmacContext(this, type); + + if (type == QLatin1String("aes128-ecb")) + return new nssCipherContext(this, type); + if (type == QLatin1String("aes128-cbc")) + return new nssCipherContext(this, type); + if (type == QLatin1String("des-ecb")) + return new nssCipherContext(this, type); + if (type == QLatin1String("des-cbc")) + return new nssCipherContext(this, type); + if (type == QLatin1String("des-cbc-pkcs7")) + return new nssCipherContext(this, type); + if (type == QLatin1String("tripledes-ecb")) + return new nssCipherContext(this, type); + else + return nullptr; + } +}; + +class nssPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + QCA::Provider *createProvider() override + { + return new nssProvider; + } +}; + +#include "qca-nss.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-nss/qcextra b/local/recipes/libs/qca/source/plugins/qca-nss/qcextra new file mode 100755 index 0000000000..fef4f18bcd --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-nss/qcextra @@ -0,0 +1,9 @@ +#!/bin/sh + +cat >extra.pri < + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-ossl/README b/local/recipes/libs/qca/source/plugins/qca-ossl/README new file mode 100644 index 0000000000..a2bd6148ae --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-ossl/README @@ -0,0 +1,39 @@ +QCA OSSL plugin version 2.0.0 +----------------------------- +Date: October 11th, 2007 +Website: http://delta.affinix.com/qca/ +Mailing List: Delta Project + +Authors: + Justin Karneges + Brad Hards + +This plugin provides features based on OpenSSL. It implements: +* Hashing - SHA1, SHA0, RIPEMD160, MD2, MD4, MD5 +* Hashing - SHA224, SHA256, SHA384 and SHA512 (for openssl 0.9.8) +* Block Ciphers +* Keyed Hash Message Authentication Code (HMAC), using SHA1, MD5, RIPEMD160 +* Public keys - RSA, DSA, Diffie-Hellman +* PKCS#12 +* SSL/TLS +* CMS (for S/MIME) + +Requirements: + OpenSSL Library (http://www.openssl.org/) + +Installing +---------- + +For Unix/Linux/Mac: + + ./configure + make + make install + +For Windows: + + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + diff --git a/local/recipes/libs/qca/source/plugins/qca-ossl/TODO b/local/recipes/libs/qca/source/plugins/qca-ossl/TODO new file mode 100644 index 0000000000..66595de513 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-ossl/TODO @@ -0,0 +1,10 @@ +need to implement locking callbacks. +need to integrate secure memory plugin and test +figure out why Valgrind reports so many memory leaks +implement bitSize() for PKey. +fix keyLength() for Blowfish cipher +implement all ietf dl groups + +ca signing +async TLS +when inserting trusted items into X509_STORE, sort by latest expiration first diff --git a/local/recipes/libs/qca/source/plugins/qca-ossl/qca-ossl.cpp b/local/recipes/libs/qca/source/plugins/qca-ossl/qca-ossl.cpp new file mode 100644 index 0000000000..f41fcbb5cc --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-ossl/qca-ossl.cpp @@ -0,0 +1,6948 @@ +/* + * Copyright (C) 2004-2007 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * Copyright (C) 2013-2016 Ivan Romanov + * Copyright (C) 2017 Fabian Vogt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef OPENSSL_VERSION_MAJOR +#include +#endif + +#include + +using namespace QCA; + +namespace { +struct DsaDeleter +{ + void operator()(DSA *pointer) + { + if (pointer) + DSA_free(pointer); + } +}; + +static bool s_legacyProviderAvailable = false; +} // end of anonymous namespace + +namespace opensslQCAPlugin { + +//---------------------------------------------------------------------------- +// Util +//---------------------------------------------------------------------------- +static SecureArray bio2buf(BIO *b) +{ + SecureArray buf; + while (true) { + SecureArray block(1024); + int ret = BIO_read(b, block.data(), block.size()); + if (ret <= 0) + break; + block.resize(ret); + buf.append(block); + if (ret != 1024) + break; + } + BIO_free(b); + return buf; +} + +static QByteArray bio2ba(BIO *b) +{ + QByteArray buf; + while (true) { + QByteArray block(1024, 0); + int ret = BIO_read(b, block.data(), block.size()); + if (ret <= 0) + break; + block.resize(ret); + buf.append(block); + if (ret != 1024) + break; + } + BIO_free(b); + return buf; +} + +static BigInteger bn2bi(const BIGNUM *n) +{ + SecureArray buf(BN_num_bytes(n) + 1); + buf[0] = 0; // positive + BN_bn2bin(n, (unsigned char *)buf.data() + 1); + return BigInteger(buf); +} + +static BigInteger bn2bi_free(BIGNUM *n) +{ + BigInteger bi = bn2bi(n); + BN_free(n); + return bi; +} + +static BIGNUM *bi2bn(const BigInteger &n) +{ + SecureArray buf = n.toArray(); + return BN_bin2bn((const unsigned char *)buf.data(), buf.size(), nullptr); +} + +// take lowest bytes of BIGNUM to fit +// pad with high byte zeroes to fit +static SecureArray bn2fixedbuf(const BIGNUM *n, int size) +{ + SecureArray buf(BN_num_bytes(n)); + BN_bn2bin(n, (unsigned char *)buf.data()); + + SecureArray out(size); + memset(out.data(), 0, size); + int len = qMin(size, buf.size()); + memcpy(out.data() + (size - len), buf.data(), len); + return out; +} + +static SecureArray dsasig_der_to_raw(const SecureArray &in) +{ + DSA_SIG *sig = DSA_SIG_new(); + const unsigned char *inp = (const unsigned char *)in.data(); + d2i_DSA_SIG(&sig, &inp, in.size()); + + const BIGNUM *bnr, *bns; + DSA_SIG_get0(sig, &bnr, &bns); + + SecureArray part_r = bn2fixedbuf(bnr, 20); + SecureArray part_s = bn2fixedbuf(bns, 20); + SecureArray result; + result.append(part_r); + result.append(part_s); + + DSA_SIG_free(sig); + return result; +} + +static SecureArray dsasig_raw_to_der(const SecureArray &in) +{ + if (in.size() != 40) + return SecureArray(); + + DSA_SIG *sig = DSA_SIG_new(); + SecureArray part_r(20); + BIGNUM *bnr; + SecureArray part_s(20); + BIGNUM *bns; + memcpy(part_r.data(), in.data(), 20); + memcpy(part_s.data(), in.data() + 20, 20); + bnr = BN_bin2bn((const unsigned char *)part_r.data(), part_r.size(), nullptr); + bns = BN_bin2bn((const unsigned char *)part_s.data(), part_s.size(), nullptr); + + if (DSA_SIG_set0(sig, bnr, bns) == 0) + return SecureArray(); + // Not documented what happens in the failure case, free bnr and bns? + + int len = i2d_DSA_SIG(sig, nullptr); + SecureArray result(len); + unsigned char *p = (unsigned char *)result.data(); + i2d_DSA_SIG(sig, &p); + + DSA_SIG_free(sig); + return result; +} + +static int passphrase_cb(char *buf, int size, int rwflag, void *u) +{ + Q_UNUSED(buf); + Q_UNUSED(size); + Q_UNUSED(rwflag); + Q_UNUSED(u); + return 0; +} + +/*static bool is_basic_constraint(const ConstraintType &t) +{ + bool basic = false; + switch(t.known()) + { + case DigitalSignature: + case NonRepudiation: + case KeyEncipherment: + case DataEncipherment: + case KeyAgreement: + case KeyCertificateSign: + case CRLSign: + case EncipherOnly: + case DecipherOnly: + basic = true; + break; + + case ServerAuth: + case ClientAuth: + case CodeSigning: + case EmailProtection: + case IPSecEndSystem: + case IPSecTunnel: + case IPSecUser: + case TimeStamping: + case OCSPSigning: + break; + } + return basic; +} + +static Constraints basic_only(const Constraints &list) +{ + Constraints out; + for(int n = 0; n < list.count(); ++n) + { + if(is_basic_constraint(list[n])) + out += list[n]; + } + return out; +} + +static Constraints ext_only(const Constraints &list) +{ + Constraints out; + for(int n = 0; n < list.count(); ++n) + { + if(!is_basic_constraint(list[n])) + out += list[n]; + } + return out; +}*/ + +// logic from Botan +/*static Constraints find_constraints(const PKeyContext &key, const Constraints &orig) +{ + Constraints constraints; + + if(key.key()->type() == PKey::RSA) + constraints += KeyEncipherment; + + if(key.key()->type() == PKey::DH) + constraints += KeyAgreement; + + if(key.key()->type() == PKey::RSA || key.key()->type() == PKey::DSA) + { + constraints += DigitalSignature; + constraints += NonRepudiation; + } + + Constraints limits = basic_only(orig); + Constraints the_rest = ext_only(orig); + + if(!limits.isEmpty()) + { + Constraints reduced; + for(int n = 0; n < constraints.count(); ++n) + { + if(limits.contains(constraints[n])) + reduced += constraints[n]; + } + constraints = reduced; + } + + constraints += the_rest; + + return constraints; +}*/ + +static void try_add_name_item(X509_NAME **name, int nid, const QString &val) +{ + if (val.isEmpty()) + return; + const QByteArray buf = val.toLatin1(); + if (!(*name)) + *name = X509_NAME_new(); + X509_NAME_add_entry_by_NID(*name, nid, MBSTRING_ASC, (const unsigned char *)buf.data(), buf.size(), -1, 0); +} + +static X509_NAME *new_cert_name(const CertificateInfo &info) +{ + X509_NAME *name = nullptr; + // FIXME support multiple items of each type + try_add_name_item(&name, NID_commonName, info.value(CommonName)); + try_add_name_item(&name, NID_countryName, info.value(Country)); + try_add_name_item(&name, NID_localityName, info.value(Locality)); + try_add_name_item(&name, NID_stateOrProvinceName, info.value(State)); + try_add_name_item(&name, NID_organizationName, info.value(Organization)); + try_add_name_item(&name, NID_organizationalUnitName, info.value(OrganizationalUnit)); + return name; +} + +static void try_get_name_item(X509_NAME *name, int nid, const CertificateInfoType &t, CertificateInfo *info) +{ + int loc; + loc = -1; + while ((loc = X509_NAME_get_index_by_NID(name, nid, loc)) != -1) { + X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); + ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); + QByteArray cs((const char *)data->data, data->length); + info->insert(t, QString::fromLatin1(cs)); + } +} + +static void +try_get_name_item_by_oid(X509_NAME *name, const QString &oidText, const CertificateInfoType &t, CertificateInfo *info) +{ + ASN1_OBJECT *oid = OBJ_txt2obj(oidText.toLatin1().data(), 1); // 1 = only accept dotted input + if (!oid) + return; + + int loc; + loc = -1; + while ((loc = X509_NAME_get_index_by_OBJ(name, oid, loc)) != -1) { + X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, loc); + ASN1_STRING *data = X509_NAME_ENTRY_get_data(ne); + QByteArray cs((const char *)data->data, data->length); + info->insert(t, QString::fromLatin1(cs)); + qDebug() << "oid: " << oidText << ", result: " << cs; + } + ASN1_OBJECT_free(oid); +} + +static CertificateInfo get_cert_name(X509_NAME *name) +{ + CertificateInfo info; + try_get_name_item(name, NID_commonName, CommonName, &info); + try_get_name_item(name, NID_countryName, Country, &info); + try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.3"), IncorporationCountry, &info); + try_get_name_item(name, NID_localityName, Locality, &info); + try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.1"), IncorporationLocality, &info); + try_get_name_item(name, NID_stateOrProvinceName, State, &info); + try_get_name_item_by_oid(name, QStringLiteral("1.3.6.1.4.1.311.60.2.1.2"), IncorporationState, &info); + try_get_name_item(name, NID_organizationName, Organization, &info); + try_get_name_item(name, NID_organizationalUnitName, OrganizationalUnit, &info); + + // legacy email + { + CertificateInfo p9_info; + try_get_name_item(name, NID_pkcs9_emailAddress, EmailLegacy, &p9_info); + const QList emails = info.values(Email); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QMultiMapIterator it(p9_info); +#else + QMapIterator it(p9_info); +#endif + while (it.hasNext()) { + it.next(); + if (!emails.contains(it.value())) + info.insert(Email, it.value()); + } + } + + return info; +} + +static X509_EXTENSION *new_subject_key_id(X509 *cert) +{ + X509V3_CTX ctx; + X509V3_set_ctx_nodb(&ctx); + X509V3_set_ctx(&ctx, nullptr, cert, nullptr, nullptr, 0); + X509_EXTENSION *ex = X509V3_EXT_conf_nid(nullptr, &ctx, NID_subject_key_identifier, (char *)"hash"); + return ex; +} + +static X509_EXTENSION *new_basic_constraints(bool ca, int pathlen) +{ + BASIC_CONSTRAINTS *bs = BASIC_CONSTRAINTS_new(); + bs->ca = (ca ? 1 : 0); + bs->pathlen = ASN1_INTEGER_new(); + ASN1_INTEGER_set(bs->pathlen, pathlen); + + X509_EXTENSION *ex = X509V3_EXT_i2d(NID_basic_constraints, 1, bs); // 1 = critical + BASIC_CONSTRAINTS_free(bs); + return ex; +} + +static void get_basic_constraints(X509_EXTENSION *ex, bool *ca, int *pathlen) +{ + BASIC_CONSTRAINTS *bs = (BASIC_CONSTRAINTS *)X509V3_EXT_d2i(ex); + *ca = (bs->ca ? true : false); + if (bs->pathlen) + *pathlen = ASN1_INTEGER_get(bs->pathlen); + else + *pathlen = 0; + BASIC_CONSTRAINTS_free(bs); +} + +enum ConstraintBit +{ + Bit_DigitalSignature = 0, + Bit_NonRepudiation = 1, + Bit_KeyEncipherment = 2, + Bit_DataEncipherment = 3, + Bit_KeyAgreement = 4, + Bit_KeyCertificateSign = 5, + Bit_CRLSign = 6, + Bit_EncipherOnly = 7, + Bit_DecipherOnly = 8 +}; + +static QByteArray ipaddress_string_to_bytes(const QString &) +{ + return QByteArray(4, 0); +} + +static GENERAL_NAME *new_general_name(const CertificateInfoType &t, const QString &val) +{ + GENERAL_NAME *name = nullptr; + switch (t.known()) { + case Email: + { + const QByteArray buf = val.toLatin1(); + + ASN1_IA5STRING *str = ASN1_IA5STRING_new(); + ASN1_STRING_set((ASN1_STRING *)str, (const unsigned char *)buf.data(), buf.size()); + + name = GENERAL_NAME_new(); + name->type = GEN_EMAIL; + name->d.rfc822Name = str; + break; + } + case URI: + { + const QByteArray buf = val.toLatin1(); + + ASN1_IA5STRING *str = ASN1_IA5STRING_new(); + ASN1_STRING_set((ASN1_STRING *)str, (const unsigned char *)buf.data(), buf.size()); + + name = GENERAL_NAME_new(); + name->type = GEN_URI; + name->d.uniformResourceIdentifier = str; + break; + } + case DNS: + { + const QByteArray buf = val.toLatin1(); + + ASN1_IA5STRING *str = ASN1_IA5STRING_new(); + ASN1_STRING_set((ASN1_STRING *)str, (const unsigned char *)buf.data(), buf.size()); + + name = GENERAL_NAME_new(); + name->type = GEN_DNS; + name->d.dNSName = str; + break; + } + case IPAddress: + { + const QByteArray buf = ipaddress_string_to_bytes(val); + + ASN1_OCTET_STRING *str = ASN1_OCTET_STRING_new(); + ASN1_STRING_set((ASN1_STRING *)str, (const unsigned char *)buf.data(), buf.size()); + + name = GENERAL_NAME_new(); + name->type = GEN_IPADD; + name->d.iPAddress = str; + break; + } + case XMPP: + { + const QByteArray buf = val.toUtf8(); + + ASN1_UTF8STRING *str = ASN1_UTF8STRING_new(); + ASN1_STRING_set((ASN1_STRING *)str, (const unsigned char *)buf.data(), buf.size()); + + ASN1_TYPE *at = ASN1_TYPE_new(); + at->type = V_ASN1_UTF8STRING; + at->value.utf8string = str; + + OTHERNAME *other = OTHERNAME_new(); + other->type_id = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input + other->value = at; + + name = GENERAL_NAME_new(); + name->type = GEN_OTHERNAME; + name->d.otherName = other; + break; + } + default: + break; + } + return name; +} + +static void try_add_general_name(GENERAL_NAMES **gn, const CertificateInfoType &t, const QString &val) +{ + if (val.isEmpty()) + return; + GENERAL_NAME *name = new_general_name(t, val); + if (name) { + if (!(*gn)) + *gn = sk_GENERAL_NAME_new_null(); + sk_GENERAL_NAME_push(*gn, name); + } +} + +static X509_EXTENSION *new_cert_subject_alt_name(const CertificateInfo &info) +{ + GENERAL_NAMES *gn = nullptr; + // FIXME support multiple items of each type + try_add_general_name(&gn, Email, info.value(Email)); + try_add_general_name(&gn, URI, info.value(URI)); + try_add_general_name(&gn, DNS, info.value(DNS)); + try_add_general_name(&gn, IPAddress, info.value(IPAddress)); + try_add_general_name(&gn, XMPP, info.value(XMPP)); + if (!gn) + return nullptr; + + X509_EXTENSION *ex = X509V3_EXT_i2d(NID_subject_alt_name, 0, gn); + sk_GENERAL_NAME_pop_free(gn, GENERAL_NAME_free); + return ex; +} + +static GENERAL_NAME *find_next_general_name(GENERAL_NAMES *names, int type, int *pos) +{ + int temp = *pos; + GENERAL_NAME *gn = nullptr; + *pos = -1; + for (int n = temp; n < sk_GENERAL_NAME_num(names); ++n) { + GENERAL_NAME *i = sk_GENERAL_NAME_value(names, n); + if (i->type == type) { + gn = i; + *pos = n; + break; + } + } + return gn; +} + +static QByteArray qca_ASN1_STRING_toByteArray(ASN1_STRING *x) +{ + return QByteArray(reinterpret_cast(ASN1_STRING_get0_data(x)), ASN1_STRING_length(x)); +} + +static void try_get_general_name(GENERAL_NAMES *names, const CertificateInfoType &t, CertificateInfo *info) +{ + switch (t.known()) { + case Email: + { + int pos = 0; + while (pos != -1) { + GENERAL_NAME *gn = find_next_general_name(names, GEN_EMAIL, &pos); + if (pos != -1) { + const QByteArray cs = qca_ASN1_STRING_toByteArray(gn->d.rfc822Name); + info->insert(t, QString::fromLatin1(cs)); + ++pos; + } + } + break; + } + case URI: + { + int pos = 0; + while (pos != -1) { + GENERAL_NAME *gn = find_next_general_name(names, GEN_URI, &pos); + if (pos != -1) { + const QByteArray cs = qca_ASN1_STRING_toByteArray(gn->d.uniformResourceIdentifier); + info->insert(t, QString::fromLatin1(cs)); + ++pos; + } + } + break; + } + case DNS: + { + int pos = 0; + while (pos != -1) { + GENERAL_NAME *gn = find_next_general_name(names, GEN_DNS, &pos); + if (pos != -1) { + const QByteArray cs = qca_ASN1_STRING_toByteArray(gn->d.dNSName); + info->insert(t, QString::fromLatin1(cs)); + ++pos; + } + } + break; + } + case IPAddress: + { + int pos = 0; + while (pos != -1) { + GENERAL_NAME *gn = find_next_general_name(names, GEN_IPADD, &pos); + if (pos != -1) { + ASN1_OCTET_STRING *str = gn->d.iPAddress; + const QByteArray buf = qca_ASN1_STRING_toByteArray(str); + + QString out; + // IPv4 (TODO: handle IPv6) + if (buf.size() == 4) { + out = QStringLiteral("0.0.0.0"); + } else + break; + info->insert(t, out); + ++pos; + } + } + break; + } + case XMPP: + { + int pos = 0; + while (pos != -1) { + GENERAL_NAME *gn = find_next_general_name(names, GEN_OTHERNAME, &pos); + if (pos != -1) { + OTHERNAME *other = gn->d.otherName; + if (!other) + break; + + ASN1_OBJECT *obj = OBJ_txt2obj("1.3.6.1.5.5.7.8.5", 1); // 1 = only accept dotted input + if (OBJ_cmp(other->type_id, obj) != 0) + break; + ASN1_OBJECT_free(obj); + + ASN1_TYPE *at = other->value; + if (at->type != V_ASN1_UTF8STRING) + break; + + ASN1_UTF8STRING *str = at->value.utf8string; + const QByteArray buf = qca_ASN1_STRING_toByteArray(str); + info->insert(t, QString::fromUtf8(buf)); + ++pos; + } + } + break; + } + default: + break; + } +} + +static CertificateInfo get_cert_alt_name(X509_EXTENSION *ex) +{ + CertificateInfo info; + GENERAL_NAMES *gn = (GENERAL_NAMES *)X509V3_EXT_d2i(ex); + try_get_general_name(gn, Email, &info); + try_get_general_name(gn, URI, &info); + try_get_general_name(gn, DNS, &info); + try_get_general_name(gn, IPAddress, &info); + try_get_general_name(gn, XMPP, &info); + GENERAL_NAMES_free(gn); + return info; +} + +static X509_EXTENSION *new_cert_key_usage(const Constraints &constraints) +{ + ASN1_BIT_STRING *keyusage = nullptr; + for (int n = 0; n < constraints.count(); ++n) { + int bit = -1; + switch (constraints[n].known()) { + case DigitalSignature: + bit = Bit_DigitalSignature; + break; + case NonRepudiation: + bit = Bit_NonRepudiation; + break; + case KeyEncipherment: + bit = Bit_KeyEncipherment; + break; + case DataEncipherment: + bit = Bit_DataEncipherment; + break; + case KeyAgreement: + bit = Bit_KeyAgreement; + break; + case KeyCertificateSign: + bit = Bit_KeyCertificateSign; + break; + case CRLSign: + bit = Bit_CRLSign; + break; + case EncipherOnly: + bit = Bit_EncipherOnly; + break; + case DecipherOnly: + bit = Bit_DecipherOnly; + break; + default: + break; + } + if (bit != -1) { + if (!keyusage) + keyusage = ASN1_BIT_STRING_new(); + ASN1_BIT_STRING_set_bit(keyusage, bit, 1); + } + } + if (!keyusage) + return nullptr; + + X509_EXTENSION *ex = X509V3_EXT_i2d(NID_key_usage, 1, keyusage); // 1 = critical + ASN1_BIT_STRING_free(keyusage); + return ex; +} + +static Constraints get_cert_key_usage(X509_EXTENSION *ex) +{ + Constraints constraints; + int bit_table[9] = {DigitalSignature, + NonRepudiation, + KeyEncipherment, + DataEncipherment, + KeyAgreement, + KeyCertificateSign, + CRLSign, + EncipherOnly, + DecipherOnly}; + + ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ex); + for (int n = 0; n < 9; ++n) { + if (ASN1_BIT_STRING_get_bit(keyusage, n)) + constraints += ConstraintType((ConstraintTypeKnown)bit_table[n]); + } + ASN1_BIT_STRING_free(keyusage); + return constraints; +} + +static X509_EXTENSION *new_cert_ext_key_usage(const Constraints &constraints) +{ + EXTENDED_KEY_USAGE *extkeyusage = nullptr; + for (int n = 0; n < constraints.count(); ++n) { + int nid = -1; + // TODO: don't use known/nid, and instead just use OIDs + switch (constraints[n].known()) { + case ServerAuth: + nid = NID_server_auth; + break; + case ClientAuth: + nid = NID_client_auth; + break; + case CodeSigning: + nid = NID_code_sign; + break; + case EmailProtection: + nid = NID_email_protect; + break; + case IPSecEndSystem: + nid = NID_ipsecEndSystem; + break; + case IPSecTunnel: + nid = NID_ipsecTunnel; + break; + case IPSecUser: + nid = NID_ipsecUser; + break; + case TimeStamping: + nid = NID_time_stamp; + break; + case OCSPSigning: + nid = NID_OCSP_sign; + break; + default: + break; + } + if (nid != -1) { + if (!extkeyusage) + extkeyusage = sk_ASN1_OBJECT_new_null(); + ASN1_OBJECT *obj = OBJ_nid2obj(nid); + sk_ASN1_OBJECT_push(extkeyusage, obj); + } + } + if (!extkeyusage) + return nullptr; + + X509_EXTENSION *ex = X509V3_EXT_i2d(NID_ext_key_usage, 0, extkeyusage); // 0 = not critical + sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); + return ex; +} + +static Constraints get_cert_ext_key_usage(X509_EXTENSION *ex) +{ + Constraints constraints; + + EXTENDED_KEY_USAGE *extkeyusage = (EXTENDED_KEY_USAGE *)X509V3_EXT_d2i(ex); + for (int n = 0; n < sk_ASN1_OBJECT_num(extkeyusage); ++n) { + ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(extkeyusage, n); + int nid = OBJ_obj2nid(obj); + if (nid == NID_undef) + continue; + + // TODO: don't use known/nid, and instead just use OIDs + int t = -1; + switch (nid) { + case NID_server_auth: + t = ServerAuth; + break; + case NID_client_auth: + t = ClientAuth; + break; + case NID_code_sign: + t = CodeSigning; + break; + case NID_email_protect: + t = EmailProtection; + break; + case NID_ipsecEndSystem: + t = IPSecEndSystem; + break; + case NID_ipsecTunnel: + t = IPSecTunnel; + break; + case NID_ipsecUser: + t = IPSecUser; + break; + case NID_time_stamp: + t = TimeStamping; + break; + case NID_OCSP_sign: + t = OCSPSigning; + break; + }; + + if (t == -1) + continue; + + constraints.append(ConstraintType((ConstraintTypeKnown)t)); + } + sk_ASN1_OBJECT_pop_free(extkeyusage, ASN1_OBJECT_free); + return constraints; +} + +static X509_EXTENSION *new_cert_policies(const QStringList &policies) +{ + STACK_OF(POLICYINFO) *pols = nullptr; + for (int n = 0; n < policies.count(); ++n) { + const QByteArray cs = policies[n].toLatin1(); + ASN1_OBJECT *obj = OBJ_txt2obj(cs.data(), 1); // 1 = only accept dotted input + if (!obj) + continue; + if (!pols) + pols = sk_POLICYINFO_new_null(); + POLICYINFO *pol = POLICYINFO_new(); + pol->policyid = obj; + sk_POLICYINFO_push(pols, pol); + } + if (!pols) + return nullptr; + + X509_EXTENSION *ex = X509V3_EXT_i2d(NID_certificate_policies, 0, pols); // 0 = not critical + sk_POLICYINFO_pop_free(pols, POLICYINFO_free); + return ex; +} + +static QStringList get_cert_policies(X509_EXTENSION *ex) +{ + QStringList out; + STACK_OF(POLICYINFO) *pols = (STACK_OF(POLICYINFO) *)X509V3_EXT_d2i(ex); + for (int n = 0; n < sk_POLICYINFO_num(pols); ++n) { + POLICYINFO *pol = sk_POLICYINFO_value(pols, n); + QByteArray buf(128, 0); + const auto len = OBJ_obj2txt((char *)buf.data(), buf.size(), pol->policyid, 1); // 1 = only accept dotted input + if (len > 0) + out += QString::fromLatin1(buf.left(len)); + } + sk_POLICYINFO_pop_free(pols, POLICYINFO_free); + return out; +} + +static QByteArray get_cert_subject_key_id(X509_EXTENSION *ex) +{ + ASN1_OCTET_STRING *skid = (ASN1_OCTET_STRING *)X509V3_EXT_d2i(ex); + const QByteArray out = qca_ASN1_STRING_toByteArray(skid); + ASN1_OCTET_STRING_free(skid); + return out; +} + +// If you get any more crashes in this code, please provide a copy +// of the cert to bradh AT frogmouth.net +static QByteArray get_cert_issuer_key_id(X509_EXTENSION *ex) +{ + AUTHORITY_KEYID *akid = (AUTHORITY_KEYID *)X509V3_EXT_d2i(ex); + QByteArray out; + if (akid->keyid) + out = qca_ASN1_STRING_toByteArray(akid->keyid); + AUTHORITY_KEYID_free(akid); + return out; +} + +static Validity convert_verify_error(int err) +{ + // TODO: ErrorExpiredCA + Validity rc; + switch (err) { + case X509_V_ERR_CERT_REJECTED: + rc = ErrorRejected; + break; + case X509_V_ERR_CERT_UNTRUSTED: + rc = ErrorUntrusted; + break; + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + rc = ErrorSignatureFailed; + break; + case X509_V_ERR_INVALID_CA: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + rc = ErrorInvalidCA; + break; + case X509_V_ERR_INVALID_PURPOSE: // note: not used by store verify + rc = ErrorInvalidPurpose; + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + rc = ErrorSelfSigned; + break; + case X509_V_ERR_CERT_REVOKED: + rc = ErrorRevoked; + break; + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + rc = ErrorPathLengthExceeded; + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_NOT_YET_VALID: + case X509_V_ERR_CRL_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + rc = ErrorExpired; + break; + case X509_V_ERR_APPLICATION_VERIFICATION: + case X509_V_ERR_OUT_OF_MEM: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + default: + rc = ErrorValidityUnknown; + break; + } + return rc; +} + +EVP_PKEY *qca_d2i_PKCS8PrivateKey(const SecureArray &in, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + PKCS8_PRIV_KEY_INFO *p8inf; + + // first try unencrypted form + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(bi, nullptr); + BIO_free(bi); + if (!p8inf) { + X509_SIG *p8; + + // now try encrypted form + bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + p8 = d2i_PKCS8_bio(bi, nullptr); + BIO_free(bi); + if (!p8) + return nullptr; + + // get passphrase + char psbuf[PEM_BUFSIZE]; + int klen; + if (cb) + klen = cb(psbuf, PEM_BUFSIZE, 0, u); + else + klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); + if (klen <= 0) { + PEMerr(PEM_F_D2I_PKCS8PRIVATEKEY_BIO, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + return nullptr; + } + + // decrypt it + p8inf = PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if (!p8inf) + return nullptr; + } + + EVP_PKEY *ret = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if (!ret) + return nullptr; + if (x) { + if (*x) + EVP_PKEY_free(*x); + *x = ret; + } + return ret; +} + +class opensslHashContext : public HashContext +{ + Q_OBJECT +public: + opensslHashContext(const EVP_MD *algorithm, Provider *p, const QString &type) + : HashContext(p, type) + { + m_algorithm = algorithm; + m_context = EVP_MD_CTX_new(); + EVP_DigestInit(m_context, m_algorithm); + } + + opensslHashContext(const opensslHashContext &other) + : HashContext(other) + { + m_algorithm = other.m_algorithm; + m_context = EVP_MD_CTX_new(); + EVP_MD_CTX_copy_ex(m_context, other.m_context); + } + + ~opensslHashContext() override + { + EVP_MD_CTX_free(m_context); + } + + void clear() override + { + EVP_MD_CTX_free(m_context); + m_context = EVP_MD_CTX_new(); + EVP_DigestInit(m_context, m_algorithm); + } + + void update(const MemoryRegion &a) override + { + EVP_DigestUpdate(m_context, (unsigned char *)a.data(), a.size()); + } + + MemoryRegion final() override + { + SecureArray a(EVP_MD_size(m_algorithm)); + EVP_DigestFinal(m_context, (unsigned char *)a.data(), nullptr); + return a; + } + + Provider::Context *clone() const override + { + return new opensslHashContext(*this); + } + +protected: + const EVP_MD *m_algorithm; + EVP_MD_CTX *m_context; +}; + +class opensslPbkdf1Context : public KDFContext +{ + Q_OBJECT +public: + opensslPbkdf1Context(const EVP_MD *algorithm, Provider *p, const QString &type) + : KDFContext(p, type) + { + Q_ASSERT(s_legacyProviderAvailable); + m_algorithm = algorithm; + m_context = EVP_MD_CTX_new(); + EVP_DigestInit(m_context, m_algorithm); + } + + opensslPbkdf1Context(const opensslPbkdf1Context &other) + : KDFContext(other) + { + m_algorithm = other.m_algorithm; + m_context = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(m_context, other.m_context); + } + + ~opensslPbkdf1Context() override + { + EVP_MD_CTX_free(m_context); + } + + Provider::Context *clone() const override + { + return new opensslPbkdf1Context(*this); + } + + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) override + { + /* from RFC2898: + Steps: + + 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output + "derived key too long" and stop. + */ + if (keyLength > (unsigned int)EVP_MD_size(m_algorithm)) { + std::cout << "derived key too long" << std::endl; + return SymmetricKey(); + } + + /* + 2. Apply the underlying hash function Hash for c iterations to the + concatenation of the password P and the salt S, then extract + the first dkLen octets to produce a derived key DK: + + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + DK = Tc<0..dkLen-1> + */ + // calculate T_1 + EVP_DigestUpdate(m_context, (unsigned char *)secret.data(), secret.size()); + EVP_DigestUpdate(m_context, (unsigned char *)salt.data(), salt.size()); + SecureArray a(EVP_MD_size(m_algorithm)); + EVP_DigestFinal(m_context, (unsigned char *)a.data(), nullptr); + + // calculate T_2 up to T_c + for (unsigned int i = 2; i <= iterationCount; ++i) { + EVP_DigestInit(m_context, m_algorithm); + EVP_DigestUpdate(m_context, (unsigned char *)a.data(), a.size()); + EVP_DigestFinal(m_context, (unsigned char *)a.data(), nullptr); + } + + // shrink a to become DK, of the required length + a.resize(keyLength); + + /* + 3. Output the derived key DK. + */ + return a; + } + + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) override + { + Q_ASSERT(iterationCount != nullptr); + QElapsedTimer timer; + + /* from RFC2898: + Steps: + + 1. If dkLen > 16 for MD2 and MD5, or dkLen > 20 for SHA-1, output + "derived key too long" and stop. + */ + if (keyLength > (unsigned int)EVP_MD_size(m_algorithm)) { + std::cout << "derived key too long" << std::endl; + return SymmetricKey(); + } + + /* + 2. Apply the underlying hash function Hash for M milliseconds + to the concatenation of the password P and the salt S, incrementing c, + then extract the first dkLen octets to produce a derived key DK: + + time from M to 0 + T_1 = Hash (P || S) , + T_2 = Hash (T_1) , + ... + T_c = Hash (T_{c-1}) , + when time = 0: stop, + DK = Tc<0..dkLen-1> + */ + // calculate T_1 + EVP_DigestUpdate(m_context, (unsigned char *)secret.data(), secret.size()); + EVP_DigestUpdate(m_context, (unsigned char *)salt.data(), salt.size()); + SecureArray a(EVP_MD_size(m_algorithm)); + EVP_DigestFinal(m_context, (unsigned char *)a.data(), nullptr); + + // calculate T_2 up to T_c + *iterationCount = 2 - 1; // <- Have to remove 1, unless it computes one + timer.start(); // ^ time more than the base function + // ^ with the same iterationCount + while (timer.elapsed() < msecInterval) { + EVP_DigestInit(m_context, m_algorithm); + EVP_DigestUpdate(m_context, (unsigned char *)a.data(), a.size()); + EVP_DigestFinal(m_context, (unsigned char *)a.data(), nullptr); + ++(*iterationCount); + } + + // shrink a to become DK, of the required length + a.resize(keyLength); + + /* + 3. Output the derived key DK. + */ + return a; + } + +protected: + const EVP_MD *m_algorithm; + EVP_MD_CTX *m_context; +}; + +class opensslPbkdf2Context : public KDFContext +{ + Q_OBJECT +public: + opensslPbkdf2Context(Provider *p, const QString &type) + : KDFContext(p, type) + { + } + + Provider::Context *clone() const override + { + return new opensslPbkdf2Context(*this); + } + + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) override + { + SecureArray out(keyLength); + PKCS5_PBKDF2_HMAC_SHA1((char *)secret.data(), + secret.size(), + (unsigned char *)salt.data(), + salt.size(), + iterationCount, + keyLength, + (unsigned char *)out.data()); + return out; + } + + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) override + { + Q_ASSERT(iterationCount != nullptr); + QElapsedTimer timer; + SecureArray out(keyLength); + + *iterationCount = 0; + timer.start(); + + // PBKDF2 needs an iterationCount itself, unless PBKDF1. + // So we need to calculate first the number of iterations for + // That time interval, then feed the iterationCounts to PBKDF2 + while (timer.elapsed() < msecInterval) { + PKCS5_PBKDF2_HMAC_SHA1((char *)secret.data(), + secret.size(), + (unsigned char *)salt.data(), + salt.size(), + 1, + keyLength, + (unsigned char *)out.data()); + ++(*iterationCount); + } + + // Now we can directely call makeKey base function, + // as we now have the iterationCount + out = makeKey(secret, salt, keyLength, *iterationCount); + + return out; + } + +protected: +}; + +class opensslHkdfContext : public HKDFContext +{ + Q_OBJECT +public: + opensslHkdfContext(Provider *p, const QString &type) + : HKDFContext(p, type) + { + } + + Provider::Context *clone() const override + { + return new opensslHkdfContext(*this); + } + + SymmetricKey makeKey(const SecureArray &secret, + const InitializationVector &salt, + const InitializationVector &info, + unsigned int keyLength) override + { + SecureArray out(keyLength); + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr); + EVP_PKEY_derive_init(pctx); + EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()); + EVP_PKEY_CTX_set1_hkdf_salt(pctx, (const unsigned char *)salt.data(), int(salt.size())); + EVP_PKEY_CTX_set1_hkdf_key(pctx, (const unsigned char *)secret.data(), int(secret.size())); + EVP_PKEY_CTX_add1_hkdf_info(pctx, (const unsigned char *)info.data(), int(info.size())); + size_t outlen = out.size(); + EVP_PKEY_derive(pctx, reinterpret_cast(out.data()), &outlen); + EVP_PKEY_CTX_free(pctx); + return out; + } +}; + +class opensslHMACContext : public MACContext +{ + Q_OBJECT +public: + opensslHMACContext(const EVP_MD *algorithm, Provider *p, const QString &type) + : MACContext(p, type) + { + m_algorithm = algorithm; + m_context = HMAC_CTX_new(); + } + + opensslHMACContext(const opensslHMACContext &other) + : MACContext(other) + { + m_algorithm = other.m_algorithm; + m_context = HMAC_CTX_new(); + HMAC_CTX_copy(m_context, other.m_context); + } + + ~opensslHMACContext() override + { + HMAC_CTX_free(m_context); + } + + void setup(const SymmetricKey &key) override + { + HMAC_Init_ex(m_context, key.data(), key.size(), m_algorithm, nullptr); + } + + KeyLength keyLength() const override + { + return anyKeyLength(); + } + + void update(const MemoryRegion &a) override + { + HMAC_Update(m_context, (unsigned char *)a.data(), a.size()); + } + + void final(MemoryRegion *out) override + { + SecureArray sa(EVP_MD_size(m_algorithm), 0); + HMAC_Final(m_context, (unsigned char *)sa.data(), nullptr); + HMAC_CTX_reset(m_context); + *out = sa; + } + + Provider::Context *clone() const override + { + return new opensslHMACContext(*this); + } + +protected: + HMAC_CTX *m_context; + const EVP_MD *m_algorithm; +}; + +//---------------------------------------------------------------------------- +// EVPKey +//---------------------------------------------------------------------------- + +// note: this class squelches processing errors, since QCA doesn't care about them +class EVPKey +{ +public: + enum State + { + Idle, + SignActive, + SignError, + VerifyActive, + VerifyError + }; + EVP_PKEY *pkey; + EVP_MD_CTX *mdctx; + State state; + bool raw_type; + SecureArray raw; + + EVPKey() + { + pkey = nullptr; + raw_type = false; + state = Idle; + mdctx = EVP_MD_CTX_new(); + } + + EVPKey(const EVPKey &from) + { + pkey = from.pkey; + EVP_PKEY_up_ref(pkey); + raw_type = false; + state = Idle; + mdctx = EVP_MD_CTX_new(); + EVP_MD_CTX_copy(mdctx, from.mdctx); + } + + EVPKey &operator=(const EVPKey &from) = delete; + + ~EVPKey() + { + reset(); + EVP_MD_CTX_free(mdctx); + } + + void reset() + { + if (pkey) + EVP_PKEY_free(pkey); + pkey = nullptr; + raw.clear(); + raw_type = false; + } + + void startSign(const EVP_MD *type) + { + state = SignActive; + if (!type) { + raw_type = true; + raw.clear(); + } else { + raw_type = false; + EVP_MD_CTX_init(mdctx); + if (!EVP_SignInit_ex(mdctx, type, nullptr)) + state = SignError; + } + } + + void startVerify(const EVP_MD *type) + { + state = VerifyActive; + if (!type) { + raw_type = true; + raw.clear(); + } else { + raw_type = false; + EVP_MD_CTX_init(mdctx); + if (!EVP_VerifyInit_ex(mdctx, type, nullptr)) + state = VerifyError; + } + } + + void update(const MemoryRegion &in) + { + if (state == SignActive) { + if (raw_type) + raw += in; + else if (!EVP_SignUpdate(mdctx, in.data(), (unsigned int)in.size())) + state = SignError; + } else if (state == VerifyActive) { + if (raw_type) + raw += in; + else if (!EVP_VerifyUpdate(mdctx, in.data(), (unsigned int)in.size())) + state = VerifyError; + } + } + + SecureArray endSign() + { + if (state == SignActive) { + SecureArray out(EVP_PKEY_size(pkey)); + unsigned int len = out.size(); + if (raw_type) { + int type = EVP_PKEY_id(pkey); + + if (type == EVP_PKEY_RSA) { + const RSA *rsa = EVP_PKEY_get0_RSA(pkey); + if (RSA_private_encrypt(raw.size(), + (unsigned char *)raw.data(), + (unsigned char *)out.data(), + (RSA *)rsa, + RSA_PKCS1_PADDING) == -1) { + state = SignError; + return SecureArray(); + } + } else if (type == EVP_PKEY_DSA) { + state = SignError; + return SecureArray(); + } else { + state = SignError; + return SecureArray(); + } + } else { + if (!EVP_SignFinal(mdctx, (unsigned char *)out.data(), &len, pkey)) { + state = SignError; + return SecureArray(); + } + } + out.resize(len); + state = Idle; + return out; + } else + return SecureArray(); + } + + bool endVerify(const SecureArray &sig) + { + if (state == VerifyActive) { + if (raw_type) { + SecureArray out(EVP_PKEY_size(pkey)); + int len = 0; + + int type = EVP_PKEY_id(pkey); + + if (type == EVP_PKEY_RSA) { + const RSA *rsa = EVP_PKEY_get0_RSA(pkey); + if ((len = RSA_public_decrypt(sig.size(), + (unsigned char *)sig.data(), + (unsigned char *)out.data(), + (RSA *)rsa, + RSA_PKCS1_PADDING)) == -1) { + state = VerifyError; + return false; + } + } else if (type == EVP_PKEY_DSA) { + state = VerifyError; + return false; + } else { + state = VerifyError; + return false; + } + + out.resize(len); + + if (out != raw) { + state = VerifyError; + return false; + } + } else { + if (EVP_VerifyFinal(mdctx, (unsigned char *)sig.data(), (unsigned int)sig.size(), pkey) != 1) { + state = VerifyError; + return false; + } + } + state = Idle; + return true; + } else + return false; + } +}; + +//---------------------------------------------------------------------------- +// MyDLGroup +//---------------------------------------------------------------------------- + +// IETF primes from Botan +static const char *IETF_1024_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381" + "FFFFFFFF FFFFFFFF"; + +static const char *IETF_2048_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + "15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"; + +static const char *IETF_4096_PRIME = + "FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" + "29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" + "EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" + "E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" + "EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" + "C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" + "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" + "670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" + "E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" + "DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" + "15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" + "ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" + "ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" + "F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" + "BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" + "43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" + "88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" + "2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" + "287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" + "1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" + "93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" + "FFFFFFFF FFFFFFFF"; + +#ifndef OPENSSL_FIPS +// JCE seeds from Botan +static const char *JCE_512_SEED = "B869C82B 35D70E1B 1FF91B28 E37A62EC DC34409B"; +static const int JCE_512_COUNTER = 123; + +static const char *JCE_768_SEED = "77D0F8C4 DAD15EB8 C4F2F8D6 726CEFD9 6D5BB399"; +static const int JCE_768_COUNTER = 263; + +static const char *JCE_1024_SEED = "8D515589 4229D5E6 89EE01E6 018A237E 2CAE64CD"; +static const int JCE_1024_COUNTER = 92; +#endif + +static QByteArray dehex(const QByteArray &hex) +{ + QString str; + for (const char c : hex) { + if (c != ' ') + str += QLatin1Char(c); + } + return hexToArray(str); +} + +static BigInteger decode(const QByteArray &prime) +{ + QByteArray a(1, 0); // 1 byte of zero padding + a.append(dehex(prime)); + return BigInteger(SecureArray(a)); +} + +#ifndef OPENSSL_FIPS +static QByteArray decode_seed(const QByteArray &hex_seed) +{ + return dehex(hex_seed); +} +#endif + +class DLParams +{ +public: + BigInteger p, q, g; +}; + +#ifndef OPENSSL_FIPS + +static bool make_dlgroup(const QByteArray &seed, int bits, int counter, DLParams *params) +{ + int ret_counter; + std::unique_ptr dsa(DSA_new()); + if (!dsa) + return false; + + if (DSA_generate_parameters_ex( + dsa.get(), bits, (const unsigned char *)seed.data(), seed.size(), &ret_counter, nullptr, nullptr) != 1) + return false; + + if (ret_counter != counter) + return false; + + const BIGNUM *bnp, *bnq, *bng; + DSA_get0_pqg(dsa.get(), &bnp, &bnq, &bng); + params->p = bn2bi(bnp); + params->q = bn2bi(bnq); + params->g = bn2bi(bng); + + return true; +} +#endif + +static bool get_dlgroup(const BigInteger &p, const BigInteger &g, DLParams *params) +{ + params->p = p; + params->q = BigInteger(0); + params->g = g; + return true; +} + +class DLGroupMaker : public QThread +{ + Q_OBJECT +public: + DLGroupSet set; + bool ok; + DLParams params; + + DLGroupMaker(DLGroupSet _set) + { + set = _set; + } + + ~DLGroupMaker() override + { + wait(); + } + + void run() override + { + switch (set) { +#ifndef OPENSSL_FIPS + case DSA_512: + ok = make_dlgroup(decode_seed(JCE_512_SEED), 512, JCE_512_COUNTER, ¶ms); + break; + + case DSA_768: + ok = make_dlgroup(decode_seed(JCE_768_SEED), 768, JCE_768_COUNTER, ¶ms); + break; + + case DSA_1024: + ok = make_dlgroup(decode_seed(JCE_1024_SEED), 1024, JCE_1024_COUNTER, ¶ms); + break; +#endif + + case IETF_1024: + ok = get_dlgroup(decode(IETF_1024_PRIME), 2, ¶ms); + break; + + case IETF_2048: + ok = get_dlgroup(decode(IETF_2048_PRIME), 2, ¶ms); + break; + + case IETF_4096: + ok = get_dlgroup(decode(IETF_4096_PRIME), 2, ¶ms); + break; + + default: + ok = false; + break; + } + } +}; + +class MyDLGroup : public DLGroupContext +{ + Q_OBJECT +public: + DLGroupMaker *gm; + bool wasBlocking; + DLParams params; + bool empty; + + MyDLGroup(Provider *p) + : DLGroupContext(p) + { + gm = nullptr; + empty = true; + } + + MyDLGroup(const MyDLGroup &from) + : DLGroupContext(from.provider()) + { + gm = nullptr; + empty = true; + } + + ~MyDLGroup() override + { + delete gm; + } + + Provider::Context *clone() const override + { + return new MyDLGroup(*this); + } + + QList supportedGroupSets() const override + { + QList list; + + // DSA_* was removed in FIPS specification + // https://bugzilla.redhat.com/show_bug.cgi?id=1144655 +#ifndef OPENSSL_FIPS + list += DSA_512; + list += DSA_768; + list += DSA_1024; +#endif + list += IETF_1024; + list += IETF_2048; + list += IETF_4096; + return list; + } + + bool isNull() const override + { + return empty; + } + + void fetchGroup(DLGroupSet set, bool block) override + { + params = DLParams(); + empty = true; + + gm = new DLGroupMaker(set); + wasBlocking = block; + if (block) { + gm->run(); + gm_finished(); + } else { + connect(gm, &DLGroupMaker::finished, this, &MyDLGroup::gm_finished); + gm->start(); + } + } + + void getResult(BigInteger *p, BigInteger *q, BigInteger *g) const override + { + *p = params.p; + *q = params.q; + *g = params.g; + } + +private Q_SLOTS: + void gm_finished() + { + bool ok = gm->ok; + if (ok) { + params = gm->params; + empty = false; + } + + if (wasBlocking) + delete gm; + else + gm->deleteLater(); + gm = nullptr; + + if (!wasBlocking) + emit finished(); + } +}; + +//---------------------------------------------------------------------------- +// RSAKey +//---------------------------------------------------------------------------- +namespace { +static const auto RsaDeleter = [](RSA *pointer) { + if (pointer) + RSA_free((RSA *)pointer); +}; + +static const auto BnDeleter = [](BIGNUM *pointer) { + if (pointer) + BN_free((BIGNUM *)pointer); +}; +} // end of anonymous namespace + +class RSAKeyMaker : public QThread +{ + Q_OBJECT +public: + RSA *result; + int bits, exp; + + RSAKeyMaker(int _bits, int _exp, QObject *parent = nullptr) + : QThread(parent) + , result(nullptr) + , bits(_bits) + , exp(_exp) + { + } + + ~RSAKeyMaker() override + { + wait(); + if (result) + RSA_free(result); + } + + void run() override + { + std::unique_ptr rsa(RSA_new(), RsaDeleter); + if (!rsa) + return; + + std::unique_ptr e(BN_new(), BnDeleter); + if (!e) + return; + + BN_clear(e.get()); + if (BN_set_word(e.get(), exp) != 1) + return; + + if (RSA_generate_key_ex(rsa.get(), bits, e.get(), nullptr) == 0) { + return; + } + + result = rsa.release(); + } + + RSA *takeResult() + { + RSA *rsa = result; + result = nullptr; + return rsa; + } +}; + +class RSAKey : public RSAContext +{ + Q_OBJECT +public: + EVPKey evp; + RSAKeyMaker *keymaker; + bool wasBlocking; + bool sec; + + RSAKey(Provider *p) + : RSAContext(p) + { + keymaker = nullptr; + sec = false; + } + + RSAKey(const RSAKey &from) + : RSAContext(from.provider()) + , evp(from.evp) + { + keymaker = nullptr; + sec = from.sec; + } + + ~RSAKey() override + { + delete keymaker; + } + + Provider::Context *clone() const override + { + return new RSAKey(*this); + } + + bool isNull() const override + { + return (evp.pkey ? false : true); + } + + PKey::Type type() const override + { + return PKey::RSA; + } + + bool isPrivate() const override + { + return sec; + } + + bool canExport() const override + { + return true; + } + + void convertToPublic() override + { + if (!sec) + return; + + // extract the public key into DER format + const RSA *rsa_pkey = EVP_PKEY_get0_RSA(evp.pkey); + int len = i2d_RSAPublicKey(rsa_pkey, nullptr); + SecureArray result(len); + unsigned char *p = (unsigned char *)result.data(); + i2d_RSAPublicKey(rsa_pkey, &p); + p = (unsigned char *)result.data(); + + // put the DER public key back into openssl + evp.reset(); + RSA *rsa = d2i_RSAPublicKey(nullptr, (const unsigned char **)&p, result.size()); + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(evp.pkey, rsa); + sec = false; + } + + int bits() const override + { + return EVP_PKEY_bits(evp.pkey); + } + + int maximumEncryptSize(EncryptionAlgorithm alg) const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + int size = 0; + switch (alg) { + case EME_PKCS1v15: + size = RSA_size(rsa) - 11 - 1; + break; + case EME_PKCS1_OAEP: + size = RSA_size(rsa) - 41 - 1; + break; + case EME_PKCS1v15_SSL: + size = RSA_size(rsa) - 11 - 1; + break; + case EME_NO_PADDING: + size = RSA_size(rsa) - 1; + break; + } + + return size; + } + + SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + SecureArray buf = in; + int max = maximumEncryptSize(alg); + + if (buf.size() > max) + buf.resize(max); + SecureArray result(RSA_size(rsa)); + + int pad; + switch (alg) { + case EME_PKCS1v15: + pad = RSA_PKCS1_PADDING; + break; + case EME_PKCS1_OAEP: + pad = RSA_PKCS1_OAEP_PADDING; + break; +// OPENSSL_VERSION_MAJOR is only defined on openssl > 3.0 +// that doesn't have RSA_SSLV23_PADDING so we can use it negatively here +#ifndef OPENSSL_VERSION_MAJOR + case EME_PKCS1v15_SSL: + pad = RSA_SSLV23_PADDING; + break; +#endif + case EME_NO_PADDING: + pad = RSA_NO_PADDING; + break; + default: + return SecureArray(); + break; + } + + int ret; + if (isPrivate()) + ret = RSA_private_encrypt( + buf.size(), (unsigned char *)buf.data(), (unsigned char *)result.data(), (RSA *)rsa, pad); + else + ret = RSA_public_encrypt( + buf.size(), (unsigned char *)buf.data(), (unsigned char *)result.data(), (RSA *)rsa, pad); + + if (ret < 0) + return SecureArray(); + result.resize(ret); + + return result; + } + + bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + SecureArray result(RSA_size(rsa)); + int pad; + + switch (alg) { + case EME_PKCS1v15: + pad = RSA_PKCS1_PADDING; + break; + case EME_PKCS1_OAEP: + pad = RSA_PKCS1_OAEP_PADDING; + break; +// OPENSSL_VERSION_MAJOR is only defined on openssl > 3.0 +// that doesn't have RSA_SSLV23_PADDING so we can use it negatively here +#ifndef OPENSSL_VERSION_MAJOR + case EME_PKCS1v15_SSL: + pad = RSA_SSLV23_PADDING; + break; +#endif + case EME_NO_PADDING: + pad = RSA_NO_PADDING; + break; + default: + return false; + break; + } + + int ret; + if (isPrivate()) + ret = RSA_private_decrypt( + in.size(), (unsigned char *)in.data(), (unsigned char *)result.data(), (RSA *)rsa, pad); + else + ret = RSA_public_decrypt( + in.size(), (unsigned char *)in.data(), (unsigned char *)result.data(), (RSA *)rsa, pad); + + if (ret < 0) + return false; + result.resize(ret); + + *out = result; + return true; + } + + void startSign(SignatureAlgorithm alg, SignatureFormat) override + { + const EVP_MD *md = nullptr; + if (alg == EMSA3_SHA1) + md = EVP_sha1(); + else if (alg == EMSA3_MD5) + md = EVP_md5(); + else if (alg == EMSA3_SHA224) + md = EVP_sha224(); + else if (alg == EMSA3_SHA256) + md = EVP_sha256(); + else if (alg == EMSA3_SHA384) + md = EVP_sha384(); + else if (alg == EMSA3_SHA512) + md = EVP_sha512(); + else if (alg == EMSA3_Raw) { + // md = 0 + } else if (s_legacyProviderAvailable) { + if (alg == EMSA3_RIPEMD160) + md = EVP_ripemd160(); +#ifdef HAVE_OPENSSL_MD2 + else if (alg == EMSA3_MD2) + md = EVP_md2(); +#endif + } + + evp.startSign(md); + } + + void startVerify(SignatureAlgorithm alg, SignatureFormat) override + { + const EVP_MD *md = nullptr; + if (alg == EMSA3_SHA1) + md = EVP_sha1(); + else if (alg == EMSA3_MD5) + md = EVP_md5(); + else if (alg == EMSA3_SHA224) + md = EVP_sha224(); + else if (alg == EMSA3_SHA256) + md = EVP_sha256(); + else if (alg == EMSA3_SHA384) + md = EVP_sha384(); + else if (alg == EMSA3_SHA512) + md = EVP_sha512(); + else if (alg == EMSA3_Raw) { + // md = 0 + } else if (s_legacyProviderAvailable) { + if (alg == EMSA3_RIPEMD160) + md = EVP_ripemd160(); +#ifdef HAVE_OPENSSL_MD2 + else if (alg == EMSA3_MD2) + md = EVP_md2(); +#endif + } + evp.startVerify(md); + } + + void update(const MemoryRegion &in) override + { + evp.update(in); + } + + QByteArray endSign() override + { + return evp.endSign().toByteArray(); + } + + bool endVerify(const QByteArray &sig) override + { + return evp.endVerify(sig); + } + + void createPrivate(int bits, int exp, bool block) override + { + evp.reset(); + + keymaker = new RSAKeyMaker(bits, exp, !block ? this : nullptr); + wasBlocking = block; + if (block) { + keymaker->run(); + km_finished(); + } else { + connect(keymaker, &RSAKeyMaker::finished, this, &RSAKey::km_finished); + keymaker->start(); + } + } + + void createPrivate(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d) override + { + evp.reset(); + + RSA *rsa = RSA_new(); + if (RSA_set0_key(rsa, bi2bn(n), bi2bn(e), bi2bn(d)) == 0 || RSA_set0_factors(rsa, bi2bn(p), bi2bn(q)) == 0) { + // Free BIGNUMS? + RSA_free(rsa); + return; + } + + // When private key has no Public Exponent (e) or Private Exponent (d) + // need to disable blinding. Otherwise decryption will be broken. + // http://www.mail-archive.com/openssl-users@openssl.org/msg63530.html + if (e == BigInteger(0) || d == BigInteger(0)) + RSA_blinding_off(rsa); + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(evp.pkey, rsa); + sec = true; + } + + void createPublic(const BigInteger &n, const BigInteger &e) override + { + evp.reset(); + + RSA *rsa = RSA_new(); + if (RSA_set0_key(rsa, bi2bn(n), bi2bn(e), nullptr) == 0) { + RSA_free(rsa); + return; + } + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(evp.pkey, rsa); + sec = false; + } + + BigInteger n() const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + const BIGNUM *bnn; + RSA_get0_key(rsa, &bnn, nullptr, nullptr); + return bn2bi(bnn); + } + + BigInteger e() const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + const BIGNUM *bne; + RSA_get0_key(rsa, nullptr, &bne, nullptr); + return bn2bi(bne); + } + + BigInteger p() const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + const BIGNUM *bnp; + RSA_get0_factors(rsa, &bnp, nullptr); + return bn2bi(bnp); + } + + BigInteger q() const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + const BIGNUM *bnq; + RSA_get0_factors(rsa, nullptr, &bnq); + return bn2bi(bnq); + } + + BigInteger d() const override + { + const RSA *rsa = EVP_PKEY_get0_RSA(evp.pkey); + const BIGNUM *bnd; + RSA_get0_key(rsa, nullptr, nullptr, &bnd); + return bn2bi(bnd); + } + +private Q_SLOTS: + void km_finished() + { + RSA *rsa = keymaker->takeResult(); + if (wasBlocking) + delete keymaker; + else + keymaker->deleteLater(); + keymaker = nullptr; + + if (rsa) { + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(evp.pkey, rsa); + sec = true; + } + + if (!wasBlocking) + emit finished(); + } +}; + +//---------------------------------------------------------------------------- +// DSAKey +//---------------------------------------------------------------------------- +class DSAKeyMaker : public QThread +{ + Q_OBJECT +public: + DLGroup domain; + DSA *result; + + DSAKeyMaker(const DLGroup &_domain, QObject *parent = nullptr) + : QThread(parent) + , domain(_domain) + , result(nullptr) + { + } + + ~DSAKeyMaker() override + { + wait(); + if (result) + DSA_free(result); + } + + void run() override + { + std::unique_ptr dsa(DSA_new()); + BIGNUM *pne = bi2bn(domain.p()), *qne = bi2bn(domain.q()), *gne = bi2bn(domain.g()); + + if (!DSA_set0_pqg(dsa.get(), pne, qne, gne)) { + return; + } + if (!DSA_generate_key(dsa.get())) { + // OPENSSL_VERSION_MAJOR is only defined in openssl3 +#ifdef OPENSSL_VERSION_MAJOR + // HACK + // in openssl3 there is an internal flag for "legacy" values + // bits < 2048 && seed_len <= 20 + // set in ossl_ffc_params_FIPS186_2_generate (called by DSA_generate_parameters_ex) + // that we have no way to get or set, so if the bits are smaller than 2048 we generate + // a dsa from a dummy seed and then override the p/q/g with the ones we want + // so we can reuse the internal flag + if (BN_num_bits(pne) < 2048) { + int dummy; + dsa.reset(DSA_new()); + if (DSA_generate_parameters_ex( + dsa.get(), 512, (const unsigned char *)"THIS_IS_A_DUMMY_SEED", 20, &dummy, nullptr, nullptr) != + 1) { + return; + } + pne = bi2bn(domain.p()); + qne = bi2bn(domain.q()); + gne = bi2bn(domain.g()); + if (!DSA_set0_pqg(dsa.get(), pne, qne, gne)) { + return; + } + if (!DSA_generate_key(dsa.get())) { + return; + } + } else { + return; + } +#else + return; +#endif + } + result = dsa.release(); + } + + DSA *takeResult() + { + DSA *dsa = result; + result = nullptr; + return dsa; + } +}; + +// note: DSA doesn't use SignatureAlgorithm, since EMSA1 is always assumed +class DSAKey : public DSAContext +{ + Q_OBJECT +public: + EVPKey evp; + DSAKeyMaker *keymaker; + bool wasBlocking; + bool transformsig; + bool sec; + + DSAKey(Provider *p) + : DSAContext(p) + { + keymaker = nullptr; + sec = false; + } + + DSAKey(const DSAKey &from) + : DSAContext(from.provider()) + , evp(from.evp) + { + keymaker = nullptr; + sec = from.sec; + } + + ~DSAKey() override + { + delete keymaker; + } + + Provider::Context *clone() const override + { + return new DSAKey(*this); + } + + bool isNull() const override + { + return (evp.pkey ? false : true); + } + + PKey::Type type() const override + { + return PKey::DSA; + } + + bool isPrivate() const override + { + return sec; + } + + bool canExport() const override + { + return true; + } + + void convertToPublic() override + { + if (!sec) + return; + + // extract the public key into DER format + const DSA *dsa_pkey = EVP_PKEY_get0_DSA(evp.pkey); + int len = i2d_DSAPublicKey(dsa_pkey, nullptr); + SecureArray result(len); + unsigned char *p = (unsigned char *)result.data(); + i2d_DSAPublicKey(dsa_pkey, &p); + p = (unsigned char *)result.data(); + + // put the DER public key back into openssl + evp.reset(); + DSA *dsa = d2i_DSAPublicKey(nullptr, (const unsigned char **)&p, result.size()); + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(evp.pkey, dsa); + sec = false; + } + + int bits() const override + { + return EVP_PKEY_bits(evp.pkey); + } + + void startSign(SignatureAlgorithm, SignatureFormat format) override + { + // openssl native format is DER, so transform otherwise + if (format != DERSequence) + transformsig = true; + else + transformsig = false; + + evp.startSign(EVP_sha1()); + } + + void startVerify(SignatureAlgorithm, SignatureFormat format) override + { + // openssl native format is DER, so transform otherwise + if (format != DERSequence) + transformsig = true; + else + transformsig = false; + + evp.startVerify(EVP_sha1()); + } + + void update(const MemoryRegion &in) override + { + evp.update(in); + } + + QByteArray endSign() override + { + SecureArray out = evp.endSign(); + if (transformsig) + return dsasig_der_to_raw(out).toByteArray(); + else + return out.toByteArray(); + } + + bool endVerify(const QByteArray &sig) override + { + SecureArray in; + if (transformsig) + in = dsasig_raw_to_der(sig); + else + in = sig; + return evp.endVerify(in); + } + + void createPrivate(const DLGroup &domain, bool block) override + { + evp.reset(); + + keymaker = new DSAKeyMaker(domain, !block ? this : nullptr); + wasBlocking = block; + if (block) { + keymaker->run(); + km_finished(); + } else { + connect(keymaker, &DSAKeyMaker::finished, this, &DSAKey::km_finished); + keymaker->start(); + } + } + + void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) override + { + evp.reset(); + + DSA *dsa = DSA_new(); + BIGNUM *bnp = bi2bn(domain.p()); + BIGNUM *bnq = bi2bn(domain.q()); + BIGNUM *bng = bi2bn(domain.g()); + BIGNUM *bnpub_key = bi2bn(y); + BIGNUM *bnpriv_key = bi2bn(x); + + if (!DSA_set0_pqg(dsa, bnp, bnq, bng) || !DSA_set0_key(dsa, bnpub_key, bnpriv_key)) { + DSA_free(dsa); + return; + } + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(evp.pkey, dsa); + sec = true; + } + + void createPublic(const DLGroup &domain, const BigInteger &y) override + { + evp.reset(); + + DSA *dsa = DSA_new(); + BIGNUM *bnp = bi2bn(domain.p()); + BIGNUM *bnq = bi2bn(domain.q()); + BIGNUM *bng = bi2bn(domain.g()); + BIGNUM *bnpub_key = bi2bn(y); + + if (!DSA_set0_pqg(dsa, bnp, bnq, bng) || !DSA_set0_key(dsa, bnpub_key, nullptr)) { + DSA_free(dsa); + return; + } + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(evp.pkey, dsa); + sec = false; + } + + DLGroup domain() const override + { + const DSA *dsa = EVP_PKEY_get0_DSA(evp.pkey); + const BIGNUM *bnp, *bnq, *bng; + DSA_get0_pqg(dsa, &bnp, &bnq, &bng); + return DLGroup(bn2bi(bnp), bn2bi(bnq), bn2bi(bng)); + } + + BigInteger y() const override + { + const DSA *dsa = EVP_PKEY_get0_DSA(evp.pkey); + const BIGNUM *bnpub_key; + DSA_get0_key(dsa, &bnpub_key, nullptr); + return bn2bi(bnpub_key); + } + + BigInteger x() const override + { + const DSA *dsa = EVP_PKEY_get0_DSA(evp.pkey); + const BIGNUM *bnpriv_key; + DSA_get0_key(dsa, nullptr, &bnpriv_key); + return bn2bi(bnpriv_key); + } + +private Q_SLOTS: + void km_finished() + { + DSA *dsa = keymaker->takeResult(); + if (wasBlocking) + delete keymaker; + else + keymaker->deleteLater(); + keymaker = nullptr; + + if (dsa) { + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DSA(evp.pkey, dsa); + sec = true; + } + + if (!wasBlocking) + emit finished(); + } +}; + +//---------------------------------------------------------------------------- +// DHKey +//---------------------------------------------------------------------------- +class DHKeyMaker : public QThread +{ + Q_OBJECT +public: + DLGroup domain; + DH *result; + + DHKeyMaker(const DLGroup &_domain, QObject *parent = nullptr) + : QThread(parent) + , domain(_domain) + , result(nullptr) + { + } + + ~DHKeyMaker() override + { + wait(); + if (result) + DH_free(result); + } + + void run() override + { + DH *dh = DH_new(); + BIGNUM *bnp = bi2bn(domain.p()); + BIGNUM *bng = bi2bn(domain.g()); + if (!DH_set0_pqg(dh, bnp, nullptr, bng) || !DH_generate_key(dh)) { + DH_free(dh); + return; + } + result = dh; + } + + DH *takeResult() + { + DH *dh = result; + result = nullptr; + return dh; + } +}; + +class DHKey : public DHContext +{ + Q_OBJECT +public: + EVPKey evp; + DHKeyMaker *keymaker; + bool wasBlocking; + bool sec; + + DHKey(Provider *p) + : DHContext(p) + { + keymaker = nullptr; + sec = false; + } + + DHKey(const DHKey &from) + : DHContext(from.provider()) + , evp(from.evp) + { + keymaker = nullptr; + sec = from.sec; + } + + ~DHKey() override + { + delete keymaker; + } + + Provider::Context *clone() const override + { + return new DHKey(*this); + } + + bool isNull() const override + { + return (evp.pkey ? false : true); + } + + PKey::Type type() const override + { + return PKey::DH; + } + + bool isPrivate() const override + { + return sec; + } + + bool canExport() const override + { + return true; + } + + void convertToPublic() override + { + if (!sec) + return; + + const DH *orig = EVP_PKEY_get0_DH(evp.pkey); + DH *dh = DH_new(); + const BIGNUM *bnp, *bng, *bnpub_key; + DH_get0_pqg(orig, &bnp, nullptr, &bng); + DH_get0_key(orig, &bnpub_key, nullptr); + + DH_set0_key(dh, BN_dup(bnpub_key), nullptr); + DH_set0_pqg(dh, BN_dup(bnp), nullptr, BN_dup(bng)); + + evp.reset(); + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DH(evp.pkey, dh); + sec = false; + } + + int bits() const override + { + return EVP_PKEY_bits(evp.pkey); + } + + SymmetricKey deriveKey(const PKeyBase &theirs) override + { + const DH *dh = EVP_PKEY_get0_DH(evp.pkey); + const DH *them = EVP_PKEY_get0_DH(static_cast(&theirs)->evp.pkey); + const BIGNUM *bnpub_key; + DH_get0_key(them, &bnpub_key, nullptr); + + SecureArray result(DH_size(dh)); + int ret = DH_compute_key((unsigned char *)result.data(), bnpub_key, (DH *)dh); + if (ret <= 0) + return SymmetricKey(); + result.resize(ret); + return SymmetricKey(result); + } + + void createPrivate(const DLGroup &domain, bool block) override + { + evp.reset(); + + keymaker = new DHKeyMaker(domain, !block ? this : nullptr); + wasBlocking = block; + if (block) { + keymaker->run(); + km_finished(); + } else { + connect(keymaker, &DHKeyMaker::finished, this, &DHKey::km_finished); + keymaker->start(); + } + } + + void createPrivate(const DLGroup &domain, const BigInteger &y, const BigInteger &x) override + { + evp.reset(); + + DH *dh = DH_new(); + BIGNUM *bnp = bi2bn(domain.p()); + BIGNUM *bng = bi2bn(domain.g()); + BIGNUM *bnpub_key = bi2bn(y); + BIGNUM *bnpriv_key = bi2bn(x); + + if (!DH_set0_key(dh, bnpub_key, bnpriv_key) || !DH_set0_pqg(dh, bnp, nullptr, bng)) { + DH_free(dh); + return; + } + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DH(evp.pkey, dh); + sec = true; + } + + void createPublic(const DLGroup &domain, const BigInteger &y) override + { + evp.reset(); + + DH *dh = DH_new(); + BIGNUM *bnp = bi2bn(domain.p()); + BIGNUM *bng = bi2bn(domain.g()); + BIGNUM *bnpub_key = bi2bn(y); + + if (!DH_set0_key(dh, bnpub_key, nullptr) || !DH_set0_pqg(dh, bnp, nullptr, bng)) { + DH_free(dh); + return; + } + + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DH(evp.pkey, dh); + sec = false; + } + + DLGroup domain() const override + { + const DH *dh = EVP_PKEY_get0_DH(evp.pkey); + const BIGNUM *bnp, *bng; + DH_get0_pqg(dh, &bnp, nullptr, &bng); + return DLGroup(bn2bi(bnp), bn2bi(bng)); + } + + BigInteger y() const override + { + const DH *dh = EVP_PKEY_get0_DH(evp.pkey); + const BIGNUM *bnpub_key; + DH_get0_key(dh, &bnpub_key, nullptr); + return bn2bi(bnpub_key); + } + + BigInteger x() const override + { + const DH *dh = EVP_PKEY_get0_DH(evp.pkey); + const BIGNUM *bnpriv_key; + DH_get0_key(dh, nullptr, &bnpriv_key); + return bn2bi(bnpriv_key); + } + +private Q_SLOTS: + void km_finished() + { + DH *dh = keymaker->takeResult(); + if (wasBlocking) + delete keymaker; + else + keymaker->deleteLater(); + keymaker = nullptr; + + if (dh) { + evp.pkey = EVP_PKEY_new(); + EVP_PKEY_assign_DH(evp.pkey, dh); + sec = true; + } + + if (!wasBlocking) + emit finished(); + } +}; + +//---------------------------------------------------------------------------- +// QCA-based RSA_METHOD +//---------------------------------------------------------------------------- + +// only supports EMSA3_Raw for now +class QCA_RSA_METHOD +{ +public: + RSAPrivateKey key; + + QCA_RSA_METHOD(const RSAPrivateKey &_key, RSA *rsa) + { + key = _key; + RSA_set_method(rsa, rsa_method()); + RSA_set_app_data(rsa, this); + BIGNUM *bnn = bi2bn(_key.n()); + BIGNUM *bne = bi2bn(_key.e()); + + RSA_set0_key(rsa, bnn, bne, nullptr); + } + + RSA_METHOD *rsa_method() + { + static RSA_METHOD *ops = nullptr; + + if (!ops) { + ops = RSA_meth_dup(RSA_get_default_method()); + RSA_meth_set_priv_enc(ops, nullptr); // pkcs11_rsa_encrypt + RSA_meth_set_priv_dec(ops, rsa_priv_dec); // pkcs11_rsa_encrypt + RSA_meth_set_sign(ops, nullptr); + RSA_meth_set_verify(ops, nullptr); // pkcs11_rsa_verify + RSA_meth_set_finish(ops, rsa_finish); + } + return ops; + } + + static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) + { + QCA::EncryptionAlgorithm algo; + + if (padding == RSA_PKCS1_PADDING) { + algo = QCA::EME_PKCS1v15; + } else if (padding == RSA_PKCS1_OAEP_PADDING) { + algo = QCA::EME_PKCS1_OAEP; + } else { + RSAerr(RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + return -1; + } + + QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); + + QCA::SecureArray input; + input.resize(flen); + memcpy(input.data(), from, input.size()); + + QCA::SecureArray output; + + if (self->key.decrypt(input, &output, algo)) { + memcpy(to, output.data(), output.size()); + return output.size(); + } + + // XXX: An error should be set in this case too. + return -1; + } + + static int rsa_finish(RSA *rsa) + { + QCA_RSA_METHOD *self = (QCA_RSA_METHOD *)RSA_get_app_data(rsa); + delete self; + return 1; + } +}; + +static RSA *createFromExisting(const RSAPrivateKey &key) +{ + RSA *r = RSA_new(); + new QCA_RSA_METHOD(key, r); // will delete itself on RSA_free + return r; +} + +//---------------------------------------------------------------------------- +// MyPKeyContext +//---------------------------------------------------------------------------- +class MyPKeyContext : public PKeyContext +{ + Q_OBJECT +public: + PKeyBase *k; + + MyPKeyContext(Provider *p) + : PKeyContext(p) + { + k = nullptr; + } + + ~MyPKeyContext() override + { + delete k; + } + + Provider::Context *clone() const override + { + MyPKeyContext *c = new MyPKeyContext(*this); + c->k = (PKeyBase *)k->clone(); + return c; + } + + QList supportedTypes() const override + { + QList list; + list += PKey::RSA; + list += PKey::DSA; + list += PKey::DH; + return list; + } + + QList supportedIOTypes() const override + { + QList list; + list += PKey::RSA; + list += PKey::DSA; + return list; + } + + QList supportedPBEAlgorithms() const override + { + QList list; + list += PBES2_DES_SHA1; + list += PBES2_TripleDES_SHA1; + return list; + } + + PKeyBase *key() override + { + return k; + } + + const PKeyBase *key() const override + { + return k; + } + + void setKey(PKeyBase *key) override + { + k = key; + } + + bool importKey(const PKeyBase *key) override + { + Q_UNUSED(key); + return false; + } + + EVP_PKEY *get_pkey() const + { + PKey::Type t = k->type(); + if (t == PKey::RSA) + return static_cast(k)->evp.pkey; + else if (t == PKey::DSA) + return static_cast(k)->evp.pkey; + else + return static_cast(k)->evp.pkey; + } + + PKeyBase *pkeyToBase(EVP_PKEY *pkey, bool sec) const + { + PKeyBase *nk = nullptr; + int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); + if (pkey_type == EVP_PKEY_RSA) { + RSAKey *c = new RSAKey(provider()); + c->evp.pkey = pkey; + c->sec = sec; + nk = c; + } else if (pkey_type == EVP_PKEY_DSA) { + DSAKey *c = new DSAKey(provider()); + c->evp.pkey = pkey; + c->sec = sec; + nk = c; + } else if (pkey_type == EVP_PKEY_DH) { + DHKey *c = new DHKey(provider()); + c->evp.pkey = pkey; + c->sec = sec; + nk = c; + } else { + EVP_PKEY_free(pkey); + } + return nk; + } + + QByteArray publicToDER() const override + { + EVP_PKEY *pkey = get_pkey(); + + int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); + + // OpenSSL does not have DH import/export support + if (pkey_type == EVP_PKEY_DH) + return QByteArray(); + + BIO *bo = BIO_new(BIO_s_mem()); + i2d_PUBKEY_bio(bo, pkey); + const QByteArray buf = bio2ba(bo); + return buf; + } + + QString publicToPEM() const override + { + EVP_PKEY *pkey = get_pkey(); + + int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); + + // OpenSSL does not have DH import/export support + if (pkey_type == EVP_PKEY_DH) + return QString(); + + BIO *bo = BIO_new(BIO_s_mem()); + PEM_write_bio_PUBKEY(bo, pkey); + const QByteArray buf = bio2ba(bo); + return QString::fromLatin1(buf); + } + + ConvertResult publicFromDER(const QByteArray &in) override + { + delete k; + k = nullptr; + + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + EVP_PKEY *pkey = d2i_PUBKEY_bio(bi, nullptr); + BIO_free(bi); + + if (!pkey) + return ErrorDecode; + + k = pkeyToBase(pkey, false); + if (k) + return ConvertGood; + else + return ErrorDecode; + } + + ConvertResult publicFromPEM(const QString &s) override + { + delete k; + k = nullptr; + + const QByteArray in = s.toLatin1(); + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + EVP_PKEY *pkey = PEM_read_bio_PUBKEY(bi, nullptr, passphrase_cb, nullptr); + BIO_free(bi); + + if (!pkey) + return ErrorDecode; + + k = pkeyToBase(pkey, false); + if (k) + return ConvertGood; + else + return ErrorDecode; + } + + SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + // if(pbe == PBEDefault) + // pbe = PBES2_TripleDES_SHA1; + + const EVP_CIPHER *cipher = nullptr; + if (pbe == PBES2_TripleDES_SHA1) + cipher = EVP_des_ede3_cbc(); + else if (pbe == PBES2_DES_SHA1) + cipher = EVP_des_cbc(); + + if (!cipher) + return SecureArray(); + + EVP_PKEY *pkey = get_pkey(); + int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); + + // OpenSSL does not have DH import/export support + if (pkey_type == EVP_PKEY_DH) + return SecureArray(); + + BIO *bo = BIO_new(BIO_s_mem()); + if (!passphrase.isEmpty()) + i2d_PKCS8PrivateKey_bio(bo, pkey, cipher, nullptr, 0, nullptr, (void *)passphrase.data()); + else + i2d_PKCS8PrivateKey_bio(bo, pkey, nullptr, nullptr, 0, nullptr, nullptr); + SecureArray buf = bio2buf(bo); + return buf; + } + + QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + // if(pbe == PBEDefault) + // pbe = PBES2_TripleDES_SHA1; + + const EVP_CIPHER *cipher = nullptr; + if (pbe == PBES2_TripleDES_SHA1) + cipher = EVP_des_ede3_cbc(); + else if (pbe == PBES2_DES_SHA1) + cipher = EVP_des_cbc(); + + if (!cipher) + return QString(); + + EVP_PKEY *pkey = get_pkey(); + int pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey)); + + // OpenSSL does not have DH import/export support + if (pkey_type == EVP_PKEY_DH) + return QString(); + + BIO *bo = BIO_new(BIO_s_mem()); + if (!passphrase.isEmpty()) + PEM_write_bio_PKCS8PrivateKey(bo, pkey, cipher, nullptr, 0, nullptr, (void *)passphrase.data()); + else + PEM_write_bio_PKCS8PrivateKey(bo, pkey, nullptr, nullptr, 0, nullptr, nullptr); + SecureArray buf = bio2buf(bo); + return QString::fromLatin1(buf.toByteArray()); + } + + ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override + { + delete k; + k = nullptr; + + EVP_PKEY *pkey; + if (!passphrase.isEmpty()) + pkey = qca_d2i_PKCS8PrivateKey(in, nullptr, nullptr, (void *)passphrase.data()); + else + pkey = qca_d2i_PKCS8PrivateKey(in, nullptr, passphrase_cb, nullptr); + + if (!pkey) + return ErrorDecode; + + k = pkeyToBase(pkey, true); + if (k) + return ConvertGood; + else + return ErrorDecode; + } + + ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override + { + delete k; + k = nullptr; + + const QByteArray in = s.toLatin1(); + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + EVP_PKEY *pkey; + if (!passphrase.isEmpty()) + pkey = PEM_read_bio_PrivateKey(bi, nullptr, nullptr, (void *)passphrase.data()); + else + pkey = PEM_read_bio_PrivateKey(bi, nullptr, passphrase_cb, nullptr); + BIO_free(bi); + + if (!pkey) + return ErrorDecode; + + k = pkeyToBase(pkey, true); + if (k) + return ConvertGood; + else + return ErrorDecode; + } +}; + +//---------------------------------------------------------------------------- +// MyCertContext +//---------------------------------------------------------------------------- +class X509Item +{ +public: + X509 *cert; + X509_REQ *req; + X509_CRL *crl; + + enum Type + { + TypeCert, + TypeReq, + TypeCRL + }; + + X509Item() + { + cert = nullptr; + req = nullptr; + crl = nullptr; + } + + X509Item(const X509Item &from) + { + cert = nullptr; + req = nullptr; + crl = nullptr; + *this = from; + } + + ~X509Item() + { + reset(); + } + + X509Item &operator=(const X509Item &from) + { + if (this != &from) { + reset(); + cert = from.cert; + req = from.req; + crl = from.crl; + + if (cert) + X509_up_ref(cert); + if (req) { + // Not exposed, so copy + req = X509_REQ_dup(req); + } + if (crl) + X509_CRL_up_ref(crl); + } + + return *this; + } + + void reset() + { + if (cert) { + X509_free(cert); + cert = nullptr; + } + if (req) { + X509_REQ_free(req); + req = nullptr; + } + if (crl) { + X509_CRL_free(crl); + crl = nullptr; + } + } + + bool isNull() const + { + return (!cert && !req && !crl); + } + + QByteArray toDER() const + { + BIO *bo = BIO_new(BIO_s_mem()); + if (cert) + i2d_X509_bio(bo, cert); + else if (req) + i2d_X509_REQ_bio(bo, req); + else if (crl) + i2d_X509_CRL_bio(bo, crl); + const QByteArray buf = bio2ba(bo); + return buf; + } + + QString toPEM() const + { + BIO *bo = BIO_new(BIO_s_mem()); + if (cert) + PEM_write_bio_X509(bo, cert); + else if (req) + PEM_write_bio_X509_REQ(bo, req); + else if (crl) + PEM_write_bio_X509_CRL(bo, crl); + const QByteArray buf = bio2ba(bo); + return QString::fromLatin1(buf); + } + + ConvertResult fromDER(const QByteArray &in, Type t) + { + reset(); + + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + + if (t == TypeCert) + cert = d2i_X509_bio(bi, nullptr); + else if (t == TypeReq) + req = d2i_X509_REQ_bio(bi, nullptr); + else if (t == TypeCRL) + crl = d2i_X509_CRL_bio(bi, nullptr); + + BIO_free(bi); + + if (isNull()) + return ErrorDecode; + + return ConvertGood; + } + + ConvertResult fromPEM(const QString &s, Type t) + { + reset(); + + const QByteArray in = s.toLatin1(); + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + + if (t == TypeCert) + cert = PEM_read_bio_X509(bi, nullptr, passphrase_cb, nullptr); + else if (t == TypeReq) + req = PEM_read_bio_X509_REQ(bi, nullptr, passphrase_cb, nullptr); + else if (t == TypeCRL) + crl = PEM_read_bio_X509_CRL(bi, nullptr, passphrase_cb, nullptr); + + BIO_free(bi); + + if (isNull()) + return ErrorDecode; + + return ConvertGood; + } +}; + +// (taken from kdelibs) -- Justin +// +// This code is mostly taken from OpenSSL v0.9.5a +// by Eric Young +QDateTime ASN1_UTCTIME_QDateTime(const ASN1_UTCTIME *tm, int *isGmt) +{ + QDateTime qdt; + char *v; + int gmt = 0; + int i; + int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; + QDate qdate; + QTime qtime; + + i = tm->length; + v = (char *)tm->data; + + if (i < 10) + goto auq_err; + if (v[i - 1] == 'Z') + gmt = 1; + for (i = 0; i < 10; i++) + if ((v[i] > '9') || (v[i] < '0')) + goto auq_err; + y = (v[0] - '0') * 10 + (v[1] - '0'); + if (y < 50) + y += 100; + M = (v[2] - '0') * 10 + (v[3] - '0'); + if ((M > 12) || (M < 1)) + goto auq_err; + d = (v[4] - '0') * 10 + (v[5] - '0'); + h = (v[6] - '0') * 10 + (v[7] - '0'); + m = (v[8] - '0') * 10 + (v[9] - '0'); + if ((v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) + s = (v[10] - '0') * 10 + (v[11] - '0'); + + // localize the date and display it. + qdate.setDate(y + 1900, M, d); + qtime.setHMS(h, m, s); + qdt.setDate(qdate); + qdt.setTime(qtime); + if (gmt) + qdt.setTimeSpec(Qt::UTC); +auq_err: + if (isGmt) + *isGmt = gmt; + return qdt; +} + +class MyCertContext; +static bool sameChain(STACK_OF(X509) * ossl, const QList &qca); + +// TODO: support read/write of multiple info values with the same name +class MyCertContext : public CertContext +{ + Q_OBJECT +public: + X509Item item; + CertContextProps _props; + + MyCertContext(Provider *p) + : CertContext(p) + { + // printf("[%p] ** created\n", this); + } + + MyCertContext(const MyCertContext &from) + : CertContext(from) + , item(from.item) + , _props(from._props) + { + // printf("[%p] ** created as copy (from [%p])\n", this, &from); + } + + ~MyCertContext() override + { + // printf("[%p] ** deleted\n", this); + } + + Provider::Context *clone() const override + { + return new MyCertContext(*this); + } + + QByteArray toDER() const override + { + return item.toDER(); + } + + QString toPEM() const override + { + return item.toPEM(); + } + + ConvertResult fromDER(const QByteArray &a) override + { + _props = CertContextProps(); + ConvertResult r = item.fromDER(a, X509Item::TypeCert); + if (r == ConvertGood) + make_props(); + return r; + } + + ConvertResult fromPEM(const QString &s) override + { + _props = CertContextProps(); + ConvertResult r = item.fromPEM(s, X509Item::TypeCert); + if (r == ConvertGood) + make_props(); + return r; + } + + void fromX509(X509 *x) + { + X509_up_ref(x); + item.cert = x; + make_props(); + } + + bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) override + { + _props = CertContextProps(); + item.reset(); + + CertificateInfo info = opts.info(); + + // Note: removing default constraints, let the app choose these if it wants + Constraints constraints = opts.constraints(); + // constraints - logic from Botan + /*Constraints constraints; + if(opts.isCA()) + { + constraints += KeyCertificateSign; + constraints += CRLSign; + } + else + constraints = find_constraints(priv, opts.constraints());*/ + + EVP_PKEY *pk = static_cast(&priv)->get_pkey(); + X509_EXTENSION *ex; + + const EVP_MD *md; + if (priv.key()->type() == PKey::RSA || priv.key()->type() == PKey::DSA) + md = EVP_sha256(); + else + return false; + + // create + X509 *x = X509_new(); + X509_set_version(x, 2); + + // serial + BIGNUM *bn = bi2bn(opts.serialNumber()); + BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x)); + BN_free(bn); + + // validity period + ASN1_TIME_set(X509_get_notBefore(x), opts.notValidBefore().toSecsSinceEpoch()); + ASN1_TIME_set(X509_get_notAfter(x), opts.notValidAfter().toSecsSinceEpoch()); + + // public key + X509_set_pubkey(x, pk); + + // subject + X509_NAME *name = new_cert_name(info); + X509_set_subject_name(x, name); + + // issuer == subject + X509_set_issuer_name(x, name); + + // subject key id + ex = new_subject_key_id(x); + { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // CA mode + ex = new_basic_constraints(opts.isCA(), opts.pathLimit()); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // subject alt name + ex = new_cert_subject_alt_name(info); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // key usage + ex = new_cert_key_usage(constraints); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // extended key usage + ex = new_cert_ext_key_usage(constraints); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // policies + ex = new_cert_policies(opts.policies()); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // finished + X509_sign(x, pk, md); + + item.cert = x; + make_props(); + return true; + } + + const CertContextProps *props() const override + { + // printf("[%p] grabbing props\n", this); + return &_props; + } + + bool compare(const CertContext *other) const override + { + const CertContextProps *a = &_props; + const CertContextProps *b = other->props(); + + PublicKey akey, bkey; + PKeyContext *ac = subjectPublicKey(); + akey.change(ac); + PKeyContext *bc = other->subjectPublicKey(); + bkey.change(bc); + + // logic from Botan + if (a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) + return false; + + if (a->issuer != b->issuer || a->subject != b->subject) + return false; + if (a->serial != b->serial || a->version != b->version) + return false; + if (a->start != b->start || a->end != b->end) + return false; + + return true; + } + + // does a new + PKeyContext *subjectPublicKey() const override + { + MyPKeyContext *kc = new MyPKeyContext(provider()); + EVP_PKEY *pkey = X509_get_pubkey(item.cert); + PKeyBase *kb = kc->pkeyToBase(pkey, false); + kc->setKey(kb); + return kc; + } + + bool isIssuerOf(const CertContext *other) const override + { + // to check a single issuer, we make a list of 1 + STACK_OF(X509) *untrusted_list = sk_X509_new_null(); + + const MyCertContext *our_cc = this; + X509 *x = our_cc->item.cert; + X509_up_ref(x); + sk_X509_push(untrusted_list, x); + + const MyCertContext *other_cc = static_cast(other); + X509 *ox = other_cc->item.cert; + + X509_STORE *store = X509_STORE_new(); + + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + X509_STORE_CTX_init(ctx, store, ox, untrusted_list); + + // we don't care about the verify result here + X509_verify_cert(ctx); + + // grab the chain, which may not be fully populated + STACK_OF(X509) *chain = X509_STORE_CTX_get_chain(ctx); + + bool ok = false; + + // chain should be exactly 2 items + QList expected; + expected += other_cc; + expected += our_cc; + if (chain && sameChain(chain, expected)) + ok = true; + + // cleanup + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + sk_X509_pop_free(untrusted_list, X509_free); + + return ok; + } + + // implemented later because it depends on MyCRLContext + Validity validate(const QList &trusted, + const QList &untrusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const override; + + Validity validate_chain(const QList &chain, + const QList &trusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const override; + + void make_props() + { + X509 *x = item.cert; + CertContextProps p; + + p.version = X509_get_version(x); + + ASN1_INTEGER *ai = X509_get_serialNumber(x); + if (ai) { + char *rep = i2s_ASN1_INTEGER(nullptr, ai); + QString str = QString::fromLatin1(rep); + OPENSSL_free(rep); + p.serial.fromString(str); + } + + p.start = ASN1_UTCTIME_QDateTime(X509_get_notBefore(x), nullptr); + p.end = ASN1_UTCTIME_QDateTime(X509_get_notAfter(x), nullptr); + + CertificateInfo subject, issuer; + + subject = get_cert_name(X509_get_subject_name(x)); + issuer = get_cert_name(X509_get_issuer_name(x)); + + p.isSelfSigned = (X509_V_OK == X509_check_issued(x, x)); + + p.isCA = false; + p.pathLimit = 0; + int pos = X509_get_ext_by_NID(x, NID_basic_constraints, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + get_basic_constraints(ex, &p.isCA, &p.pathLimit); + } + + pos = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + subject.unite(get_cert_alt_name(ex)); + } + + pos = X509_get_ext_by_NID(x, NID_issuer_alt_name, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + issuer.unite(get_cert_alt_name(ex)); + } + + pos = X509_get_ext_by_NID(x, NID_key_usage, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + p.constraints = get_cert_key_usage(ex); + } + + pos = X509_get_ext_by_NID(x, NID_ext_key_usage, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + p.constraints += get_cert_ext_key_usage(ex); + } + + pos = X509_get_ext_by_NID(x, NID_certificate_policies, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + p.policies = get_cert_policies(ex); + } + + const ASN1_BIT_STRING *signature; + + X509_get0_signature(&signature, nullptr, x); + if (signature) { + p.sig = QByteArray(signature->length, 0); + for (int i = 0; i < signature->length; i++) + p.sig[i] = signature->data[i]; + } + + switch (X509_get_signature_nid(x)) { + case NID_sha1WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA1; + break; + case NID_md5WithRSAEncryption: + p.sigalgo = QCA::EMSA3_MD5; + break; +#ifdef HAVE_OPENSSL_MD2 + case NID_md2WithRSAEncryption: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; + break; +#endif + case NID_ripemd160WithRSA: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; + break; + case NID_dsaWithSHA1: + p.sigalgo = QCA::EMSA1_SHA1; + break; + case NID_sha224WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA224; + break; + case NID_sha256WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA256; + break; + case NID_sha384WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA384; + break; + case NID_sha512WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA512; + break; + default: + qDebug() << "Unknown signature value: " << X509_get_signature_nid(x); + p.sigalgo = QCA::SignatureUnknown; + } + + pos = X509_get_ext_by_NID(x, NID_subject_key_identifier, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + p.subjectId += get_cert_subject_key_id(ex); + } + + pos = X509_get_ext_by_NID(x, NID_authority_key_identifier, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_get_ext(x, pos); + if (ex) + p.issuerId += get_cert_issuer_key_id(ex); + } + + // FIXME: super hack + CertificateOptions opts; + opts.setInfo(subject); + p.subject = opts.infoOrdered(); + opts.setInfo(issuer); + p.issuer = opts.infoOrdered(); + + _props = p; + // printf("[%p] made props: [%s]\n", this, _props.subject[CommonName].toLatin1().data()); + } +}; + +bool sameChain(STACK_OF(X509) * ossl, const QList &qca) +{ + if (sk_X509_num(ossl) != qca.count()) + return false; + + for (int n = 0; n < sk_X509_num(ossl); ++n) { + X509 *a = sk_X509_value(ossl, n); + X509 *b = qca[n]->item.cert; + if (X509_cmp(a, b) != 0) + return false; + } + + return true; +} + +//---------------------------------------------------------------------------- +// MyCAContext +//---------------------------------------------------------------------------- +// Thanks to Pascal Patry +class MyCAContext : public CAContext +{ + Q_OBJECT +public: + X509Item caCert; + MyPKeyContext *privateKey; + + MyCAContext(Provider *p) + : CAContext(p) + { + privateKey = nullptr; + } + + MyCAContext(const MyCAContext &from) + : CAContext(from) + , caCert(from.caCert) + { + privateKey = static_cast(from.privateKey->clone()); + } + + ~MyCAContext() override + { + delete privateKey; + } + + CertContext *certificate() const override + { + MyCertContext *cert = new MyCertContext(provider()); + + cert->fromX509(caCert.cert); + return cert; + } + + CertContext *createCertificate(const PKeyContext &pub, const CertificateOptions &opts) const override + { + // TODO: implement + Q_UNUSED(pub) + Q_UNUSED(opts) + return nullptr; + } + + CRLContext *createCRL(const QDateTime &nextUpdate) const override + { + // TODO: implement + Q_UNUSED(nextUpdate) + return nullptr; + } + + void setup(const CertContext &cert, const PKeyContext &priv) override + { + caCert = static_cast(cert).item; + delete privateKey; + privateKey = nullptr; + privateKey = static_cast(priv.clone()); + } + + CertContext *signRequest(const CSRContext &req, const QDateTime ¬ValidAfter) const override + { + MyCertContext *cert = nullptr; + const EVP_MD *md = nullptr; + X509 *x = nullptr; + const CertContextProps &props = *req.props(); + CertificateOptions subjectOpts; + X509_NAME *subjectName = nullptr; + X509_EXTENSION *ex = nullptr; + + if (privateKey->key()->type() == PKey::RSA) + md = EVP_sha1(); + else if (privateKey->key()->type() == PKey::DSA) + md = EVP_sha1(); + else + return nullptr; + + cert = new MyCertContext(provider()); + + subjectOpts.setInfoOrdered(props.subject); + subjectName = new_cert_name(subjectOpts.info()); + + // create + x = X509_new(); + X509_set_version(x, 2); + + // serial + BIGNUM *bn = bi2bn(props.serial); + BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x)); + BN_free(bn); + + // validity period + ASN1_TIME_set(X509_get_notBefore(x), QDateTime::currentDateTimeUtc().toSecsSinceEpoch()); + ASN1_TIME_set(X509_get_notAfter(x), notValidAfter.toSecsSinceEpoch()); + + X509_set_pubkey(x, static_cast(req.subjectPublicKey())->get_pkey()); + X509_set_subject_name(x, subjectName); + X509_set_issuer_name(x, X509_get_subject_name(caCert.cert)); + + // subject key id + ex = new_subject_key_id(x); + { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // CA mode + ex = new_basic_constraints(props.isCA, props.pathLimit); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // subject alt name + ex = new_cert_subject_alt_name(subjectOpts.info()); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // key usage + ex = new_cert_key_usage(props.constraints); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // extended key usage + ex = new_cert_ext_key_usage(props.constraints); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + // policies + ex = new_cert_policies(props.policies); + if (ex) { + X509_add_ext(x, ex, -1); + X509_EXTENSION_free(ex); + } + + if (!X509_sign(x, privateKey->get_pkey(), md)) { + X509_free(x); + delete cert; + return nullptr; + } + + cert->fromX509(x); + X509_free(x); + return cert; + } + + CRLContext * + updateCRL(const CRLContext &crl, const QList &entries, const QDateTime &nextUpdate) const override + { + // TODO: implement + Q_UNUSED(crl) + Q_UNUSED(entries) + Q_UNUSED(nextUpdate) + return nullptr; + } + + Provider::Context *clone() const override + { + return new MyCAContext(*this); + } +}; + +//---------------------------------------------------------------------------- +// MyCSRContext +//---------------------------------------------------------------------------- +class MyCSRContext : public CSRContext +{ + Q_OBJECT +public: + X509Item item; + CertContextProps _props; + + MyCSRContext(Provider *p) + : CSRContext(p) + { + } + + MyCSRContext(const MyCSRContext &from) + : CSRContext(from) + , item(from.item) + , _props(from._props) + { + } + + Provider::Context *clone() const override + { + return new MyCSRContext(*this); + } + + QByteArray toDER() const override + { + return item.toDER(); + } + + QString toPEM() const override + { + return item.toPEM(); + } + + ConvertResult fromDER(const QByteArray &a) override + { + _props = CertContextProps(); + ConvertResult r = item.fromDER(a, X509Item::TypeReq); + if (r == ConvertGood) + make_props(); + return r; + } + + ConvertResult fromPEM(const QString &s) override + { + _props = CertContextProps(); + ConvertResult r = item.fromPEM(s, X509Item::TypeReq); + if (r == ConvertGood) + make_props(); + return r; + } + + bool canUseFormat(CertificateRequestFormat f) const override + { + if (f == PKCS10) + return true; + return false; + } + + bool createRequest(const CertificateOptions &opts, const PKeyContext &priv) override + { + _props = CertContextProps(); + item.reset(); + + CertificateInfo info = opts.info(); + + // Note: removing default constraints, let the app choose these if it wants + Constraints constraints = opts.constraints(); + // constraints - logic from Botan + /*Constraints constraints; + if(opts.isCA()) + { + constraints += KeyCertificateSign; + constraints += CRLSign; + } + else + constraints = find_constraints(priv, opts.constraints());*/ + + EVP_PKEY *pk = static_cast(&priv)->get_pkey(); + X509_EXTENSION *ex; + + const EVP_MD *md; + if (priv.key()->type() == PKey::RSA) + md = EVP_sha1(); + else if (priv.key()->type() == PKey::DSA) + md = EVP_sha1(); + else + return false; + + // create + X509_REQ *x = X509_REQ_new(); + + // public key + X509_REQ_set_pubkey(x, pk); + + // subject + X509_NAME *name = new_cert_name(info); + X509_REQ_set_subject_name(x, name); + + // challenge + const QByteArray cs = opts.challenge().toLatin1(); + if (!cs.isEmpty()) + X509_REQ_add1_attr_by_NID( + x, NID_pkcs9_challengePassword, MBSTRING_UTF8, (const unsigned char *)cs.data(), -1); + + STACK_OF(X509_EXTENSION) *exts = sk_X509_EXTENSION_new_null(); + + // CA mode + ex = new_basic_constraints(opts.isCA(), opts.pathLimit()); + if (ex) + sk_X509_EXTENSION_push(exts, ex); + + // subject alt name + ex = new_cert_subject_alt_name(info); + if (ex) + sk_X509_EXTENSION_push(exts, ex); + + // key usage + ex = new_cert_key_usage(constraints); + if (ex) + sk_X509_EXTENSION_push(exts, ex); + + // extended key usage + ex = new_cert_ext_key_usage(constraints); + if (ex) + sk_X509_EXTENSION_push(exts, ex); + + // policies + ex = new_cert_policies(opts.policies()); + if (ex) + sk_X509_EXTENSION_push(exts, ex); + + if (sk_X509_EXTENSION_num(exts) > 0) + X509_REQ_add_extensions(x, exts); + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + + // finished + X509_REQ_sign(x, pk, md); + + item.req = x; + make_props(); + return true; + } + + const CertContextProps *props() const override + { + return &_props; + } + + bool compare(const CSRContext *other) const override + { + const CertContextProps *a = &_props; + const CertContextProps *b = other->props(); + + PublicKey akey, bkey; + PKeyContext *ac = subjectPublicKey(); + akey.change(ac); + PKeyContext *bc = other->subjectPublicKey(); + bkey.change(bc); + + if (a->sig != b->sig || a->sigalgo != b->sigalgo || akey != bkey) + return false; + + // TODO: Anything else we should compare? + + return true; + } + + PKeyContext *subjectPublicKey() const override // does a new + { + MyPKeyContext *kc = new MyPKeyContext(provider()); + EVP_PKEY *pkey = X509_REQ_get_pubkey(item.req); + PKeyBase *kb = kc->pkeyToBase(pkey, false); + kc->setKey(kb); + return kc; + } + + QString toSPKAC() const override + { + return QString(); + } + + ConvertResult fromSPKAC(const QString &s) override + { + Q_UNUSED(s); + return ErrorDecode; + } + + void make_props() + { + X509_REQ *x = item.req; + CertContextProps p; + + // TODO: QString challenge; + + p.format = PKCS10; + + CertificateInfo subject; + + subject = get_cert_name(X509_REQ_get_subject_name(x)); + + STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x); + + p.isCA = false; + p.pathLimit = 0; + int pos = X509v3_get_ext_by_NID(exts, NID_basic_constraints, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509v3_get_ext(exts, pos); + if (ex) + get_basic_constraints(ex, &p.isCA, &p.pathLimit); + } + + pos = X509v3_get_ext_by_NID(exts, NID_subject_alt_name, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509v3_get_ext(exts, pos); + if (ex) + subject.unite(get_cert_alt_name(ex)); + } + + pos = X509v3_get_ext_by_NID(exts, NID_key_usage, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509v3_get_ext(exts, pos); + if (ex) + p.constraints = get_cert_key_usage(ex); + } + + pos = X509v3_get_ext_by_NID(exts, NID_ext_key_usage, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509v3_get_ext(exts, pos); + if (ex) + p.constraints += get_cert_ext_key_usage(ex); + } + + pos = X509v3_get_ext_by_NID(exts, NID_certificate_policies, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509v3_get_ext(exts, pos); + if (ex) + p.policies = get_cert_policies(ex); + } + + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + + const ASN1_BIT_STRING *signature; + + X509_REQ_get0_signature(x, &signature, nullptr); + if (signature) { + p.sig = QByteArray(signature->length, 0); + for (int i = 0; i < signature->length; i++) + p.sig[i] = signature->data[i]; + } + + switch (X509_REQ_get_signature_nid(x)) { + case NID_sha1WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA1; + break; + case NID_md5WithRSAEncryption: + p.sigalgo = QCA::EMSA3_MD5; + break; +#ifdef HAVE_OPENSSL_MD2 + case NID_md2WithRSAEncryption: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; + break; +#endif + case NID_ripemd160WithRSA: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; + break; + case NID_dsaWithSHA1: + p.sigalgo = QCA::EMSA1_SHA1; + break; + default: + qDebug() << "Unknown signature value: " << X509_REQ_get_signature_nid(x); + p.sigalgo = QCA::SignatureUnknown; + } + + // FIXME: super hack + CertificateOptions opts; + opts.setInfo(subject); + p.subject = opts.infoOrdered(); + + _props = p; + } +}; + +//---------------------------------------------------------------------------- +// MyCRLContext +//---------------------------------------------------------------------------- +class MyCRLContext : public CRLContext +{ + Q_OBJECT +public: + X509Item item; + CRLContextProps _props; + + MyCRLContext(Provider *p) + : CRLContext(p) + { + } + + MyCRLContext(const MyCRLContext &from) + : CRLContext(from) + , item(from.item) + { + } + + Provider::Context *clone() const override + { + return new MyCRLContext(*this); + } + + QByteArray toDER() const override + { + return item.toDER(); + } + + QString toPEM() const override + { + return item.toPEM(); + } + + ConvertResult fromDER(const QByteArray &a) override + { + _props = CRLContextProps(); + ConvertResult r = item.fromDER(a, X509Item::TypeCRL); + if (r == ConvertGood) + make_props(); + return r; + } + + ConvertResult fromPEM(const QString &s) override + { + ConvertResult r = item.fromPEM(s, X509Item::TypeCRL); + if (r == ConvertGood) + make_props(); + return r; + } + + void fromX509(X509_CRL *x) + { + X509_CRL_up_ref(x); + item.crl = x; + make_props(); + } + + const CRLContextProps *props() const override + { + return &_props; + } + + bool compare(const CRLContext *other) const override + { + const CRLContextProps *a = &_props; + const CRLContextProps *b = other->props(); + + if (a->issuer != b->issuer) + return false; + if (a->number != b->number) + return false; + if (a->thisUpdate != b->thisUpdate) + return false; + if (a->nextUpdate != b->nextUpdate) + return false; + if (a->revoked != b->revoked) + return false; + if (a->sig != b->sig) + return false; + if (a->sigalgo != b->sigalgo) + return false; + if (a->issuerId != b->issuerId) + return false; + + return true; + } + + void make_props() + { + X509_CRL *x = item.crl; + + CRLContextProps p; + + CertificateInfo issuer; + + issuer = get_cert_name(X509_CRL_get_issuer(x)); + + p.thisUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get0_lastUpdate(x), nullptr); + p.nextUpdate = ASN1_UTCTIME_QDateTime(X509_CRL_get0_nextUpdate(x), nullptr); + + STACK_OF(X509_REVOKED) *revokeStack = X509_CRL_get_REVOKED(x); + + for (int i = 0; i < sk_X509_REVOKED_num(revokeStack); ++i) { + X509_REVOKED *rev = sk_X509_REVOKED_value(revokeStack, i); + BigInteger serial = bn2bi_free(ASN1_INTEGER_to_BN(X509_REVOKED_get0_serialNumber(rev), nullptr)); + QDateTime time = ASN1_UTCTIME_QDateTime(X509_REVOKED_get0_revocationDate(rev), nullptr); + QCA::CRLEntry::Reason reason = QCA::CRLEntry::Unspecified; + int pos = X509_REVOKED_get_ext_by_NID(rev, NID_crl_reason, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_REVOKED_get_ext(rev, pos); + if (ex) { + ASN1_ENUMERATED *result = (ASN1_ENUMERATED *)X509V3_EXT_d2i(ex); + switch (ASN1_ENUMERATED_get(result)) { + case CRL_REASON_UNSPECIFIED: + reason = QCA::CRLEntry::Unspecified; + break; + case CRL_REASON_KEY_COMPROMISE: + reason = QCA::CRLEntry::KeyCompromise; + break; + case CRL_REASON_CA_COMPROMISE: + reason = QCA::CRLEntry::CACompromise; + break; + case CRL_REASON_AFFILIATION_CHANGED: + reason = QCA::CRLEntry::AffiliationChanged; + break; + case CRL_REASON_SUPERSEDED: + reason = QCA::CRLEntry::Superseded; + break; + case CRL_REASON_CESSATION_OF_OPERATION: + reason = QCA::CRLEntry::CessationOfOperation; + break; + case CRL_REASON_CERTIFICATE_HOLD: + reason = QCA::CRLEntry::CertificateHold; + break; + case CRL_REASON_REMOVE_FROM_CRL: + reason = QCA::CRLEntry::RemoveFromCRL; + break; + case CRL_REASON_PRIVILEGE_WITHDRAWN: + reason = QCA::CRLEntry::PrivilegeWithdrawn; + break; + case CRL_REASON_AA_COMPROMISE: + reason = QCA::CRLEntry::AACompromise; + break; + default: + reason = QCA::CRLEntry::Unspecified; + break; + } + ASN1_ENUMERATED_free(result); + } + } + CRLEntry thisEntry(serial, time, reason); + p.revoked.append(thisEntry); + } + + const ASN1_BIT_STRING *signature; + + X509_CRL_get0_signature(x, &signature, nullptr); + if (signature) { + p.sig = QByteArray(signature->length, 0); + for (int i = 0; i < signature->length; i++) + p.sig[i] = signature->data[i]; + } + + switch (X509_CRL_get_signature_nid(x)) { + case NID_sha1WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA1; + break; + case NID_md5WithRSAEncryption: + p.sigalgo = QCA::EMSA3_MD5; + break; +#ifdef HAVE_OPENSSL_MD2 + case NID_md2WithRSAEncryption: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_MD2 : QCA::SignatureUnknown; + break; +#endif + case NID_ripemd160WithRSA: + p.sigalgo = s_legacyProviderAvailable ? QCA::EMSA3_RIPEMD160 : QCA::SignatureUnknown; + break; + case NID_dsaWithSHA1: + p.sigalgo = QCA::EMSA1_SHA1; + break; + case NID_sha224WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA224; + break; + case NID_sha256WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA256; + break; + case NID_sha384WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA384; + break; + case NID_sha512WithRSAEncryption: + p.sigalgo = QCA::EMSA3_SHA512; + break; + default: + qWarning() << "Unknown signature value: " << X509_CRL_get_signature_nid(x); + p.sigalgo = QCA::SignatureUnknown; + } + + int pos = X509_CRL_get_ext_by_NID(x, NID_authority_key_identifier, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_CRL_get_ext(x, pos); + if (ex) + p.issuerId += get_cert_issuer_key_id(ex); + } + + p.number = -1; + pos = X509_CRL_get_ext_by_NID(x, NID_crl_number, -1); + if (pos != -1) { + X509_EXTENSION *ex = X509_CRL_get_ext(x, pos); + if (ex) { + ASN1_INTEGER *result = (ASN1_INTEGER *)X509V3_EXT_d2i(ex); + p.number = ASN1_INTEGER_get(result); + ASN1_INTEGER_free(result); + } + } + + // FIXME: super hack + CertificateOptions opts; + opts.setInfo(issuer); + p.issuer = opts.infoOrdered(); + + _props = p; + } +}; + +//---------------------------------------------------------------------------- +// MyCertCollectionContext +//---------------------------------------------------------------------------- +class MyCertCollectionContext : public CertCollectionContext +{ + Q_OBJECT +public: + MyCertCollectionContext(Provider *p) + : CertCollectionContext(p) + { + } + + Provider::Context *clone() const override + { + return new MyCertCollectionContext(*this); + } + + QByteArray toPKCS7(const QList &certs, const QList &crls) const override + { + // TODO: implement + Q_UNUSED(certs); + Q_UNUSED(crls); + return QByteArray(); + } + + ConvertResult fromPKCS7(const QByteArray &a, QList *certs, QList *crls) const override + { + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, a.data(), a.size()); + PKCS7 *p7 = d2i_PKCS7_bio(bi, nullptr); + BIO_free(bi); + if (!p7) + return ErrorDecode; + + STACK_OF(X509) *xcerts = nullptr; + STACK_OF(X509_CRL) *xcrls = nullptr; + + int i = OBJ_obj2nid(p7->type); + if (i == NID_pkcs7_signed) { + xcerts = p7->d.sign->cert; + xcrls = p7->d.sign->crl; + } else if (i == NID_pkcs7_signedAndEnveloped) { + xcerts = p7->d.signed_and_enveloped->cert; + xcrls = p7->d.signed_and_enveloped->crl; + } + + QList _certs; + QList _crls; + + if (xcerts) { + for (int n = 0; n < sk_X509_num(xcerts); ++n) { + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(sk_X509_value(xcerts, n)); + _certs += cc; + } + } + if (xcrls) { + for (int n = 0; n < sk_X509_CRL_num(xcrls); ++n) { + MyCRLContext *cc = new MyCRLContext(provider()); + cc->fromX509(sk_X509_CRL_value(xcrls, n)); + _crls += cc; + } + } + + PKCS7_free(p7); + + *certs = _certs; + *crls = _crls; + + return ConvertGood; + } +}; + +static bool usage_check(const MyCertContext &cc, UsageMode u) +{ + if (cc._props.constraints.isEmpty()) { + // then any usage is OK + return true; + } + + switch (u) { + case UsageAny: + return true; + break; + case UsageTLSServer: + return cc._props.constraints.contains(ServerAuth); + break; + case UsageTLSClient: + return cc._props.constraints.contains(ClientAuth); + break; + case UsageCodeSigning: + return cc._props.constraints.contains(CodeSigning); + break; + case UsageEmailProtection: + return cc._props.constraints.contains(EmailProtection); + break; + case UsageTimeStamping: + return cc._props.constraints.contains(TimeStamping); + break; + case UsageCRLSigning: + return cc._props.constraints.contains(CRLSign); + break; + default: + return true; + } +} + +Validity MyCertContext::validate(const QList &trusted, + const QList &untrusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const +{ + // TODO + Q_UNUSED(vf); + + STACK_OF(X509) *trusted_list = sk_X509_new_null(); + STACK_OF(X509) *untrusted_list = sk_X509_new_null(); + QList crl_list; + + int n; + for (n = 0; n < trusted.count(); ++n) { + const MyCertContext *cc = static_cast(trusted[n]); + X509 *x = cc->item.cert; + X509_up_ref(x); + sk_X509_push(trusted_list, x); + } + for (n = 0; n < untrusted.count(); ++n) { + const MyCertContext *cc = static_cast(untrusted[n]); + X509 *x = cc->item.cert; + X509_up_ref(x); + sk_X509_push(untrusted_list, x); + } + for (n = 0; n < crls.count(); ++n) { + const MyCRLContext *cc = static_cast(crls[n]); + X509_CRL *x = cc->item.crl; + X509_CRL_up_ref(x); + crl_list.append(x); + } + + const MyCertContext *cc = this; + X509 *x = cc->item.cert; + + // verification happens through a store "context" + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + + // make a store of crls + X509_STORE *store = X509_STORE_new(); + for (int n = 0; n < crl_list.count(); ++n) + X509_STORE_add_crl(store, crl_list[n]); + + // the first initialization handles untrusted certs, crls, and target cert + X509_STORE_CTX_init(ctx, store, x, untrusted_list); + + // this initializes the trusted certs + X509_STORE_CTX_trusted_stack(ctx, trusted_list); + + // verify! + int ret = X509_verify_cert(ctx); + int err = -1; + if (!ret) + err = X509_STORE_CTX_get_error(ctx); + + // cleanup + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + + sk_X509_pop_free(trusted_list, X509_free); + sk_X509_pop_free(untrusted_list, X509_free); + for (int n = 0; n < crl_list.count(); ++n) + X509_CRL_free(crl_list[n]); + + if (!ret) + return convert_verify_error(err); + + if (!usage_check(*cc, u)) + return ErrorInvalidPurpose; + + return ValidityGood; +} + +Validity MyCertContext::validate_chain(const QList &chain, + const QList &trusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const +{ + // TODO + Q_UNUSED(vf); + + STACK_OF(X509) *trusted_list = sk_X509_new_null(); + STACK_OF(X509) *untrusted_list = sk_X509_new_null(); + QList crl_list; + + int n; + for (n = 0; n < trusted.count(); ++n) { + const MyCertContext *cc = static_cast(trusted[n]); + X509 *x = cc->item.cert; + X509_up_ref(x); + sk_X509_push(trusted_list, x); + } + for (n = 1; n < chain.count(); ++n) { + const MyCertContext *cc = static_cast(chain[n]); + X509 *x = cc->item.cert; + X509_up_ref(x); + sk_X509_push(untrusted_list, x); + } + for (n = 0; n < crls.count(); ++n) { + const MyCRLContext *cc = static_cast(crls[n]); + X509_CRL *x = cc->item.crl; + X509_CRL_up_ref(x); + crl_list.append(x); + } + + const MyCertContext *cc = static_cast(chain[0]); + X509 *x = cc->item.cert; + + // verification happens through a store "context" + X509_STORE_CTX *ctx = X509_STORE_CTX_new(); + + // make a store of crls + X509_STORE *store = X509_STORE_new(); + for (int n = 0; n < crl_list.count(); ++n) + X509_STORE_add_crl(store, crl_list[n]); + + // the first initialization handles untrusted certs, crls, and target cert + X509_STORE_CTX_init(ctx, store, x, untrusted_list); + + // this initializes the trusted certs + X509_STORE_CTX_trusted_stack(ctx, trusted_list); + + // verify! + int ret = X509_verify_cert(ctx); + int err = -1; + if (!ret) + err = X509_STORE_CTX_get_error(ctx); + + // grab the chain, which may not be fully populated + STACK_OF(X509) *xchain = X509_STORE_CTX_get_chain(ctx); + + // make sure the chain is what we expect. the reason we need to do + // this is because I don't think openssl cares about the order of + // input. that is, if there's a chain A<-B<-C, and we input A as + // the base cert, with B and C as the issuers, we will get a + // successful validation regardless of whether the issuer list is + // in the order B,C or C,B. we don't want an input chain of A,C,B + // to be considered correct, so we must account for that here. + QList expected; + for (int n = 0; n < chain.count(); ++n) + expected += static_cast(chain[n]); + if (!xchain || !sameChain(xchain, expected)) + err = ErrorValidityUnknown; + + // cleanup + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + + sk_X509_pop_free(trusted_list, X509_free); + sk_X509_pop_free(untrusted_list, X509_free); + for (int n = 0; n < crl_list.count(); ++n) + X509_CRL_free(crl_list[n]); + + if (!ret) + return convert_verify_error(err); + + if (!usage_check(*cc, u)) + return ErrorInvalidPurpose; + + return ValidityGood; +} + +class MyPKCS12Context : public PKCS12Context +{ + Q_OBJECT +public: + MyPKCS12Context(Provider *p) + : PKCS12Context(p) + { + } + + ~MyPKCS12Context() override + { + } + + Provider::Context *clone() const override + { + return nullptr; + } + + QByteArray toPKCS12(const QString &name, + const QList &chain, + const PKeyContext &priv, + const SecureArray &passphrase) const override + { + if (chain.count() < 1) + return QByteArray(); + + X509 *cert = static_cast(chain[0])->item.cert; + STACK_OF(X509) *ca = sk_X509_new_null(); + if (chain.count() > 1) { + for (int n = 1; n < chain.count(); ++n) { + X509 *x = static_cast(chain[n])->item.cert; + X509_up_ref(x); + sk_X509_push(ca, x); + } + } + const MyPKeyContext &pk = static_cast(priv); + PKCS12 *p12 = PKCS12_create( + (char *)passphrase.data(), (char *)name.toLatin1().data(), pk.get_pkey(), cert, ca, 0, 0, 0, 0, 0); + sk_X509_pop_free(ca, X509_free); + + if (!p12) + return QByteArray(); + + BIO *bo = BIO_new(BIO_s_mem()); + i2d_PKCS12_bio(bo, p12); + const QByteArray out = bio2ba(bo); + return out; + } + + ConvertResult fromPKCS12(const QByteArray &in, + const SecureArray &passphrase, + QString *name, + QList *chain, + PKeyContext **priv) const override + { + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + PKCS12 *p12 = d2i_PKCS12_bio(bi, nullptr); + BIO_free(bi); + if (!p12) + return ErrorDecode; + + EVP_PKEY *pkey; + X509 *cert; + STACK_OF(X509) *ca = nullptr; + if (!PKCS12_parse(p12, passphrase.data(), &pkey, &cert, &ca)) { + PKCS12_free(p12); + return ErrorDecode; + } + PKCS12_free(p12); + + // require private key + if (!pkey) { + if (cert) + X509_free(cert); + if (ca) + sk_X509_pop_free(ca, X509_free); + return ErrorDecode; + } + + // TODO: require cert + + int aliasLength; + char *aliasData = (char *)X509_alias_get0(cert, &aliasLength); + *name = QString::fromLatin1(aliasData, aliasLength); + + MyPKeyContext *pk = new MyPKeyContext(provider()); + PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() + if (!k) { + delete pk; + if (cert) + X509_free(cert); + if (ca) + sk_X509_pop_free(ca, X509_free); + return ErrorDecode; + } + pk->k = k; + *priv = pk; + + QList certs; + if (cert) { + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(cert); + certs.append(cc); + X509_free(cert); + } + if (ca) { + // TODO: reorder in chain-order? + // TODO: throw out certs that don't fit the chain? + for (int n = 0; n < sk_X509_num(ca); ++n) { + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(sk_X509_value(ca, n)); + certs.append(cc); + } + sk_X509_pop_free(ca, X509_free); + } + + // reorder, throw out + QCA::CertificateChain ch; + for (int n = 0; n < certs.count(); ++n) { + QCA::Certificate cert; + cert.change(certs[n]); + ch += cert; + } + certs.clear(); + ch = ch.complete(QList()); + for (int n = 0; n < ch.count(); ++n) { + MyCertContext *cc = (MyCertContext *)ch[n].context(); + certs += (new MyCertContext(*cc)); + } + ch.clear(); + + *chain = certs; + return ConvertGood; + } +}; + +// TODO: test to ensure there is no cert-test lag +static bool ssl_init = false; +class MyTLSContext : public TLSContext +{ + Q_OBJECT +public: + enum + { + Good, + TryAgain, + Bad + }; + enum + { + Idle, + Connect, + Accept, + Handshake, + Active, + Closing + }; + + bool serv; // true if we are acting as a server + int mode; + QByteArray sendQueue; + QByteArray recvQueue; + + CertificateCollection trusted; + Certificate cert, peercert; // TODO: support cert chains + PrivateKey key; + QString targetHostName; + + Result result_result; + QByteArray result_to_net; + int result_encoded; + QByteArray result_plain; + + SSL *ssl; + const SSL_METHOD *method; + SSL_CTX *context; + BIO *rbio, *wbio; + Validity vr; + bool v_eof; + + MyTLSContext(Provider *p) + : TLSContext(p, QStringLiteral("tls")) + { + if (!ssl_init) { + SSL_library_init(); + SSL_load_error_strings(); + ssl_init = true; + } + + ssl = nullptr; + context = nullptr; + reset(); + } + + ~MyTLSContext() override + { + reset(); + } + + Provider::Context *clone() const override + { + return nullptr; + } + + void reset() override + { + if (ssl) { + SSL_free(ssl); + ssl = nullptr; + } + if (context) { + SSL_CTX_free(context); + context = nullptr; + } + + cert = Certificate(); + key = PrivateKey(); + + sendQueue.resize(0); + recvQueue.resize(0); + mode = Idle; + peercert = Certificate(); + vr = ErrorValidityUnknown; + v_eof = false; + } + + // dummy verification function for SSL_set_verify() + static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) + { + Q_UNUSED(preverify_ok); + Q_UNUSED(x509_ctx); + + // don't terminate handshake in case of verification failure + return 1; + } + + QStringList supportedCipherSuites(const TLS::Version &version) const override + { + OpenSSL_add_ssl_algorithms(); + SSL_CTX *ctx = nullptr; + switch (version) { +#ifndef OPENSSL_NO_SSL3_METHOD + case TLS::SSL_v3: + // Here should be used TLS_client_method() but on Fedora + // it doesn't return any SSL ciphers. + ctx = SSL_CTX_new(SSLv3_client_method()); + SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); + SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION); + break; +#endif + case TLS::TLS_v1: + ctx = SSL_CTX_new(TLS_client_method()); + SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); + break; + case TLS::DTLS_v1: + default: + /* should not happen - should be in a "dtls" provider*/ + qWarning("Unexpected enum in cipherSuites"); + ctx = nullptr; + } + if (nullptr == ctx) + return QStringList(); + + SSL *ssl = SSL_new(ctx); + if (nullptr == ssl) { + SSL_CTX_free(ctx); + return QStringList(); + } + + STACK_OF(SSL_CIPHER) *sk = SSL_get1_supported_ciphers(ssl); + QStringList cipherList; + for (int i = 0; i < sk_SSL_CIPHER_num(sk); ++i) { + const SSL_CIPHER *thisCipher = sk_SSL_CIPHER_value(sk, i); + cipherList += QString::fromLatin1(SSL_CIPHER_standard_name(thisCipher)); + } + sk_SSL_CIPHER_free(sk); + + SSL_free(ssl); + SSL_CTX_free(ctx); + + return cipherList; + } + + bool canCompress() const override + { + // TODO + return false; + } + + bool canSetHostName() const override + { + // TODO + return false; + } + + int maxSSF() const override + { + // TODO + return 256; + } + + void setConstraints(int minSSF, int maxSSF) override + { + // TODO + Q_UNUSED(minSSF); + Q_UNUSED(maxSSF); + } + + void setConstraints(const QStringList &cipherSuiteList) override + { + // TODO + Q_UNUSED(cipherSuiteList); + } + + void setup(bool serverMode, const QString &hostName, bool compress) override + { + serv = serverMode; + if (false == serverMode) { + // client + targetHostName = hostName; + } + Q_UNUSED(compress); // TODO + } + + void setTrustedCertificates(const CertificateCollection &_trusted) override + { + trusted = _trusted; + } + + void setIssuerList(const QList &issuerList) override + { + Q_UNUSED(issuerList); // TODO + } + + void setCertificate(const CertificateChain &_cert, const PrivateKey &_key) override + { + if (!_cert.isEmpty()) + cert = _cert.primary(); // TODO: take the whole chain + key = _key; + } + + void setSessionId(const TLSSessionContext &id) override + { + // TODO + Q_UNUSED(id); + } + + void shutdown() override + { + mode = Closing; + } + + void start() override + { + bool ok; + if (serv) + ok = priv_startServer(); + else + ok = priv_startClient(); + result_result = ok ? Success : Error; + + doResultsReady(); + } + + void update(const QByteArray &from_net, const QByteArray &from_app) override + { + if (mode == Active) { + bool ok = true; + if (!from_app.isEmpty()) + ok = priv_encode(from_app, &result_to_net, &result_encoded); + if (ok) + ok = priv_decode(from_net, &result_plain, &result_to_net); + result_result = ok ? Success : Error; + } else if (mode == Closing) + result_result = priv_shutdown(from_net, &result_to_net); + else + result_result = priv_handshake(from_net, &result_to_net); + + // printf("update (from_net=%d, to_net=%d, from_app=%d, to_app=%d)\n", from_net.size(), result_to_net.size(), + // from_app.size(), result_plain.size()); + + doResultsReady(); + } + + bool priv_startClient() + { + // serv = false; + method = SSLv23_client_method(); + if (!init()) + return false; + mode = Connect; + return true; + } + + bool priv_startServer() + { + // serv = true; + method = SSLv23_server_method(); + if (!init()) + return false; + mode = Accept; + return true; + } + + Result priv_handshake(const QByteArray &from_net, QByteArray *to_net) + { + if (!from_net.isEmpty()) + BIO_write(rbio, from_net.data(), from_net.size()); + + if (mode == Connect) { + int ret = doConnect(); + if (ret == Good) { + mode = Handshake; + } else if (ret == Bad) { + reset(); + return Error; + } + } + + if (mode == Accept) { + int ret = doAccept(); + if (ret == Good) { + getCert(); + mode = Active; + } else if (ret == Bad) { + reset(); + return Error; + } + } + + if (mode == Handshake) { + int ret = doHandshake(); + if (ret == Good) { + getCert(); + mode = Active; + } else if (ret == Bad) { + reset(); + return Error; + } + } + + // process outgoing + *to_net = readOutgoing(); + + if (mode == Active) + return Success; + else + return Continue; + } + + Result priv_shutdown(const QByteArray &from_net, QByteArray *to_net) + { + if (!from_net.isEmpty()) + BIO_write(rbio, from_net.data(), from_net.size()); + + int ret = doShutdown(); + if (ret == Bad) { + reset(); + return Error; + } + + *to_net = readOutgoing(); + + if (ret == Good) { + mode = Idle; + return Success; + } else { + // mode = Closing; + return Continue; + } + } + + bool priv_encode(const QByteArray &plain, QByteArray *to_net, int *enc) + { + if (mode != Active) + return false; + sendQueue.append(plain); + + int encoded = 0; + if (sendQueue.size() > 0) { + int ret = SSL_write(ssl, sendQueue.data(), sendQueue.size()); + + enum + { + Good, + Continue, + Done, + Error + }; + int m; + if (ret <= 0) { + int x = SSL_get_error(ssl, ret); + if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + m = Continue; + else if (x == SSL_ERROR_ZERO_RETURN) + m = Done; + else + m = Error; + } else { + m = Good; + encoded = ret; + int newsize = sendQueue.size() - encoded; + char *r = sendQueue.data(); + memmove(r, r + encoded, newsize); + sendQueue.resize(newsize); + } + + if (m == Done) { + sendQueue.resize(0); + v_eof = true; + return false; + } + if (m == Error) { + sendQueue.resize(0); + return false; + } + } + + *to_net += readOutgoing(); + *enc = encoded; + return true; + } + + bool priv_decode(const QByteArray &from_net, QByteArray *plain, QByteArray *to_net) + { + if (mode != Active) + return false; + if (!from_net.isEmpty()) + BIO_write(rbio, from_net.data(), from_net.size()); + + QByteArray a; + while (!v_eof) { + a.resize(8192); + int ret = SSL_read(ssl, a.data(), a.size()); + // printf("SSL_read = %d\n", ret); + if (ret > 0) { + if (ret != (int)a.size()) + a.resize(ret); + // printf("SSL_read chunk: [%s]\n", qPrintable(arrayToHex(a))); + recvQueue.append(a); + } else if (ret <= 0) { + ERR_print_errors_fp(stdout); + int x = SSL_get_error(ssl, ret); + // printf("SSL_read error = %d\n", x); + if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + break; + else if (x == SSL_ERROR_ZERO_RETURN) + v_eof = true; + else + return false; + } + } + + *plain = recvQueue; + recvQueue.resize(0); + + // could be outgoing data also + *to_net += readOutgoing(); + return true; + } + + bool waitForResultsReady(int msecs) override + { + // TODO: for now, all operations block anyway + Q_UNUSED(msecs); + return true; + } + + Result result() const override + { + return result_result; + } + + QByteArray to_net() override + { + const QByteArray a = result_to_net; + result_to_net.clear(); + return a; + } + + int encoded() const override + { + return result_encoded; + } + + QByteArray to_app() override + { + const QByteArray a = result_plain; + result_plain.clear(); + return a; + } + + bool eof() const override + { + return v_eof; + } + + bool clientHelloReceived() const override + { + // TODO + return false; + } + + bool serverHelloReceived() const override + { + // TODO + return false; + } + + QString hostName() const override + { + // TODO + return QString(); + } + + bool certificateRequested() const override + { + // TODO + return false; + } + + QList issuerList() const override + { + // TODO + return QList(); + } + + SessionInfo sessionInfo() const override + { + SessionInfo sessInfo; + + SSL_SESSION *session = SSL_get0_session(ssl); + sessInfo.isCompressed = (0 != SSL_SESSION_get_compress_id(session)); + int ssl_version = SSL_version(ssl); + + if (ssl_version == TLS1_VERSION) + sessInfo.version = TLS::TLS_v1; + else if (ssl_version == SSL3_VERSION) + sessInfo.version = TLS::SSL_v3; + else if (ssl_version == SSL2_VERSION) + sessInfo.version = TLS::SSL_v2; + else { + qDebug("unexpected version response"); + sessInfo.version = TLS::TLS_v1; + } + + sessInfo.cipherSuite = QString::fromLatin1(SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl))); + + sessInfo.cipherMaxBits = SSL_get_cipher_bits(ssl, &(sessInfo.cipherBits)); + + sessInfo.id = nullptr; // TODO: session resuming + + return sessInfo; + } + + QByteArray unprocessed() override + { + QByteArray a; + int size = BIO_pending(rbio); + if (size <= 0) + return a; + a.resize(size); + + int r = BIO_read(rbio, a.data(), size); + if (r <= 0) { + a.resize(0); + return a; + } + if (r != size) + a.resize(r); + return a; + } + + Validity peerCertificateValidity() const override + { + return vr; + } + + CertificateChain peerCertificateChain() const override + { + // TODO: support whole chain + CertificateChain chain; + chain.append(peercert); + return chain; + } + + void doResultsReady() + { + QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection); + } + + bool init() + { + context = SSL_CTX_new(method); + if (!context) + return false; + + // setup the cert store + { + X509_STORE *store = SSL_CTX_get_cert_store(context); + const QList cert_list = trusted.certificates(); + const QList crl_list = trusted.crls(); + int n; + for (n = 0; n < cert_list.count(); ++n) { + const MyCertContext *cc = static_cast(cert_list[n].context()); + X509 *x = cc->item.cert; + // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + X509_STORE_add_cert(store, x); + } + for (n = 0; n < crl_list.count(); ++n) { + const MyCRLContext *cc = static_cast(crl_list[n].context()); + X509_CRL *x = cc->item.crl; + // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); + X509_STORE_add_crl(store, x); + } + } + + ssl = SSL_new(context); + if (!ssl) { + SSL_CTX_free(context); + context = nullptr; + return false; + } + SSL_set_ssl_method(ssl, method); // can this return error? + +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + if (targetHostName.isEmpty() == false) { + // we have a target + // this might fail, but we ignore that for now + char *hostname = targetHostName.toLatin1().data(); + SSL_set_tlsext_host_name(ssl, hostname); + } +#endif + + // setup the memory bio + rbio = BIO_new(BIO_s_mem()); + wbio = BIO_new(BIO_s_mem()); + + // this passes control of the bios to ssl. we don't need to free them. + SSL_set_bio(ssl, rbio, wbio); + + // FIXME: move this to after server hello + // setup the cert to send + if (!cert.isNull() && !key.isNull()) { + PrivateKey nkey = key; + + const PKeyContext *tmp_kc = static_cast(nkey.context()); + + if (!tmp_kc->sameProvider(this)) { + // fprintf(stderr, "experimental: private key supplied by a different provider\n"); + + // make a pkey pointing to the existing private key + EVP_PKEY *pkey; + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, createFromExisting(nkey.toRSA())); + + // make a new private key object to hold it + MyPKeyContext *pk = new MyPKeyContext(provider()); + PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() + pk->k = k; + nkey.change(pk); + } + + const MyCertContext *cc = static_cast(cert.context()); + const MyPKeyContext *kc = static_cast(nkey.context()); + + if (SSL_use_certificate(ssl, cc->item.cert) != 1) { + SSL_free(ssl); + SSL_CTX_free(context); + return false; + } + if (SSL_use_PrivateKey(ssl, kc->get_pkey()) != 1) { + SSL_free(ssl); + SSL_CTX_free(context); + return false; + } + } + + // request a certificate from the client, if in server mode + if (serv) { + SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, ssl_verify_callback); + } + + return true; + } + + void getCert() + { + // verify the certificate + Validity code = ErrorValidityUnknown; + STACK_OF(X509) *x_chain = SSL_get_peer_cert_chain(ssl); + // X509 *x = SSL_get_peer_certificate(ssl); + if (x_chain) { + CertificateChain chain; + + if (serv) { + X509 *x = SSL_get_peer_certificate(ssl); + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(x); + Certificate cert; + cert.change(cc); + chain += cert; + } + + for (int n = 0; n < sk_X509_num(x_chain); ++n) { + X509 *x = sk_X509_value(x_chain, n); + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(x); + Certificate cert; + cert.change(cc); + chain += cert; + } + + peercert = chain.primary(); + +#ifdef Q_OS_MAC + code = chain.validate(trusted); +#else + int ret = SSL_get_verify_result(ssl); + if (ret == X509_V_OK) + code = ValidityGood; + else + code = convert_verify_error(ret); +#endif + } else { + peercert = Certificate(); + } + vr = code; + } + + int doConnect() + { + int ret = SSL_connect(ssl); + if (ret < 0) { + int x = SSL_get_error(ssl, ret); + if (x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + return TryAgain; + else + return Bad; + } else if (ret == 0) + return Bad; + return Good; + } + + int doAccept() + { + int ret = SSL_accept(ssl); + if (ret < 0) { + int x = SSL_get_error(ssl, ret); + if (x == SSL_ERROR_WANT_CONNECT || x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + return TryAgain; + else + return Bad; + } else if (ret == 0) + return Bad; + return Good; + } + + int doHandshake() + { + int ret = SSL_do_handshake(ssl); + if (ret < 0) { + int x = SSL_get_error(ssl, ret); + if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + return TryAgain; + else + return Bad; + } else if (ret == 0) + return Bad; + return Good; + } + + int doShutdown() + { + int ret = SSL_shutdown(ssl); + if (ret >= 1) + return Good; + else { + if (ret == 0) + return TryAgain; + int x = SSL_get_error(ssl, ret); + if (x == SSL_ERROR_WANT_READ || x == SSL_ERROR_WANT_WRITE) + return TryAgain; + return Bad; + } + } + + QByteArray readOutgoing() + { + QByteArray a; + int size = BIO_pending(wbio); + if (size <= 0) + return a; + a.resize(size); + + int r = BIO_read(wbio, a.data(), size); + if (r <= 0) { + a.resize(0); + return a; + } + if (r != size) + a.resize(r); + return a; + } +}; + +class CMSContext : public SMSContext +{ + Q_OBJECT +public: + CertificateCollection trustedCerts; + CertificateCollection untrustedCerts; + QList privateKeys; + + CMSContext(Provider *p) + : SMSContext(p, QStringLiteral("cms")) + { + } + + ~CMSContext() override + { + } + + Provider::Context *clone() const override + { + return nullptr; + } + + void setTrustedCertificates(const CertificateCollection &trusted) override + { + trustedCerts = trusted; + } + + void setUntrustedCertificates(const CertificateCollection &untrusted) override + { + untrustedCerts = untrusted; + } + + void setPrivateKeys(const QList &keys) override + { + privateKeys = keys; + } + + MessageContext *createMessage() override; +}; + +STACK_OF(X509) * get_pk7_certs(PKCS7 *p7) +{ + int i = OBJ_obj2nid(p7->type); + if (i == NID_pkcs7_signed) + return p7->d.sign->cert; + else if (i == NID_pkcs7_signedAndEnveloped) + return p7->d.signed_and_enveloped->cert; + else + return nullptr; +} + +class MyMessageContextThread : public QThread +{ + Q_OBJECT +public: + SecureMessage::Format format; + SecureMessage::SignMode signMode; + Certificate cert; + PrivateKey key; + STACK_OF(X509) * other_certs; + BIO *bi; + int flags; + PKCS7 *p7; + bool ok; + QByteArray out, sig; + + MyMessageContextThread(QObject *parent = nullptr) + : QThread(parent) + , ok(false) + { + } + +protected: + void run() override + { + MyCertContext *cc = static_cast(cert.context()); + MyPKeyContext *kc = static_cast(key.context()); + X509 *cx = cc->item.cert; + EVP_PKEY *kx = kc->get_pkey(); + + p7 = PKCS7_sign(cx, kx, other_certs, bi, flags); + + BIO_free(bi); + sk_X509_pop_free(other_certs, X509_free); + + if (p7) { + // printf("good\n"); + BIO *bo; + + // BIO *bo = BIO_new(BIO_s_mem()); + // i2d_PKCS7_bio(bo, p7); + // PEM_write_bio_PKCS7(bo, p7); + // SecureArray buf = bio2buf(bo); + // printf("[%s]\n", buf.data()); + + bo = BIO_new(BIO_s_mem()); + if (format == SecureMessage::Binary) + i2d_PKCS7_bio(bo, p7); + else // Ascii + PEM_write_bio_PKCS7(bo, p7); + + if (SecureMessage::Detached == signMode) + sig = bio2ba(bo); + else + out = bio2ba(bo); + + ok = true; + } else { + printf("bad here\n"); + ERR_print_errors_fp(stdout); + } + } +}; + +class MyMessageContext : public MessageContext +{ + Q_OBJECT +public: + CMSContext *cms; + SecureMessageKey signer; + SecureMessageKeyList to; + SecureMessage::SignMode signMode; + bool bundleSigner; + bool smime; + SecureMessage::Format format; + + Operation op; + bool _finished; + + QByteArray in, out; + QByteArray sig; + int total; + + CertificateChain signerChain; + int ver_ret; + + MyMessageContextThread *thread; + + MyMessageContext(CMSContext *_cms, Provider *p) + : MessageContext(p, QStringLiteral("cmsmsg")) + { + cms = _cms; + + total = 0; + + ver_ret = 0; + + thread = nullptr; + } + + ~MyMessageContext() override + { + } + + Provider::Context *clone() const override + { + return nullptr; + } + + bool canSignMultiple() const override + { + return false; + } + + SecureMessage::Type type() const override + { + return SecureMessage::CMS; + } + + void reset() override + { + } + + void setupEncrypt(const SecureMessageKeyList &keys) override + { + to = keys; + } + + void setupSign(const SecureMessageKeyList &keys, SecureMessage::SignMode m, bool bundleSigner, bool smime) override + { + signer = keys.first(); + signMode = m; + this->bundleSigner = bundleSigner; + this->smime = smime; + } + + void setupVerify(const QByteArray &detachedSig) override + { + // TODO + sig = detachedSig; + } + + void start(SecureMessage::Format f, Operation op) override + { + format = f; + _finished = false; + + // TODO: other operations + // if(op == Sign) + //{ + this->op = op; + //} + // else if(op == Encrypt) + //{ + // this->op = op; + //} + } + + void update(const QByteArray &in) override + { + this->in.append(in); + total += in.size(); + QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); + } + + QByteArray read() override + { + return out; + } + + int written() override + { + int x = total; + total = 0; + return x; + } + + void end() override + { + _finished = true; + + // sign + if (op == Sign) { + const CertificateChain chain = signer.x509CertificateChain(); + Certificate cert = chain.primary(); + QList nonroots; + if (chain.count() > 1) { + for (int n = 1; n < chain.count(); ++n) + nonroots.append(chain[n]); + } + PrivateKey key = signer.x509PrivateKey(); + + const PKeyContext *tmp_kc = static_cast(key.context()); + + if (!tmp_kc->sameProvider(this)) { + // fprintf(stderr, "experimental: private key supplied by a different provider\n"); + + // make a pkey pointing to the existing private key + EVP_PKEY *pkey; + pkey = EVP_PKEY_new(); + EVP_PKEY_assign_RSA(pkey, createFromExisting(key.toRSA())); + + // make a new private key object to hold it + MyPKeyContext *pk = new MyPKeyContext(provider()); + PKeyBase *k = pk->pkeyToBase(pkey, true); // does an EVP_PKEY_free() + pk->k = k; + key.change(pk); + } + + // allow different cert provider. this is just a + // quick hack, enough to please qca-test + if (!cert.context()->sameProvider(this)) { + // fprintf(stderr, "experimental: cert supplied by a different provider\n"); + cert = Certificate::fromDER(cert.toDER()); + if (cert.isNull() || !cert.context()->sameProvider(this)) { + // fprintf(stderr, "error converting cert\n"); + } + } + + // MyCertContext *cc = static_cast(cert.context()); + // MyPKeyContext *kc = static_cast(key.context()); + + // X509 *cx = cc->item.cert; + // EVP_PKEY *kx = kc->get_pkey(); + + STACK_OF(X509) * other_certs; + BIO *bi; + int flags; + // PKCS7 *p7; + + // nonroots + other_certs = sk_X509_new_null(); + for (int n = 0; n < nonroots.count(); ++n) { + X509 *x = static_cast(nonroots[n].context())->item.cert; + X509_up_ref(x); + sk_X509_push(other_certs, x); + } + + // printf("bundling %d other_certs\n", sk_X509_num(other_certs)); + + bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + + flags = 0; + flags |= PKCS7_BINARY; + if (SecureMessage::Detached == signMode) { + flags |= PKCS7_DETACHED; + } + if (false == bundleSigner) + flags |= PKCS7_NOCERTS; + + if (thread) + delete thread; + thread = new MyMessageContextThread(this); + thread->format = format; + thread->signMode = signMode; + thread->cert = cert; + thread->key = key; + thread->other_certs = other_certs; + thread->bi = bi; + thread->flags = flags; + connect(thread, &MyMessageContextThread::finished, this, &MyMessageContext::thread_finished); + thread->start(); + } else if (op == Encrypt) { + // TODO: support multiple recipients + Certificate target = to.first().x509CertificateChain().primary(); + + STACK_OF(X509) * other_certs; + BIO *bi; + int flags; + PKCS7 *p7; + + other_certs = sk_X509_new_null(); + X509 *x = static_cast(target.context())->item.cert; + X509_up_ref(x); + sk_X509_push(other_certs, x); + + bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + + flags = 0; + flags |= PKCS7_BINARY; + p7 = PKCS7_encrypt(other_certs, bi, EVP_des_ede3_cbc(), flags); // TODO: cipher? + + BIO_free(bi); + sk_X509_pop_free(other_certs, X509_free); + + if (p7) { + // FIXME: format + BIO *bo = BIO_new(BIO_s_mem()); + i2d_PKCS7_bio(bo, p7); + // PEM_write_bio_PKCS7(bo, p7); + out = bio2ba(bo); + PKCS7_free(p7); + } else { + printf("bad\n"); + return; + } + } else if (op == Verify) { + // TODO: support non-detached sigs + + BIO *out = BIO_new(BIO_s_mem()); + BIO *bi = BIO_new(BIO_s_mem()); + if (false == sig.isEmpty()) { + // We have detached signature + BIO_write(bi, sig.data(), sig.size()); + } else { + BIO_write(bi, in.data(), in.size()); + } + PKCS7 *p7; + if (format == SecureMessage::Binary) + p7 = d2i_PKCS7_bio(bi, nullptr); + else // Ascii + p7 = PEM_read_bio_PKCS7(bi, nullptr, passphrase_cb, nullptr); + BIO_free(bi); + + if (!p7) { + // TODO + printf("bad1\n"); + QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); + return; + } + + // intermediates/signers that may not be in the blob + STACK_OF(X509) *other_certs = sk_X509_new_null(); + QList untrusted_list = cms->untrustedCerts.certificates(); + const QList untrusted_crls = cms->untrustedCerts.crls(); // we'll use the crls later + for (int n = 0; n < untrusted_list.count(); ++n) { + X509 *x = static_cast(untrusted_list[n].context())->item.cert; + X509_up_ref(x); + sk_X509_push(other_certs, x); + } + + // get the possible message signers + QList signers; + STACK_OF(X509) *xs = PKCS7_get0_signers(p7, other_certs, 0); + if (xs) { + for (int n = 0; n < sk_X509_num(xs); ++n) { + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(sk_X509_value(xs, n)); + Certificate cert; + cert.change(cc); + // printf("signer: [%s]\n", qPrintable(cert.commonName())); + signers.append(cert); + } + sk_X509_free(xs); + } + + // get the rest of the certificates lying around + QList others; + xs = get_pk7_certs(p7); // don't free + if (xs) { + for (int n = 0; n < sk_X509_num(xs); ++n) { + MyCertContext *cc = new MyCertContext(provider()); + cc->fromX509(sk_X509_value(xs, n)); + Certificate cert; + cert.change(cc); + others.append(cert); + // printf("other: [%s]\n", qPrintable(cert.commonName())); + } + } + + // signer needs to be supplied in the message itself + // or via cms->untrustedCerts + if (signers.isEmpty()) { + QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); + return; + } + + // FIXME: handle more than one signer + CertificateChain chain; + chain += signers[0]; + + // build chain + chain = chain.complete(others); + + signerChain = chain; + + X509_STORE *store = X509_STORE_new(); + const QList cert_list = cms->trustedCerts.certificates(); + QList crl_list = cms->trustedCerts.crls(); + for (int n = 0; n < cert_list.count(); ++n) { + // printf("trusted: [%s]\n", qPrintable(cert_list[n].commonName())); + const MyCertContext *cc = static_cast(cert_list[n].context()); + X509 *x = cc->item.cert; + // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + X509_STORE_add_cert(store, x); + } + for (int n = 0; n < crl_list.count(); ++n) { + const MyCRLContext *cc = static_cast(crl_list[n].context()); + X509_CRL *x = cc->item.crl; + // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); + X509_STORE_add_crl(store, x); + } + // add these crls also + crl_list = untrusted_crls; + for (int n = 0; n < crl_list.count(); ++n) { + const MyCRLContext *cc = static_cast(crl_list[n].context()); + X509_CRL *x = cc->item.crl; + // CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL); + X509_STORE_add_crl(store, x); + } + + int ret; + if (!sig.isEmpty()) { + // Detached signMode + bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + ret = PKCS7_verify(p7, other_certs, store, bi, nullptr, 0); + BIO_free(bi); + } else { + ret = PKCS7_verify(p7, other_certs, store, nullptr, out, 0); + // qDebug() << "Verify: " << ret; + } + // if(!ret) + // ERR_print_errors_fp(stdout); + sk_X509_pop_free(other_certs, X509_free); + X509_STORE_free(store); + PKCS7_free(p7); + + ver_ret = ret; + // TODO + + QMetaObject::invokeMethod(this, "updated", Qt::QueuedConnection); + } else if (op == Decrypt) { + bool ok = false; + for (int n = 0; n < cms->privateKeys.count(); ++n) { + CertificateChain chain = cms->privateKeys[n].x509CertificateChain(); + Certificate cert = chain.primary(); + PrivateKey key = cms->privateKeys[n].x509PrivateKey(); + + MyCertContext *cc = static_cast(cert.context()); + MyPKeyContext *kc = static_cast(key.context()); + + X509 *cx = cc->item.cert; + EVP_PKEY *kx = kc->get_pkey(); + + BIO *bi = BIO_new(BIO_s_mem()); + BIO_write(bi, in.data(), in.size()); + PKCS7 *p7 = d2i_PKCS7_bio(bi, nullptr); + BIO_free(bi); + + if (!p7) { + // TODO + printf("bad1\n"); + return; + } + + BIO *bo = BIO_new(BIO_s_mem()); + int ret = PKCS7_decrypt(p7, kx, cx, bo, 0); + PKCS7_free(p7); + if (!ret) + continue; + + ok = true; + out = bio2ba(bo); + break; + } + + if (!ok) { + // TODO + printf("bad2\n"); + return; + } + } + } + + bool finished() const override + { + return _finished; + } + + bool waitForFinished(int msecs) override + { + // TODO + Q_UNUSED(msecs); + + if (thread) { + thread->wait(); + getresults(); + } + return true; + } + + bool success() const override + { + // TODO + return true; + } + + SecureMessage::Error errorCode() const override + { + // TODO + return SecureMessage::ErrorUnknown; + } + + QByteArray signature() const override + { + return sig; + } + + QString hashName() const override + { + // TODO + return QStringLiteral("sha1"); + } + + SecureMessageSignatureList signers() const override + { + // only report signers for verify + if (op != Verify) + return SecureMessageSignatureList(); + + SecureMessageKey key; + if (!signerChain.isEmpty()) + key.setX509CertificateChain(signerChain); + + // TODO/FIXME !!! InvalidSignature might be used here even + // if the signature is just fine, and the key is invalid + // (we need to use InvalidKey instead). + + Validity vr = ErrorValidityUnknown; + if (!signerChain.isEmpty()) + vr = signerChain.validate(cms->trustedCerts, cms->untrustedCerts.crls()); + + SecureMessageSignature::IdentityResult ir; + if (vr == ValidityGood) + ir = SecureMessageSignature::Valid; + else + ir = SecureMessageSignature::InvalidKey; + + if (!ver_ret) + ir = SecureMessageSignature::InvalidSignature; + + SecureMessageSignature s(ir, vr, key, QDateTime::currentDateTime()); + + // TODO + return SecureMessageSignatureList() << s; + } + + void getresults() + { + sig = thread->sig; + out = thread->out; + } + +private Q_SLOTS: + void thread_finished() + { + getresults(); + emit updated(); + } +}; + +MessageContext *CMSContext::createMessage() +{ + return new MyMessageContext(this, provider()); +} + +class opensslCipherContext : public CipherContext +{ + Q_OBJECT +public: + opensslCipherContext(const EVP_CIPHER *algorithm, const int pad, Provider *p, const QString &type) + : CipherContext(p, type) + { + m_cryptoAlgorithm = algorithm; + m_context = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_init(m_context); + m_pad = pad; + m_type = type; + } + + opensslCipherContext(const opensslCipherContext &other) + : CipherContext(other) + { + m_cryptoAlgorithm = other.m_cryptoAlgorithm; + m_context = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_copy(m_context, other.m_context); + m_direction = other.m_direction; + m_pad = other.m_pad; + m_type = other.m_type; + m_tag = other.m_tag; + } + + ~opensslCipherContext() override + { + EVP_CIPHER_CTX_cleanup(m_context); + EVP_CIPHER_CTX_free(m_context); + } + + void setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag) override + { + m_tag = tag; + m_direction = dir; + if ((m_cryptoAlgorithm == EVP_des_ede3()) && (key.size() == 16)) { + // this is really a two key version of triple DES. + m_cryptoAlgorithm = EVP_des_ede(); + } + if (Encode == m_direction) { + EVP_EncryptInit_ex(m_context, m_cryptoAlgorithm, nullptr, nullptr, nullptr); + EVP_CIPHER_CTX_set_key_length(m_context, key.size()); + if (m_type.endsWith(QLatin1String("gcm")) || m_type.endsWith(QLatin1String("ccm"))) { + int parameter = m_type.endsWith(QLatin1String("gcm")) ? EVP_CTRL_GCM_SET_IVLEN : EVP_CTRL_CCM_SET_IVLEN; + EVP_CIPHER_CTX_ctrl(m_context, parameter, iv.size(), nullptr); + } + EVP_EncryptInit_ex( + m_context, nullptr, nullptr, (const unsigned char *)(key.data()), (const unsigned char *)(iv.data())); + } else { + EVP_DecryptInit_ex(m_context, m_cryptoAlgorithm, nullptr, nullptr, nullptr); + EVP_CIPHER_CTX_set_key_length(m_context, key.size()); + if (m_type.endsWith(QLatin1String("gcm")) || m_type.endsWith(QLatin1String("ccm"))) { + int parameter = m_type.endsWith(QLatin1String("gcm")) ? EVP_CTRL_GCM_SET_IVLEN : EVP_CTRL_CCM_SET_IVLEN; + EVP_CIPHER_CTX_ctrl(m_context, parameter, iv.size(), nullptr); + } + EVP_DecryptInit_ex( + m_context, nullptr, nullptr, (const unsigned char *)(key.data()), (const unsigned char *)(iv.data())); + } + + EVP_CIPHER_CTX_set_padding(m_context, m_pad); + } + + Provider::Context *clone() const override + { + return new opensslCipherContext(*this); + } + + int blockSize() const override + { + return EVP_CIPHER_CTX_block_size(m_context); + } + + AuthTag tag() const override + { + return m_tag; + } + + bool update(const SecureArray &in, SecureArray *out) override + { + // This works around a problem in OpenSSL, where it asserts if + // there is nothing to encrypt. + if (0 == in.size()) + return true; + + out->resize(in.size() + blockSize()); + int resultLength; + if (Encode == m_direction) { + if (0 == + EVP_EncryptUpdate( + m_context, (unsigned char *)out->data(), &resultLength, (unsigned char *)in.data(), in.size())) { + return false; + } + } else { + if (0 == + EVP_DecryptUpdate( + m_context, (unsigned char *)out->data(), &resultLength, (unsigned char *)in.data(), in.size())) { + return false; + } + } + out->resize(resultLength); + return true; + } + + bool final(SecureArray *out) override + { + out->resize(blockSize()); + int resultLength; + if (Encode == m_direction) { + if (0 == EVP_EncryptFinal_ex(m_context, (unsigned char *)out->data(), &resultLength)) { + return false; + } + if (m_tag.size() && (m_type.endsWith(QLatin1String("gcm")) || m_type.endsWith(QLatin1String("ccm")))) { + int parameter = m_type.endsWith(QLatin1String("gcm")) ? EVP_CTRL_GCM_GET_TAG : EVP_CTRL_CCM_GET_TAG; + if (0 == EVP_CIPHER_CTX_ctrl(m_context, parameter, m_tag.size(), (unsigned char *)m_tag.data())) { + return false; + } + } + } else { + if (m_tag.size() && (m_type.endsWith(QLatin1String("gcm")) || m_type.endsWith(QLatin1String("ccm")))) { + int parameter = m_type.endsWith(QLatin1String("gcm")) ? EVP_CTRL_GCM_SET_TAG : EVP_CTRL_CCM_SET_TAG; + if (0 == EVP_CIPHER_CTX_ctrl(m_context, parameter, m_tag.size(), m_tag.data())) { + return false; + } + } + if (0 == EVP_DecryptFinal_ex(m_context, (unsigned char *)out->data(), &resultLength)) { + return false; + } + } + out->resize(resultLength); + return true; + } + + // Change cipher names + KeyLength keyLength() const override + { + if (s_legacyProviderAvailable) { + if (m_type.left(4) == QLatin1String("des-")) { + return KeyLength(8, 8, 1); + } else if (m_type.left(5) == QLatin1String("cast5")) { + return KeyLength(5, 16, 1); + } else if (m_type.left(8) == QLatin1String("blowfish")) { + // Don't know - TODO + return KeyLength(1, 32, 1); + } + } + if (m_type.left(6) == QLatin1String("aes128")) { + return KeyLength(16, 16, 1); + } else if (m_type.left(6) == QLatin1String("aes192")) { + return KeyLength(24, 24, 1); + } else if (m_type.left(6) == QLatin1String("aes256")) { + return KeyLength(32, 32, 1); + } else if (m_type.left(9) == QLatin1String("tripledes")) { + return KeyLength(16, 24, 1); + } + return KeyLength(0, 1, 1); + } + +protected: + EVP_CIPHER_CTX *m_context; + const EVP_CIPHER *m_cryptoAlgorithm; + Direction m_direction; + int m_pad; + QString m_type; + AuthTag m_tag; +}; + +static QStringList all_hash_types() +{ + QStringList list; + list += QStringLiteral("sha1"); +#ifdef HAVE_OPENSSL_SHA0 + list += QStringLiteral("sha0"); +#endif + list += QStringLiteral("md5"); +#ifdef SHA224_DIGEST_LENGTH + list += QStringLiteral("sha224"); +#endif +#ifdef SHA256_DIGEST_LENGTH + list += QStringLiteral("sha256"); +#endif +#ifdef SHA384_DIGEST_LENGTH + list += QStringLiteral("sha384"); +#endif +#ifdef SHA512_DIGEST_LENGTH + list += QStringLiteral("sha512"); +#endif + if (s_legacyProviderAvailable) { + list += QStringLiteral("ripemd160"); +#ifdef HAVE_OPENSSL_MD2 + list += QStringLiteral("md2"); +#endif + list += QStringLiteral("md4"); +#ifdef OBJ_whirlpool + list += QStringLiteral("whirlpool"); +#endif + } + + return list; +} + +static QStringList all_cipher_types() +{ + QStringList list; + list += QStringLiteral("aes128-ecb"); + list += QStringLiteral("aes128-cfb"); + list += QStringLiteral("aes128-cbc"); + list += QStringLiteral("aes128-cbc-pkcs7"); + list += QStringLiteral("aes128-ofb"); +#ifdef HAVE_OPENSSL_AES_CTR + list += QStringLiteral("aes128-ctr"); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + list += QStringLiteral("aes128-gcm"); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + list += QStringLiteral("aes128-ccm"); +#endif + list += QStringLiteral("aes192-ecb"); + list += QStringLiteral("aes192-cfb"); + list += QStringLiteral("aes192-cbc"); + list += QStringLiteral("aes192-cbc-pkcs7"); + list += QStringLiteral("aes192-ofb"); +#ifdef HAVE_OPENSSL_AES_CTR + list += QStringLiteral("aes192-ctr"); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + list += QStringLiteral("aes192-gcm"); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + list += QStringLiteral("aes192-ccm"); +#endif + list += QStringLiteral("aes256-ecb"); + list += QStringLiteral("aes256-cbc"); + list += QStringLiteral("aes256-cbc-pkcs7"); + list += QStringLiteral("aes256-cfb"); + list += QStringLiteral("aes256-ofb"); +#ifdef HAVE_OPENSSL_AES_CTR + list += QStringLiteral("aes256-ctr"); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + list += QStringLiteral("aes256-gcm"); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + list += QStringLiteral("aes256-ccm"); +#endif + list += QStringLiteral("tripledes-ecb"); + list += QStringLiteral("tripledes-cbc"); + if (s_legacyProviderAvailable) { + list += QStringLiteral("blowfish-ecb"); + list += QStringLiteral("blowfish-cbc-pkcs7"); + list += QStringLiteral("blowfish-cbc"); + list += QStringLiteral("blowfish-cfb"); + list += QStringLiteral("blowfish-ofb"); + list += QStringLiteral("des-ecb"); + list += QStringLiteral("des-ecb-pkcs7"); + list += QStringLiteral("des-cbc"); + list += QStringLiteral("des-cbc-pkcs7"); + list += QStringLiteral("des-cfb"); + list += QStringLiteral("des-ofb"); +#ifndef OPENSSL_NO_CAST + list += QStringLiteral("cast5-ecb"); + list += QStringLiteral("cast5-cbc"); + list += QStringLiteral("cast5-cbc-pkcs7"); + list += QStringLiteral("cast5-cfb"); + list += QStringLiteral("cast5-ofb"); +#endif + } + return list; +} + +static QStringList all_mac_types() +{ + QStringList list; + list += QStringLiteral("hmac(md5)"); + list += QStringLiteral("hmac(sha1)"); +#ifdef SHA224_DIGEST_LENGTH + list += QStringLiteral("hmac(sha224)"); +#endif +#ifdef SHA256_DIGEST_LENGTH + list += QStringLiteral("hmac(sha256)"); +#endif +#ifdef SHA384_DIGEST_LENGTH + list += QStringLiteral("hmac(sha384)"); +#endif +#ifdef SHA512_DIGEST_LENGTH + list += QStringLiteral("hmac(sha512)"); +#endif + if (s_legacyProviderAvailable) { + list += QStringLiteral("hmac(ripemd160)"); + } + return list; +} + +class opensslInfoContext : public InfoContext +{ + Q_OBJECT +public: + opensslInfoContext(Provider *p) + : InfoContext(p) + { + } + + Provider::Context *clone() const override + { + return new opensslInfoContext(*this); + } + + QStringList supportedHashTypes() const override + { + return all_hash_types(); + } + + QStringList supportedCipherTypes() const override + { + return all_cipher_types(); + } + + QStringList supportedMACTypes() const override + { + return all_mac_types(); + } +}; + +class opensslRandomContext : public RandomContext +{ + Q_OBJECT +public: + opensslRandomContext(QCA::Provider *p) + : RandomContext(p) + { + } + + Context *clone() const override + { + return new opensslRandomContext(*this); + } + + QCA::SecureArray nextBytes(int size) override + { + QCA::SecureArray buf(size); + int r; + // FIXME: loop while we don't have enough random bytes. + while (true) { + r = RAND_bytes((unsigned char *)(buf.data()), size); + if (r == 1) + break; // success + } + return buf; + } +}; + +} + +using namespace opensslQCAPlugin; + +class opensslProvider : public Provider +{ +public: + bool openssl_initted; + + opensslProvider() + { + openssl_initted = false; +// OPENSSL_VERSION_MAJOR is only defined in openssl3 +#ifdef OPENSSL_VERSION_MAJOR + /* Load the legacy providers into the default (NULL) library context */ + if (OSSL_PROVIDER_try_load(nullptr, "legacy", 1)) { + s_legacyProviderAvailable = true; + } +#else + s_legacyProviderAvailable = true; +#endif + } + + void init() override + { + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + // seed the RNG if it's not seeded yet + if (RAND_status() == 0) { + std::srand(time(nullptr)); + char buf[128]; + for (char &n : buf) + n = std::rand(); + RAND_seed(buf, 128); + } + + openssl_initted = true; + } + + ~opensslProvider() override + { + // FIXME: ? for now we never deinit, in case other libs/code + // are using openssl + /*if(!openssl_initted) + return; + // todo: any other shutdown? + EVP_cleanup(); + //ENGINE_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_remove_state(0); + ERR_free_strings();*/ + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("qca-ossl"); + } + + QString credit() const override + { + return QStringLiteral( + "This product includes cryptographic software " + "written by Eric Young (eay@cryptsoft.com)"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("random"); + list += all_hash_types(); + list += all_mac_types(); + list += all_cipher_types(); + if (s_legacyProviderAvailable) { +#ifdef HAVE_OPENSSL_MD2 + list += QStringLiteral("pbkdf1(md2)"); +#endif + list += QStringLiteral("pbkdf1(sha1)"); + } + list += QStringLiteral("pkcs12"); + list += QStringLiteral("pbkdf2(sha1)"); + list += QStringLiteral("hkdf(sha256)"); + list += QStringLiteral("pkey"); + list += QStringLiteral("dlgroup"); + list += QStringLiteral("rsa"); + list += QStringLiteral("dsa"); + list += QStringLiteral("dh"); + list += QStringLiteral("cert"); + list += QStringLiteral("csr"); + list += QStringLiteral("crl"); + list += QStringLiteral("certcollection"); + list += QStringLiteral("tls"); + list += QStringLiteral("cms"); + list += QStringLiteral("ca"); + + return list; + } + + Context *createContext(const QString &type) override + { + // OpenSSL_add_all_digests(); + if (type == QLatin1String("random")) + return new opensslRandomContext(this); + else if (type == QLatin1String("info")) + return new opensslInfoContext(this); + else if (type == QLatin1String("sha1")) + return new opensslHashContext(EVP_sha1(), this, type); +#ifdef HAVE_OPENSSL_SHA0 + else if (type == QLatin1String("sha0")) + return new opensslHashContext(EVP_sha(), this, type); +#endif + else if (type == QLatin1String("md5")) + return new opensslHashContext(EVP_md5(), this, type); +#ifdef SHA224_DIGEST_LENGTH + else if (type == QLatin1String("sha224")) + return new opensslHashContext(EVP_sha224(), this, type); +#endif +#ifdef SHA256_DIGEST_LENGTH + else if (type == QLatin1String("sha256")) + return new opensslHashContext(EVP_sha256(), this, type); +#endif +#ifdef SHA384_DIGEST_LENGTH + else if (type == QLatin1String("sha384")) + return new opensslHashContext(EVP_sha384(), this, type); +#endif +#ifdef SHA512_DIGEST_LENGTH + else if (type == QLatin1String("sha512")) + return new opensslHashContext(EVP_sha512(), this, type); +#endif + else if (type == QLatin1String("pbkdf2(sha1)")) + return new opensslPbkdf2Context(this, type); + else if (type == QLatin1String("hkdf(sha256)")) + return new opensslHkdfContext(this, type); + else if (type == QLatin1String("hmac(md5)")) + return new opensslHMACContext(EVP_md5(), this, type); + else if (type == QLatin1String("hmac(sha1)")) + return new opensslHMACContext(EVP_sha1(), this, type); +#ifdef SHA224_DIGEST_LENGTH + else if (type == QLatin1String("hmac(sha224)")) + return new opensslHMACContext(EVP_sha224(), this, type); +#endif +#ifdef SHA256_DIGEST_LENGTH + else if (type == QLatin1String("hmac(sha256)")) + return new opensslHMACContext(EVP_sha256(), this, type); +#endif +#ifdef SHA384_DIGEST_LENGTH + else if (type == QLatin1String("hmac(sha384)")) + return new opensslHMACContext(EVP_sha384(), this, type); +#endif +#ifdef SHA512_DIGEST_LENGTH + else if (type == QLatin1String("hmac(sha512)")) + return new opensslHMACContext(EVP_sha512(), this, type); +#endif + else if (type == QLatin1String("aes128-ecb")) + return new opensslCipherContext(EVP_aes_128_ecb(), 0, this, type); + else if (type == QLatin1String("aes128-cfb")) + return new opensslCipherContext(EVP_aes_128_cfb(), 0, this, type); + else if (type == QLatin1String("aes128-cbc")) + return new opensslCipherContext(EVP_aes_128_cbc(), 0, this, type); + else if (type == QLatin1String("aes128-cbc-pkcs7")) + return new opensslCipherContext(EVP_aes_128_cbc(), 1, this, type); + else if (type == QLatin1String("aes128-ofb")) + return new opensslCipherContext(EVP_aes_128_ofb(), 0, this, type); +#ifdef HAVE_OPENSSL_AES_CTR + else if (type == QLatin1String("aes128-ctr")) + return new opensslCipherContext(EVP_aes_128_ctr(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + else if (type == QLatin1String("aes128-gcm")) + return new opensslCipherContext(EVP_aes_128_gcm(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + else if (type == QLatin1String("aes128-ccm")) + return new opensslCipherContext(EVP_aes_128_ccm(), 0, this, type); +#endif + else if (type == QLatin1String("aes192-ecb")) + return new opensslCipherContext(EVP_aes_192_ecb(), 0, this, type); + else if (type == QLatin1String("aes192-cfb")) + return new opensslCipherContext(EVP_aes_192_cfb(), 0, this, type); + else if (type == QLatin1String("aes192-cbc")) + return new opensslCipherContext(EVP_aes_192_cbc(), 0, this, type); + else if (type == QLatin1String("aes192-cbc-pkcs7")) + return new opensslCipherContext(EVP_aes_192_cbc(), 1, this, type); + else if (type == QLatin1String("aes192-ofb")) + return new opensslCipherContext(EVP_aes_192_ofb(), 0, this, type); +#ifdef HAVE_OPENSSL_AES_CTR + else if (type == QLatin1String("aes192-ctr")) + return new opensslCipherContext(EVP_aes_192_ctr(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + else if (type == QLatin1String("aes192-gcm")) + return new opensslCipherContext(EVP_aes_192_gcm(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + else if (type == QLatin1String("aes192-ccm")) + return new opensslCipherContext(EVP_aes_192_ccm(), 0, this, type); +#endif + else if (type == QLatin1String("aes256-ecb")) + return new opensslCipherContext(EVP_aes_256_ecb(), 0, this, type); + else if (type == QLatin1String("aes256-cfb")) + return new opensslCipherContext(EVP_aes_256_cfb(), 0, this, type); + else if (type == QLatin1String("aes256-cbc")) + return new opensslCipherContext(EVP_aes_256_cbc(), 0, this, type); + else if (type == QLatin1String("aes256-cbc-pkcs7")) + return new opensslCipherContext(EVP_aes_256_cbc(), 1, this, type); + else if (type == QLatin1String("aes256-ofb")) + return new opensslCipherContext(EVP_aes_256_ofb(), 0, this, type); +#ifdef HAVE_OPENSSL_AES_CTR + else if (type == QLatin1String("aes256-ctr")) + return new opensslCipherContext(EVP_aes_256_ctr(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_GCM + else if (type == QLatin1String("aes256-gcm")) + return new opensslCipherContext(EVP_aes_256_gcm(), 0, this, type); +#endif +#ifdef HAVE_OPENSSL_AES_CCM + else if (type == QLatin1String("aes256-ccm")) + return new opensslCipherContext(EVP_aes_256_ccm(), 0, this, type); +#endif + else if (type == QLatin1String("pkey")) + return new MyPKeyContext(this); + else if (type == QLatin1String("dlgroup")) + return new MyDLGroup(this); + else if (type == QLatin1String("rsa")) + return new RSAKey(this); + else if (type == QLatin1String("dsa")) + return new DSAKey(this); + else if (type == QLatin1String("dh")) + return new DHKey(this); + else if (type == QLatin1String("cert")) + return new MyCertContext(this); + else if (type == QLatin1String("csr")) + return new MyCSRContext(this); + else if (type == QLatin1String("crl")) + return new MyCRLContext(this); + else if (type == QLatin1String("certcollection")) + return new MyCertCollectionContext(this); + else if (type == QLatin1String("tls")) + return new MyTLSContext(this); + else if (type == QLatin1String("cms")) + return new CMSContext(this); + else if (type == QLatin1String("ca")) + return new MyCAContext(this); + else if (type == QLatin1String("tripledes-ecb")) + return new opensslCipherContext(EVP_des_ede3(), 0, this, type); + else if (type == QLatin1String("tripledes-cbc")) + return new opensslCipherContext(EVP_des_ede3_cbc(), 0, this, type); + else if (type == QLatin1String("pkcs12")) + return new MyPKCS12Context(this); + + else if (s_legacyProviderAvailable) { + if (type == QLatin1String("blowfish-ecb")) + return new opensslCipherContext(EVP_bf_ecb(), 0, this, type); + else if (type == QLatin1String("blowfish-cfb")) + return new opensslCipherContext(EVP_bf_cfb(), 0, this, type); + else if (type == QLatin1String("blowfish-ofb")) + return new opensslCipherContext(EVP_bf_ofb(), 0, this, type); + else if (type == QLatin1String("blowfish-cbc")) + return new opensslCipherContext(EVP_bf_cbc(), 0, this, type); + else if (type == QLatin1String("blowfish-cbc-pkcs7")) + return new opensslCipherContext(EVP_bf_cbc(), 1, this, type); + else if (type == QLatin1String("des-ecb")) + return new opensslCipherContext(EVP_des_ecb(), 0, this, type); + else if (type == QLatin1String("des-ecb-pkcs7")) + return new opensslCipherContext(EVP_des_ecb(), 1, this, type); + else if (type == QLatin1String("des-cbc")) + return new opensslCipherContext(EVP_des_cbc(), 0, this, type); + else if (type == QLatin1String("des-cbc-pkcs7")) + return new opensslCipherContext(EVP_des_cbc(), 1, this, type); + else if (type == QLatin1String("des-cfb")) + return new opensslCipherContext(EVP_des_cfb(), 0, this, type); + else if (type == QLatin1String("des-ofb")) + return new opensslCipherContext(EVP_des_ofb(), 0, this, type); +#ifndef OPENSSL_NO_CAST + else if (type == QLatin1String("cast5-ecb")) + return new opensslCipherContext(EVP_cast5_ecb(), 0, this, type); + else if (type == QLatin1String("cast5-cbc")) + return new opensslCipherContext(EVP_cast5_cbc(), 0, this, type); + else if (type == QLatin1String("cast5-cbc-pkcs7")) + return new opensslCipherContext(EVP_cast5_cbc(), 1, this, type); + else if (type == QLatin1String("cast5-cfb")) + return new opensslCipherContext(EVP_cast5_cfb(), 0, this, type); + else if (type == QLatin1String("cast5-ofb")) + return new opensslCipherContext(EVP_cast5_ofb(), 0, this, type); +#endif + else if (type == QLatin1String("hmac(ripemd160)")) + return new opensslHMACContext(EVP_ripemd160(), this, type); + else if (type == QLatin1String("ripemd160")) + return new opensslHashContext(EVP_ripemd160(), this, type); +#ifdef HAVE_OPENSSL_MD2 + else if (type == QLatin1String("md2")) + return new opensslHashContext(EVP_md2(), this, type); + else if (type == QLatin1String("pbkdf1(md2)")) + return new opensslPbkdf1Context(EVP_md2(), this, type); +#endif + else if (type == QLatin1String("md4")) + return new opensslHashContext(EVP_md4(), this, type); +#ifdef OBJ_whirlpool + else if (type == QLatin1String("whirlpool")) + return new opensslHashContext(EVP_whirlpool(), this, type); +#endif + else if (type == QLatin1String("pbkdf1(sha1)")) + return new opensslPbkdf1Context(EVP_sha1(), this, type); + } + + return nullptr; + } +}; + +class opensslPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + Provider *createProvider() override + { + return new opensslProvider; + } +}; + +#include "qca-ossl.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-pkcs11/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-pkcs11/CMakeLists.txt new file mode 100644 index 0000000000..daec754751 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-pkcs11/CMakeLists.txt @@ -0,0 +1,40 @@ +# qca-pkcs11 + +if(WITH_pkcs11_PLUGIN STREQUAL "yes") + find_package(OpenSSL REQUIRED) + find_package(Pkcs11Helper REQUIRED) +else() + find_package(OpenSSL) + find_package(Pkcs11Helper) +endif() + +if(OPENSSL_FOUND AND PKCS11H_FOUND) + enable_plugin("pkcs11") + set(QCA_PKCS11_SOURCES qca-pkcs11.cpp) + + add_library(qca-pkcs11 ${PLUGIN_TYPE} ${QCA_PKCS11_SOURCES}) + + if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-pkcs11 PROPERTY SUFFIX ".dylib") + endif() + + add_definitions(${PKCS11H_CFLAGS_OTHER}) + include_directories(${PKCS11H_INCLUDE_DIRS}) + target_link_libraries(qca-pkcs11 Qt${QT_MAJOR_VERSION}::Core) + target_link_libraries(qca-pkcs11 ${QCA_LIB_NAME}) + target_link_libraries(qca-pkcs11 ${PKCS11H_LDFLAGS}) + if (WIN32) + target_link_libraries(qca-pkcs11 pkcs11-helper.dll) + endif() + + if(NOT DEVELOPER_MODE) + install(TARGETS qca-pkcs11 + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-pkcs11 ${QCA_CRYPTO_INSTALL_DIR}) + endif() +else() + disable_plugin("pkcs11") +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-pkcs11/COPYING b/local/recipes/libs/qca/source/plugins/qca-pkcs11/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-pkcs11/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-pkcs11/README b/local/recipes/libs/qca/source/plugins/qca-pkcs11/README new file mode 100644 index 0000000000..11032f8db3 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-pkcs11/README @@ -0,0 +1,89 @@ +qca-pkcs11 2.0.0 -- PKCS#11 Plug-in to QCA + +ABOUT + qca-pkcs11 enables QCA smartcard integration. + + qca-pkcs11 supports the following features: + - Multiple providers. + - Multiple tokens. + - Private key signature and decryption. + - Keystore objects serialization. + - Keystore update notifications. + - Asker integration for token and PIN. + +DEPENDENCIES + pkcs11-helper>=1.02 + http://www.opensc-project.org/ + +INSTALL + For Unix/Linux/Mac: + ./configure + make + make install + + For Windows: + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + +CONFIGURATION + Configuration is stored at ~/.config/Affinix/QCA.conf, in order to + generate default configuration use: + + $ qcatool config save qca-pkcs11 + + Attributes: + allow_load_rootca (Boolean) + Allow loading root certificate authorities' certificate + from token. Loading root certificates from PKCS#11 enabled + tokens is highly insecure, as public objects can be added + without user notice. + + allow_protected_authentication (Boolean) + Enable/disable global protected authentication support. + If disabled, no protected authentication will be allowed, + even if provider supports this feature. + + pin_cache (Integer) + Maximum PIN/session cache period in seconds. + -1 is infinite, until provider invalidates session. + + log_level (Integer) + Log level of pkcs11-helper, can be from 0-5. + + provider_##_enabled (Boolean) + Provider at this index is enabled. + + provider_##_name (String) + Provider unique friendly name. + + provider_##_library (String) + Provider library to load. + + provider_##_allow_protected_authentication (Boolean) + Enable protected authentication if provider supports the feature. + + provider_##_cert_private (Boolean) + Provider stores the certificates as private objects. + + provider_##_private_mask (Integer) + Provider private key mask: + 0 Determine automatically. + 1 Use sign. + 2 Use sign recover. + 4 Use decrypt. + 8 Use unwrap. + + provider_##_slotevent_method (String) + auto Determine automatically. + trigger Use trigger. + poll Use poll. + + provider_##_slotevent_timeout (Integer) + Timeout for slotevent in poll mode. + Specify 0 for default. + +AUTHORS + Alon Bar-Lev + diff --git a/local/recipes/libs/qca/source/plugins/qca-pkcs11/qca-pkcs11.cpp b/local/recipes/libs/qca/source/plugins/qca-pkcs11/qca-pkcs11.cpp new file mode 100644 index 0000000000..50f74d59e4 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-pkcs11/qca-pkcs11.cpp @@ -0,0 +1,2240 @@ +/* + * Copyright (C) 2004 Justin Karneges + * Copyright (C) 2006-2007 Alon Bar-Lev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace QCA; + +// qPrintable is ASCII only!!! +#define myPrintable(s) (s).toUtf8().constData() + +static inline QString certificateHash(const Certificate &cert) +{ + if (cert.isNull()) { + return QString(); + } else { + return Hash(QStringLiteral("sha1")).hashToString(cert.toDER()); + } +} + +//---------------------------------------------------------------------------- +// pkcs11Provider +//---------------------------------------------------------------------------- +class pkcs11Provider : public Provider +{ +private: + static const int _CONFIG_MAX_PROVIDERS; + + bool _lowLevelInitialized; + bool _slotEventsActive; + bool _slotEventsLowLevelActive; + QStringList _providers; + +public: + bool _allowLoadRootCA; + +public: + pkcs11Provider(); + ~pkcs11Provider() override; + +public: + int qcaVersion() const override; + + void init() override; + + void deinit() override; + + QString name() const override; + + QStringList features() const override; + + Context *createContext(const QString &type) override; + + void startSlotEvents(); + + void stopSlotEvents(); + + QVariantMap defaultConfig() const override; + + void configChanged(const QVariantMap &config) override; + +protected: + static void __logHook(void *const global_data, const unsigned flags, const char *const format, va_list args); + + static void __slotEventHook(void *const global_data); + + static PKCS11H_BOOL __tokenPromptHook(void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry); + + static PKCS11H_BOOL __pinPromptHook(void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry, + char *const pin, + const size_t pin_max); + + void _logHook(const unsigned flags, const char *const format, va_list args); + + void _slotEventHook(); + + PKCS11H_BOOL + _tokenPromptHook(void *const user_data, const pkcs11h_token_id_t token); + + PKCS11H_BOOL + _pinPromptHook(void *const user_data, const pkcs11h_token_id_t token, char *const pin, const size_t pin_max); +}; + +namespace pkcs11QCAPlugin { + +class pkcs11KeyStoreEntryContext; + +//---------------------------------------------------------------------------- +// pkcs11KeyStoreListContext +//---------------------------------------------------------------------------- +class pkcs11KeyStoreListContext : public KeyStoreListContext +{ + Q_OBJECT + +private: + struct pkcs11KeyStoreItem + { + protected: + int _id; + pkcs11h_token_id_t _token_id; + QList _certs; + + public: + pkcs11KeyStoreItem(const int id, const pkcs11h_token_id_t token_id) + { + _id = id; + ; + pkcs11h_token_duplicateTokenId(&_token_id, token_id); + } + + ~pkcs11KeyStoreItem() + { + if (_token_id != nullptr) { + pkcs11h_token_freeTokenId(_token_id); + } + } + + pkcs11KeyStoreItem(const pkcs11KeyStoreItem &) = delete; + pkcs11KeyStoreItem &operator=(const pkcs11KeyStoreItem &) = delete; + + inline int id() const + { + return _id; + } + + inline pkcs11h_token_id_t tokenId() const + { + return _token_id; + } + + void registerCertificates(const QList &certs) + { + foreach (Certificate i, certs) { + if (std::find(_certs.begin(), _certs.end(), i) == _certs.end()) { + _certs += i; + } + } + } + + QMap friendlyNames() + { + const QStringList names = makeFriendlyNames(_certs); + QMap friendlyNames; + + for (int i = 0; i < names.size(); i++) { + friendlyNames.insert(certificateHash(_certs[i]), names[i]); + } + + return friendlyNames; + } + }; + int _last_id; + typedef QList _stores_t; + _stores_t _stores; + QHash _storesById; + QMutex _mutexStores; + bool _initialized; + +public: + pkcs11KeyStoreListContext(Provider *p); + + ~pkcs11KeyStoreListContext() override; + + Provider::Context *clone() const override; + +public: + void start() override; + + void setUpdatesEnabled(bool enabled) override; + + KeyStoreEntryContext *entry(int id, const QString &entryId) override; + + KeyStoreEntryContext *entryPassive(const QString &serialized) override; + + KeyStore::Type type(int id) const override; + + QString storeId(int id) const override; + + QString name(int id) const override; + + QList entryTypes(int id) const override; + + QList keyStores() override; + + QList entryList(int id) override; + + bool _tokenPrompt(void *const user_data, const pkcs11h_token_id_t token_id); + + bool _pinPrompt(void *const user_data, const pkcs11h_token_id_t token_id, SecureArray &pin); + + void _emit_diagnosticText(const QString &t); + +private Q_SLOTS: + void doReady(); + + void doUpdated(); + +private: + pkcs11KeyStoreItem *_registerTokenId(const pkcs11h_token_id_t token_id); + + void _clearStores(); + + pkcs11KeyStoreEntryContext *_keyStoreEntryByCertificateId(const pkcs11h_certificate_id_t certificate_id, + const bool has_private, + const CertificateChain &chain, + const QString &description) const; + + QString _tokenId2storeId(const pkcs11h_token_id_t token_id) const; + + QString _serializeCertificate(const pkcs11h_certificate_id_t certificate_id, + const CertificateChain &chain, + const bool has_private) const; + + void _deserializeCertificate(const QString &from, + pkcs11h_certificate_id_t *const p_certificate_id, + bool *const p_has_private, + CertificateChain &chain) const; + + QString _escapeString(const QString &from) const; + + QString _unescapeString(const QString &from) const; +}; + +static pkcs11KeyStoreListContext *s_keyStoreList = nullptr; + +//---------------------------------------------------------------------------- +// pkcs11Exception +//---------------------------------------------------------------------------- +class pkcs11Exception +{ +private: + CK_RV _rv; + QString _msg; + +private: + pkcs11Exception() + { + } + +public: + pkcs11Exception(const CK_RV rv, const QString &msg) + { + _rv = rv; + _msg = msg; + } + + CK_RV + rv() const + { + return _rv; + } + + QString message() const + { + return _msg + QStringLiteral(" ") + QString::fromLatin1(pkcs11h_getMessage(_rv)); + } +}; + +//---------------------------------------------------------------------------- +// pkcs11RSAContext +//---------------------------------------------------------------------------- +class pkcs11RSAContext : public RSAContext +{ + Q_OBJECT + +private: + bool _has_privateKeyRole; + pkcs11h_certificate_id_t _pkcs11h_certificate_id; + pkcs11h_certificate_t _pkcs11h_certificate; + RSAPublicKey _pubkey; + QString _serialized; + + struct _sign_data_s + { + SignatureAlgorithm alg; + Hash *hash; + QByteArray raw; + + _sign_data_s() + { + hash = nullptr; + } + } _sign_data; + +public: + pkcs11RSAContext(Provider *p, + const pkcs11h_certificate_id_t pkcs11h_certificate_id, + const QString &serialized, + const RSAPublicKey &pubkey) + : RSAContext(p) + { + CK_RV rv; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::pkcs11RSAContext1 - entry"), Logger::Debug); + + _has_privateKeyRole = true; + _pkcs11h_certificate_id = nullptr; + _pkcs11h_certificate = nullptr; + _pubkey = pubkey; + _serialized = serialized; + _clearSign(); + + if ((rv = pkcs11h_certificate_duplicateCertificateId(&_pkcs11h_certificate_id, pkcs11h_certificate_id)) != + CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Memory error")); + } + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::pkcs11RSAContext1 - return"), Logger::Debug); + } + + pkcs11RSAContext(const pkcs11RSAContext &from) + : RSAContext(from.provider()) + { + CK_RV rv; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::pkcs11RSAContextC - entry"), Logger::Debug); + + _has_privateKeyRole = from._has_privateKeyRole; + _pkcs11h_certificate_id = nullptr; + _pkcs11h_certificate = nullptr; + _pubkey = from._pubkey; + _serialized = from._serialized; + _sign_data.hash = nullptr; + _clearSign(); + + if ((rv = pkcs11h_certificate_duplicateCertificateId(&_pkcs11h_certificate_id, from._pkcs11h_certificate_id)) != + CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Memory error")); + } + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::pkcs11RSAContextC - return"), Logger::Debug); + } + + ~pkcs11RSAContext() override + { + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::~pkcs11RSAContext - entry"), Logger::Debug); + + _clearSign(); + + if (_pkcs11h_certificate != nullptr) { + pkcs11h_certificate_freeCertificate(_pkcs11h_certificate); + _pkcs11h_certificate = nullptr; + } + + if (_pkcs11h_certificate_id != nullptr) { + pkcs11h_certificate_freeCertificateId(_pkcs11h_certificate_id); + _pkcs11h_certificate_id = nullptr; + } + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::~pkcs11RSAContext - return"), Logger::Debug); + } + + Provider::Context *clone() const override + { + return new pkcs11RSAContext(*this); + } + +public: + bool isNull() const override + { + return _pubkey.isNull(); + } + + PKey::Type type() const override + { + return _pubkey.type(); + } + + bool isPrivate() const override + { + return _has_privateKeyRole; + } + + bool canExport() const override + { + return !_has_privateKeyRole; + } + + void convertToPublic() override + { + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::convertToPublic - entry"), Logger::Debug); + + if (_has_privateKeyRole) { + if (_pkcs11h_certificate != nullptr) { + pkcs11h_certificate_freeCertificate(_pkcs11h_certificate); + _pkcs11h_certificate = nullptr; + } + _has_privateKeyRole = false; + } + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::convertToPublic - return"), Logger::Debug); + } + + int bits() const override + { + return _pubkey.bitSize(); + } + + int maximumEncryptSize(EncryptionAlgorithm alg) const override + { + return _pubkey.maximumEncryptSize(alg); + } + + SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override + { + return _pubkey.encrypt(in, alg); + } + + bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override + { + bool session_locked = false; + bool ret = false; + + QCA_logTextMessage( + QString::asprintf("pkcs11RSAContext::decrypt - decrypt in.size()=%d, alg=%d", in.size(), (int)alg), + Logger::Debug); + + try { + CK_MECHANISM_TYPE mech; + CK_RV rv; + size_t my_size; + + switch (alg) { + case EME_PKCS1v15: + mech = CKM_RSA_PKCS; + break; + case EME_PKCS1_OAEP: + mech = CKM_RSA_PKCS_OAEP; + break; + default: + throw pkcs11Exception(CKR_FUNCTION_NOT_SUPPORTED, QStringLiteral("Invalid algorithm")); + break; + } + + _ensureCertificate(); + + if ((rv = pkcs11h_certificate_lockSession(_pkcs11h_certificate)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot lock session")); + } + session_locked = true; + + if ((rv = pkcs11h_certificate_decryptAny(_pkcs11h_certificate, + mech, + (const unsigned char *)in.constData(), + in.size(), + nullptr, + &my_size)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Decryption error")); + } + + out->resize(my_size); + + if ((rv = pkcs11h_certificate_decryptAny(_pkcs11h_certificate, + mech, + (const unsigned char *)in.constData(), + in.size(), + (unsigned char *)out->data(), + &my_size)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Decryption error")); + } + + rv = out->resize(my_size); + + if ((rv = pkcs11h_certificate_releaseSession(_pkcs11h_certificate)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot release session")); + } + session_locked = false; + + ret = true; + } catch (const pkcs11Exception &e) { + if (session_locked) { + pkcs11h_certificate_releaseSession(_pkcs11h_certificate); + session_locked = false; + } + + if (s_keyStoreList != nullptr) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Cannot decrypt: %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + } + + QCA_logTextMessage(QString::asprintf("pkcs11RSAContext::decrypt - decrypt out->size()=%d", out->size()), + Logger::Debug); + + return ret; + } + + void startSign(SignatureAlgorithm alg, SignatureFormat) override + { + _clearSign(); + + _sign_data.alg = alg; + + switch (_sign_data.alg) { + case EMSA3_SHA1: + _sign_data.hash = new Hash(QStringLiteral("sha1")); + break; + case EMSA3_MD5: + _sign_data.hash = new Hash(QStringLiteral("md5")); + break; + case EMSA3_MD2: + _sign_data.hash = new Hash(QStringLiteral("md2")); + break; + case EMSA3_Raw: + break; + case SignatureUnknown: + case EMSA1_SHA1: + case EMSA3_RIPEMD160: + default: + QCA_logTextMessage(QString::asprintf("PKCS#11: Invalid hash algorithm %d", _sign_data.alg), + Logger::Warning); + break; + } + } + + void startVerify(SignatureAlgorithm alg, SignatureFormat sf) override + { + _pubkey.startVerify(alg, sf); + } + + void update(const MemoryRegion &in) override + { + if (_has_privateKeyRole) { + if (_sign_data.hash != nullptr) { + _sign_data.hash->update(in); + } else { + _sign_data.raw.append(in.toByteArray()); + } + } else { + _pubkey.update(in); + } + } + + QByteArray endSign() override + { + QByteArray result; + bool session_locked = false; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::endSign - entry"), Logger::Debug); + + try { + QByteArray final; + CK_RV rv; + + // from some strange reason I got 2047... (for some) <---- BUG?!?!?! + int myrsa_size = (_pubkey.bitSize() + 7) / 8; + + if (_sign_data.hash != nullptr) { + final = emsa3Encode(_sign_data.hash->type(), _sign_data.hash->final().toByteArray(), myrsa_size); + } else { + final = _sign_data.raw; + } + + if (final.size() == 0) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Cannot encode signature")); + } + + _ensureCertificate(); + + size_t my_size; + + if ((rv = pkcs11h_certificate_lockSession(_pkcs11h_certificate)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot lock session")); + } + session_locked = true; + + if ((rv = pkcs11h_certificate_signAny(_pkcs11h_certificate, + CKM_RSA_PKCS, + (const unsigned char *) final.constData(), + (size_t) final.size(), + nullptr, + &my_size)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Signature failed")); + } + + result.resize(my_size); + + if ((rv = pkcs11h_certificate_signAny(_pkcs11h_certificate, + CKM_RSA_PKCS, + (const unsigned char *) final.constData(), + (size_t) final.size(), + (unsigned char *)result.data(), + &my_size)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Signature failed")); + } + + result.resize(my_size); + + if ((rv = pkcs11h_certificate_releaseSession(_pkcs11h_certificate)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot release session")); + } + session_locked = false; + + } catch (const pkcs11Exception &e) { + result.clear(); + + if (session_locked) { + pkcs11h_certificate_releaseSession(_pkcs11h_certificate); + session_locked = false; + } + + if (s_keyStoreList != nullptr) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Cannot sign: %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + } + + _clearSign(); + + QCA_logTextMessage( + QString::asprintf("pkcs11RSAContext::endSign - return result.size ()=%d", int(result.size())), + Logger::Debug); + + return result; + } + + virtual bool validSignature(const QByteArray &sig) + { + return _pubkey.validSignature(sig); + } + + void createPrivate(int bits, int exp, bool block) override + { + Q_UNUSED(bits); + Q_UNUSED(exp); + Q_UNUSED(block); + } + + void createPrivate(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d) override + { + Q_UNUSED(n); + Q_UNUSED(e); + Q_UNUSED(p); + Q_UNUSED(q); + Q_UNUSED(d); + } + + void createPublic(const BigInteger &n, const BigInteger &e) override + { + Q_UNUSED(n); + Q_UNUSED(e); + } + + BigInteger n() const override + { + return _pubkey.n(); + } + + BigInteger e() const override + { + return _pubkey.e(); + } + + BigInteger p() const override + { + return BigInteger(); + } + + BigInteger q() const override + { + return BigInteger(); + } + + BigInteger d() const override + { + return BigInteger(); + } + +public: + PublicKey _publicKey() const + { + return _pubkey; + } + + bool _isTokenAvailable() const + { + bool ret; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::_ensureTokenAvailable - entry"), Logger::Debug); + + ret = pkcs11h_token_ensureAccess(_pkcs11h_certificate_id->token_id, nullptr, 0) == CKR_OK; + + QCA_logTextMessage(QString::asprintf("pkcs11RSAContext::_ensureTokenAvailable - return ret=%d", ret ? 1 : 0), + Logger::Debug); + + return ret; + } + + bool _ensureTokenAccess() + { + bool ret; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::_ensureTokenAccess - entry"), Logger::Debug); + + ret = pkcs11h_token_ensureAccess(_pkcs11h_certificate_id->token_id, nullptr, PKCS11H_PROMPT_MASK_ALLOW_ALL) == + CKR_OK; + + QCA_logTextMessage(QString::asprintf("pkcs11RSAContext::_ensureTokenAccess - return ret=%d", ret ? 1 : 0), + Logger::Debug); + + return ret; + } + +private: + void _clearSign() + { + _sign_data.raw.clear(); + _sign_data.alg = SignatureUnknown; + delete _sign_data.hash; + _sign_data.hash = nullptr; + } + + void _ensureCertificate() + { + CK_RV rv; + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::_ensureCertificate - entry"), Logger::Debug); + + if (_pkcs11h_certificate == nullptr) { + if ((rv = pkcs11h_certificate_create(_pkcs11h_certificate_id, + &_serialized, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + PKCS11H_PIN_CACHE_INFINITE, + &_pkcs11h_certificate)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot create low-level certificate")); + } + } + + QCA_logTextMessage(QStringLiteral("pkcs11RSAContext::_ensureCertificate - return"), Logger::Debug); + } +}; + +//---------------------------------------------------------------------------- +// pkcs11PKeyContext +//---------------------------------------------------------------------------- +class pkcs11PKeyContext : public PKeyContext +{ + Q_OBJECT + +private: + PKeyBase *_k; + +public: + pkcs11PKeyContext(Provider *p) + : PKeyContext(p) + { + _k = nullptr; + } + + ~pkcs11PKeyContext() override + { + delete _k; + _k = nullptr; + } + + Provider::Context *clone() const override + { + pkcs11PKeyContext *c = new pkcs11PKeyContext(*this); + c->_k = (PKeyBase *)_k->clone(); + return c; + } + +public: + QList supportedTypes() const override + { + QList list; + list += PKey::RSA; + return list; + } + + QList supportedIOTypes() const override + { + QList list; + list += PKey::RSA; + return list; + } + + QList supportedPBEAlgorithms() const override + { + QList list; + return list; + } + + PKeyBase *key() override + { + return _k; + } + + const PKeyBase *key() const override + { + return _k; + } + + void setKey(PKeyBase *key) override + { + delete _k; + _k = key; + } + + bool importKey(const PKeyBase *key) override + { + Q_UNUSED(key); + return false; + } + + static int passphrase_cb(char *buf, int size, int rwflag, void *u) + { + Q_UNUSED(buf); + Q_UNUSED(size); + Q_UNUSED(rwflag); + Q_UNUSED(u); + return 0; + } + + QByteArray publicToDER() const override + { + return static_cast(_k)->_publicKey().toDER(); + } + + QString publicToPEM() const override + { + return static_cast(_k)->_publicKey().toPEM(); + } + + ConvertResult publicFromDER(const QByteArray &in) override + { + Q_UNUSED(in); + return ErrorDecode; + } + + ConvertResult publicFromPEM(const QString &s) override + { + Q_UNUSED(s); + return ErrorDecode; + } + + SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + Q_UNUSED(passphrase); + Q_UNUSED(pbe); + return SecureArray(); + } + + QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + Q_UNUSED(passphrase); + Q_UNUSED(pbe); + return QString(); + } + + ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override + { + Q_UNUSED(in); + Q_UNUSED(passphrase); + return ErrorDecode; + } + + ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override + { + Q_UNUSED(s); + Q_UNUSED(passphrase); + return ErrorDecode; + } +}; + +//---------------------------------------------------------------------------- +// pkcs11KeyStoreEntryContext +//---------------------------------------------------------------------------- +class pkcs11KeyStoreEntryContext : public KeyStoreEntryContext +{ + Q_OBJECT +private: + KeyStoreEntry::Type _item_type; + KeyBundle _key; + Certificate _cert; + QString _storeId; + QString _id; + QString _serialized; + QString _storeName; + QString _name; + +public: + pkcs11KeyStoreEntryContext(const Certificate &cert, + const QString &storeId, + const QString &serialized, + const QString &storeName, + const QString &name, + Provider *p) + : KeyStoreEntryContext(p) + { + _item_type = KeyStoreEntry::TypeCertificate; + _cert = cert; + _storeId = storeId; + _id = certificateHash(_cert); + _serialized = serialized; + _storeName = storeName; + _name = name; + } + + pkcs11KeyStoreEntryContext(const KeyBundle &key, + const QString &storeId, + const QString &serialized, + const QString &storeName, + const QString &name, + Provider *p) + : KeyStoreEntryContext(p) + { + _item_type = KeyStoreEntry::TypeKeyBundle; + _key = key; + _storeId = storeId, _id = certificateHash(key.certificateChain().primary()); + _serialized = serialized; + _storeName = storeName; + _name = name; + } + + pkcs11KeyStoreEntryContext(const pkcs11KeyStoreEntryContext &from) + : KeyStoreEntryContext(from) + { + _item_type = from._item_type; + _key = from._key; + _storeId = from._storeId; + _id = from._id; + _serialized = from._serialized; + _storeName = from._storeName; + _name = from._name; + } + + Provider::Context *clone() const override + { + return new pkcs11KeyStoreEntryContext(*this); + } + +public: + KeyStoreEntry::Type type() const override + { + return _item_type; + } + + QString name() const override + { + return _name; + } + + QString id() const override + { + return _id; + } + + KeyBundle keyBundle() const override + { + return _key; + } + + Certificate certificate() const override + { + return _cert; + } + + QString storeId() const override + { + return _storeId; + } + + QString storeName() const override + { + return _storeName; + } + + bool isAvailable() const override + { + return static_cast(static_cast(_key.privateKey().context())->key()) + ->_isTokenAvailable(); + } + + bool ensureAccess() override + { + return static_cast(static_cast(_key.privateKey().context())->key()) + ->_ensureTokenAccess(); + } + + QString serialize() const override + { + return _serialized; + } +}; + +//---------------------------------------------------------------------------- +// pkcs11QCACrypto +//---------------------------------------------------------------------------- +class pkcs11QCACrypto +{ +private: + static int _pkcs11h_crypto_qca_initialize(void *const global_data) + { + Q_UNUSED(global_data); + + return TRUE; // krazy:exclude=captruefalse + } + + static int _pkcs11h_crypto_qca_uninitialize(void *const global_data) + { + Q_UNUSED(global_data); + + return TRUE; // krazy:exclude=captruefalse + } + + static int _pkcs11h_crypto_qca_certificate_get_expiration(void *const global_data, + const unsigned char *const blob, + const size_t blob_size, + time_t *const expiration) + { + Q_UNUSED(global_data); + + Certificate cert = Certificate::fromDER(QByteArray((char *)blob, blob_size)); + + *expiration = cert.notValidAfter().toSecsSinceEpoch(); + + return TRUE; // krazy:exclude=captruefalse + } + + static int _pkcs11h_crypto_qca_certificate_get_dn(void *const global_data, + const unsigned char *const blob, + const size_t blob_size, + char *const dn, + const size_t dn_max) + { + Q_UNUSED(global_data); + + Certificate cert = Certificate::fromDER(QByteArray((char *)blob, blob_size)); + QString qdn = cert.subjectInfoOrdered().toString(); + + if ((size_t)qdn.length() > dn_max - 1) { + return FALSE; // krazy:exclude=captruefalse + } else { + qstrcpy(dn, myPrintable(qdn)); + return TRUE; // krazy:exclude=captruefalse + } + } + + static int _pkcs11h_crypto_qca_certificate_is_issuer(void *const global_data, + const unsigned char *const signer_blob, + const size_t signer_blob_size, + const unsigned char *const cert_blob, + const size_t cert_blob_size) + { + Q_UNUSED(global_data); + + Certificate signer = Certificate::fromDER(QByteArray((char *)signer_blob, signer_blob_size)); + + Certificate cert = Certificate::fromDER(QByteArray((char *)cert_blob, cert_blob_size)); + + return signer.isIssuerOf(cert); + } + +public: + static pkcs11h_engine_crypto_t crypto; +}; + +pkcs11h_engine_crypto_t pkcs11QCACrypto::crypto = {nullptr, + _pkcs11h_crypto_qca_initialize, + _pkcs11h_crypto_qca_uninitialize, + _pkcs11h_crypto_qca_certificate_get_expiration, + _pkcs11h_crypto_qca_certificate_get_dn, + _pkcs11h_crypto_qca_certificate_is_issuer}; + +//---------------------------------------------------------------------------- +// pkcs11KeyStoreListContext +//---------------------------------------------------------------------------- +pkcs11KeyStoreListContext::pkcs11KeyStoreListContext(Provider *p) + : KeyStoreListContext(p) +{ + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::pkcs11KeyStoreListContext - entry Provider=%p", (void *)p), + Logger::Debug); + + _last_id = 0; + _initialized = false; + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::pkcs11KeyStoreListContext - return"), Logger::Debug); +} + +pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext() +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext - entry"), Logger::Debug); + + s_keyStoreList = nullptr; + _clearStores(); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::~pkcs11KeyStoreListContext - return"), Logger::Debug); +} + +Provider::Context *pkcs11KeyStoreListContext::clone() const +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::clone - entry/return"), Logger::Debug); + return nullptr; +} + +void pkcs11KeyStoreListContext::start() +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::start - entry"), Logger::Debug); + + QMetaObject::invokeMethod(this, "doReady", Qt::QueuedConnection); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::start - return"), Logger::Debug); +} + +void pkcs11KeyStoreListContext::setUpdatesEnabled(bool enabled) +{ + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::setUpdatesEnabled - entry enabled=%d", enabled ? 1 : 0), + Logger::Debug); + + try { + pkcs11Provider *p = static_cast(provider()); + if (enabled) { + p->startSlotEvents(); + } else { + p->stopSlotEvents(); + } + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Start event failed %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::setUpdatesEnabled - return"), Logger::Debug); +} + +KeyStoreEntryContext *pkcs11KeyStoreListContext::entry(int id, const QString &entryId) +{ + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::entry - entry/return id=%d entryId='%s'", + id, + myPrintable(entryId)), + Logger::Debug); + + Q_UNUSED(id); + Q_UNUSED(entryId); + return nullptr; +} + +KeyStoreEntryContext *pkcs11KeyStoreListContext::entryPassive(const QString &serialized) +{ + KeyStoreEntryContext *entry = nullptr; + pkcs11h_certificate_id_t certificate_id = nullptr; + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::entryPassive - entry serialized='%s'", myPrintable(serialized)), + Logger::Debug); + + try { + if (serialized.startsWith(QLatin1String("qca-pkcs11/"))) { + CertificateChain chain; + bool has_private; + + _deserializeCertificate(serialized, &certificate_id, &has_private, chain); + pkcs11KeyStoreItem *sentry = _registerTokenId(certificate_id->token_id); + sentry->registerCertificates(chain); + QMap friendlyNames = sentry->friendlyNames(); + + entry = _keyStoreEntryByCertificateId( + certificate_id, has_private, chain, friendlyNames[certificateHash(chain.primary())]); + } + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Add key store entry %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + + if (certificate_id != nullptr) { + pkcs11h_certificate_freeCertificateId(certificate_id); + certificate_id = nullptr; + } + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::entryPassive - return entry=%p", (void *)entry), + Logger::Debug); + + return entry; +} + +KeyStore::Type pkcs11KeyStoreListContext::type(int id) const +{ + Q_UNUSED(id); + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::type - entry/return id=%d", id), Logger::Debug); + + return KeyStore::SmartCard; +} + +QString pkcs11KeyStoreListContext::storeId(int id) const +{ + QString ret; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::storeId - entry id=%d", id), Logger::Debug); + + if (_storesById.contains(id)) { + ret = _tokenId2storeId(_storesById[id]->tokenId()); + } + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::storeId - return ret=%s", myPrintable(ret)), + Logger::Debug); + + return ret; +} + +QString pkcs11KeyStoreListContext::name(int id) const +{ + QString ret; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::name - entry id=%d", id), Logger::Debug); + + if (_storesById.contains(id)) { + ret = QString::fromLatin1(_storesById[id]->tokenId()->label); + } + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::name - return ret=%s", myPrintable(ret)), + Logger::Debug); + + return ret; +} + +QList pkcs11KeyStoreListContext::entryTypes(int id) const +{ + Q_UNUSED(id); + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::entryTypes - entry/return id=%d", id), + Logger::Debug); + + QList list; + list += KeyStoreEntry::TypeKeyBundle; + list += KeyStoreEntry::TypeCertificate; + return list; +} + +QList pkcs11KeyStoreListContext::keyStores() +{ + pkcs11h_token_id_list_t tokens = nullptr; + QList out; + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::keyStores - entry"), Logger::Debug); + + try { + CK_RV rv; + + /* + * Get available tokens + */ + if ((rv = pkcs11h_token_enumTokenIds(PKCS11H_ENUM_METHOD_CACHE_EXIST, &tokens)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Enumerating tokens")); + } + + /* + * Register all tokens, unmark + * them from remove list + */ + QList to_remove = _storesById.keys(); + for (pkcs11h_token_id_list_t entry = tokens; entry != nullptr; entry = entry->next) { + pkcs11KeyStoreItem *item = _registerTokenId(entry->token_id); + out += item->id(); + to_remove.removeAll(item->id()); + } + + /* + * Remove all items + * that were not discovered + */ + { + QMutexLocker l(&_mutexStores); + + foreach (int i, to_remove) { + pkcs11KeyStoreItem *item = _storesById[i]; + + _storesById.remove(item->id()); + _stores.removeAll(item); + + delete item; + item = nullptr; + } + } + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Cannot get key stores: %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + + if (tokens != nullptr) { + pkcs11h_token_freeTokenIdList(tokens); + } + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::keyStores - return out.size()=%d", int(out.size())), + Logger::Debug); + + return out; +} + +QList pkcs11KeyStoreListContext::entryList(int id) +{ + pkcs11h_certificate_id_list_t certs = nullptr; + QList out; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::entryList - entry id=%d", id), Logger::Debug); + + try { + CK_RV rv; + + if (_storesById.contains(id)) { + pkcs11KeyStoreItem *entry = _storesById[id]; + + pkcs11h_certificate_id_list_t issuers = nullptr; + pkcs11h_certificate_id_list_t current = nullptr; + QList listCerts; + QList listIssuers; + int i = 0; + + if ((rv = pkcs11h_certificate_enumTokenCertificateIds(entry->tokenId(), + PKCS11H_ENUM_METHOD_CACHE, + nullptr, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + &issuers, + &certs)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Enumerate certificates")); + } + + for (current = certs; current != nullptr; current = current->next) { + if (current->certificate_id->certificate_blob_size > 0) { + listCerts += Certificate::fromDER(QByteArray((char *)current->certificate_id->certificate_blob, + current->certificate_id->certificate_blob_size)); + } + } + + for (current = issuers; current != nullptr; current = current->next) { + if (current->certificate_id->certificate_blob_size > 0) { + listIssuers += Certificate::fromDER(QByteArray((char *)current->certificate_id->certificate_blob, + current->certificate_id->certificate_blob_size)); + } + } + + entry->registerCertificates(listIssuers + listCerts); + QMap friendlyNames = entry->friendlyNames(); + + QList listIssuersForComplete; + if (dynamic_cast(provider())->_allowLoadRootCA) { + listIssuersForComplete = listIssuers; + } else { + foreach (Certificate c, listIssuers) { + if (!c.isSelfSigned()) { + listIssuersForComplete += c; + } + } + } + + for (i = 0, current = issuers; current != nullptr; i++, current = current->next) { + try { + if (listIssuers[i].isNull()) { + throw pkcs11Exception(CKR_ARGUMENTS_BAD, QStringLiteral("Invalid certificate")); + } + + if (listIssuers[i].isSelfSigned() && dynamic_cast(provider())->_allowLoadRootCA) { + CertificateChain chain = CertificateChain(listIssuers[i]).complete(listIssuersForComplete); + out += _keyStoreEntryByCertificateId( + current->certificate_id, false, chain, friendlyNames[certificateHash(chain.primary())]); + } + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText(QString::asprintf( + "PKCS#11: Add key store entry %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + } + + for (i = 0, current = certs; current != nullptr; i++, current = current->next) { + try { + if (listCerts[i].isNull()) { + throw pkcs11Exception(CKR_ARGUMENTS_BAD, QStringLiteral("Invalid certificate")); + } + + CertificateChain chain = CertificateChain(listCerts[i]).complete(listIssuersForComplete); + out += _keyStoreEntryByCertificateId( + current->certificate_id, true, chain, friendlyNames[certificateHash(chain.primary())]); + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText(QString::asprintf( + "PKCS#11: Add key store entry %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + } + } + } catch (const pkcs11Exception &e) { + s_keyStoreList->_emit_diagnosticText( + QString::asprintf("PKCS#11: Enumerating store failed %lu-'%s'.\n", e.rv(), myPrintable(e.message()))); + } + + if (certs != nullptr) { + pkcs11h_certificate_freeCertificateIdList(certs); + } + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::entryList - return out.size()=%d", int(out.size())), + Logger::Debug); + + return out; +} + +bool pkcs11KeyStoreListContext::_tokenPrompt(void *const user_data, const pkcs11h_token_id_t token_id) +{ + KeyStoreEntry entry; + KeyStoreEntryContext *context = nullptr; + QString storeId, storeName; + bool ret = false; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_tokenPrompt - entry user_data=%p, token_id=%p", + user_data, + (void *)token_id), + Logger::Debug); + + if (user_data != nullptr) { + QString *serialized = (QString *)user_data; + context = entryPassive(*serialized); + storeId = context->storeId(); + storeName = context->storeName(); + entry.change(context); + } else { + _registerTokenId(token_id); + storeId = _tokenId2storeId(token_id); + storeName = QString::fromLatin1(token_id->label); + } + + TokenAsker asker; + asker.ask(KeyStoreInfo(KeyStore::SmartCard, storeId, storeName), entry, context); + asker.waitForResponse(); + if (asker.accepted()) { + ret = true; + } + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_tokenPrompt - return ret=%d", ret ? 1 : 0), + Logger::Debug); + + return ret; +} + +bool pkcs11KeyStoreListContext::_pinPrompt(void *const user_data, const pkcs11h_token_id_t token_id, SecureArray &pin) +{ + KeyStoreEntry entry; + KeyStoreEntryContext *context = nullptr; + QString storeId, storeName; + bool ret = false; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_pinPrompt - entry user_data=%p, token_id=%p", + user_data, + (void *)token_id), + Logger::Debug); + + pin = SecureArray(); + + if (user_data != nullptr) { + QString *serialized = (QString *)user_data; + context = entryPassive(*serialized); + storeId = context->storeId(); + storeName = context->storeName(); + entry.change(context); + } else { + _registerTokenId(token_id); + storeId = _tokenId2storeId(token_id); + storeName = QString::fromLatin1(token_id->label); + } + + PasswordAsker asker; + asker.ask(Event::StylePIN, KeyStoreInfo(KeyStore::SmartCard, storeId, storeName), entry, context); + asker.waitForResponse(); + if (asker.accepted()) { + ret = true; + pin = asker.password(); + } + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_pinPrompt - return ret=%d", ret ? 1 : 0), + Logger::Debug); + + return ret; +} + +void pkcs11KeyStoreListContext::_emit_diagnosticText(const QString &t) +{ + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_emit_diagnosticText - entry t='%s'", myPrintable(t)), + Logger::Debug); + + QCA_logTextMessage(t, Logger::Warning); + + emit diagnosticText(t); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::_emit_diagnosticText - return"), Logger::Debug); +} + +void pkcs11KeyStoreListContext::doReady() +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::doReady - entry"), Logger::Debug); + + emit busyEnd(); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::doReady - return"), Logger::Debug); +} + +void pkcs11KeyStoreListContext::doUpdated() +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::doUpdated - entry"), Logger::Debug); + + emit updated(); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::doUpdated - return"), Logger::Debug); +} + +pkcs11KeyStoreListContext::pkcs11KeyStoreItem * +pkcs11KeyStoreListContext::_registerTokenId(const pkcs11h_token_id_t token_id) +{ + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_registerTokenId - entry token_id=%p", (void *)token_id), + Logger::Debug); + + QMutexLocker l(&_mutexStores); + + _stores_t::iterator i = _stores.begin(); + + while (i != _stores.end() && !pkcs11h_token_sameTokenId(token_id, (*i)->tokenId())) { + i++; + } + + pkcs11KeyStoreItem *entry = nullptr; + + if (i == _stores.end()) { + /* + * Deal with last_id overlap + */ + while (_storesById.find(++_last_id) != _storesById.end()) + ; + + entry = new pkcs11KeyStoreItem(_last_id, token_id); + + _stores += entry; + _storesById.insert(entry->id(), entry); + } else { + entry = (*i); + } + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_registerTokenId - return entry=%p", (void *)token_id), + Logger::Debug); + + return entry; +} + +void pkcs11KeyStoreListContext::_clearStores() +{ + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::_clearStores - entry"), Logger::Debug); + + QMutexLocker l(&_mutexStores); + + _storesById.clear(); + foreach (pkcs11KeyStoreItem *i, _stores) { + delete i; + } + + _stores.clear(); + + QCA_logTextMessage(QStringLiteral("pkcs11KeyStoreListContext::_clearStores - return"), Logger::Debug); +} + +pkcs11KeyStoreEntryContext * +pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId(const pkcs11h_certificate_id_t certificate_id, + const bool has_private, + const CertificateChain &chain, + const QString &_description) const +{ + pkcs11KeyStoreEntryContext *entry = nullptr; + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId - entry " + "certificate_id=%p, has_private=%d, chain.size()=%d", + (void *)certificate_id, + has_private ? 1 : 0, + int(chain.size())), + Logger::Debug); + + if (certificate_id == nullptr) { + throw pkcs11Exception(CKR_ARGUMENTS_BAD, QStringLiteral("Missing certificate object")); + } + + QString serialized = _serializeCertificate(certificate_id, chain, has_private); + + QString description = _description; + const Certificate &cert = chain.primary(); + if (description.isEmpty()) { + description = cert.subjectInfoOrdered().toString() + QStringLiteral(" by ") + + cert.issuerInfo().value(CommonName, QStringLiteral("Unknown")); + } + + if (has_private) { + pkcs11RSAContext *rsakey = + new pkcs11RSAContext(provider(), certificate_id, serialized, cert.subjectPublicKey().toRSA()); + + pkcs11PKeyContext *pkc = new pkcs11PKeyContext(provider()); + pkc->setKey(rsakey); + PrivateKey privkey; + privkey.change(pkc); + KeyBundle key; + key.setCertificateChainAndKey(chain, privkey); + + entry = new pkcs11KeyStoreEntryContext(key, + _tokenId2storeId(certificate_id->token_id), + serialized, + QString::fromLatin1(certificate_id->token_id->label), + description, + provider()); + } else { + entry = new pkcs11KeyStoreEntryContext(cert, + _tokenId2storeId(certificate_id->token_id), + serialized, + QString::fromLatin1(certificate_id->token_id->label), + description, + provider()); + } + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_keyStoreEntryByCertificateId - return entry=%p", (void *)entry), + Logger::Debug); + + return entry; +} + +QString pkcs11KeyStoreListContext::_tokenId2storeId(const pkcs11h_token_id_t token_id) const +{ + QString storeId; + size_t len; + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_tokenId2storeId - entry token_id=%p", (void *)token_id), + Logger::Debug); + + if (pkcs11h_token_serializeTokenId(nullptr, &len, token_id) != CKR_OK) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Cannot serialize token id")); + } + + QByteArray buf; + buf.resize((int)len); + + if (pkcs11h_token_serializeTokenId(buf.data(), &len, token_id) != CKR_OK) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Cannot serialize token id")); + } + + buf.resize((int)len); + + storeId = QStringLiteral("qca-pkcs11/") + _escapeString(QString::fromUtf8(buf)); + + QCA_logTextMessage( + QString::asprintf("pkcs11KeyStoreListContext::_tokenId2storeId - return storeId='%s'", myPrintable(storeId)), + Logger::Debug); + + return storeId; +} + +QString pkcs11KeyStoreListContext::_serializeCertificate(const pkcs11h_certificate_id_t certificate_id, + const CertificateChain &chain, + const bool has_private) const +{ + QString serialized; + size_t len; + + QCA_logTextMessage( + QString::asprintf( + "pkcs11KeyStoreListContext::_serializeCertificate - entry certificate_id=%p, xx, has_private=%d", + (void *)certificate_id, + has_private ? 1 : 0), + Logger::Debug); + + if (pkcs11h_certificate_serializeCertificateId(nullptr, &len, certificate_id) != CKR_OK) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Cannot serialize certificate id")); + } + + QByteArray buf; + buf.resize((int)len); + + if (pkcs11h_certificate_serializeCertificateId(buf.data(), &len, certificate_id) != CKR_OK) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Cannot serialize certificate id")); + } + + buf.resize((int)len); + + serialized = QString::asprintf( + "qca-pkcs11/0/%s/%d/", myPrintable(_escapeString(QString::fromUtf8(buf))), has_private ? 1 : 0); + + QStringList list; + foreach (Certificate i, chain) { + list += _escapeString(Base64().arrayToString(i.toDER())); + } + + serialized.append(list.join(QStringLiteral("/"))); + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_serializeCertificate - return serialized='%s'", + myPrintable(serialized)), + Logger::Debug); + + return serialized; +} + +void pkcs11KeyStoreListContext::_deserializeCertificate(const QString &from, + pkcs11h_certificate_id_t *const p_certificate_id, + bool *const p_has_private, + CertificateChain &chain) const +{ + pkcs11h_certificate_id_t certificate_id = nullptr; + chain.clear(); + + QCA_logTextMessage(QString::asprintf("pkcs11KeyStoreListContext::_deserializeCertificate - entry from='%s', " + "p_certificate_id=%p, p_has_private=%p", + myPrintable(from), + (void *)p_certificate_id, + (void *)p_has_private), + Logger::Debug); + + try { + int n = 0; + CK_RV rv; + + *p_certificate_id = nullptr; + *p_has_private = false; + + const QStringList list = from.split(QStringLiteral("/")); + + if (list.size() < 5) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Invalid serialization")); + } + + if (list[n++] != QLatin1String("qca-pkcs11")) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Invalid serialization")); + } + + if (list[n++].toInt() != 0) { + throw pkcs11Exception(CKR_FUNCTION_FAILED, QStringLiteral("Invalid serialization version")); + } + + if ((rv = pkcs11h_certificate_deserializeCertificateId(&certificate_id, + myPrintable(_unescapeString(list[n++])))) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Invalid serialization")); + } + + *p_has_private = list[n++].toInt() != 0; + + const QByteArray endCertificateBytes = Base64().stringToArray(_unescapeString(list[n++])).toByteArray(); + Certificate endCertificate = Certificate::fromDER(endCertificateBytes); + + if (endCertificate.isNull()) { + throw pkcs11Exception(rv, QStringLiteral("Invalid certificate")); + } + + if ((rv = pkcs11h_certificate_setCertificateIdCertificateBlob(certificate_id, + (const unsigned char *)endCertificateBytes.data(), + (size_t)endCertificateBytes.size())) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Invalid serialization")); + } + + chain = endCertificate; + while (n < list.size()) { + Certificate cert = Certificate::fromDER(Base64().stringToArray(_unescapeString(list[n++])).toByteArray()); + if (cert.isNull()) { + throw pkcs11Exception(rv, QStringLiteral("Invalid certificate")); + } + chain += cert; + } + + *p_certificate_id = certificate_id; + certificate_id = nullptr; + } catch (...) { + if (certificate_id != nullptr) { + pkcs11h_certificate_freeCertificateId(certificate_id); + certificate_id = nullptr; + } + throw; + } + + QCA_logTextMessage( + QString::asprintf( + "pkcs11KeyStoreListContext::_deserializeCertificate - return *p_certificate_id=%p, chain.size()=%d", + (void *)*p_certificate_id, + int(chain.size())), + Logger::Debug); +} + +QString pkcs11KeyStoreListContext::_escapeString(const QString &from) const +{ + QString to; + + foreach (QChar c, from) { + if (c == QLatin1Char('/') || c == QLatin1Char('\\')) { + to += QString::asprintf("\\x%04x", c.unicode()); + } else { + to += c; + } + } + + return to; +} + +QString pkcs11KeyStoreListContext::_unescapeString(const QString &from) const +{ + QString to; + + for (int i = 0; i < from.size(); i++) { + QChar c = from[i]; + + if (c == QLatin1Char('\\')) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + to += QChar((ushort)QStringView(from).mid(i + 2, 4).toInt(nullptr, 16)); +#else + to += QChar((ushort)from.midRef(i + 2, 4).toInt(nullptr, 16)); +#endif + i += 5; + } else { + to += c; + } + } + + return to; +} + +} + +using namespace pkcs11QCAPlugin; + +const int pkcs11Provider::_CONFIG_MAX_PROVIDERS = 10; + +//---------------------------------------------------------------------------- +// pkcs11Provider +//---------------------------------------------------------------------------- +pkcs11Provider::pkcs11Provider() +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::pkcs11Provider - entry"), Logger::Debug); + + _lowLevelInitialized = false; + _slotEventsActive = false; + _slotEventsLowLevelActive = false; + _allowLoadRootCA = false; + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::pkcs11Provider - return"), Logger::Debug); +} + +pkcs11Provider::~pkcs11Provider() +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::~pkcs11Provider - entry/return"), Logger::Debug); +} + +int pkcs11Provider::qcaVersion() const +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::qcaVersion - entry/return"), Logger::Debug); + + return QCA_VERSION; +} + +void pkcs11Provider::init() +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::init - entry"), Logger::Debug); + + try { + CK_RV rv; + + if ((rv = pkcs11h_engine_setCrypto(&pkcs11QCACrypto::crypto)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot set crypto")); + } + + if ((rv = pkcs11h_initialize()) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot initialize")); + } + + if ((rv = pkcs11h_setLogHook(__logHook, this)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot set hook")); + } + + pkcs11h_setLogLevel(0); + + if ((rv = pkcs11h_setTokenPromptHook(__tokenPromptHook, this)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot set hook")); + } + + if ((rv = pkcs11h_setPINPromptHook(__pinPromptHook, this)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot set hook")); + } + + _lowLevelInitialized = true; + } catch (const pkcs11Exception &e) { + QCA_logTextMessage(e.message(), Logger::Error); + appendPluginDiagnosticText( + QString::asprintf("An error %s during initialization of qca-pkcs11 plugin\n", myPrintable(e.message()))); + } catch (...) { + QCA_logTextMessage(QStringLiteral("PKCS#11: Unknown error during provider initialization"), Logger::Error); + appendPluginDiagnosticText(QStringLiteral("Unknown error during initialization of qca-pkcs11 plugin\n")); + } + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::init - return"), Logger::Debug); +} + +void pkcs11Provider::deinit() +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::deinit - entry"), Logger::Debug); + + delete s_keyStoreList; + s_keyStoreList = nullptr; + + pkcs11h_terminate(); + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::deinit - return"), Logger::Debug); +} + +QString pkcs11Provider::name() const +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::name - entry/return"), Logger::Debug); + + return QStringLiteral("qca-pkcs11"); +} + +QStringList pkcs11Provider::features() const +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::features - entry/return"), Logger::Debug); + + QStringList list; + list += QStringLiteral("smartcard"); // indicator, not algorithm + list += QStringLiteral("pkey"); + list += QStringLiteral("keystorelist"); + return list; +} + +Provider::Context *pkcs11Provider::createContext(const QString &type) +{ + Provider::Context *context = nullptr; + + QCA_logTextMessage(QString::asprintf("pkcs11Provider::createContext - entry type='%s'", myPrintable(type)), + Logger::Debug); + + if (_lowLevelInitialized) { + if (type == QLatin1String("keystorelist")) { + if (s_keyStoreList == nullptr) { + s_keyStoreList = new pkcs11KeyStoreListContext(this); + } + context = s_keyStoreList; + } + } + + QCA_logTextMessage(QString::asprintf("pkcs11Provider::createContext - return context=%p", (void *)context), + Logger::Debug); + + return context; +} + +void pkcs11Provider::startSlotEvents() +{ + CK_RV rv; + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::startSlotEvents - entry"), Logger::Debug); + + if (_lowLevelInitialized) { + if (!_slotEventsLowLevelActive) { + if ((rv = pkcs11h_setSlotEventHook(__slotEventHook, this)) != CKR_OK) { + throw pkcs11Exception(rv, QStringLiteral("Cannot start slot events")); + } + + _slotEventsLowLevelActive = true; + } + + _slotEventsActive = true; + } + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::startSlotEvents - return"), Logger::Debug); +} + +void pkcs11Provider::stopSlotEvents() +{ + QCA_logTextMessage(QStringLiteral("pkcs11Provider::stopSlotEvents - entry/return"), Logger::Debug); + + _slotEventsActive = false; +} + +QVariantMap pkcs11Provider::defaultConfig() const +{ + QVariantMap mytemplate; + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::defaultConfig - entry/return"), Logger::Debug); + + mytemplate[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/qca-pkcs11#1.0"); + mytemplate[QStringLiteral("allow_load_rootca")] = false; + mytemplate[QStringLiteral("allow_protected_authentication")] = true; + mytemplate[QStringLiteral("pin_cache")] = PKCS11H_PIN_CACHE_INFINITE; + mytemplate[QStringLiteral("log_level")] = 0; + for (int i = 0; i < _CONFIG_MAX_PROVIDERS; i++) { + mytemplate[QString::asprintf("provider_%02d_enabled", i)] = false; + mytemplate[QString::asprintf("provider_%02d_name", i)] = QLatin1String(""); + mytemplate[QString::asprintf("provider_%02d_library", i)] = QLatin1String(""); + mytemplate[QString::asprintf("provider_%02d_allow_protected_authentication", i)] = true; + mytemplate[QString::asprintf("provider_%02d_cert_private", i)] = false; + mytemplate[QString::asprintf("provider_%02d_private_mask", i)] = PKCS11H_PRIVATEMODE_MASK_AUTO; + mytemplate[QString::asprintf("provider_%02d_slotevent_method", i)] = QStringLiteral("auto"); + mytemplate[QString::asprintf("provider_%02d_slotevent_timeout", i)] = 0; + } + + return mytemplate; +} + +void pkcs11Provider::configChanged(const QVariantMap &config) +{ + CK_RV rv = CKR_OK; + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::configChanged - entry"), Logger::Debug); + + if (!_lowLevelInitialized) { + QCA_logTextMessage(QStringLiteral("PKCS#11: Not initialized"), Logger::Error); + return; + } + + _allowLoadRootCA = config[QStringLiteral("allow_load_rootca")].toBool(); + + pkcs11h_setLogLevel(config[QStringLiteral("log_level")].toInt()); + pkcs11h_setProtectedAuthentication(config[QStringLiteral("allow_protected_authentication")].toBool() != false + ? TRUE + : FALSE // krazy:exclude=captruefalse + ); + pkcs11h_setPINCachePeriod(config[QStringLiteral("pin_cache")].toInt()); + + /* + * Remove current providers + */ + foreach (QString i, _providers) { + pkcs11h_removeProvider(myPrintable(i)); + } + _providers.clear(); + + /* + * Add new providers + */ + for (int i = 0; i < _CONFIG_MAX_PROVIDERS; i++) { + bool enabled = config[QString::asprintf("provider_%02d_enabled", i)].toBool(); + QString provider = config[QString::asprintf("provider_%02d_library", i)].toString(); + QString name = config[QString::asprintf("provider_%02d_name", i)].toString(); + QString qslotevent = config[QString::asprintf("provider_%02d_slotevent_method", i)].toString(); + unsigned slotevent = PKCS11H_SLOTEVENT_METHOD_AUTO; + if (qslotevent == QLatin1String("trigger")) { + slotevent = PKCS11H_SLOTEVENT_METHOD_TRIGGER; + } else if (qslotevent == QLatin1String("poll")) { + slotevent = PKCS11H_SLOTEVENT_METHOD_POLL; + } + + if (name.isEmpty()) { + name = provider; + } + + if (enabled && !provider.isEmpty()) { + QCA_logTextMessage( + QString::asprintf("Loading PKCS#11 provider '%s' (%s)", myPrintable(name), myPrintable(provider)), + Logger::Information); + + if ((rv = pkcs11h_addProvider( + myPrintable(name), + myPrintable(provider), + config[QString::asprintf("provider_%02d_allow_protected_authentication", i)].toBool() != false + ? TRUE + : FALSE, // krazy:exclude=captruefalse + (unsigned)config[QString::asprintf("provider_%02d_private_mask", i)].toInt(), + slotevent, + (unsigned)config[QString::asprintf("provider_%02d_slotevent_timeout", i)].toInt(), + config[QString::asprintf("provider_%02d_cert_private", i)].toBool() != false + ? TRUE + : FALSE // krazy:exclude=captruefalse + )) != CKR_OK) { + QCA_logTextMessage(QString::asprintf("PKCS#11: Cannot log provider '%s'-'%s' %lu-'%s'.\n", + myPrintable(name), + myPrintable(provider), + rv, + pkcs11h_getMessage(rv)), + Logger::Error); + appendPluginDiagnosticText(QString::asprintf("Cannot load PKCS#11 provider '%s'\n", myPrintable(name))); + } else { + _providers += provider; + } + } + } + + QCA_logTextMessage(QStringLiteral("pkcs11Provider::configChanged - return"), Logger::Debug); +} + +void pkcs11Provider::__logHook(void *const global_data, const unsigned flags, const char *const format, va_list args) +{ + pkcs11Provider *me = (pkcs11Provider *)global_data; + me->_logHook(flags, format, args); +} + +void pkcs11Provider::__slotEventHook(void *const global_data) +{ + pkcs11Provider *me = (pkcs11Provider *)global_data; + me->_slotEventHook(); +} + +PKCS11H_BOOL +pkcs11Provider::__tokenPromptHook(void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry) +{ + Q_UNUSED(retry); + + pkcs11Provider *me = (pkcs11Provider *)global_data; + return me->_tokenPromptHook(user_data, token); +} + +PKCS11H_BOOL +pkcs11Provider::__pinPromptHook(void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry, + char *const pin, + const size_t pin_max) +{ + Q_UNUSED(retry); + + pkcs11Provider *me = (pkcs11Provider *)global_data; + return me->_pinPromptHook(user_data, token, pin, pin_max); +} + +void pkcs11Provider::_logHook(const unsigned flags, const char *const format, va_list args) +{ + Logger::Severity severity; + + switch (flags) { + case PKCS11H_LOG_DEBUG2: + case PKCS11H_LOG_DEBUG1: + severity = Logger::Debug; + break; + case PKCS11H_LOG_INFO: + severity = Logger::Information; + break; + case PKCS11H_LOG_WARN: + severity = Logger::Warning; + break; + case PKCS11H_LOG_ERROR: + severity = Logger::Error; + break; + default: + severity = Logger::Debug; + break; + } + + //@BEGIN-WORKAROUND + // Qt vsprintf cannot can NULL for %s as vsprintf does. + // QCA_logTextMessage (QString ().vsprintf (format, args), severity); + char buffer[2048]; + qvsnprintf(buffer, sizeof(buffer) - 1, format, args); + buffer[sizeof(buffer) - 1] = '\x0'; + QCA_logTextMessage(QString::fromLatin1(buffer), severity); + //@END-WORKAROUND +} + +void pkcs11Provider::_slotEventHook() +{ + /* + * This is called from a separate + * thread. + */ + if (s_keyStoreList != nullptr && _slotEventsActive) { + QMetaObject::invokeMethod(s_keyStoreList, "doUpdated", Qt::QueuedConnection); + } +} + +PKCS11H_BOOL +pkcs11Provider::_tokenPromptHook(void *const user_data, const pkcs11h_token_id_t token) +{ + if (s_keyStoreList != nullptr) { + return s_keyStoreList->_tokenPrompt(user_data, token) ? TRUE : FALSE; // krazy:exclude=captruefalse + } + + return FALSE; // krazy:exclude=captruefalse +} + +PKCS11H_BOOL +pkcs11Provider::_pinPromptHook(void *const user_data, + const pkcs11h_token_id_t token, + char *const pin, + const size_t pin_max) +{ + PKCS11H_BOOL ret = FALSE; // krazy:exclude=captruefalse + + if (s_keyStoreList != nullptr) { + SecureArray qpin; + + if (s_keyStoreList->_pinPrompt(user_data, token, qpin)) { + if ((size_t)qpin.size() < pin_max - 1) { + memmove(pin, qpin.constData(), qpin.size()); + pin[qpin.size()] = '\0'; + ret = TRUE; // krazy:exclude=captruefalse + } + } + } + + return ret; // krazy:exclude=captruefalse +} + +class pkcs11Plugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) + +public: + Provider *createProvider() override + { + return new pkcs11Provider; + } +}; + +#include "qca-pkcs11.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-softstore/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-softstore/CMakeLists.txt new file mode 100644 index 0000000000..e3e2d55a90 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-softstore/CMakeLists.txt @@ -0,0 +1,24 @@ +# qca-softstore + +enable_plugin("softstore") +set(QCA_SOFTSTORE_SOURCES qca-softstore.cpp) + +add_library(qca-softstore ${PLUGIN_TYPE} ${QCA_SOFTSTORE_SOURCES}) + +if(APPLE AND ${PLUGIN_TYPE} STREQUAL "MODULE") + set_property(TARGET qca-softstore PROPERTY SUFFIX ".dylib") +endif() + +add_definitions(${SOFTSTOREH_DEFINITIONS}) +include_directories(${SOFTSTOREH_INCLUDE_DIR}) +target_link_libraries(qca-softstore Qt${QT_MAJOR_VERSION}::Core) +target_link_libraries(qca-softstore ${QCA_LIB_NAME}) + +if(NOT DEVELOPER_MODE) + install(TARGETS qca-softstore + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}") + + install_pdb(qca-softstore ${QCA_CRYPTO_INSTALL_DIR}) +endif() diff --git a/local/recipes/libs/qca/source/plugins/qca-softstore/COPYING b/local/recipes/libs/qca/source/plugins/qca-softstore/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-softstore/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-softstore/README b/local/recipes/libs/qca/source/plugins/qca-softstore/README new file mode 100644 index 0000000000..fc81810a18 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-softstore/README @@ -0,0 +1,80 @@ +qca-softstore -- Software certificate store Plug-in to QCA + +ABOUT + qca-softstore provides simple persistent certificate store for QCA framework. + + The plug-in defers the private key access and passphrase prompt to the point + it is actually required, thus enabling the use of files stored on removable media. + + The plug-in also handles the private key objects as not exportable for applications. + + In order to defer the passphrase prompt, the certificate object must be extracted + during configuration, this also apply to PKCS#12 files, since the certificate + is encrypted within the format. + +DEPENDENCIES + None. + +CONFIGURATION + Configuration is stored at ~/.config/Affinix/QCA.conf, in order to + generate default configuration use: + + $ qcatool --config save qca-softstore + + Attributes: + entry_##_enabled (Boolean) + Provider at this index is enabled. + + entry_##_name (String) + Name of entry. + + entry_##_public_type (String) + Type of public component: + + x509chain + entry_##_public is X.509 certificate chain. + Each certificate is encoded in base64. + List separator is '!'. + First entry is end certificate. + + entry_##_public (String) + By entry_##_public_type. + + entry_##_private_type (String) + Type of private component: + + pkcs12 + entry_##_private is PKCS#12 format file name. + + pkcs8 + entry_##_private is base64 encoded PKCS#8 format. + + pkcs8-file-pem + entry_##_private is PEM RSA key file name or PKCS#8 PEM encoded. + + pkcs8-file-der + entry_##_private is PKCS#8 DER format. + + entry_##_private (String) + By entry_##_private_type. + + entry_##_no_passphrase (Boolean) + true if entry_##_private is not protected by passphrase. + + entry_##_unlock_timeout (Integer) + Time in seconds to until passphrase should be prompted again. + Specify -1 for infinite. + +USEFUL COMMANDS + pkcs12->RSA PEM + openssl pkcs12 -in -nocerts -out + + pkcs12->Certificate PEM + openssl pkcs12 -in -nokeys -out + + RSA PEM->PKCS#8 + openssl pkcs8 -in -topk8 -out -outform DER + +AUTHORS + Alon Bar-Lev + diff --git a/local/recipes/libs/qca/source/plugins/qca-softstore/qca-softstore.cpp b/local/recipes/libs/qca/source/plugins/qca-softstore/qca-softstore.cpp new file mode 100644 index 0000000000..1a748ce4aa --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-softstore/qca-softstore.cpp @@ -0,0 +1,1150 @@ +/* + * Copyright (C) 2007 Alon Bar-Lev + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include +#include +#include + +using namespace QCA; + +// qPrintable is ASCII only!!! +#define myPrintable(s) (s).toUtf8().constData() + +namespace softstoreQCAPlugin { + +class softstoreKeyStoreListContext; +static softstoreKeyStoreListContext *s_keyStoreList = nullptr; + +enum KeyType +{ + keyTypeInvalid, + keyTypePKCS12, + keyTypePKCS8Inline, + keyTypePKCS8FilePEM, + keyTypePKCS8FileDER +}; + +enum PublicType +{ + publicTypeInvalid, + publicTypeX509Chain +}; + +struct SoftStoreEntry +{ + QString name; + CertificateChain chain; + KeyType keyReferenceType; + QString keyReference; + bool noPassphrase; + int unlockTimeout; +}; + +class softstorePKeyBase : public PKeyBase +{ + Q_OBJECT + +private: + bool _has_privateKeyRole; + SoftStoreEntry _entry; + QString _serialized; + PrivateKey _privkey; + PrivateKey _privkeySign; + PublicKey _pubkey; + QDateTime dueTime; + +public: + static inline QString typeToString(PKey::Type t) + { + switch (t) { + case PKey::RSA: + return QStringLiteral("rsa"); + case PKey::DSA: + return QStringLiteral("dsa"); + case PKey::DH: + return QStringLiteral("dh"); + default: + return QLatin1String(""); + } + } + + softstorePKeyBase(const SoftStoreEntry &entry, const QString &serialized, Provider *p) + : PKeyBase(p, QStringLiteral("rsa") /*typeToString (entry.chain.primary ().subjectPublicKey ().type ())*/) + { + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - entry"), Logger::Debug); + + _has_privateKeyRole = true; + _entry = entry; + _serialized = serialized; + _pubkey = _entry.chain.primary().subjectPublicKey(); + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - return"), Logger::Debug); + } + + softstorePKeyBase(const softstorePKeyBase &from) + : PKeyBase(from.provider(), QStringLiteral("rsa") /*typeToString (from._pubkey.type ())*/) + { + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - entry"), Logger::Debug); + + _has_privateKeyRole = from._has_privateKeyRole; + _entry = from._entry; + _serialized = from._serialized; + _pubkey = from._pubkey; + _privkey = from._privkey; + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - return"), Logger::Debug); + } + + ~softstorePKeyBase() override + { + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - entry"), Logger::Debug); + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - return"), Logger::Debug); + } + + Provider::Context *clone() const override + { + return new softstorePKeyBase(*this); + } + +public: + bool isNull() const override + { + return _pubkey.isNull(); + } + + PKey::Type type() const override + { + return _pubkey.type(); + } + + bool isPrivate() const override + { + return _has_privateKeyRole; + } + + bool canExport() const override + { + return !_has_privateKeyRole; + } + + void convertToPublic() override + { + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - entry"), Logger::Debug); + + if (_has_privateKeyRole) { + _has_privateKeyRole = false; + } + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - return"), Logger::Debug); + } + + int bits() const override + { + return _pubkey.bitSize(); + } + + int maximumEncryptSize(EncryptionAlgorithm alg) const override + { + return _pubkey.maximumEncryptSize(alg); + } + + SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override + { + return _pubkey.encrypt(in, alg); + } + + bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override + { + if (_ensureAccess()) { + return _privkey.decrypt(in, out, alg); + } else { + return false; + } + } + + void startSign(SignatureAlgorithm alg, SignatureFormat format) override + { + if (_ensureAccess()) { + /* + * We must use one object thought + * signing, so it won't expire by + * it-self or during passphrase. + */ + _privkeySign = _privkey; + _privkeySign.startSign(alg, format); + } + } + + void startVerify(SignatureAlgorithm alg, SignatureFormat sf) override + { + _pubkey.startVerify(alg, sf); + } + + void update(const MemoryRegion &in) override + { + if (_has_privateKeyRole) { + _privkeySign.update(in); + } else { + _pubkey.update(in); + } + } + + QByteArray endSign() override + { + const QByteArray r = _privkeySign.signature(); + _privkeySign = PrivateKey(); + return r; + } + + virtual bool validSignature(const QByteArray &sig) + { + return _pubkey.validSignature(sig); + } + + virtual void createPrivate(int bits, int exp, bool block) + { + Q_UNUSED(bits); + Q_UNUSED(exp); + Q_UNUSED(block); + } + + virtual void createPrivate(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d) + { + Q_UNUSED(n); + Q_UNUSED(e); + Q_UNUSED(p); + Q_UNUSED(q); + Q_UNUSED(d); + } + + virtual void createPublic(const BigInteger &n, const BigInteger &e) + { + Q_UNUSED(n); + Q_UNUSED(e); + } + +public: + PublicKey _publicKey() const + { + return _pubkey; + } + + bool _ensureAccess() + { + bool ret = false; + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - entry"), Logger::Debug); + + if (_entry.unlockTimeout != -1) { + if (dueTime >= QDateTime::currentDateTime()) { + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - dueTime reached, clearing"), + Logger::Debug); + _privkey = PrivateKey(); + } + } + + if (!_privkey.isNull()) { + ret = true; + } else { + KeyStoreEntry entry; + KeyStoreEntryContext *context = nullptr; + QString storeId, storeName; + ConvertResult cresult; + + QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - no current key, creating"), + Logger::Debug); + + // too lazy to create scope + context = reinterpret_cast(s_keyStoreList)->entryPassive(_serialized); + if (context != nullptr) { + storeId = context->storeId(); + storeName = context->storeName(); + entry.change(context); + } + + while (!ret) { + SecureArray passphrase; + + switch (_entry.keyReferenceType) { + case keyTypeInvalid: + case keyTypePKCS8Inline: + break; + case keyTypePKCS12: + case keyTypePKCS8FilePEM: + case keyTypePKCS8FileDER: + { + QFile file(_entry.keyReference); + while (!file.open(QIODevice::ReadOnly)) { + TokenAsker asker; + asker.ask(KeyStoreInfo(KeyStore::SmartCard, storeId, storeName), entry, context); + asker.waitForResponse(); + if (!asker.accepted()) { + goto cleanup1; + } + } + } break; + } + + if (!_entry.noPassphrase) { + PasswordAsker asker; + asker.ask(Event::StylePassphrase, KeyStoreInfo(KeyStore::User, storeId, storeName), entry, context); + asker.waitForResponse(); + passphrase = asker.password(); + if (!asker.accepted()) { + goto cleanup1; + } + } + + switch (_entry.keyReferenceType) { + case keyTypeInvalid: + break; + case keyTypePKCS12: + { + KeyBundle bundle = KeyBundle::fromFile(_entry.keyReference, passphrase, &cresult); + if (cresult == ConvertGood) { + _privkey = bundle.privateKey(); + ret = true; + } + } break; + case keyTypePKCS8Inline: + { + PrivateKey k = + PrivateKey::fromDER(Base64().stringToArray(_entry.keyReference), passphrase, &cresult); + if (cresult == ConvertGood) { + _privkey = k; + ret = true; + } + } break; + case keyTypePKCS8FilePEM: + { + PrivateKey k = PrivateKey::fromPEMFile(_entry.keyReference, passphrase, &cresult); + if (cresult == ConvertGood) { + _privkey = k; + ret = true; + } + } break; + case keyTypePKCS8FileDER: + { + QFile file(_entry.keyReference); + if (file.open(QIODevice::ReadOnly)) { + const QByteArray contents = file.readAll(); + + PrivateKey k = PrivateKey::fromDER(contents, passphrase, &cresult); + if (cresult == ConvertGood) { + _privkey = k; + ret = true; + } + } + } break; + } + } + + if (_entry.unlockTimeout != -1) { + dueTime = QDateTime::currentDateTime().addSecs(_entry.unlockTimeout); + } + + cleanup1:; + } + + QCA_logTextMessage(QString::asprintf("softstorePKeyBase::_ensureAccess - return ret=%d", ret ? 1 : 0), + Logger::Debug); + + return ret; + } +}; + +class softstorePKeyContext : public PKeyContext +{ + Q_OBJECT + +private: + PKeyBase *_k; + +public: + softstorePKeyContext(Provider *p) + : PKeyContext(p) + { + _k = nullptr; + } + + ~softstorePKeyContext() override + { + delete _k; + _k = nullptr; + } + + Provider::Context *clone() const override + { + softstorePKeyContext *c = new softstorePKeyContext(*this); + c->_k = (PKeyBase *)_k->clone(); + return c; + } + +public: + QList supportedTypes() const override + { + QList list; + list += static_cast(_k)->_publicKey().type(); + return list; + } + + QList supportedIOTypes() const override + { + QList list; + list += static_cast(_k)->_publicKey().type(); + return list; + } + + QList supportedPBEAlgorithms() const override + { + QList list; + return list; + } + + PKeyBase *key() override + { + return _k; + } + + const PKeyBase *key() const override + { + return _k; + } + + void setKey(PKeyBase *key) override + { + delete _k; + _k = key; + } + + bool importKey(const PKeyBase *key) override + { + Q_UNUSED(key); + return false; + } + + static int passphrase_cb(char *buf, int size, int rwflag, void *u) + { + Q_UNUSED(buf); + Q_UNUSED(size); + Q_UNUSED(rwflag); + Q_UNUSED(u); + return 0; + } + + QByteArray publicToDER() const override + { + return static_cast(_k)->_publicKey().toDER(); + } + + QString publicToPEM() const override + { + return static_cast(_k)->_publicKey().toPEM(); + } + + ConvertResult publicFromDER(const QByteArray &in) override + { + Q_UNUSED(in); + return ErrorDecode; + } + + ConvertResult publicFromPEM(const QString &s) override + { + Q_UNUSED(s); + return ErrorDecode; + } + + SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + Q_UNUSED(passphrase); + Q_UNUSED(pbe); + return SecureArray(); + } + + QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override + { + Q_UNUSED(passphrase); + Q_UNUSED(pbe); + return QString(); + } + + ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override + { + Q_UNUSED(in); + Q_UNUSED(passphrase); + return ErrorDecode; + } + + ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override + { + Q_UNUSED(s); + Q_UNUSED(passphrase); + return ErrorDecode; + } +}; + +class softstoreKeyStoreEntryContext : public KeyStoreEntryContext +{ + Q_OBJECT +private: + KeyStoreEntry::Type _item_type; + KeyBundle _key; + SoftStoreEntry _entry; + QString _serialized; + +public: + softstoreKeyStoreEntryContext(const KeyBundle &key, + const SoftStoreEntry &entry, + const QString &serialized, + Provider *p) + : KeyStoreEntryContext(p) + { + _item_type = KeyStoreEntry::TypeKeyBundle; + _key = key; + _entry = entry; + _serialized = serialized; + } + + softstoreKeyStoreEntryContext(const softstoreKeyStoreEntryContext &from) + : KeyStoreEntryContext(from) + { + _item_type = from._item_type; + _key = from._key; + _entry = from._entry; + _serialized = from._serialized; + } + + Provider::Context *clone() const override + { + return new softstoreKeyStoreEntryContext(*this); + } + +public: + KeyStoreEntry::Type type() const override + { + return KeyStoreEntry::TypeKeyBundle; + } + + QString name() const override + { + return _entry.name; + } + + QString id() const override + { + return _entry.name; + } + + KeyBundle keyBundle() const override + { + return _key; + } + + Certificate certificate() const override + { + return _entry.chain.primary(); + } + + QString storeId() const override + { + return QString::asprintf("%s/%s", "qca-softstore", myPrintable(_entry.name)); + } + + QString storeName() const override + { + return _entry.name; + } + + bool ensureAccess() override + { + return static_cast(static_cast(_key.privateKey().context())->key()) + ->_ensureAccess(); + } + + QString serialize() const override + { + return _serialized; + } +}; + +class softstoreKeyStoreListContext : public KeyStoreListContext +{ + Q_OBJECT + +private: + int _last_id; + QList _entries; + +public: + softstoreKeyStoreListContext(Provider *p) + : KeyStoreListContext(p) + { + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::softstoreKeyStoreListContext - entry Provider=%p", + (void *)p), + Logger::Debug); + + _last_id = 0; + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::softstoreKeyStoreListContext - return"), + Logger::Debug); + } + + ~softstoreKeyStoreListContext() override + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - entry"), + Logger::Debug); + + s_keyStoreList = nullptr; + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - return"), + Logger::Debug); + } + + Provider::Context *clone() const override + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::clone - entry/return"), Logger::Debug); + return nullptr; + } + +public: + void start() override + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - entry"), Logger::Debug); + + QMetaObject::invokeMethod(this, "doReady", Qt::QueuedConnection); + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - return"), Logger::Debug); + } + + void setUpdatesEnabled(bool enabled) override + { + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::setUpdatesEnabled - entry/return enabled=%d", + enabled ? 1 : 0), + Logger::Debug); + } + + KeyStoreEntryContext *entry(int id, const QString &entryId) override + { + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entry - entry/return id=%d entryId='%s'", + id, + myPrintable(entryId)), + Logger::Debug); + + Q_UNUSED(id); + Q_UNUSED(entryId); + return nullptr; + } + + KeyStoreEntryContext *entryPassive(const QString &serialized) override + { + KeyStoreEntryContext *entry = nullptr; + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryPassive - entry serialized='%s'", + myPrintable(serialized)), + Logger::Debug); + + if (serialized.startsWith(QLatin1String("qca-softstore/"))) { + SoftStoreEntry sentry; + + if (_deserializeSoftStoreEntry(serialized, sentry)) { + entry = _keyStoreEntryBySoftStoreEntry(sentry); + } + } + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::entryPassive - return entry=%p", (void *)entry), + Logger::Debug); + + return entry; + } + + KeyStore::Type type(int id) const override + { + Q_UNUSED(id); + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::type - entry/return id=%d", id), + Logger::Debug); + + return KeyStore::User; + } + + QString storeId(int id) const override + { + QString ret; + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - entry id=%d", id), Logger::Debug); + + ret = QStringLiteral("qca-softstore"); + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - return ret=%s", myPrintable(ret)), + Logger::Debug); + + return ret; + } + + QString name(int id) const override + { + QString ret; + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - entry id=%d", id), Logger::Debug); + + ret = QStringLiteral("User Software Store"); + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - return ret=%s", myPrintable(ret)), + Logger::Debug); + + return ret; + } + + QList entryTypes(int id) const override + { + Q_UNUSED(id); + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryTypes - entry/return id=%d", id), + Logger::Debug); + + QList list; + list += KeyStoreEntry::TypeKeyBundle; + list += KeyStoreEntry::TypeCertificate; + return list; + } + + QList keyStores() override + { + QList list; + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::keyStores - entry"), Logger::Debug); + + list += _last_id; + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::keyStores - return out.size()=%d", int(list.size())), + Logger::Debug); + + return list; + } + + QList entryList(int id) override + { + QList list; + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryList - entry id=%d", id), + Logger::Debug); + + foreach (const SoftStoreEntry &e, _entries) { + list += _keyStoreEntryBySoftStoreEntry(e); + } + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::entryList - return out.size()=%d", int(list.size())), + Logger::Debug); + + return list; + } + + void _emit_diagnosticText(const QString &t) + { + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::_emit_diagnosticText - entry t='%s'", myPrintable(t)), + Logger::Debug); + + QCA_logTextMessage(t, Logger::Warning); + + emit diagnosticText(t); + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_emit_diagnosticText - return"), + Logger::Debug); + } + +private Q_SLOTS: + void doReady() + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - entry"), Logger::Debug); + + emit busyEnd(); + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - return"), Logger::Debug); + } + + void doUpdated() + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - entry"), Logger::Debug); + + emit updated(); + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - return"), Logger::Debug); + } + +public: + void _updateConfig(const QVariantMap &config, const int maxEntries) + { + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - entry"), Logger::Debug); + + QMap keyTypeMap; + keyTypeMap[QStringLiteral("pkcs12")] = keyTypePKCS12; + keyTypeMap[QStringLiteral("pkcs8")] = keyTypePKCS8Inline; + keyTypeMap[QStringLiteral("pkcs8-file-pem")] = keyTypePKCS8FilePEM; + keyTypeMap[QStringLiteral("pkcs8-file-der")] = keyTypePKCS8FileDER; + + QMap publicTypeMap; + publicTypeMap[QStringLiteral("x509chain")] = publicTypeX509Chain; + + _last_id++; + _entries.clear(); + + for (int i = 0; i < maxEntries; i++) { + if (config[QString::asprintf("entry_%02d_enabled", i)].toBool()) { + ConvertResult cresult; + SoftStoreEntry entry; + PublicType publicType = publicTypeInvalid; + + entry.name = config[QString::asprintf("entry_%02d_name", i)].toString(); + const QString stringReferenceType = config[QString::asprintf("entry_%02d_private_type", i)].toString(); + const QString stringPublicType = config[QString::asprintf("entry_%02d_public_type", i)].toString(); + entry.noPassphrase = config[QString::asprintf("entry_%02d_no_passphrase", i)].toBool(); + entry.unlockTimeout = config[QString::asprintf("entry_%02d_unlock_timeout", i)].toInt(); + + if (publicTypeMap.contains(stringPublicType)) { + publicType = publicTypeMap[stringPublicType]; + } else { + _emit_diagnosticText(QString::asprintf("Software Store: Bad public key type of '%s' entry.\n", + myPrintable(entry.name))); + goto cleanup1; + } + + if (keyTypeMap.contains(stringReferenceType)) { + entry.keyReferenceType = keyTypeMap[stringReferenceType]; + } else { + _emit_diagnosticText(QString::asprintf("Software Store: Bad private key type of '%s' entry.\n", + myPrintable(entry.name))); + goto cleanup1; + } + + entry.keyReference = config[QString::asprintf("entry_%02d_private", i)].toString(); + + switch (publicType) { + case publicTypeInvalid: + goto cleanup1; + break; + case publicTypeX509Chain: + const QStringList base64certs = + config[QString::asprintf("entry_%02d_public", i)].toString().split(QStringLiteral("!")); + + foreach (const QString &s, base64certs) { + entry.chain += Certificate::fromDER(Base64().stringToArray(s).toByteArray(), &cresult); + } + + if (cresult != ConvertGood) { + _emit_diagnosticText(QString::asprintf( + "Software Store: Cannot load certificate of '%s' entry.\n", myPrintable(entry.name))); + goto cleanup1; + } + break; + } + + _entries += entry; + + cleanup1:; // nothing to do for this entry. + } + } + + QMetaObject::invokeMethod(s_keyStoreList, "doUpdated", Qt::QueuedConnection); + + QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - return"), Logger::Debug); + } + +private: + QString _serializeSoftStoreEntry(const SoftStoreEntry &entry) const + { + QString serialized; + + QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - entry name=%s", + myPrintable(entry.name)), + Logger::Debug); + + serialized = QString::asprintf("qca-softstore/0/%s/%d/%s/%d/%d/x509chain/", + myPrintable(_escapeString(entry.name)), + entry.keyReferenceType, + myPrintable(_escapeString(entry.keyReference)), + entry.noPassphrase ? 1 : 0, + entry.unlockTimeout); + + QStringList list; + foreach (const Certificate &i, entry.chain) { + list += _escapeString(Base64().arrayToString(i.toDER())); + } + + serialized.append(list.join(QStringLiteral("/"))); + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - return serialized='%s'", + myPrintable(serialized)), + Logger::Debug); + + return serialized; + } + + bool _deserializeSoftStoreEntry(const QString &serialized, SoftStoreEntry &entry) const + { + bool ret = false; + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::_deserializeSoftStoreEntry - entry from='%s'", + myPrintable(serialized)), + Logger::Debug); + + entry = SoftStoreEntry(); + + const QStringList list = serialized.split(QStringLiteral("/")); + int n = 0; + + if (list.size() < 8) { + goto cleanup; + } + + if (list[n++] != QLatin1String("qca-softstore")) { + goto cleanup; + } + + if (list[n++].toInt() != 0) { + goto cleanup; + } + + entry.name = _unescapeString(list[n++]); + entry.keyReferenceType = (KeyType)list[n++].toInt(); + entry.keyReference = _unescapeString(list[n++]); + entry.noPassphrase = list[n++].toInt() != 0; + entry.unlockTimeout = list[n++].toInt(); + n++; // skip public key for now. + + while (n < list.size()) { + Certificate cert = Certificate::fromDER(Base64().stringToArray(_unescapeString(list[n++])).toByteArray()); + if (cert.isNull()) { + goto cleanup; + } + entry.chain += cert; + } + + ret = true; + + cleanup: + + QCA_logTextMessage( + QString::asprintf( + "softstoreKeyStoreListContext::_deserializeSoftStoreEntry - return ret=%d chain.size()=%d", + ret ? 1 : 0, + int(entry.chain.size())), + Logger::Debug); + + return ret; + } + + softstoreKeyStoreEntryContext *_keyStoreEntryBySoftStoreEntry(const SoftStoreEntry &sentry) const + { + softstoreKeyStoreEntryContext *entry = nullptr; + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - entry name=%s", + myPrintable(sentry.name)), + Logger::Debug); + + QString serialized = _serializeSoftStoreEntry(sentry); + + softstorePKeyBase *pkey = new softstorePKeyBase(sentry, serialized, provider()); + + softstorePKeyContext *pkc = new softstorePKeyContext(provider()); + pkc->setKey(pkey); + PrivateKey privkey; + privkey.change(pkc); + KeyBundle key; + key.setCertificateChainAndKey(sentry.chain, privkey); + + entry = new softstoreKeyStoreEntryContext(key, sentry, serialized, provider()); + + QCA_logTextMessage( + QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - return entry=%p", + (void *)entry), + Logger::Debug); + + return entry; + } + + QString _escapeString(const QString &from) const + { + QString to; + + foreach (const QChar &c, from) { + if (c == QLatin1Char('/') || c == QLatin1Char('\\')) { + to += QString::asprintf("\\x%04x", c.unicode()); + } else { + to += c; + } + } + + return to; + } + + QString _unescapeString(const QString &from) const + { + QString to; + + for (int i = 0; i < from.size(); i++) { + QChar c = from[i]; + + if (c == QLatin1Char('\\')) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + to += QChar((ushort)QStringView(from).mid(i + 2, 4).toInt(nullptr, 16)); +#else + to += QChar((ushort)from.midRef(i + 2, 4).toInt(nullptr, 16)); +#endif + i += 5; + } else { + to += c; + } + } + + return to; + } +}; + +} + +using namespace softstoreQCAPlugin; + +class softstoreProvider : public Provider +{ +private: + static const int _CONFIG_MAX_ENTRIES; + + QVariantMap _config; + +public: + softstoreProvider() + { + } + + ~softstoreProvider() override + { + } + +public: + int qcaVersion() const override + { + return QCA_VERSION; + } + + void init() override + { + } + + QString name() const override + { + return QStringLiteral("qca-softstore"); + } + + QStringList features() const override + { + QCA_logTextMessage(QStringLiteral("softstoreProvider::features - entry/return"), Logger::Debug); + + QStringList list; + list += QStringLiteral("pkey"); + list += QStringLiteral("keystorelist"); + return list; + } + + Context *createContext(const QString &type) override + { + Provider::Context *context = nullptr; + + QCA_logTextMessage(QString::asprintf("softstoreProvider::createContext - entry type='%s'", myPrintable(type)), + Logger::Debug); + + if (type == QLatin1String("keystorelist")) { + if (s_keyStoreList == nullptr) { + s_keyStoreList = new softstoreKeyStoreListContext(this); + s_keyStoreList->_updateConfig(_config, _CONFIG_MAX_ENTRIES); + } + context = s_keyStoreList; + } + + QCA_logTextMessage(QString::asprintf("softstoreProvider::createContext - return context=%p", (void *)context), + Logger::Debug); + + return context; + } + + QVariantMap defaultConfig() const override + { + QVariantMap mytemplate; + + QCA_logTextMessage(QStringLiteral("softstoreProvider::defaultConfig - entry/return"), Logger::Debug); + + mytemplate[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/qca-softstore#1.0"); + for (int i = 0; i < _CONFIG_MAX_ENTRIES; i++) { + mytemplate[QString::asprintf("entry_%02d_enabled", i)] = false; + mytemplate[QString::asprintf("entry_%02d_name", i)] = QLatin1String(""); + mytemplate[QString::asprintf("entry_%02d_public_type", i)] = QLatin1String(""); + mytemplate[QString::asprintf("entry_%02d_private_type", i)] = QLatin1String(""); + mytemplate[QString::asprintf("entry_%02d_public", i)] = QLatin1String(""); + mytemplate[QString::asprintf("entry_%02d_private", i)] = QLatin1String(""); + mytemplate[QString::asprintf("entry_%02d_unlock_timeout", i)] = -1; + mytemplate[QString::asprintf("entry_%02d_no_passphrase", i)] = false; + } + + return mytemplate; + } + + void configChanged(const QVariantMap &config) override + { + QCA_logTextMessage(QStringLiteral("softstoreProvider::configChanged - entry"), Logger::Debug); + + _config = config; + + if (s_keyStoreList != nullptr) { + s_keyStoreList->_updateConfig(_config, _CONFIG_MAX_ENTRIES); + } + + QCA_logTextMessage(QStringLiteral("softstoreProvider::configChanged - return"), Logger::Debug); + } +}; + +const int softstoreProvider::_CONFIG_MAX_ENTRIES = 50; + +class softstorePlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) + +public: + Provider *createProvider() override + { + return new softstoreProvider; + } +}; + +#include "qca-softstore.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-test/qca-test.cpp b/local/recipes/libs/qca/source/plugins/qca-test/qca-test.cpp new file mode 100644 index 0000000000..48b82d7c4d --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-test/qca-test.cpp @@ -0,0 +1,805 @@ +/* + * Copyright (C) 2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include + +using namespace QCA; + +static char cert_pem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIIBsTCCAVugAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRQwEgYDVQQDEwtUZXN0\n" + "IENlcnQgMTELMAkGA1UEBhMCVVMxEzARBgNVBAoTClRlc3QgT3JnIDEwHhcNMDcw\n" + "NjE5MjAzOTI4WhcNMTIwNjE5MjAzOTI4WjA4MRQwEgYDVQQDEwtUZXN0IENlcnQg\n" + "MTELMAkGA1UEBhMCVVMxEzARBgNVBAoTClRlc3QgT3JnIDEwXDANBgkqhkiG9w0B\n" + "AQEFAANLADBIAkEA3645RS/xBlWnjju6moaRYQuIDo7fwM+GxhE91HECLAg3Hnkr\n" + "I+qx96VXd006olOn8MrkbjSqcTJ4LcDaCGI1YwIDAQABo1AwTjAdBgNVHQ4EFgQU\n" + "nm5lNkkblHdoB0gLeh8mB6Ed+TMwDwYDVR0TAQH/BAUwAwIBADAcBgNVHREEFTAT\n" + "gRF0ZXN0MUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQUFAANBAFTtXtwfYcJZBsXJ\n" + "+Ckm9qbg7qR/XRERDzeR0yhHZE7F/jU5YQv7+iJL4l95iH9PkZNOk15Tu/Kzzekx\n" + "6CTXzKA=\n" + "-----END CERTIFICATE-----"; + +static char key_n_dec[] = + "1171510158037441543813157379806833168225785177834459013412026750" + "9262193808059395366696241600386200064326196137137376912654785051" + "560621331316573341676090723"; + +static char key_e_dec[] = "65537"; + +//---------------------------------------------------------------------------- +// TestProvider +//---------------------------------------------------------------------------- +class TestProvider : public Provider +{ +public: + TestProvider() + { + appendPluginDiagnosticText("TestProvider constructed\n"); + } + + void init() + { + appendPluginDiagnosticText("TestProvider initialized\n"); + } + + void deinit() + { + appendPluginDiagnosticText("TestProvider deinitialized\n"); + } + + ~TestProvider() + { + appendPluginDiagnosticText("TestProvider destructed\n"); + } + + int version() const + { + return 0x010203; // 1.2.3 + } + + int qcaVersion() const + { + return QCA_VERSION; + } + + QString name() const + { + return "qca-test"; + } + + QStringList features() const + { + QStringList list; + list += "keystorelist"; + return list; + } + + Context *createContext(const QString &type); +}; + +//---------------------------------------------------------------------------- +// TestData +//---------------------------------------------------------------------------- +class TestKeyStore +{ +public: + int contextId; + KeyStore::Type type; + QString storeId; + QString name; + bool readOnly; + bool avail; // for simplicity, all items share this global toggle + + QList certs; + + TestKeyStore() + : contextId(-1) + , type(KeyStore::SmartCard) + , readOnly(true) + , avail(true) + { + } +}; + +class TestData +{ +public: + int context_at; + QList stores; + + TestData() + : context_at(0) + { + } +}; + +//---------------------------------------------------------------------------- +// TestRSAContext +//---------------------------------------------------------------------------- +static KeyStoreEntry make_entry(Provider *p, TestKeyStore *store); + +class TestRSAContext : public RSAContext +{ + Q_OBJECT +public: + bool priv; + TestKeyStore *store; + + TestRSAContext(Provider *p) + : RSAContext(p) + , priv(true) + , store(0) + { + } + + TestRSAContext(const TestRSAContext &from) + : RSAContext(from) + , priv(from.priv) + , store(from.store) + { + } + + Context *clone() const + { + return new TestRSAContext(*this); + } + + virtual bool isNull() const + { + return false; + } + + virtual PKey::Type type() const + { + return PKey::RSA; + } + + virtual bool isPrivate() const + { + return priv; + } + + virtual bool canExport() const + { + return false; + } + + virtual void convertToPublic() + { + priv = false; + } + + virtual int bits() const + { + return 2048; + } + + virtual void startSign(SignatureAlgorithm alg, SignatureFormat format) + { + Q_UNUSED(alg); + Q_UNUSED(format); + } + + virtual void update(const MemoryRegion &in) + { + Q_UNUSED(in); + } + + virtual QByteArray endSign() + { + if (!store) + return QByteArray(); + + while (store->contextId == -1 || !store->avail) { + KeyStoreInfo info(store->type, store->storeId, store->name); + KeyStoreEntry entry = make_entry(provider(), store); + + TokenAsker asker; + asker.ask(info, entry, 0); + asker.waitForResponse(); + if (!asker.accepted()) + return QByteArray(); + } + + return "foobar"; + } + + virtual void createPrivate(int bits, int exp, bool block) + { + Q_UNUSED(bits); + Q_UNUSED(exp); + Q_UNUSED(block); + } + + virtual void createPrivate(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d) + { + Q_UNUSED(n); + Q_UNUSED(e); + Q_UNUSED(p); + Q_UNUSED(q); + Q_UNUSED(d); + } + + virtual void createPublic(const BigInteger &n, const BigInteger &e) + { + Q_UNUSED(n); + Q_UNUSED(e); + } + + virtual BigInteger n() const + { + return BigInteger(QString(key_n_dec)); + } + + virtual BigInteger e() const + { + return BigInteger(QString(key_e_dec)); + } + + virtual BigInteger p() const + { + return BigInteger(); + } + + virtual BigInteger q() const + { + return BigInteger(); + } + + virtual BigInteger d() const + { + return BigInteger(); + } +}; + +//---------------------------------------------------------------------------- +// TestPKeyContext +//---------------------------------------------------------------------------- +class TestPKeyContext : public PKeyContext +{ + Q_OBJECT +public: + TestRSAContext *_key; + + TestPKeyContext(Provider *p) + : PKeyContext(p) + , _key(0) + { + } + + TestPKeyContext(const TestPKeyContext &from) + : PKeyContext(from) + , _key(0) + { + if (from._key) + _key = (TestRSAContext *)from._key->clone(); + } + + ~TestPKeyContext() + { + delete _key; + } + + Context *clone() const + { + return new TestPKeyContext(*this); + } + + virtual QList supportedTypes() const + { + QList list; + list += PKey::RSA; + return list; + } + + virtual QList supportedIOTypes() const + { + return QList(); + } + + virtual QList supportedPBEAlgorithms() const + { + return QList(); + } + + virtual PKeyBase *key() + { + return _key; + } + + virtual const PKeyBase *key() const + { + return _key; + } + + virtual void setKey(PKeyBase *key) + { + delete _key; + _key = (TestRSAContext *)key; + } + + virtual bool importKey(const PKeyBase *key) + { + Q_UNUSED(key); + return false; + } +}; + +//---------------------------------------------------------------------------- +// TestCertContext +//---------------------------------------------------------------------------- +class TestCertContext : public CertContext +{ + Q_OBJECT +public: + CertContextProps _props; + + TestCertContext(Provider *p) + : CertContext(p) + { + } + + Context *clone() const + { + return new TestCertContext(*this); + } + + virtual QByteArray toDER() const + { + QStringList lines = toPEM().split('\n'); + lines.removeFirst(); + lines.removeLast(); + QString enc = lines.join(""); + return Base64().stringToArray(enc).toByteArray(); + } + + virtual QString toPEM() const + { + return QString(cert_pem); + } + + virtual ConvertResult fromDER(const QByteArray &a) + { + Q_UNUSED(a); + return ErrorDecode; + } + + virtual ConvertResult fromPEM(const QString &s) + { + Q_UNUSED(s); + return ErrorDecode; + } + + virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv) + { + Q_UNUSED(opts); + Q_UNUSED(priv); + return false; + } + + virtual const CertContextProps *props() const + { + return &_props; + } + + virtual bool compare(const CertContext *other) const + { + Q_UNUSED(other); + return false; + } + + virtual PKeyContext *subjectPublicKey() const + { + TestRSAContext *rsa1 = new TestRSAContext(provider()); + rsa1->priv = false; + TestPKeyContext *kc1 = new TestPKeyContext(provider()); + kc1->setKey(rsa1); + return kc1; + } + + virtual bool isIssuerOf(const CertContext *other) const + { + Q_UNUSED(other); + return false; + } + + virtual Validity validate(const QList &trusted, + const QList &untrusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const + { + Q_UNUSED(trusted); + Q_UNUSED(untrusted); + Q_UNUSED(crls); + Q_UNUSED(u); + Q_UNUSED(vf); + return ErrorValidityUnknown; + } + + virtual Validity validate_chain(const QList &chain, + const QList &trusted, + const QList &crls, + UsageMode u, + ValidateFlags vf) const + { + Q_UNUSED(chain); + Q_UNUSED(trusted); + Q_UNUSED(crls); + Q_UNUSED(u); + Q_UNUSED(vf); + return ErrorValidityUnknown; + } +}; + +//---------------------------------------------------------------------------- +// TestKeyStoreEntryContext +//---------------------------------------------------------------------------- +class TestKeyStoreEntryContext : public KeyStoreEntryContext +{ + Q_OBJECT +public: + QString _id, _name, _storeId, _storeName; + KeyBundle kb; + TestKeyStore *store; + + TestKeyStoreEntryContext(Provider *p) + : KeyStoreEntryContext(p) + { + } + + virtual Context *clone() const + { + return new TestKeyStoreEntryContext(*this); + } + + virtual KeyStoreEntry::Type type() const + { + return KeyStoreEntry::TypeKeyBundle; + } + + virtual QString id() const + { + return _id; + } + + virtual QString name() const + { + return _name; + } + + virtual QString storeId() const + { + return _storeId; + } + + virtual QString storeName() const + { + return _storeName; + } + + virtual bool isAvailable() const + { + return store->avail; + } + + virtual QString serialize() const + { + return QString("qca-test-1/fake_serialized"); + } + + virtual KeyBundle keyBundle() const + { + return kb; + } + + virtual bool ensureAccess() + { + return true; + } +}; + +KeyStoreEntry make_entry(Provider *p, TestKeyStore *store) +{ + KeyStoreEntry entry; + TestKeyStoreEntryContext *kse = new TestKeyStoreEntryContext(p); + kse->_id = QString::number(0); + kse->_name = store->certs[0].certificateChain().primary().commonName(); + kse->_storeId = store->storeId; + kse->_storeName = store->name; + kse->kb = store->certs[0]; + kse->store = store; + entry.change(kse); + return entry; +} + +//---------------------------------------------------------------------------- +// TestKeyStoreListContext +//---------------------------------------------------------------------------- +class TestKeyStoreListContext : public KeyStoreListContext +{ + Q_OBJECT +public: + TestData data; + int step; + QTimer t; + bool first; + int next_id; + + TestKeyStoreListContext(Provider *p) + : KeyStoreListContext(p) + , t(this) + { + step = 0; + next_id = 1; + + KeyBundle cert1; + Certificate pub1; + TestCertContext *cc1 = new TestCertContext(provider()); + cc1->_props.subject += CertificateInfoPair(CertificateInfoType(CommonName), "Test Cert 1"); + pub1.change(cc1); + PrivateKey sec1; + TestRSAContext *rsa1 = new TestRSAContext(provider()); + TestPKeyContext *kc1 = new TestPKeyContext(provider()); + kc1->setKey(rsa1); + sec1.change(kc1); + cert1.setCertificateChainAndKey(pub1, sec1); + + TestKeyStore ks1; + ks1.storeId = "store1"; + ks1.name = "Test Store 1"; + ks1.certs += cert1; + ks1.avail = false; + data.stores += ks1; + + TestKeyStore ks2; + ks2.storeId = "store2"; + ks2.name = "Test Store 2"; + ks2.readOnly = false; + data.stores += ks2; + + rsa1->store = &data.stores[0]; + + connect(&t, SIGNAL(timeout()), SLOT(do_step())); + } + + int findStore(int contextId) const + { + for (int n = 0; n < data.stores.count(); ++n) { + if (data.stores[n].contextId == contextId) + return n; + } + return -1; + } + + virtual Context *clone() const + { + return 0; + } + + virtual void start() + { + first = true; + emit diagnosticText("qca-test: TestKeyStoreListContext started\n"); + t.start(2000); + } + + virtual void setUpdatesEnabled(bool enabled) + { + Q_UNUSED(enabled); + } + + virtual QList keyStores() + { + QList list; + for (int n = 0; n < data.stores.count(); ++n) { + int id = data.stores[n].contextId; + if (id != -1) + list += id; + } + return list; + } + + virtual KeyStore::Type type(int id) const + { + int at = findStore(id); + if (at == -1) + return KeyStore::SmartCard; + return data.stores[at].type; + } + + virtual QString storeId(int id) const + { + int at = findStore(id); + if (at == -1) + return QString(); + return data.stores[at].storeId; + } + + virtual QString name(int id) const + { + int at = findStore(id); + if (at == -1) + return QString(); + return data.stores[at].name; + } + + virtual bool isReadOnly(int id) const + { + int at = findStore(id); + if (at == -1) + return true; + return data.stores[at].readOnly; + } + + virtual QList entryTypes(int id) const + { + Q_UNUSED(id); + QList list; + list += KeyStoreEntry::TypeKeyBundle; + return list; + } + + virtual QList entryList(int id) + { + QList out; + int at = findStore(id); + if (at == -1) + return out; + TestKeyStore &store = data.stores[at]; + for (int n = 0; n < store.certs.count(); ++n) { + TestKeyStoreEntryContext *kse = new TestKeyStoreEntryContext(provider()); + kse->_id = QString::number(n); + kse->_name = store.certs[n].certificateChain().primary().commonName(); + kse->_storeId = store.storeId; + kse->_storeName = store.name; + kse->kb = store.certs[n]; + kse->store = &store; + out += kse; + } + return out; + } + + virtual KeyStoreEntryContext *entryPassive(const QString &serialized) + { + if (serialized == "qca-test-1/fake_serialized") { + TestKeyStore &store = data.stores[0]; + TestKeyStoreEntryContext *kse = new TestKeyStoreEntryContext(provider()); + kse->_id = QString::number(0); + kse->_name = store.certs[0].certificateChain().primary().commonName(); + kse->_storeId = store.storeId; + kse->_storeName = store.name; + kse->kb = store.certs[0]; + kse->store = &store; + return kse; + } else + return 0; + } + + virtual QString writeEntry(int id, const KeyBundle &kb) + { + int at = findStore(id); + if (at == -1) + return QString(); + if (data.stores[at].readOnly) + return QString(); + data.stores[at].certs += kb; + return QString::number(data.stores[at].certs.count() - 1); + } + + virtual bool removeEntry(int id, const QString &entryId) + { + int at = findStore(id); + if (at == -1) + return false; + if (data.stores[at].readOnly) + return false; + int index = entryId.toInt(); + if (index < 0 || index >= data.stores[at].certs.count()) + return false; + data.stores[at].certs.removeAt(index); + return true; + } + +private Q_SLOTS: + void do_step() + { + emit diagnosticText(QString("qca-test: TestKeyStoreListContext do_step %1\n").arg(step)); + + if (step == 0) { + // make first store available + data.stores[0].contextId = next_id++; + if (first) { + first = false; + emit busyEnd(); + } else + emit updated(); + } else if (step == 1) { + // make second store available + data.stores[1].contextId = next_id++; + emit updated(); + } else if (step == 2) { + // make items in the first store available + data.stores[0].avail = true; + emit storeUpdated(data.stores[0].contextId); + } else if (step == 3) { + // make the first store unavailable + data.stores[0].contextId = -1; + emit updated(); + } else if (step == 4) { + // make the first store available + data.stores[0].contextId = next_id++; + emit updated(); + } else if (step == 5) { + // make the second store unavailable + data.stores[1].contextId = -1; + emit updated(); + } else if (step == 6) { + // make the first store unavailable + data.stores[0].contextId = -1; + emit updated(); + } else if (step == 7) { + // do it all over again in 10 seconds + // (2 seconds before, 6 seconds here, 2 seconds after) + t.start(6000); + } else { + step = 0; + data.stores[0].avail = false; + + // set interval to 2 seconds + t.start(2000); + return; + } + + ++step; + } +}; + +//---------------------------------------------------------------------------- +// TestProvider +//---------------------------------------------------------------------------- +Provider::Context *TestProvider::createContext(const QString &type) +{ + if (type == "keystorelist") + return new TestKeyStoreListContext(this); + else + return 0; +} + +//---------------------------------------------------------------------------- +// TestPlugin +//---------------------------------------------------------------------------- +class TestPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) +public: + virtual Provider *createProvider() + { + return new TestProvider; + } +}; + +#include "qca-test.moc" diff --git a/local/recipes/libs/qca/source/plugins/qca-wincrypto/CMakeLists.txt b/local/recipes/libs/qca/source/plugins/qca-wincrypto/CMakeLists.txt new file mode 100644 index 0000000000..af159005c6 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wincrypto/CMakeLists.txt @@ -0,0 +1,17 @@ +# QCA WinCrypto + +IF (WIN32) + SET (QCA_WINCRYPTO_SOURCES qca-wincrypto.cpp) + + ADD_LIBRARY (qca-wincrypto MODULE ${QCA_WINCRYPTO_SOURCES}) + # use win32 includes + target_link_libraries(qca-wincrypto Qt${QT_MAJOR_VERSION}::Core) + TARGET_LINK_LIBRARIES (qca-wincrypto ${QCA_LIB_NAME}) + TARGET_LINK_LIBRARIES (qca-wincrypto advapi32) + + INSTALL (TARGETS qca-wincrypto + LIBRARY DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_CRYPTO_INSTALL_DIR}" + ) +ENDIF (WIN32) diff --git a/local/recipes/libs/qca/source/plugins/qca-wincrypto/COPYING b/local/recipes/libs/qca/source/plugins/qca-wincrypto/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wincrypto/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-wincrypto/README b/local/recipes/libs/qca/source/plugins/qca-wincrypto/README new file mode 100644 index 0000000000..d046609565 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wincrypto/README @@ -0,0 +1,25 @@ +QCA Windows Cryptography plugin +------------------------------- +Date: June 11th, 2008 +Website: http://delta.affinix.com/qca/ +Mailing List: Delta Project + +Author: Michael Leupold + +This plugin might at some point provide the means to support the +Windows Cryptographic API. Currently it only supports generating +random numbers using the CryptGenRandom call. + +This plugin should load on any version of Windows, but it will +only generate random numbers on Windows 2000 or later. + +Installing +---------- + +For Windows: + + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + diff --git a/local/recipes/libs/qca/source/plugins/qca-wincrypto/qca-wincrypto.cpp b/local/recipes/libs/qca/source/plugins/qca-wincrypto/qca-wincrypto.cpp new file mode 100644 index 0000000000..3604385693 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wincrypto/qca-wincrypto.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008 Michael Leupold + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include +#include + +#include + +#ifdef Q_OS_WIN32 + +#include + +//----------------------------------------------------------- +class WinCryptoRandomContext : public QCA::RandomContext +{ +public: + WinCryptoRandomContext(QCA::Provider *p) + : RandomContext(p) + { + } + + Context *clone() const + { + return new WinCryptoRandomContext(*this); + } + + QCA::SecureArray nextBytes(int size) + { + QCA::SecureArray buf(size); + HCRYPTPROV hProv; + + /* FIXME: currently loop while there's an error. */ + while (true) { + // acquire the crypto context + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + continue; + + if (CryptGenRandom(hProv, static_cast(size), (BYTE *)buf.data())) { + break; + } + } + + // release the crypto context + CryptReleaseContext(hProv, 0); + + return buf; + } +}; + +//----------------------------------------------------------- +class WinCryptoProvider : public QCA::Provider +{ +public: + void init() + { + } + + ~WinCryptoProvider() + { + } + + int qcaVersion() const + { + return QCA_VERSION; + } + + QString name() const + { + return "qca-wincrypto"; + } + + QStringList features() const + { + QStringList list; + list += "random"; + return list; + } + + Context *createContext(const QString &type) + { + if (type == "random") + return new WinCryptoRandomContext(this); + else + return 0; + } +}; + +//----------------------------------------------------------- +class WinCryptoPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) + +public: + virtual QCA::Provider *createProvider() + { + return new WinCryptoProvider; + } +}; + +Q_EXPORT_PLUGIN2(qca_wincrypto, WinCryptoPlugin); + +#endif // Q_OS_WIN32 diff --git a/local/recipes/libs/qca/source/plugins/qca-wingss/COPYING b/local/recipes/libs/qca/source/plugins/qca-wingss/COPYING new file mode 100644 index 0000000000..b1e3f5a263 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wingss/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/qca/source/plugins/qca-wingss/README b/local/recipes/libs/qca/source/plugins/qca-wingss/README new file mode 100644 index 0000000000..0f33f6a013 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wingss/README @@ -0,0 +1,27 @@ +QCA Windows GSS plugin version 2.0.0 +------------------------------------ +Date: May 29th, 2008 +Website: http://delta.affinix.com/qca/ +Mailing List: Delta Project + +Author: Justin Karneges + +This plugin provides SASL (GSSAPI mechanism only) using the native Windows +Security Support Provider Interface (SSPI) for Kerberos. Basically what this +means is that if your Windows computer authenticates against a domain, then +you can access capable SASL servers on that domain without a password. + +This plugin will safely load on any version of Windows, but it will only +perform its function if the Kerberos SSPI feature is present (available in +Windows 2000 or later). + +Installing +---------- + +For Windows: + + configwin rd + qmake + nmake (or make) + copy lib\*.dll qtdir\plugins\crypto + diff --git a/local/recipes/libs/qca/source/plugins/qca-wingss/qca-wingss.cpp b/local/recipes/libs/qca/source/plugins/qca-wingss/qca-wingss.cpp new file mode 100644 index 0000000000..7274f89da6 --- /dev/null +++ b/local/recipes/libs/qca/source/plugins/qca-wingss/qca-wingss.cpp @@ -0,0 +1,2112 @@ +/* + * Copyright (C) 2008 Barracuda Networks, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#ifndef FORWARD_ONLY +#include +#define SECURITY_WIN32 +#include +#endif + +using namespace QCA; + +#define PROVIDER_NAME "qca-wingss" + +#if !defined(FORWARD_ONLY) + +// some defs possibly missing from MinGW + +#ifndef SEC_E_MESSAGE_ALTERED +#define SEC_E_MESSAGE_ALTERED 0x8009030F +#endif + +#ifndef SEC_E_CONTEXT_EXPIRED +#define SEC_E_CONTEXT_EXPIRED 0x80090317 +#endif + +#ifndef SEC_E_CRYPTO_SYSTEM_INVALID +#define SEC_E_CRYPTO_SYSTEM_INVALID 0x80090337 +#endif + +#ifndef SEC_E_OUT_OF_SEQUENCE +#define SEC_E_OUT_OF_SEQUENCE 0x80090310 +#endif + +#ifndef SEC_E_BUFFER_TOO_SMALL +#define SEC_E_BUFFER_TOO_SMALL 0x80090321 +#endif + +#ifndef SECURITY_ENTRYPOINTW +#define SECURITY_ENTRYPOINTW TEXT("InitSecurityInterfaceW") +#endif + +#ifndef SECURITY_ENTRYPOINT_ANSIA +#define SECURITY_ENTRYPOINT_ANSIA "InitSecurityInterfaceA" +#endif + +#ifndef SECPKG_FLAG_GSS_COMPATIBLE +#define SECPKG_FLAG_GSS_COMPATIBLE 0x00001000 +#endif + +#ifndef SECQOP_WRAP_NO_ENCRYPT +#define SECQOP_WRAP_NO_ENCRYPT 0x80000001 +#endif + +#ifndef ISC_RET_MUTUAL_AUTH +#define ISC_RET_MUTUAL_AUTH 0x00000002 +#endif + +#ifndef ISC_RET_SEQUENCE_DETECT +#define ISC_RET_SEQUENCE_DETECT 0x00000008 +#endif + +#ifndef ISC_RET_CONFIDENTIALITY +#define ISC_RET_CONFIDENTIALITY 0x00000010 +#endif + +#ifndef ISC_RET_INTEGRITY +#define ISC_RET_INTEGRITY 0x00010000 +#endif + +#ifdef Q_CC_MINGW + +// for some reason, the MinGW definition of the W table has A functions in +// it, so we define a fixed version to use instead... + +typedef struct _FIXED_SECURITY_FUNCTION_TABLEW +{ + unsigned long dwVersion; + ENUMERATE_SECURITY_PACKAGES_FN_W EnumerateSecurityPackagesW; + QUERY_CREDENTIALS_ATTRIBUTES_FN_W QueryCredentialsAttributesW; + ACQUIRE_CREDENTIALS_HANDLE_FN_W AcquireCredentialsHandleW; + FREE_CREDENTIALS_HANDLE_FN FreeCredentialsHandle; + void SEC_FAR *Reserved2; + INITIALIZE_SECURITY_CONTEXT_FN_W InitializeSecurityContextW; + ACCEPT_SECURITY_CONTEXT_FN AcceptSecurityContext; + COMPLETE_AUTH_TOKEN_FN CompleteAuthToken; + DELETE_SECURITY_CONTEXT_FN DeleteSecurityContext; + APPLY_CONTROL_TOKEN_FN_W ApplyControlTokenW; + QUERY_CONTEXT_ATTRIBUTES_FN_W QueryContextAttributesW; + IMPERSONATE_SECURITY_CONTEXT_FN ImpersonateSecurityContext; + REVERT_SECURITY_CONTEXT_FN RevertSecurityContext; + MAKE_SIGNATURE_FN MakeSignature; + VERIFY_SIGNATURE_FN VerifySignature; + FREE_CONTEXT_BUFFER_FN FreeContextBuffer; + QUERY_SECURITY_PACKAGE_INFO_FN_W QuerySecurityPackageInfoW; + void SEC_FAR *Reserved3; + void SEC_FAR *Reserved4; + void SEC_FAR *Unknown1; + void SEC_FAR *Unknown2; + void SEC_FAR *Unknown3; + void SEC_FAR *Unknown4; + void SEC_FAR *Unknown5; + ENCRYPT_MESSAGE_FN EncryptMessage; + DECRYPT_MESSAGE_FN DecryptMessage; +} FixedSecurityFunctionTableW, *PFixedSecurityFunctionTableW; + +typedef FixedSecurityFunctionTableW MySecurityFunctionTableW; +typedef PFixedSecurityFunctionTableW PMySecurityFunctionTableW; + +#else + +typedef SecurityFunctionTableW MySecurityFunctionTableW; +typedef PSecurityFunctionTableW PMySecurityFunctionTableW; + +#endif + +#ifdef UNICODE +#define MySecurityFunctionTable MySecurityFunctionTableW +#define PMySecurityFunctionTable PMySecurityFunctionTableW +#else +#define MySecurityFunctionTable MySecurityFunctionTableA +#define PMySecurityFunctionTable PMySecurityFunctionTableA +#endif + +#endif // !defined(FORWARD_ONLY) + +namespace wingssQCAPlugin { + +//---------------------------------------------------------------------------- +// SSPI helper API +//---------------------------------------------------------------------------- + +typedef void (*sspi_logger_func)(const QString &str); + +class SspiPackage +{ +public: + QString name; + quint32 caps; + quint32 maxtok; + quint16 version; + quint16 rpcid; + QString comment; +}; + +// logger can be set even when sspi is not loaded (this is needed so logging +// during sspi_load/unload can be captured). pass 0 to disable. +void sspi_set_logger(sspi_logger_func p); + +void sspi_log(const QString &str); + +bool sspi_load(); +void sspi_unload(); + +// returns the available security packages. only the first call actually +// queries the sspi subsystem. subsequent calls return a cached result. +QList sspi_get_packagelist(); + +// refresh the package list cache. call sspi_get_packagelist afterwards to +// get the new list. +void sspi_refresh_packagelist(); + +// helper functions for logging +QString SECURITY_STATUS_toString(SECURITY_STATUS i); +QString ptr_toString(const void *p); + +//---------------------------------------------------------------------------- +// SSPI helper implementation +//---------------------------------------------------------------------------- + +Q_GLOBAL_STATIC(QMutex, sspi_mutex) +Q_GLOBAL_STATIC(QMutex, sspi_logger_mutex) + +union SecurityFunctionTableUnion { + PMySecurityFunctionTableW W; + PSecurityFunctionTableA A; + void *ptr; +}; + +static QLibrary *sspi_lib = 0; +static SecurityFunctionTableUnion sspi; +static sspi_logger_func sspi_logger; +static QList *sspi_packagelist = 0; + +void sspi_log(const QString &str) +{ + QMutexLocker locker(sspi_logger_mutex()); + + if (sspi_logger) + sspi_logger(str); +} + +void sspi_set_logger(sspi_logger_func p) +{ + QMutexLocker locker(sspi_logger_mutex()); + + sspi_logger = p; +} + +#define CASE_SS_STRING(s) \ + case s: \ + return #s; + +static const char *SECURITY_STATUS_lookup(SECURITY_STATUS i) +{ + switch (i) { + CASE_SS_STRING(SEC_E_OK); + CASE_SS_STRING(SEC_I_COMPLETE_AND_CONTINUE); + CASE_SS_STRING(SEC_I_COMPLETE_NEEDED); + CASE_SS_STRING(SEC_I_CONTINUE_NEEDED); + CASE_SS_STRING(SEC_I_INCOMPLETE_CREDENTIALS); + CASE_SS_STRING(SEC_E_UNSUPPORTED_FUNCTION); + CASE_SS_STRING(SEC_E_INVALID_TOKEN); + CASE_SS_STRING(SEC_E_MESSAGE_ALTERED); + CASE_SS_STRING(SEC_E_INSUFFICIENT_MEMORY); + CASE_SS_STRING(SEC_E_INTERNAL_ERROR); + CASE_SS_STRING(SEC_E_INVALID_HANDLE); + CASE_SS_STRING(SEC_E_LOGON_DENIED); + CASE_SS_STRING(SEC_E_NO_AUTHENTICATING_AUTHORITY); + CASE_SS_STRING(SEC_E_NO_CREDENTIALS); + CASE_SS_STRING(SEC_E_TARGET_UNKNOWN); + CASE_SS_STRING(SEC_E_WRONG_PRINCIPAL); + CASE_SS_STRING(SEC_E_BUFFER_TOO_SMALL); + CASE_SS_STRING(SEC_E_CONTEXT_EXPIRED); + CASE_SS_STRING(SEC_E_CRYPTO_SYSTEM_INVALID); + CASE_SS_STRING(SEC_E_QOP_NOT_SUPPORTED); + CASE_SS_STRING(SEC_E_INCOMPLETE_MESSAGE); + CASE_SS_STRING(SEC_E_OUT_OF_SEQUENCE); + default: + break; + } + return 0; +} + +QString SECURITY_STATUS_toString(SECURITY_STATUS i) +{ + const char *str = SECURITY_STATUS_lookup(i); + if (str) + return QString(str); + else + return QString::number(i); +} + +QString ptr_toString(const void *p) +{ + return QString().sprintf("%p", p); +} + +bool sspi_load() +{ + QMutexLocker locker(sspi_mutex()); + if (sspi_lib) + return true; + + sspi_lib = new QLibrary("secur32"); + if (!sspi_lib->load()) { + delete sspi_lib; + sspi_lib = 0; + return false; + } + + union { + INIT_SECURITY_INTERFACE_W W; + INIT_SECURITY_INTERFACE_A A; + void *ptr; + } pInitSecurityInterface; + pInitSecurityInterface.ptr = 0; + + QString securityEntrypoint; + securityEntrypoint = QString::fromUtf16((const ushort *)SECURITY_ENTRYPOINTW); + pInitSecurityInterface.W = (INIT_SECURITY_INTERFACE_W)(sspi_lib->resolve(securityEntrypoint.toLatin1().data())); + if (!pInitSecurityInterface.ptr) { + sspi_lib->unload(); + delete sspi_lib; + sspi_lib = 0; + return false; + } + + union { + PMySecurityFunctionTableW W; + PSecurityFunctionTableA A; + void *ptr; + } funcs; + funcs.ptr = 0; + + funcs.W = (PMySecurityFunctionTableW)pInitSecurityInterface.W(); + + sspi_log(QString("%1() = %2\n").arg(securityEntrypoint, ptr_toString(funcs.ptr))); + if (!funcs.ptr) { + sspi_lib->unload(); + delete sspi_lib; + sspi_lib = 0; + return false; + } + + sspi.W = funcs.W; + + return true; +} + +void sspi_unload() +{ + QMutexLocker locker(sspi_mutex()); + + sspi_lib->unload(); + delete sspi_lib; + sspi_lib = 0; + sspi.ptr = 0; +} + +static QList sspi_get_packagelist_direct() +{ + QList out; + + ULONG cPackages; + SecPkgInfoW *pPackageInfo; + SECURITY_STATUS ret = sspi.W->EnumerateSecurityPackagesW(&cPackages, &pPackageInfo); + sspi_log(QString("EnumerateSecurityPackages() = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret != SEC_E_OK) + return out; + + for (int n = 0; n < (int)cPackages; ++n) { + SecPkgInfoW *p = &pPackageInfo[n]; + SspiPackage i; + i.name = QString::fromUtf16((const ushort *)p->Name); + i.caps = p->fCapabilities; + i.version = p->wVersion; + i.rpcid = p->wRPCID; + i.maxtok = p->cbMaxToken; + i.comment = QString::fromUtf16((const ushort *)p->Comment); + out += i; + } + + ret = sspi.W->FreeContextBuffer(&pPackageInfo); + sspi_log(QString("FreeContextBuffer() = %1\n").arg(SECURITY_STATUS_toString(ret))); + + return out; +} + +static void sspi_refresh_packagelist_internal() +{ + if (sspi_packagelist) + *sspi_packagelist = sspi_get_packagelist_direct(); + else + sspi_packagelist = new QList(sspi_get_packagelist_direct()); +} + +QList sspi_get_packagelist() +{ + QMutexLocker locker(sspi_mutex()); + + if (!sspi_packagelist) + sspi_refresh_packagelist_internal(); + return *sspi_packagelist; +} + +void sspi_refresh_packagelist() +{ + QMutexLocker locker(sspi_mutex()); + + sspi_refresh_packagelist_internal(); +} + +template inline T cap_to_int(const T &t) +{ + if (sizeof(int) <= sizeof(T)) + return (int)((t > INT_MAX) ? INT_MAX : t); + else + return (int)t; +} + +//---------------------------------------------------------------------------- +// KerberosSession +//---------------------------------------------------------------------------- +// this class thinly wraps SSPI to perform kerberos. +class KerberosSession +{ +public: + enum ReturnCode + { + Success, + NeedMoreData, // for decrypt + ErrorInvalidSystem, + ErrorKerberosNotFound, + ErrorAcquireCredentials, + ErrorInitialize, + ErrorQueryContext, + ErrorEncrypt, + ErrorDecrypt + }; + + SECURITY_STATUS lastErrorCode; + + quint32 maxtok; + + bool initialized; + bool first_step; + QByteArray first_out_token; + bool authed; + + QString spn; + + CredHandle user_cred; + TimeStamp user_cred_expiry; + + CtxtHandle ctx; + ULONG ctx_attr_req; + ULONG ctx_attr; + bool have_sizes; + SecPkgContext_Sizes ctx_sizes; + SecPkgContext_StreamSizes ctx_streamSizes; + + KerberosSession() + : initialized(false) + , have_sizes(false) + { + } + + ~KerberosSession() + { + if (initialized) { + SECURITY_STATUS ret = sspi.W->DeleteSecurityContext(&ctx); + sspi_log(QString("DeleteSecurityContext() = %1\n").arg(SECURITY_STATUS_toString(ret))); + + ret = sspi.W->FreeCredentialsHandle(&user_cred); + sspi_log(QString("FreeCredentialsHandle() = %1\n").arg(SECURITY_STATUS_toString(ret))); + } + } + + ReturnCode init(const QString &_spn) + { + // ensure kerberos is available + bool found = false; + quint32 _maxtok = 0; + QList packages = sspi_get_packagelist(); + sspi_log("SSPI packages:\n"); + foreach (const SspiPackage &p, packages) { + bool gss = false; + if (p.caps & SECPKG_FLAG_GSS_COMPATIBLE) + gss = true; + + if (p.name == "Kerberos" && gss) { + found = true; + _maxtok = p.maxtok; + } + + QString gssstr = gss ? "yes" : "no"; + sspi_log(QString(" %1 (gss=%2, maxtok=%3)\n").arg(p.name, gssstr, QString::number(p.maxtok))); + } + + if (!found) + return ErrorKerberosNotFound; + + // get the logged-in user's credentials + SECURITY_STATUS ret = sspi.W->AcquireCredentialsHandleW((SEC_WCHAR *)0, // we want creds of logged-in user + (SEC_WCHAR *)QString("Kerberos").utf16(), + SECPKG_CRED_OUTBOUND, + 0, // don't need a LUID + 0, // default credentials for kerberos + 0, // not used + 0, // not used + &user_cred, + &user_cred_expiry); + sspi_log(QString("AcquireCredentialsHandle() = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret != SEC_E_OK) { + lastErrorCode = ret; + return ErrorAcquireCredentials; + } + + maxtok = _maxtok; + authed = false; + spn = _spn; + + SecBuffer outbuf; + outbuf.BufferType = SECBUFFER_TOKEN; + outbuf.cbBuffer = 0; + outbuf.pvBuffer = NULL; + + SecBufferDesc outbufdesc; + outbufdesc.ulVersion = SECBUFFER_VERSION; + outbufdesc.cBuffers = 1; + outbufdesc.pBuffers = &outbuf; + + ctx_attr_req = 0; + + // not strictly required, but some SSPI calls seem to always + // allocate memory, so for consistency we'll explicity + // request to have it that way all the time + ctx_attr_req |= ISC_REQ_ALLOCATE_MEMORY; + + // required by SASL GSSAPI RFC + ctx_attr_req |= ISC_REQ_INTEGRITY; + + // required for security layer + ctx_attr_req |= ISC_REQ_MUTUAL_AUTH; + ctx_attr_req |= ISC_REQ_SEQUENCE_DETECT; + + // required for encryption + ctx_attr_req |= ISC_REQ_CONFIDENTIALITY; + + // other options that may be of use, but we currently aren't + // using: + // ISC_REQ_DELEGATE + // ISC_REQ_REPLAY_DETECT + + ret = sspi.W->InitializeSecurityContextW(&user_cred, + 0, // NULL for the first call + (SEC_WCHAR *)spn.utf16(), + ctx_attr_req, + 0, + SECURITY_NETWORK_DREP, + 0, // NULL for first call + 0, + &ctx, + &outbufdesc, + &ctx_attr, + 0); // don't care about expiration + sspi_log(QString("InitializeSecurityContext(*, 0, ...) = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) { + if (outbuf.pvBuffer) { + first_out_token.resize(outbuf.cbBuffer); + memcpy(first_out_token.data(), outbuf.pvBuffer, outbuf.cbBuffer); + + SECURITY_STATUS fret = sspi.W->FreeContextBuffer(outbuf.pvBuffer); + sspi_log(QString("FreeContextBuffer() = %1\n").arg(SECURITY_STATUS_toString(fret))); + } + + if (ret == SEC_E_OK) + authed = true; + } else { + // ret was an error, or some unexpected value like + // SEC_I_COMPLETE_NEEDED or + // SEC_I_COMPLETE_AND_CONTINUE, which i believe are + // not used for kerberos + + lastErrorCode = ret; + + ret = sspi.W->FreeCredentialsHandle(&user_cred); + sspi_log(QString("FreeCredentialsHandle() = %1\n").arg(SECURITY_STATUS_toString(ret))); + + return ErrorInitialize; + } + + initialized = true; + first_step = true; + + return Success; + } + + ReturnCode step(const QByteArray &in, QByteArray *out, bool *authenticated) + { + if (authed) { + out->clear(); + *authenticated = true; + return Success; + } + + if (first_step) { + // ignore 'in' + + *out = first_out_token; + first_out_token.clear(); + + first_step = false; + } else { + SecBuffer outbuf; + outbuf.BufferType = SECBUFFER_TOKEN; + outbuf.cbBuffer = 0; + outbuf.pvBuffer = NULL; + + SecBufferDesc outbufdesc; + outbufdesc.ulVersion = SECBUFFER_VERSION; + outbufdesc.cBuffers = 1; + outbufdesc.pBuffers = &outbuf; + + SecBuffer inbuf; + inbuf.BufferType = SECBUFFER_TOKEN; + inbuf.cbBuffer = in.size(); + inbuf.pvBuffer = (void *)in.data(); + + SecBufferDesc inbufdesc; + inbufdesc.ulVersion = SECBUFFER_VERSION; + inbufdesc.cBuffers = 1; + inbufdesc.pBuffers = &inbuf; + + SECURITY_STATUS ret = sspi.W->InitializeSecurityContextW(&user_cred, + &ctx, + (SEC_WCHAR *)spn.utf16(), + ctx_attr_req, + 0, + SECURITY_NETWORK_DREP, + &inbufdesc, + 0, + &ctx, + &outbufdesc, + &ctx_attr, + 0); // don't care about expiration + sspi_log(QString("InitializeSecurityContext(*, ctx, ...) = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret == SEC_E_OK || ret == SEC_I_CONTINUE_NEEDED) { + if (outbuf.pvBuffer) { + out->resize(outbuf.cbBuffer); + memcpy(out->data(), outbuf.pvBuffer, outbuf.cbBuffer); + + SECURITY_STATUS fret = sspi.W->FreeContextBuffer(outbuf.pvBuffer); + sspi_log(QString("FreeContextBuffer() = %1\n").arg(SECURITY_STATUS_toString(fret))); + } else + out->clear(); + + if (ret == SEC_E_OK) + authed = true; + } else { + // ret was an error, or some unexpected value like + // SEC_I_COMPLETE_NEEDED or + // SEC_I_COMPLETE_AND_CONTINUE, which i believe are + // not used for kerberos + + lastErrorCode = ret; + + ret = sspi.W->DeleteSecurityContext(&ctx); + sspi_log(QString("DeleteSecurityContext() = %1\n").arg(SECURITY_STATUS_toString(ret))); + + ret = sspi.W->FreeCredentialsHandle(&user_cred); + sspi_log(QString("FreeCredentialsHandle() = %1\n").arg(SECURITY_STATUS_toString(ret))); + + initialized = false; + return ErrorInitialize; + } + } + + *authenticated = authed; + return Success; + } + + // private + bool ensure_sizes_cached() + { + if (!have_sizes) { + SECURITY_STATUS ret = sspi.W->QueryContextAttributesW(&ctx, SECPKG_ATTR_SIZES, &ctx_sizes); + sspi_log(QString("QueryContextAttributes(ctx, SECPKG_ATTR_SIZES, ...) = %1\n") + .arg(SECURITY_STATUS_toString(ret))); + if (ret != SEC_E_OK) { + lastErrorCode = ret; + return false; + } + + // for some reason, querying the stream sizes returns + // SEC_E_UNSUPPORTED_FUNCTION on my system, even + // though the docs say it should work and putty + // wingss also calls it. + + // all we really need is cbMaximumMessage, and since + // we can't query for it, we'll hard code some + // value. according to putty wingss, the max size + // is essentially unbounded anyway, so this should + // be safe to do. + ctx_streamSizes.cbMaximumMessage = 8192; + + // ret = sspi.W->QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &ctx_streamSizes); + // sspi_log(QString("QueryContextAttributes(ctx, SECPKG_ATTR_STREAM_SIZES, ...) = + // %1\n").arg(SECURITY_STATUS_toString(ret))); if(ret != SEC_E_OK) + //{ + // lastErrorCode = ret; + // return ErrorQueryContext; + //} + + have_sizes = true; + } + + return true; + } + + ReturnCode get_max_encrypt_size(int *max) + { + if (!ensure_sizes_cached()) + return ErrorQueryContext; + + *max = cap_to_int(ctx_streamSizes.cbMaximumMessage); + + return Success; + } + + ReturnCode encode(const QByteArray &in, QByteArray *out, bool encrypt) + { + if (!ensure_sizes_cached()) + return ErrorQueryContext; + + QByteArray tokenbuf(ctx_sizes.cbSecurityTrailer, 0); + QByteArray padbuf(ctx_sizes.cbBlockSize, 0); + + // we assume here, like putty wingss, that the output size is + // less than or equal to the input size. honestly I don't + // see how this is clear from the SSPI documentation, but + // the code seems to work so we'll go with it... + QByteArray databuf = in; + + SecBuffer buf[3]; + buf[0].BufferType = SECBUFFER_TOKEN; + buf[0].cbBuffer = tokenbuf.size(); + buf[0].pvBuffer = tokenbuf.data(); + buf[1].BufferType = SECBUFFER_DATA; + buf[1].cbBuffer = databuf.size(); + buf[1].pvBuffer = databuf.data(); + buf[2].BufferType = SECBUFFER_PADDING; + buf[2].cbBuffer = padbuf.size(); + buf[2].pvBuffer = padbuf.data(); + + SecBufferDesc bufdesc; + bufdesc.ulVersion = SECBUFFER_VERSION; + bufdesc.cBuffers = 3; + bufdesc.pBuffers = buf; + + SECURITY_STATUS ret = sspi.W->EncryptMessage(&ctx, encrypt ? 0 : SECQOP_WRAP_NO_ENCRYPT, &bufdesc, 0); + sspi_log(QString("EncryptMessage() = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret != SEC_E_OK) { + lastErrorCode = ret; + return ErrorEncrypt; + } + + QByteArray fullbuf; + for (int i = 0; i < (int)bufdesc.cBuffers; ++i) + fullbuf += QByteArray((const char *)bufdesc.pBuffers[i].pvBuffer, bufdesc.pBuffers[i].cbBuffer); + + *out = fullbuf; + return Success; + } + + ReturnCode decode(const QByteArray &in, QByteArray *out, bool *encrypted) + { + SecBuffer buf[2]; + buf[0].BufferType = SECBUFFER_DATA; + buf[0].cbBuffer = 0; + buf[0].pvBuffer = NULL; + buf[1].BufferType = SECBUFFER_STREAM; + buf[1].cbBuffer = in.size(); + buf[1].pvBuffer = (void *)in.data(); + + SecBufferDesc bufdesc; + bufdesc.ulVersion = SECBUFFER_VERSION; + bufdesc.cBuffers = 2; + bufdesc.pBuffers = buf; + + ULONG fQOP; + SECURITY_STATUS ret = sspi.W->DecryptMessage(&ctx, &bufdesc, 0, &fQOP); + sspi_log(QString("DecryptMessage() = %1\n").arg(SECURITY_STATUS_toString(ret))); + if (ret == SEC_E_INCOMPLETE_MESSAGE) { + return NeedMoreData; + } else if (ret != SEC_E_OK) { + lastErrorCode = ret; + return ErrorDecrypt; + } + + if (buf[0].pvBuffer) { + out->resize(buf[0].cbBuffer); + memcpy(out->data(), buf[0].pvBuffer, buf[0].cbBuffer); + + SECURITY_STATUS ret = sspi.W->FreeContextBuffer(buf[0].pvBuffer); + sspi_log(QString("FreeContextBuffer() = %1\n").arg(SECURITY_STATUS_toString(ret))); + } else + out->clear(); + + if (fQOP & SECQOP_WRAP_NO_ENCRYPT) + *encrypted = false; + else + *encrypted = true; + + return Success; + } +}; + +//---------------------------------------------------------------------------- +// SaslGssapiSession +//---------------------------------------------------------------------------- +// this class wraps KerberosSession to perform SASL GSSAPI. it hides away +// any SSPI details, and is thus very simple to use. +class SaslGssapiSession +{ +private: + int secflags; + KerberosSession sess; + int mode; // 0 = kerberos tokens, 1 = app packets + bool authed; + QByteArray inbuf; + + int max_enc_size; // most we can encrypt to them + int max_dec_size; // most we are expected to decrypt from them + +public: + enum SecurityFlags + { + // only one of these should be set + RequireAtLeastInt = 0x0001, + RequireConf = 0x0002 + }; + + enum ReturnCode + { + Success, + ErrorInit, + ErrorKerberosStep, + ErrorAppTokenDecode, + ErrorAppTokenIsEncrypted, + ErrorAppTokenWrongSize, + ErrorAppTokenInvalid, + ErrorAppTokenEncode, + ErrorLayerTooWeak, + ErrorEncode, + ErrorDecode, + ErrorDecodeTooLarge, + ErrorDecodeNotEncrypted + }; + + // set this before auth, if you want + QString authzid; + + // read-only + bool do_layer, do_conf; + + SaslGssapiSession() + { + } + + ReturnCode init(const QString &proto, const QString &fqdn, int _secflags) + { + secflags = _secflags; + mode = 0; // kerberos tokens + authed = false; + + do_layer = false; + do_conf = false; + + if (sess.init(proto + '/' + fqdn) != KerberosSession::Success) + return ErrorInit; + + return Success; + } + + ReturnCode step(const QByteArray &in, QByteArray *out, bool *authenticated) + { + if (authed) { + out->clear(); + *authenticated = true; + return Success; + } + + if (mode == 0) // kerberos tokens + { + bool kerb_authed; + if (sess.step(in, out, &kerb_authed) != KerberosSession::Success) + return ErrorKerberosStep; + + if (kerb_authed) + mode = 1; // switch to app packets + + *authenticated = false; + } else if (mode == 1) { + bool layerPossible = false; + bool encryptionPossible = false; + if (sess.ctx_attr & ISC_RET_INTEGRITY && sess.ctx_attr & ISC_RET_MUTUAL_AUTH && + sess.ctx_attr & ISC_RET_SEQUENCE_DETECT) { + layerPossible = true; + + if (sess.ctx_attr & ISC_RET_CONFIDENTIALITY) + encryptionPossible = true; + } + + if (layerPossible) { + if (encryptionPossible) + sspi_log("Kerberos application data protection supported (with encryption)\n"); + else + sspi_log("Kerberos application data protection supported (without encryption)\n"); + } else + sspi_log("No Kerberos application data protection supported\n"); + + QByteArray decbuf; + bool encrypted; + if (sess.decode(in, &decbuf, &encrypted) != KerberosSession::Success) { + sspi_log("Error decoding application token\n"); + return ErrorAppTokenDecode; + } + + // this packet is supposed to be not encrypted + if (encrypted) { + sspi_log("Error, application token is encrypted\n"); + return ErrorAppTokenIsEncrypted; + } + + // packet must be exactly 4 bytes + if (decbuf.size() != 4) { + sspi_log("Error, application token is the wrong size\n"); + return ErrorAppTokenWrongSize; + } + + QString str; + str.sprintf("%02x%02x%02x%02x", + (unsigned int)decbuf[0], + (unsigned int)decbuf[1], + (unsigned int)decbuf[2], + (unsigned int)decbuf[3]); + sspi_log(QString("Received application token: [%1]\n").arg(str)); + + unsigned char layermask = decbuf[0]; + quint32 maxsize = 0; + maxsize += (unsigned char)decbuf[1]; + maxsize <<= 8; + maxsize += (unsigned char)decbuf[2]; + maxsize <<= 8; + maxsize += (unsigned char)decbuf[3]; + + // if 'None' is all that is supported, then maxsize + // must be zero + if (layermask == 1 && maxsize > 0) { + sspi_log("Error, supports no security layer but the max buffer size is not zero\n"); + return ErrorAppTokenInvalid; + } + + // convert maxsize to a signed int, by capping it + int _max_enc_size = cap_to_int(maxsize); + + // parse out layermask + bool saslLayerNone = false; + bool saslLayerInt = false; + bool saslLayerConf = false; + QStringList saslLayerModes; + if (layermask & 1) { + saslLayerNone = true; + saslLayerModes += "None"; + } + if (layermask & 2) { + saslLayerInt = true; + saslLayerModes += "Int"; + } + if (layermask & 4) { + saslLayerConf = true; + saslLayerModes += "Conf"; + } + + sspi_log(QString("Security layer modes supported: %1\n").arg(saslLayerModes.join(", "))); + sspi_log(QString("Security layer max packet size: %1\n").arg(maxsize)); + + // create outbound application token + QByteArray obuf(4, 0); // initially 4 bytes + + // set one of use_conf or use_int, but not both + bool use_conf = false; + bool use_int = false; + if (encryptionPossible && saslLayerConf) + use_conf = true; + else if (layerPossible && saslLayerInt) + use_int = true; + else if (!saslLayerNone) { + sspi_log("Error, no compatible layer mode supported, not even 'None'\n"); + return ErrorLayerTooWeak; + } + + if ((secflags & RequireConf) && !use_conf) { + sspi_log("Error, 'Conf' required but not supported\n"); + return ErrorLayerTooWeak; + } + + if ((secflags & RequireAtLeastInt) && !use_conf && !use_int) { + sspi_log("Error, 'Conf' or 'Int' required but not supported\n"); + return ErrorLayerTooWeak; + } + + if (use_conf) { + sspi_log("Using 'Conf' layer\n"); + obuf[0] = 4; + } else if (use_int) { + sspi_log("Using 'Int' layer\n"); + obuf[0] = 2; + } else { + sspi_log("Using 'None' layer\n"); + obuf[0] = 1; + } + + // as far as i can tell, there is no max decrypt size + // with sspi. so we'll just pick some number. + // a small one is good, to prevent excessive input + // buffering. + // in other parts of the code, it is assumed this + // value is less than INT_MAX + int _max_dec_size = 8192; // same as cyrus + + // max size must be zero if no security layer is used + if (!use_conf && !use_int) + _max_dec_size = 0; + + obuf[1] = (unsigned char)((_max_dec_size >> 16) & 0xff); + obuf[2] = (unsigned char)((_max_dec_size >> 8) & 0xff); + obuf[3] = (unsigned char)((_max_dec_size) & 0xff); + + if (!authzid.isEmpty()) + obuf += authzid.toUtf8(); + + str.clear(); + for (int n = 0; n < obuf.size(); ++n) + str += QString().sprintf("%02x", (unsigned int)obuf[n]); + sspi_log(QString("Sending application token: [%1]\n").arg(str)); + + if (sess.encode(obuf, out, false) != KerberosSession::Success) { + sspi_log("Error encoding application token\n"); + return ErrorAppTokenEncode; + } + + if (use_conf || use_int) + do_layer = true; + if (use_conf) + do_conf = true; + + max_enc_size = _max_enc_size; + max_dec_size = _max_dec_size; + + *authenticated = true; + } + + return Success; + } + + ReturnCode encode(const QByteArray &in, QByteArray *out) + { + if (!do_layer) { + *out = in; + return Success; + } + + int local_encrypt_max; + if (sess.get_max_encrypt_size(&local_encrypt_max) != KerberosSession::Success) + return ErrorEncode; + + // send no more per-packet than what our local system will + // encrypt AND no more than what the peer will accept. + int chunk_max = qMin(local_encrypt_max, max_enc_size); + if (chunk_max < 8) { + sspi_log("Error, chunk_max is ridiculously small\n"); + return ErrorEncode; + } + + QByteArray total_out; + + // break up into packets, if input exceeds max size + int encoded = 0; + while (encoded < in.size()) { + int left = in.size() - encoded; + int chunk_size = qMin(left, chunk_max); + QByteArray kerb_in = QByteArray::fromRawData(in.data() + encoded, chunk_size); + QByteArray kerb_out; + if (sess.encode(kerb_in, &kerb_out, do_conf) != KerberosSession::Success) + return ErrorEncode; + + QByteArray sasl_out(kerb_out.size() + 4, 0); + + // SASL (not GSS!) uses a 4 byte length prefix + quint32 len = kerb_out.size(); + sasl_out[0] = (unsigned char)((len >> 24) & 0xff); + sasl_out[1] = (unsigned char)((len >> 16) & 0xff); + sasl_out[2] = (unsigned char)((len >> 8) & 0xff); + sasl_out[3] = (unsigned char)((len) & 0xff); + + memcpy(sasl_out.data() + 4, kerb_out.data(), kerb_out.size()); + + encoded += kerb_in.size(); + total_out += sasl_out; + } + + *out = total_out; + return Success; + } + + ReturnCode decode(const QByteArray &in, QByteArray *out) + { + if (!do_layer) { + *out = in; + return Success; + } + + // buffer the input + inbuf += in; + + QByteArray total_out; + + // the buffer might contain many packets. decode as many + // as possible + while (1) { + if (inbuf.size() < 4) { + // need more data + break; + } + + // SASL (not GSS!) uses a 4 byte length prefix + quint32 ulen = 0; + ulen += (unsigned char)inbuf[0]; + ulen <<= 8; + ulen += (unsigned char)inbuf[1]; + ulen <<= 8; + ulen += (unsigned char)inbuf[2]; + ulen <<= 8; + ulen += (unsigned char)inbuf[3]; + + // this capping is safe, because we throw error if the value + // is too large, and an acceptable value will always be + // lower than the maximum integer size. + int len = cap_to_int(ulen); + if (len > max_dec_size) { + // this means the peer ignored our max buffer size. + // very evil, or we're under attack. + sspi_log("Error, decode size too large\n"); + return ErrorDecodeTooLarge; + } + + if (inbuf.size() - 4 < len) { + // need more data + break; + } + + // take the packet from the inbuf + QByteArray kerb_in = inbuf.mid(4, len); + memmove(inbuf.data(), inbuf.data() + len + 4, inbuf.size() - len - 4); + inbuf.resize(inbuf.size() - len - 4); + + // count incomplete packets as errors, since they are sasl framed + QByteArray kerb_out; + bool encrypted; + if (sess.decode(kerb_in, &kerb_out, &encrypted) != KerberosSession::Success) + return ErrorDecode; + + if (do_conf && !encrypted) { + sspi_log("Error, received unencrypted packet in 'Conf' mode\n"); + return ErrorDecodeNotEncrypted; + } + + total_out += kerb_out; + } + + *out = total_out; + return Success; + } +}; + +//---------------------------------------------------------------------------- +// SaslWinGss +//---------------------------------------------------------------------------- +class SaslWinGss : public SASLContext +{ + Q_OBJECT + +public: + SaslGssapiSession *sess; + bool authed; + Result _result; + SASL::AuthCondition _authCondition; + QByteArray _step_to_net; + QByteArray _to_net, _to_app; + int enc; + SafeTimer resultsReadyTrigger; + + QString opt_service, opt_host, opt_ext_id; + int opt_ext_ssf; + int opt_flags; + int opt_minssf, opt_maxssf; + + QString opt_authzid; + + SaslWinGss(Provider *p) + : SASLContext(p) + , sess(0) + , resultsReadyTrigger(this) + { + connect(&resultsReadyTrigger, SIGNAL(timeout()), SIGNAL(resultsReady())); + resultsReadyTrigger.setSingleShot(true); + } + + Provider::Context *clone() const + { + return 0; + } + + virtual void reset() + { + delete sess; + sess = 0; + authed = false; + _step_to_net.clear(); + _to_net.clear(); + _to_app.clear(); + resultsReadyTrigger.stop(); + + opt_service.clear(); + opt_host.clear(); + opt_ext_id.clear(); + opt_authzid.clear(); + } + + virtual void setup(const QString &service, + const QString &host, + const HostPort *local, + const HostPort *remote, + const QString &ext_id, + int ext_ssf) + { + // unused by this provider + Q_UNUSED(local); + Q_UNUSED(remote); + + opt_service = service; + opt_host = host; + opt_ext_id = ext_id; + opt_ext_ssf = ext_ssf; + } + + virtual void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) + { + opt_flags = (int)f; + opt_minssf = minSSF; + opt_maxssf = maxSSF; + } + + virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) + { + // we only support GSSAPI + if (!mechlist.contains("GSSAPI")) { + _result = Error; + _authCondition = SASL::NoMechanism; + resultsReadyTrigger.start(); + return; + } + + // GSSAPI (or this provider) doesn't meet these requirements + if (opt_flags & SASL::RequireForwardSecrecy || opt_flags & SASL::RequirePassCredentials || + !allowClientSendFirst) { + _result = Error; + _authCondition = SASL::NoMechanism; + resultsReadyTrigger.start(); + return; + } + + sess = new SaslGssapiSession; + sess->authzid = opt_authzid; + + int secflags = 0; + if (opt_minssf > 1) + secflags |= SaslGssapiSession::RequireConf; + else if (opt_minssf == 1) + secflags |= SaslGssapiSession::RequireAtLeastInt; + + SaslGssapiSession::ReturnCode ret = sess->init(opt_service, opt_host, secflags); + if (ret != SaslGssapiSession::Success) { + _result = Error; + _authCondition = SASL::AuthFail; + resultsReadyTrigger.start(); + return; + } + + ret = sess->step(QByteArray(), &_step_to_net, &authed); + if (ret != SaslGssapiSession::Success) { + _result = Error; + _authCondition = SASL::AuthFail; + resultsReadyTrigger.start(); + return; + } + + if (authed) + _result = Success; + else + _result = Continue; + + resultsReadyTrigger.start(); + } + + virtual void startServer(const QString &realm, bool disableServerSendLast) + { + // server mode unsupported at this time + Q_UNUSED(realm); + Q_UNUSED(disableServerSendLast); + + _result = Error; + _authCondition = SASL::AuthFail; + resultsReadyTrigger.start(); + } + + virtual void serverFirstStep(const QString &mech, const QByteArray *clientInit) + { + // server mode unsupported at this time + Q_UNUSED(mech); + Q_UNUSED(clientInit); + } + + virtual void nextStep(const QByteArray &from_net) + { + SaslGssapiSession::ReturnCode ret = sess->step(from_net, &_step_to_net, &authed); + if (ret != SaslGssapiSession::Success) { + _result = Error; + _authCondition = SASL::AuthFail; + resultsReadyTrigger.start(); + return; + } + + if (authed) + _result = Success; + else + _result = Continue; + + resultsReadyTrigger.start(); + } + + virtual void tryAgain() + { + // we never ask for params, so this function should never be + // called + } + + virtual void update(const QByteArray &from_net, const QByteArray &from_app) + { + SaslGssapiSession::ReturnCode ret; + QByteArray a; + + if (!from_net.isEmpty()) { + ret = sess->decode(from_net, &a); + if (ret != SaslGssapiSession::Success) { + _result = Error; + resultsReadyTrigger.start(); + return; + } + + _to_app += a; + } + + if (!from_app.isEmpty()) { + ret = sess->encode(from_app, &a); + if (ret != SaslGssapiSession::Success) { + _result = Error; + resultsReadyTrigger.start(); + return; + } + + _to_net += a; + enc += from_app.size(); + } + + _result = Success; + resultsReadyTrigger.start(); + } + + virtual bool waitForResultsReady(int msecs) + { + // all results are ready instantly + Q_UNUSED(msecs); + resultsReadyTrigger.stop(); + return true; + } + + virtual Result result() const + { + return _result; + } + + virtual QStringList mechlist() const + { + // server mode unsupported at this time + return QStringList(); + } + + virtual QString mech() const + { + // only mech we support :) + return "GSSAPI"; + } + + virtual bool haveClientInit() const + { + // GSSAPI always has a client init response + return true; + } + + virtual QByteArray stepData() const + { + return _step_to_net; + } + + virtual QByteArray to_net() + { + QByteArray a = _to_net; + _to_net.clear(); + enc = 0; + return a; + } + + virtual int encoded() const + { + return enc; + } + + virtual QByteArray to_app() + { + QByteArray a = _to_app; + _to_app.clear(); + return a; + } + + virtual int ssf() const + { + if (!sess->do_layer) + return 0; + + if (sess->do_conf) { + // TODO: calculate this value somehow? for now we'll + // just hard code it to 56, which is basically what + // cyrus does. + return 56; + } else + return 1; + } + + virtual SASL::AuthCondition authCondition() const + { + return _authCondition; + } + + virtual SASL::Params clientParams() const + { + // we never ask for params + return SASL::Params(); + } + + virtual void + setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) + { + // unused by this provider + Q_UNUSED(user); + Q_UNUSED(pass); + Q_UNUSED(realm); + + if (authzid) { + opt_authzid = *authzid; + if (sess) + sess->authzid = opt_authzid; + } else { + opt_authzid.clear(); + if (sess) + sess->authzid.clear(); + } + } + + virtual QStringList realmlist() const + { + // unused by this provider + return QStringList(); + } + + virtual QString username() const + { + // server mode unsupported at this time + return QString(); + } + + virtual QString authzid() const + { + // server mode unsupported at this time + return QString(); + } +}; + +#endif // !defined(FORWARD_ONLY) + +//---------------------------------------------------------------------------- +// MetaSasl +//---------------------------------------------------------------------------- +#ifndef FORWARD_ONLY +class wingssProvider; +static bool wingssProvider_have_sspi(wingssProvider *provider); +#endif + +class MetaSasl : public SASLContext +{ + Q_OBJECT + +public: + SASLContext *s; + + Result _result; + SASL::AuthCondition _authCondition; + SafeTimer resultsReadyTrigger; + Synchronizer sync; + bool waiting; + + QString opt_service, opt_host; + bool have_opt_local, have_opt_remote; + HostPort opt_local, opt_remote; + QString opt_ext_id; + int opt_ext_ssf; + SASL::AuthFlags opt_flags; + int opt_minssf, opt_maxssf; + + bool have_opt_user, have_opt_authzid, have_opt_pass, have_opt_realm; + QString opt_user, opt_authzid, opt_realm; + SecureArray opt_pass; + + class SaslProvider + { + public: + SASLContext *sasl; + bool ready; + QStringList mechlist; + + SaslProvider() + : sasl(0) + , ready(false) + { + } + }; + + QList saslProviders; + bool serverInit_active; + Result serverInit_result; + QStringList serverInit_mechlist; + + MetaSasl(Provider *p) + : SASLContext(p) + , resultsReadyTrigger(this) + , sync(this) + , waiting(false) + , serverInit_active(false) + { + s = 0; + + have_opt_user = false; + have_opt_authzid = false; + have_opt_pass = false; + have_opt_realm = false; + + connect(&resultsReadyTrigger, SIGNAL(timeout()), SIGNAL(resultsReady())); + resultsReadyTrigger.setSingleShot(true); + } + + ~MetaSasl() + { + delete s; + } + + virtual Provider::Context *clone() const + { + return 0; + } + + void clearSaslProviders() + { + foreach (const SaslProvider &sp, saslProviders) + delete sp.sasl; + + saslProviders.clear(); + } + + virtual void reset() + { + delete s; + s = 0; + + resultsReadyTrigger.stop(); + + opt_service.clear(); + opt_host.clear(); + opt_ext_id.clear(); + opt_user.clear(); + opt_authzid.clear(); + opt_realm.clear(); + opt_pass.clear(); + + have_opt_user = false; + have_opt_authzid = false; + have_opt_pass = false; + have_opt_realm = false; + + clearSaslProviders(); + serverInit_active = false; + serverInit_mechlist.clear(); + } + + virtual void setup(const QString &service, + const QString &host, + const HostPort *local, + const HostPort *remote, + const QString &ext_id, + int ext_ssf) + { + opt_service = service; + opt_host = host; + have_opt_local = false; + have_opt_remote = false; + if (local) { + have_opt_local = true; + opt_local = *local; + } + if (remote) { + have_opt_remote = true; + opt_remote = *remote; + } + opt_ext_id = ext_id; + opt_ext_ssf = ext_ssf; + } + + virtual void setConstraints(SASL::AuthFlags f, int minSSF, int maxSSF) + { + opt_flags = f; + opt_minssf = minSSF; + opt_maxssf = maxSSF; + } + + virtual void startClient(const QStringList &mechlist, bool allowClientSendFirst) + { +#ifndef FORWARD_ONLY + if (mechlist.contains("GSSAPI") && wingssProvider_have_sspi((wingssProvider *)provider())) { + s = new SaslWinGss(provider()); + } else { +#endif + // collect providers supporting sasl, in priority order. + // (note: providers() is in priority order already) + ProviderList list; + foreach (Provider *p, providers()) { + QString name = p->name(); + + // skip ourself + if (name == PROVIDER_NAME) + continue; + + if (p->features().contains("sasl")) { + // FIXME: improve qca so this isn't needed + SASL tmp_object_to_cause_plugin_init(0, name); + + // add to the list + list += p; + } + } + + if (!list.isEmpty()) { + // use the first + s = static_cast(list.first()->createContext("sasl")); + } +#ifndef FORWARD_ONLY + } +#endif + + if (!s) { + // no usable provider? throw error + _result = Error; + _authCondition = SASL::NoMechanism; + resultsReadyTrigger.start(); + return; + } + + // proper parenting + s->setParent(this); + + const HostPort *pLocal = 0; + const HostPort *pRemote = 0; + if (have_opt_local) + pLocal = &opt_local; + if (have_opt_remote) + pRemote = &opt_remote; + s->setup(opt_service, opt_host, pLocal, pRemote, opt_ext_id, opt_ext_ssf); + s->setConstraints(opt_flags, opt_minssf, opt_maxssf); + + const QString *pUser = 0; + const QString *pAuthzid = 0; + const SecureArray *pPass = 0; + const QString *pRealm = 0; + if (have_opt_user) + pUser = &opt_user; + if (have_opt_authzid) + pAuthzid = &opt_authzid; + if (have_opt_pass) + pPass = &opt_pass; + if (have_opt_realm) + pRealm = &opt_realm; + s->setClientParams(pUser, pAuthzid, pPass, pRealm); + connect(s, SIGNAL(resultsReady()), SLOT(s_resultsReady())); + + QString str = QString("MetaSasl: client using %1 with %2 mechs") + .arg(s->provider()->name(), QString::number(mechlist.count())); + QCA_logTextMessage(str, Logger::Debug); + s->startClient(mechlist, allowClientSendFirst); + } + + virtual void startServer(const QString &realm, bool disableServerSendLast) + { + // collect mechs of all providers, by starting all of them + serverInit_active = true; + + ProviderList list; + foreach (Provider *p, providers()) { + QString name = p->name(); + + // skip ourself + if (name == PROVIDER_NAME) + continue; + + if (p->features().contains("sasl")) { + // FIXME: improve qca so this isn't needed + SASL tmp_object_to_cause_plugin_init(0, name); + + // add to the list + list += p; + } + } + + foreach (Provider *p, list) { + SaslProvider sp; + + sp.sasl = static_cast(p->createContext("sasl")); + + // proper parenting + sp.sasl->setParent(this); + + const HostPort *pLocal = 0; + const HostPort *pRemote = 0; + if (have_opt_local) + pLocal = &opt_local; + if (have_opt_remote) + pRemote = &opt_remote; + sp.sasl->setup(opt_service, opt_host, pLocal, pRemote, opt_ext_id, opt_ext_ssf); + sp.sasl->setConstraints(opt_flags, opt_minssf, opt_maxssf); + connect(sp.sasl, SIGNAL(resultsReady()), SLOT(serverInit_resultsReady())); + + saslProviders += sp; + + sp.sasl->startServer(realm, disableServerSendLast); + } + } + + virtual void serverFirstStep(const QString &mech, const QByteArray *clientInit) + { + // choose a provider based on the mech + int at = choose_provider(mech); + + // extract it and clean up the rest + SASLContext *sasl = saslProviders[at].sasl; + sasl->disconnect(this); + saslProviders.removeAt(at); + clearSaslProviders(); + serverInit_active = false; + + // use the chosen provider + s = sasl; + connect(s, SIGNAL(resultsReady()), SLOT(s_resultsReady())); + s->serverFirstStep(mech, clientInit); + } + + virtual void nextStep(const QByteArray &from_net) + { + s->nextStep(from_net); + } + + virtual void tryAgain() + { + s->tryAgain(); + } + + virtual void update(const QByteArray &from_net, const QByteArray &from_app) + { + s->update(from_net, from_app); + } + + virtual bool waitForResultsReady(int msecs) + { + if (serverInit_active) { + waiting = true; + bool ret = sync.waitForCondition(msecs); + waiting = false; + return ret; + } else if (s) + return s->waitForResultsReady(msecs); + else + return true; + } + + virtual Result result() const + { + if (serverInit_active) + return serverInit_result; + else if (s) + return s->result(); + else + return _result; + } + + virtual QStringList mechlist() const + { + return serverInit_mechlist; + } + + virtual QString mech() const + { + if (s) + return s->mech(); + else + return QString(); + } + + virtual bool haveClientInit() const + { + return s->haveClientInit(); + } + + virtual QByteArray stepData() const + { + return s->stepData(); + } + + virtual QByteArray to_net() + { + return s->to_net(); + } + + virtual int encoded() const + { + return s->encoded(); + } + + virtual QByteArray to_app() + { + return s->to_app(); + } + + virtual int ssf() const + { + return s->ssf(); + } + + virtual SASL::AuthCondition authCondition() const + { + if (s) + return s->authCondition(); + else + return _authCondition; + } + + virtual SASL::Params clientParams() const + { + return s->clientParams(); + } + + virtual void + setClientParams(const QString *user, const QString *authzid, const SecureArray *pass, const QString *realm) + { + if (!s) { + if (user) { + have_opt_user = true; + opt_user = *user; + } + if (authzid) { + have_opt_authzid = true; + opt_authzid = *authzid; + } + if (pass) { + have_opt_pass = true; + opt_pass = *pass; + } + if (realm) { + have_opt_realm = true; + opt_realm = *realm; + } + } else { + s->setClientParams(user, authzid, pass, realm); + } + } + + virtual QStringList realmlist() const + { + return s->realmlist(); + } + + virtual QString username() const + { + return s->username(); + } + + virtual QString authzid() const + { + return s->authzid(); + } + +private Q_SLOTS: + void s_resultsReady() + { + emit resultsReady(); + } + + void serverInit_resultsReady() + { + SASLContext *sasl = (SASLContext *)sender(); + + int at = -1; + for (int n = 0; n < saslProviders.count(); ++n) { + if (saslProviders[n].sasl == sasl) { + at = n; + break; + } + } + if (at == -1) + return; + + if (sasl->result() == Success) { + saslProviders[at].ready = true; + saslProviders[at].mechlist = sasl->mechlist(); + + bool allReady = true; + for (int n = 0; n < saslProviders.count(); ++n) { + if (!saslProviders[n].ready) { + allReady = false; + break; + } + } + + if (allReady) { + // indicate success + serverInit_result = Success; + serverInit_mechlist = combine_mechlists(); + + if (waiting) + sync.conditionMet(); + else + emit resultsReady(); + } + } else { + delete sasl; + saslProviders.removeAt(at); + + if (saslProviders.isEmpty()) { + // indicate error + serverInit_result = Error; + _authCondition = SASL::NoMechanism; + + if (waiting) + sync.conditionMet(); + else + emit resultsReady(); + } + } + } + +private: + QStringList combine_mechlists() + { + QStringList out; + + // FIXME: consider prioritizing certain mechs? + foreach (const SaslProvider &sp, saslProviders) { + foreach (const QString &mech, sp.mechlist) { + if (!out.contains(mech)) + out += mech; + } + } + + return out; + } + + int choose_provider(const QString &mech) + { + int at = -1; + + // find a provider for this mech + for (int n = 0; n < saslProviders.count(); ++n) { + const SaslProvider &sp = saslProviders[n]; + if (sp.mechlist.contains(mech)) { + at = n; + break; + } + } + + // no provider offered this mech? then just go with the + // first provider + if (at == -1) + at = 0; + + return at; + } +}; + +class wingssProvider : public Provider +{ +public: + mutable QMutex m; + mutable bool forced_priority; + bool have_sspi; + + wingssProvider() + : forced_priority(false) + , have_sspi(false) + { + } + + virtual void init() + { +#ifndef FORWARD_ONLY + sspi_set_logger(do_log); + have_sspi = sspi_load(); +#endif + } + + ~wingssProvider() + { +#ifndef FORWARD_ONLY + if (have_sspi) + sspi_unload(); +#endif + } + + virtual int qcaVersion() const + { + return QCA_VERSION; + } + + virtual QString name() const + { + return PROVIDER_NAME; + } + + virtual QStringList features() const + { + // due to context manipulation, this plugin is only designed + // for qca 2.0 at this time, and not a possible 2.1, etc. + if ((qcaVersion() & 0xffff00) > 0x020000) + return QStringList(); + + m.lock(); + // FIXME: we need to prioritize this plugin to be higher + // than other plugins by default. unfortunately there's + // no clean way to do this. we can't change our priority + // until we are slotted into the qca provider system. the + // constructor, qcaVersion, and name functions are all + // guaranteed to be called, but unfortunately they are + // only guaranteed to be called before the slotting. the + // features function is essentially guaranteed to be called + // after the slotting though, since QCA::isSupported() + // trips it, and any proper QCA app will call isSupported. + if (!forced_priority) { + forced_priority = true; + setProviderPriority(PROVIDER_NAME, 0); + } + m.unlock(); + + QStringList list; + list += "sasl"; + return list; + } + + virtual Context *createContext(const QString &type) + { + if (type == "sasl") + return new MetaSasl(this); + else + return 0; + } + +#ifndef FORWARD_ONLY + static void do_log(const QString &str) + { + QCA_logTextMessage(str, Logger::Debug); + } +#endif +}; + +#ifndef FORWARD_ONLY +bool wingssProvider_have_sspi(wingssProvider *provider) +{ + return provider->have_sspi; +} +#endif + +} + +using namespace wingssQCAPlugin; + +//---------------------------------------------------------------------------- +// wingssPlugin +//---------------------------------------------------------------------------- + +class wingssPlugin : public QObject, public QCAPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") + Q_INTERFACES(QCAPlugin) + +public: + virtual Provider *createProvider() + { + return new wingssProvider; + } +}; + +#include "qca-wingss.moc" diff --git a/local/recipes/libs/qca/source/qca2.pc.cmake b/local/recipes/libs/qca/source/qca2.pc.cmake new file mode 100644 index 0000000000..c72558291e --- /dev/null +++ b/local/recipes/libs/qca/source/qca2.pc.cmake @@ -0,0 +1,11 @@ +prefix=@QCA_PREFIX_INSTALL_DIR@ +exec_prefix=@QCA_PREFIX_INSTALL_DIR@ +libdir=@QCA_LIBRARY_INSTALL_DIR@ +includedir=@QCA_FULL_INCLUDE_INSTALL_DIR@ + +Name: QCA +Description: Qt Cryptographic Architecture library +Version: @QCA_LIB_VERSION_STRING@ +Requires: @QCA_QT_PC_VERSION@ +Libs: @PKGCONFIG_LIBS@ +Cflags: @PKGCONFIG_CFLAGS@ diff --git a/local/recipes/libs/qca/source/src/CMakeLists.txt b/local/recipes/libs/qca/source/src/CMakeLists.txt new file mode 100644 index 0000000000..477732190d --- /dev/null +++ b/local/recipes/libs/qca/source/src/CMakeLists.txt @@ -0,0 +1,176 @@ +include(CheckIncludeFiles) +CHECK_INCLUDE_FILES(sys/filio.h HAVE_SYS_FILIO_H) +IF(HAVE_SYS_FILIO_H) + ADD_DEFINITIONS(-DHAVE_SYS_FILIO_H) +ENDIF(HAVE_SYS_FILIO_H) + +INCLUDE(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" +# include +# include +int main() { void *f = 0; return mlock(f,8); } +" MLOCK_TAKES_VOID) +if(NOT MLOCK_TAKES_VOID) + MESSAGE(STATUS "mlock(2) does not take a void *") + ADD_DEFINITIONS(-DMLOCK_NOT_VOID_PTR) +endif() + +if(DEVELOPER_MODE) + add_definitions(-DQCA_PLUGIN_PATH="${CMAKE_BINARY_DIR}/lib/${QCA_LIB_NAME}") +else() + if(USE_RELATIVE_PATHS) + add_definitions(-DQCA_PLUGIN_PATH="${QCA_PREFIX_INSTALL_DIR}/${QCA_PLUGINS_INSTALL_DIR}") + else() + add_definitions(-DQCA_PLUGIN_PATH="${QCA_PLUGINS_INSTALL_DIR}") + endif() +endif() + +# base source files + + +SET( SOURCES + qca_tools.cpp + qca_plugin.cpp + qca_textfilter.cpp + qca_basic.cpp + support/logger.cpp + qca_cert.cpp + qca_core.cpp + qca_default.cpp + qca_keystore.cpp + qca_publickey.cpp + qca_safeobj.cpp + qca_safetimer.cpp + qca_securelayer.cpp + qca_securemessage.cpp + support/qpipe.cpp + support/console.cpp + support/synchronizer.cpp + support/dirwatch.cpp + support/syncthread.cpp +) + +IF (WIN32) + SET( SOURCES ${SOURCES} qca_systemstore_win.cpp ) +elseif(APPLE AND NOT IOS) + set( SOURCES ${SOURCES} qca_systemstore_mac.cpp) +else() + SET( SOURCES ${SOURCES} qca_systemstore_flatfile.cpp ) +endif() + +# Support files +#SET( qca_HEADERS ${qca_HEADERS} support/dirwatch/dirwatch_p.h ) + +# Botan tools +SET( botan_BASE botantools/botan ) + + +INCLUDE_DIRECTORIES(support ${botan_BASE} ) + +ADD_DEFINITIONS( + -DBOTAN_TYPES_QT + -DBOTAN_NO_INIT_H + -DBOTAN_NO_CONF_H + -DBOTAN_TOOLS_ONLY + -DBOTAN_MINIMAL_BIGINT +) + +ADD_DEFINITIONS( + -DBOTAN_MP_WORD_BITS=32 + -DBOTAN_KARAT_MUL_THRESHOLD=12 + -DBOTAN_KARAT_SQR_THRESHOLD=12 + -DBOTAN_EXT_MUTEX_QT +) + +if(UNIX) + ADD_DEFINITIONS( -DBOTAN_EXT_ALLOC_MMAP) +endif() + +SET( botan_SOURCES + ${botan_BASE}/util.cpp + ${botan_BASE}/exceptn.cpp + ${botan_BASE}/mutex.cpp + ${botan_BASE}/mux_qt/mux_qt.cpp + ${botan_BASE}/charset.cpp + ${botan_BASE}/defalloc.cpp + ${botan_BASE}/mp_comba.cpp + ${botan_BASE}/mp_mul.cpp + ${botan_BASE}/mp_shift.cpp + ${botan_BASE}/mp_misc.cpp + ${botan_BASE}/divide.cpp + ${botan_BASE}/big_base.cpp + ${botan_BASE}/big_code.cpp + ${botan_BASE}/big_io.cpp + ${botan_BASE}/big_ops2.cpp + ${botan_BASE}/big_ops3.cpp + ${botan_BASE}/bit_ops.cpp + ${botan_BASE}/libstate.cpp + ${botan_BASE}/mem_pool.cpp + ${botan_BASE}/modules.cpp + ${botan_BASE}/mp_asm.cpp + ${botan_BASE}/mp_mulop.cpp + ${botan_BASE}/parsing.cpp +) + +IF (UNIX) + SET( botan_SOURCES ${botan_SOURCES} ${botan_BASE}/ml_unix/mlock.cpp) + SET( botan_SOURCES ${botan_SOURCES} ${botan_BASE}/alloc_mmap/mmap_mem.cpp) +ENDIF (UNIX) + +IF(WIN32) + SET( botan_SOURCES ${botan_SOURCES} ${botan_BASE}/ml_win32/mlock.cpp) +ENDIF(WIN32) + +SET( SOURCES ${SOURCES} ${botan_SOURCES}) + +add_library(${QCA_LIB_NAME} ${SOURCES} ${public_HEADERS}) +target_link_libraries(${QCA_LIB_NAME} PUBLIC Qt${QT_MAJOR_VERSION}::Core) +if(BUILD_WITH_QT6) + target_link_libraries(${QCA_LIB_NAME} PRIVATE Qt6::Core5Compat) +endif() + +if(WIN32) + TARGET_LINK_LIBRARIES(${QCA_LIB_NAME} PRIVATE crypt32 ws2_32) +endif() + +if(APPLE AND NOT IOS) + set(COREFOUNDATION_LIBRARY "-framework CoreFoundation") + set(COREFOUNDATION_LIBRARY_SECURITY "-framework Security") + TARGET_LINK_LIBRARIES(${QCA_LIB_NAME} PRIVATE ${COREFOUNDATION_LIBRARY} ${COREFOUNDATION_LIBRARY_SECURITY}) + + if(NOT USE_RELATIVE_PATHS) + set_target_properties(${QCA_LIB_NAME} PROPERTIES + INSTALL_NAME_DIR "${QCA_LIBRARY_INSTALL_DIR}" + ) + endif() +endif() + +if(NOT ANDROID) + set_target_properties(${QCA_LIB_NAME} PROPERTIES + VERSION ${QCA_LIB_MAJOR_VERSION}.${QCA_LIB_MINOR_VERSION}.${QCA_LIB_PATCH_VERSION} + SOVERSION ${QCA_LIB_MAJOR_VERSION} + ) +endif() + +set_target_properties(${QCA_LIB_NAME} PROPERTIES + DEFINE_SYMBOL QCA_MAKEDLL + PUBLIC_HEADER "${public_HEADERS}" + FRAMEWORK ${OSX_FRAMEWORK} + FRAMEWORK_VERSION ${QCA_LIB_MAJOR_VERSION} + EXPORT_NAME ${QCA_LIB_NAME} + ) + +if(NOT DEVELOPER_MODE) + # Do not split 'PUBLIC_HEADER ...' line. It means install headers to folder + # and set this folder as -I flag for imported target. + # Also EXPORT doesn't actually install any files. It only created a new target. + install(TARGETS ${QCA_LIB_NAME} EXPORT ${QCA_CONFIG_NAME_BASE}Targets + LIBRARY DESTINATION "${QCA_LIBRARY_INSTALL_DIR}" + RUNTIME DESTINATION "${QCA_BINARY_INSTALL_DIR}" + ARCHIVE DESTINATION "${QCA_LIBRARY_INSTALL_DIR}" + FRAMEWORK DESTINATION "${QCA_LIBRARY_INSTALL_DIR}" + PUBLIC_HEADER DESTINATION "${QCA_FULL_INCLUDE_INSTALL_DIR}" INCLUDES DESTINATION "${QCA_FULL_INCLUDE_INSTALL_DIR}" + ) + install_pdb(${QCA_LIB_NAME} ${QCA_BINARY_INSTALL_DIR}) +endif() + diff --git a/local/recipes/libs/qca/source/src/botantools/.krazy b/local/recipes/libs/qca/source/src/botantools/.krazy new file mode 100644 index 0000000000..6946ba99f3 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/.krazy @@ -0,0 +1 @@ +IGNORESUBS botan diff --git a/local/recipes/libs/qca/source/src/botantools/README b/local/recipes/libs/qca/source/src/botantools/README new file mode 100644 index 0000000000..f0625d55cb --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/README @@ -0,0 +1,84 @@ +Botantools 1.6.2 +---------------- + +Botan is written by Jack Lloyd and available at http://botan.randombit.net/ + +Description (from the website) : + Botan is a library, written in C++. It's main purpose it to provide an easy + to use, high level interface to various cryptographic primitives, such as + block ciphers, hash functions, and public key algorithms. In addition, the + intent is that Botan is as general purpose as possible, and for this reason, + it supports many standards and de-facto standards. + +"Botantools" is a subset of Botan, tailored for use with QCA. It includes +only the memory allocation, memory locking, and big integer capabilities. To +use it, just include botantools.pri in your qmake profile, and botantools.h in +your code. + +The 'botan' subfolder consists of files just from Botan. Inside are source +files (originally from Botan's 'src' folder) as well as some modules (from +'modules'). The further 'botan' subfolder contains headers (from 'include' +and modules). + +Some files had to be modified, and botantools.diff contains the differences. +Also, license headers and namespace declarations were added to all source +files, but I don't count these as real modifications, and they are not +included in the diff. The addlicenseheaders.sh script can be used to apply +the license headers. To apply the namespace declarations, build wrapns.c and +use the addnamespace.sh script. + +Files used: + + '*' indicates modification + + doc/license.txt + include/allocate.h + * include/bigint.h + include/bit_ops.h + * include/charset.h + include/defalloc.h + include/exceptn.h + * include/libstate.h + include/mem_ops.h + include/mem_pool.h + * include/modules.h + include/mp_asm.h + include/mp_asmi.h + include/mp_core.h + include/mp_types.h + include/mutex.h + * include/numthry.h + * include/parsing.h + include/secmem.h + include/stl_util.h + * include/types.h + * include/util.h + modules/alloc_mmap/mmap_mem.h + modules/alloc_mmap/mmap_mem.cpp + modules/ml_unix/mlock.cpp + modules/ml_win32/mlock.cpp + modules/mux_qt/mux_qt.h + * modules/mux_qt/mux_qt.cpp + src/big_base.cpp + * src/big_code.cpp + * src/big_io.cpp + src/big_ops2.cpp + src/big_ops3.cpp + src/bit_ops.cpp + * src/charset.cpp + src/defalloc.cpp + src/divide.cpp + src/exceptn.cpp + * src/libstate.cpp + * src/mem_pool.cpp + * src/modules.cpp + * src/mp_asm.cpp + src/mp_comba.cpp + src/mp_misc.cpp + src/mp_mul.cpp + src/mp_mulop.cpp + src/mp_shift.cpp + src/mutex.cpp + * src/parsing.cpp + * src/util.cpp + diff --git a/local/recipes/libs/qca/source/src/botantools/addlicenseheaders.sh b/local/recipes/libs/qca/source/src/botantools/addlicenseheaders.sh new file mode 100755 index 0000000000..610e1e561b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/addlicenseheaders.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +for f in `find botan -name \*.cpp -o -name \*.h` ; do + echo "/*" > file.tmp + cat botan/license.txt >> file.tmp + echo "*/" >> file.tmp + echo "// LICENSEHEADER_END" >> file.tmp + cat $f >> file.tmp + cp file.tmp $f + rm file.tmp +done + diff --git a/local/recipes/libs/qca/source/src/botantools/addnamespace.sh b/local/recipes/libs/qca/source/src/botantools/addnamespace.sh new file mode 100755 index 0000000000..6341e2bc1b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/addnamespace.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +for f in `find botan -name \*.cpp -o -name \*.h` ; do + ./wrapns $f QCA +done + diff --git a/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.cpp b/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.cpp new file mode 100644 index 0000000000..ee9f95c06e --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.cpp @@ -0,0 +1,184 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Mapping Allocator Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif + +#ifndef _XOPEN_SOURCE_EXTENDED +#define _XOPEN_SOURCE_EXTENDED 1 +#endif + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +#ifndef MAP_FAILED +#define MAP_FAILED -1 +#endif + +namespace Botan { + +namespace { + +/************************************************* + * MemoryMapping_Allocator Exception * + *************************************************/ +class MemoryMapping_Failed : public Exception +{ +public: + MemoryMapping_Failed(const std::string &msg) + : Exception("MemoryMapping_Allocator: " + msg) + { + } +}; + +} + +/************************************************* + * Memory Map a File into Memory * + *************************************************/ +void *MemoryMapping_Allocator::alloc_block(u32bit n) +{ + class TemporaryFile + { + public: + int get_fd() const + { + return fd; + } + const std::string path() const + { + return filepath; + } + + TemporaryFile(const std::string &base) + { + const std::string path = base + "XXXXXX"; + + filepath = new char[path.length() + 1]; + std::strcpy(filepath, path.c_str()); + + mode_t old_umask = umask(077); + fd = mkstemp(filepath); + umask(old_umask); + } + + ~TemporaryFile() QCA_NOEXCEPT(false) + { + delete[] filepath; + if (fd != -1 && close(fd) == -1) + throw MemoryMapping_Failed("Could not close file"); + } + + TemporaryFile(const TemporaryFile &) = delete; + TemporaryFile &operator=(const TemporaryFile &) = delete; + + private: + int fd; + char *filepath; + }; + + TemporaryFile file("/tmp/botan_"); + + if (file.get_fd() == -1) + throw MemoryMapping_Failed("Could not create file"); + + if (unlink(file.path().c_str())) + throw MemoryMapping_Failed("Could not unlink file " + file.path()); + + lseek(file.get_fd(), n - 1, SEEK_SET); + if (write(file.get_fd(), "\0", 1) != 1) + throw MemoryMapping_Failed("Could not write to file"); + + void *ptr = mmap(nullptr, n, PROT_READ | PROT_WRITE, MAP_SHARED, file.get_fd(), 0); + + if (ptr == (void *)MAP_FAILED) + throw MemoryMapping_Failed("Could not map file"); + + return ptr; +} + +/************************************************* + * Remove a Memory Mapping * + *************************************************/ +void MemoryMapping_Allocator::dealloc_block(void *ptr, u32bit n) +{ + if (ptr == nullptr) + return; +#ifdef MLOCK_NOT_VOID_PTR +#define MLOCK_TYPE_CAST (char *) +#else +#define MLOCK_TYPE_CAST +#endif + + const u32bit OVERWRITE_PASSES = 12; + const byte PATTERNS[] = { + 0x00, 0xFF, 0xAA, 0x55, 0x73, 0x8C, 0x5F, 0xA0, 0x6E, 0x91, 0x30, 0xCF, 0xD3, 0x2C, 0xAC, 0x53}; + + for (u32bit j = 0; j != OVERWRITE_PASSES; j++) { + std::memset(ptr, PATTERNS[j % sizeof(PATTERNS)], n); + if (msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) + throw MemoryMapping_Failed("Sync operation failed"); + } + std::memset(ptr, 0, n); + if (msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) + throw MemoryMapping_Failed("Sync operation failed"); + + if (munmap(MLOCK_TYPE_CAST ptr, n)) + throw MemoryMapping_Failed("Could not unmap file"); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.h b/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.h new file mode 100644 index 0000000000..4d1ca94736 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/alloc_mmap/mmap_mem.h @@ -0,0 +1,65 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Mapping Allocator Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_EXT_MMAP_ALLOCATOR_H__ +#define BOTAN_EXT_MMAP_ALLOCATOR_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Memory Mapping Allocator * + *************************************************/ +class MemoryMapping_Allocator : public Pooling_Allocator +{ +public: + MemoryMapping_Allocator() + : Pooling_Allocator(64 * 1024, false) + { + } + std::string type() const + { + return "mmap"; + } + +private: + void *alloc_block(u32bit); + void dealloc_block(void *, u32bit); +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/big_base.cpp b/local/recipes/libs/qca/source/src/botantools/botan/big_base.cpp new file mode 100644 index 0000000000..6ee7758aa6 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/big_base.cpp @@ -0,0 +1,430 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Base Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Construct a BigInt from a regular number * + *************************************************/ +BigInt::BigInt(u64bit n) +{ + set_sign(Positive); + + if (n == 0) + return; + + const u32bit limbs_needed = sizeof(u64bit) / sizeof(word); + + reg.create(4 * limbs_needed); + for (u32bit j = 0; j != limbs_needed; ++j) + reg[j] = (word)((n >> (j * MP_WORD_BITS)) & MP_WORD_MASK); +} + +/************************************************* + * Construct a BigInt of the specified size * + *************************************************/ +BigInt::BigInt(Sign s, u32bit size) +{ + reg.create(round_up(size, 8)); + signedness = s; +} + +/************************************************* + * Construct a BigInt from a "raw" BigInt * + *************************************************/ +BigInt::BigInt(const BigInt &b) +{ + const u32bit b_words = b.sig_words(); + + if (b_words) { + reg.create(round_up(b_words, 8)); + reg.copy(b.data(), b_words); + set_sign(b.sign()); + } else { + reg.create(2); + set_sign(Positive); + } +} + +BigInt &BigInt::operator=(const BigInt &) = default; + +/************************************************* + * Construct a BigInt from a string * + *************************************************/ +BigInt::BigInt(const std::string &str) +{ + Base base = Decimal; + u32bit markers = 0; + bool negative = false; + if (str.length() > 0 && str[0] == '-') { + markers += 1; + negative = true; + } + + if (str.length() > markers + 2 && str[markers] == '0' && str[markers + 1] == 'x') { + markers += 2; + base = Hexadecimal; + } else if (str.length() > markers + 1 && str[markers] == '0') { + markers += 1; + base = Octal; + } + + *this = decode((const byte *)str.data() + markers, str.length() - markers, base); + + if (negative) + set_sign(Negative); + else + set_sign(Positive); +} + +/************************************************* + * Construct a BigInt from an encoded BigInt * + *************************************************/ +BigInt::BigInt(const byte input[], u32bit length, Base base) +{ + set_sign(Positive); + *this = decode(input, length, base); +} + +/************************************************* + * Swap this BigInt with another * + *************************************************/ +void BigInt::swap(BigInt &other) +{ + std::swap(reg, other.reg); + std::swap(signedness, other.signedness); +} + +/************************************************* + * Grow the internal storage * + *************************************************/ +void BigInt::grow_reg(u32bit n) const +{ + reg.grow_to(round_up(size() + n, 8)); +} + +/************************************************* + * Grow the internal storage * + *************************************************/ +void BigInt::grow_to(u32bit n) const +{ + if (n > size()) + reg.grow_to(round_up(n, 8)); +} + +/************************************************* + * Comparison Function * + *************************************************/ +s32bit BigInt::cmp(const BigInt &n, bool check_signs) const +{ + if (check_signs) { + if (n.is_positive() && this->is_negative()) + return -1; + if (n.is_negative() && this->is_positive()) + return 1; + if (n.is_negative() && this->is_negative()) + return (-bigint_cmp(data(), sig_words(), n.data(), n.sig_words())); + } + return bigint_cmp(data(), sig_words(), n.data(), n.sig_words()); +} + +/************************************************* + * Convert this number to a u32bit, if possible * + *************************************************/ +u32bit BigInt::to_u32bit() const +{ + if (is_negative()) + throw Encoding_Error("BigInt::to_u32bit: Number is negative"); + if (bits() >= 32) + throw Encoding_Error("BigInt::to_u32bit: Number is too big to convert"); + + u32bit out = 0; + for (u32bit j = 0; j != 4; ++j) + out = (out << 8) | byte_at(3 - j); + return out; +} + +/************************************************* + * Return byte n of this number * + *************************************************/ +byte BigInt::byte_at(u32bit n) const +{ + const u32bit WORD_BYTES = sizeof(word); + u32bit word_num = n / WORD_BYTES, byte_num = n % WORD_BYTES; + if (word_num >= size()) + return 0; + else + return get_byte(WORD_BYTES - byte_num - 1, reg[word_num]); +} + +/************************************************* + * Return bit n of this number * + *************************************************/ +bool BigInt::get_bit(u32bit n) const +{ + return ((word_at(n / MP_WORD_BITS) >> (n % MP_WORD_BITS)) & 1); +} + +/************************************************* + * Return bits {offset...offset+length} * + *************************************************/ +u32bit BigInt::get_substring(u32bit offset, u32bit length) const +{ + if (length > 32) + throw Invalid_Argument("BigInt::get_substring: Substring size too big"); + + u64bit piece = 0; + for (u32bit j = 0; j != 8; ++j) + piece = (piece << 8) | byte_at((offset / 8) + (7 - j)); + + u64bit mask = (1 << length) - 1; + u32bit shift = (offset % 8); + + return static_cast((piece >> shift) & mask); +} + +/************************************************* + * Set bit number n * + *************************************************/ +void BigInt::set_bit(u32bit n) +{ + const u32bit which = n / MP_WORD_BITS; + const word mask = (word)1 << (n % MP_WORD_BITS); + if (which >= size()) + grow_to(which + 1); + reg[which] |= mask; +} + +/************************************************* + * Clear bit number n * + *************************************************/ +void BigInt::clear_bit(u32bit n) +{ + const u32bit which = n / MP_WORD_BITS; + const word mask = (word)1 << (n % MP_WORD_BITS); + if (which < size()) + reg[which] &= ~mask; +} + +/************************************************* + * Clear all but the lowest n bits * + *************************************************/ +void BigInt::mask_bits(u32bit n) +{ + if (n == 0) { + clear(); + return; + } + if (n >= bits()) + return; + + const u32bit top_word = n / MP_WORD_BITS; + const word mask = ((word)1 << (n % MP_WORD_BITS)) - 1; + + if (top_word < size()) + for (u32bit j = top_word + 1; j != size(); ++j) + reg[j] = 0; + + reg[top_word] &= mask; +} + +/************************************************* + * Count the significant words * + *************************************************/ +u32bit BigInt::sig_words() const +{ + const word *x = data(); + u32bit top_set = size(); + + while (top_set >= 4) { + word sum = x[top_set - 1] | x[top_set - 2] | x[top_set - 3] | x[top_set - 4]; + if (sum) + break; + else + top_set -= 4; + } + while (top_set && (x[top_set - 1] == 0)) + top_set--; + return top_set; +} + +/************************************************* + * Count how many bytes are being used * + *************************************************/ +u32bit BigInt::bytes() const +{ + return (bits() + 7) / 8; +} + +/************************************************* + * Count how many bits are being used * + *************************************************/ +u32bit BigInt::bits() const +{ + if (sig_words() == 0) + return 0; + + u32bit full_words = sig_words() - 1, top_bits = MP_WORD_BITS; + word top_word = word_at(full_words), mask = MP_WORD_TOP_BIT; + + while (top_bits && ((top_word & mask) == 0)) { + mask >>= 1; + top_bits--; + } + + return (full_words * MP_WORD_BITS + top_bits); +} + +/************************************************* + * Calcluate the size in a certain base * + *************************************************/ +u32bit BigInt::encoded_size(Base base) const +{ + static const double LOG_2_BASE_10 = 0.30102999566; + + if (base == Binary) + return bytes(); + else if (base == Hexadecimal) + return 2 * bytes(); + else if (base == Octal) + return ((bits() + 2) / 3); + else if (base == Decimal) + return (u32bit)((bits() * LOG_2_BASE_10) + 1); + else + throw Invalid_Argument("Unknown base for BigInt encoding"); +} + +/************************************************* + * Return true if this number is zero * + *************************************************/ +bool BigInt::is_zero() const +{ + for (u32bit j = 0; j != size(); ++j) + if (reg[j]) + return false; + return true; +} + +/************************************************* + * Set the sign * + *************************************************/ +void BigInt::set_sign(Sign s) +{ + if (is_zero()) + signedness = Positive; + else + signedness = s; +} + +/************************************************* + * Reverse the value of the sign flag * + *************************************************/ +void BigInt::flip_sign() +{ + set_sign(reverse_sign()); +} + +/************************************************* + * Return the opposite value of the current sign * + *************************************************/ +BigInt::Sign BigInt::reverse_sign() const +{ + if (sign() == Positive) + return Negative; + return Positive; +} + +/************************************************* + * Return the negation of this number * + *************************************************/ +BigInt BigInt::operator-() const +{ + BigInt x = (*this); + x.flip_sign(); + return x; +} + +/************************************************* + * Return the absolute value of this number * + *************************************************/ +BigInt BigInt::abs() const +{ + BigInt x = (*this); + x.set_sign(Positive); + return x; +} + +/************************************************* + * Encode this number into bytes * + *************************************************/ +void BigInt::binary_encode(byte output[]) const +{ + const u32bit sig_bytes = bytes(); + for (u32bit j = 0; j != sig_bytes; ++j) + output[sig_bytes - j - 1] = byte_at(j); +} + +/************************************************* + * Set this number to the value in buf * + *************************************************/ +void BigInt::binary_decode(const byte buf[], u32bit length) +{ + const u32bit WORD_BYTES = sizeof(word); + reg.create(round_up((length / WORD_BYTES) + 1, 8)); + + for (u32bit j = 0; j != length / WORD_BYTES; ++j) { + u32bit top = length - WORD_BYTES * j; + for (u32bit k = WORD_BYTES; k > 0; --k) + reg[j] = (reg[j] << 8) | buf[top - k]; + } + for (u32bit j = 0; j != length % WORD_BYTES; ++j) + reg[length / WORD_BYTES] = (reg[length / WORD_BYTES] << 8) | buf[j]; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/big_code.cpp b/local/recipes/libs/qca/source/src/botantools/botan/big_code.cpp new file mode 100644 index 0000000000..9233197fde --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/big_code.cpp @@ -0,0 +1,179 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Encoding/Decoding Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_MINIMAL_BIGINT +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +namespace Botan { + +/************************************************* + * Encode a BigInt * + *************************************************/ +void BigInt::encode(byte output[], const BigInt &n, Base base) +{ + if (base == Binary) + n.binary_encode(output); +#ifndef BOTAN_MINIMAL_BIGINT + else if (base == Hexadecimal) { + SecureVector binary(n.encoded_size(Binary)); + n.binary_encode(binary); + for (u32bit j = 0; j != binary.size(); ++j) + Hex_Encoder::encode(binary[j], output + 2 * j); + } +#endif + else if (base == Octal) { + BigInt copy = n; + const u32bit output_size = n.encoded_size(Octal); + for (u32bit j = 0; j != output_size; ++j) { + output[output_size - 1 - j] = Charset::digit2char(copy % 8); + copy /= 8; + } + } else if (base == Decimal) { + BigInt copy = n; + BigInt remainder; + copy.set_sign(Positive); + const u32bit output_size = n.encoded_size(Decimal); + for (u32bit j = 0; j != output_size; ++j) { + divide(copy, 10, copy, remainder); + output[output_size - 1 - j] = Charset::digit2char(remainder.word_at(0)); + if (copy.is_zero()) { + if (j < output_size - 1) { + int extra = output_size - 1 - j; + memmove(output, output + extra, output_size - extra); + memset(output + output_size - extra, 0, extra); + } + break; + } + } + } else + throw Invalid_Argument("Unknown BigInt encoding method"); +} + +/************************************************* + * Encode a BigInt * + *************************************************/ +SecureVector BigInt::encode(const BigInt &n, Base base) +{ + SecureVector output(n.encoded_size(base)); + encode(output, n, base); + if (base != Binary) + for (u32bit j = 0; j != output.size(); ++j) + if (output[j] == 0) + output[j] = '0'; + return output; +} + +/************************************************* + * Encode a BigInt, with leading 0s if needed * + *************************************************/ +SecureVector BigInt::encode_1363(const BigInt &n, u32bit bytes) +{ + const u32bit n_bytes = n.bytes(); + if (n_bytes > bytes) + throw Encoding_Error("encode_1363: n is too large to encode properly"); + + const u32bit leading_0s = bytes - n_bytes; + + SecureVector output(bytes); + encode(output + leading_0s, n, Binary); + return output; +} + +/************************************************* + * Decode a BigInt * + *************************************************/ +BigInt BigInt::decode(const MemoryRegion &buf, Base base) +{ + return BigInt::decode(buf, buf.size(), base); +} + +/************************************************* + * Decode a BigInt * + *************************************************/ +BigInt BigInt::decode(const byte buf[], u32bit length, Base base) +{ + BigInt r; + if (base == Binary) + r.binary_decode(buf, length); +#ifndef BOTAN_MINIMAL_BIGINT + else if (base == Hexadecimal) { + SecureVector hex; + for (u32bit j = 0; j != length; ++j) + if (Hex_Decoder::is_valid(buf[j])) + hex.append(buf[j]); + + u32bit offset = (hex.size() % 2); + SecureVector binary(hex.size() / 2 + offset); + + if (offset) { + byte temp[2] = {'0', hex[0]}; + binary[0] = Hex_Decoder::decode(temp); + } + + for (u32bit j = offset; j != binary.size(); ++j) + binary[j] = Hex_Decoder::decode(hex + 2 * j - offset); + r.binary_decode(binary, binary.size()); + } +#endif + else if (base == Decimal || base == Octal) { + const u32bit RADIX = ((base == Decimal) ? 10 : 8); + for (u32bit j = 0; j != length; ++j) { + byte x = Charset::char2digit(buf[j]); + if (x >= RADIX) { + if (RADIX == 10) + throw Invalid_Argument("BigInt: Invalid decimal string"); + else + throw Invalid_Argument("BigInt: Invalid octal string"); + } + + r *= RADIX; + r += x; + } + } else + throw Invalid_Argument("Unknown BigInt decoding method"); + return r; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/big_io.cpp b/local/recipes/libs/qca/source/src/botantools/botan/big_io.cpp new file mode 100644 index 0000000000..52c79f9437 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/big_io.cpp @@ -0,0 +1,87 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Input/Output Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +#ifndef BOTAN_MINIMAL_BIGINT + +/************************************************* + * Write the BigInt into a stream * + *************************************************/ +std::ostream &operator<<(std::ostream &stream, const BigInt &n) +{ + BigInt::Base base = BigInt::Decimal; + if (stream.flags() & std::ios::hex) + base = BigInt::Hexadecimal; + else if (stream.flags() & std::ios::oct) + base = BigInt::Octal; + + if (n == 0) + stream.write("0", 1); + else { + if (n < 0) + stream.write("-", 1); + SecureVector buffer = BigInt::encode(n, base); + u32bit skip = 0; + while (skip < buffer.size() && buffer[skip] == '0') + ++skip; + stream.write((const char *)buffer.begin() + skip, buffer.size() - skip); + } + if (!stream.good()) + throw Stream_IO_Error("BigInt output operator has failed"); + return stream; +} + +/************************************************* + * Read the BigInt from a stream * + *************************************************/ +std::istream &operator>>(std::istream &stream, BigInt &n) +{ + std::string str; + std::getline(stream, str); + if (stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("BigInt input operator has failed"); + n = BigInt(str); + return stream; +} + +#endif + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/big_ops2.cpp b/local/recipes/libs/qca/source/src/botantools/botan/big_ops2.cpp new file mode 100644 index 0000000000..bf3356f7e7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/big_ops2.cpp @@ -0,0 +1,243 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Assignment Operators Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Addition Operator * + *************************************************/ +BigInt &BigInt::operator+=(const BigInt &y) +{ + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + +#ifdef BOTAN_TYPES_QT + const u32bit reg_size = qMax(x_sw, y_sw) + 1; +#else + const u32bit reg_size = std::max(x_sw, y_sw) + 1; +#endif + grow_to(reg_size); + + if ((sign() == y.sign())) + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + else { + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + + if (relative_size < 0) { + SecureVector z(reg_size - 1); + bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); + copy_mem(reg.begin(), z.begin(), z.size()); + set_sign(y.sign()); + } else if (relative_size == 0) { + reg.clear(); + set_sign(Positive); + } else if (relative_size > 0) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + } + + return (*this); +} + +/************************************************* + * Subtraction Operator * + *************************************************/ +BigInt &BigInt::operator-=(const BigInt &y) +{ + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + +#ifdef BOTAN_TYPES_QT + const u32bit reg_size = qMax(x_sw, y_sw) + 1; +#else + const u32bit reg_size = std::max(x_sw, y_sw) + 1; +#endif + grow_to(reg_size); + + if (relative_size < 0) { + if (sign() == y.sign()) { + SecureVector z(reg_size - 1); + bigint_sub3(z, y.data(), reg_size - 1, data(), x_sw); + copy_mem(reg.begin(), z.begin(), z.size()); + } else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + + set_sign(y.reverse_sign()); + } else if (relative_size == 0) { + if (sign() == y.sign()) { + reg.clear(); + set_sign(Positive); + } else + bigint_shl1(get_reg(), x_sw, 0, 1); + } else if (relative_size > 0) { + if (sign() == y.sign()) + bigint_sub2(get_reg(), x_sw, y.data(), y_sw); + else + bigint_add2(get_reg(), reg_size - 1, y.data(), y_sw); + } + + return (*this); +} + +/************************************************* + * Multiplication Operator * + *************************************************/ +BigInt &BigInt::operator*=(const BigInt &y) +{ + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + set_sign((sign() == y.sign()) ? Positive : Negative); + + if (x_sw == 0 || y_sw == 0) { + reg.clear(); + set_sign(Positive); + } else if (x_sw == 1 && y_sw) { + grow_to(y_sw + 2); + bigint_linmul3(get_reg(), y.data(), y_sw, word_at(0)); + } else if (y_sw == 1 && x_sw) { + grow_to(x_sw + 2); + bigint_linmul2(get_reg(), x_sw, y.word_at(0)); + } else { + grow_to(size() + y.size()); + + SecureVector z(data(), x_sw); + SecureVector workspace(size()); + + bigint_mul(get_reg(), size(), workspace, z, z.size(), x_sw, y.data(), y.size(), y_sw); + } + + return (*this); +} + +/************************************************* + * Division Operator * + *************************************************/ +BigInt &BigInt::operator/=(const BigInt &y) +{ + if (y.sig_words() == 1 && power_of_2(y.word_at(0))) + (*this) >>= (y.bits() - 1); + else + (*this) = (*this) / y; + return (*this); +} + +/************************************************* + * Modulo Operator * + *************************************************/ +BigInt &BigInt::operator%=(const BigInt &mod) +{ + return (*this = (*this) % mod); +} + +/************************************************* + * Modulo Operator * + *************************************************/ +word BigInt::operator%=(word mod) +{ + if (mod == 0) + throw BigInt::DivideByZero(); + if (power_of_2(mod)) { + word result = (word_at(0) & (mod - 1)); + clear(); + grow_to(2); + reg[0] = result; + return result; + } + + word remainder = 0; + + for (u32bit j = sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, word_at(j - 1), mod); + clear(); + grow_to(2); + + if (remainder && sign() == BigInt::Negative) + reg[0] = mod - remainder; + else + reg[0] = remainder; + + set_sign(BigInt::Positive); + + return word_at(0); +} + +/************************************************* + * Left Shift Operator * + *************************************************/ +BigInt &BigInt::operator<<=(u32bit shift) +{ + if (shift) { + const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS, words = sig_words(); + + grow_to(words + shift_words + (shift_bits ? 1 : 0)); + bigint_shl1(get_reg(), words, shift_words, shift_bits); + } + + return (*this); +} + +/************************************************* + * Right Shift Operator * + *************************************************/ +BigInt &BigInt::operator>>=(u32bit shift) +{ + if (shift) { + const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS; + + bigint_shr1(get_reg(), sig_words(), shift_words, shift_bits); + + if (is_zero()) + set_sign(Positive); + } + + return (*this); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/big_ops3.cpp b/local/recipes/libs/qca/source/src/botantools/botan/big_ops3.cpp new file mode 100644 index 0000000000..25d408ed09 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/big_ops3.cpp @@ -0,0 +1,220 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Binary Operators Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Addition Operator * + *************************************************/ +BigInt operator+(const BigInt &x, const BigInt &y) +{ + const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); + +#ifdef BOTAN_TYPES_QT + BigInt z(x.sign(), qMax(x_sw, y_sw) + 1); +#else + BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); +#endif + + if ((x.sign() == y.sign())) + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + else { + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + + if (relative_size < 0) { + bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); + z.set_sign(y.sign()); + } else if (relative_size == 0) + z.set_sign(BigInt::Positive); + else if (relative_size > 0) + bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + } + + return z; +} + +/************************************************* + * Subtraction Operator * + *************************************************/ +BigInt operator-(const BigInt &x, const BigInt &y) +{ + const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); + + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + +#ifdef BOTAN_TYPES_QT + BigInt z(BigInt::Positive, qMax(x_sw, y_sw) + 1); +#else + BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); +#endif + + if (relative_size < 0) { + if (x.sign() == y.sign()) + bigint_sub3(z.get_reg(), y.data(), y_sw, x.data(), x_sw); + else + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(y.reverse_sign()); + } else if (relative_size == 0) { + if (x.sign() != y.sign()) + bigint_shl2(z.get_reg(), x.data(), x_sw, 0, 1); + } else if (relative_size > 0) { + if (x.sign() == y.sign()) + bigint_sub3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + else + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); + z.set_sign(x.sign()); + } + return z; +} + +/************************************************* + * Multiplication Operator * + *************************************************/ +BigInt operator*(const BigInt &x, const BigInt &y) +{ + const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); + + BigInt z(BigInt::Positive, x.size() + y.size()); + + if (x_sw == 1 && y_sw) + bigint_linmul3(z.get_reg(), y.data(), y_sw, x.word_at(0)); + else if (y_sw == 1 && x_sw) + bigint_linmul3(z.get_reg(), x.data(), x_sw, y.word_at(0)); + else if (x_sw && y_sw) { + SecureVector workspace(z.size()); + bigint_mul(z.get_reg(), z.size(), workspace, x.data(), x.size(), x_sw, y.data(), y.size(), y_sw); + } + + if (x_sw && y_sw && x.sign() != y.sign()) + z.flip_sign(); + return z; +} + +/************************************************* + * Division Operator * + *************************************************/ +BigInt operator/(const BigInt &x, const BigInt &y) +{ + BigInt q, r; + divide(x, y, q, r); + return q; +} + +/************************************************* + * Modulo Operator * + *************************************************/ +BigInt operator%(const BigInt &n, const BigInt &mod) +{ + if (mod.is_zero()) + throw BigInt::DivideByZero(); + if (mod.is_negative()) + throw Invalid_Argument("BigInt::operator%: modulus must be > 0"); + if (n.is_positive() && mod.is_positive() && n < mod) + return n; + + BigInt q, r; + divide(n, mod, q, r); + return r; +} + +/************************************************* + * Modulo Operator * + *************************************************/ +word operator%(const BigInt &n, word mod) +{ + if (mod == 0) + throw BigInt::DivideByZero(); + if (power_of_2(mod)) + return (n.word_at(0) & (mod - 1)); + + word remainder = 0; + + for (u32bit j = n.sig_words(); j > 0; --j) + remainder = bigint_modop(remainder, n.word_at(j - 1), mod); + + if (remainder && n.sign() == BigInt::Negative) + return mod - remainder; + return remainder; +} + +/************************************************* + * Left Shift Operator * + *************************************************/ +BigInt operator<<(const BigInt &x, u32bit shift) +{ + if (shift == 0) + return x; + + const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS; + + const u32bit x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw + shift_words + (shift_bits ? 1 : 0)); + bigint_shl2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); + return y; +} + +/************************************************* + * Right Shift Operator * + *************************************************/ +BigInt operator>>(const BigInt &x, u32bit shift) +{ + if (shift == 0) + return x; + if (x.bits() <= shift) + return 0; + + const u32bit shift_words = shift / MP_WORD_BITS, shift_bits = shift % MP_WORD_BITS, x_sw = x.sig_words(); + + BigInt y(x.sign(), x_sw - shift_words); + bigint_shr2(y.get_reg(), x.data(), x_sw, shift_words, shift_bits); + return y; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/bit_ops.cpp b/local/recipes/libs/qca/source/src/botantools/botan/bit_ops.cpp new file mode 100644 index 0000000000..c0a17e5f85 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/bit_ops.cpp @@ -0,0 +1,139 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Bit/Word Operations Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * XOR arrays together * + *************************************************/ +void xor_buf(byte data[], const byte mask[], u32bit length) +{ + while (length >= 8) { + data[0] ^= mask[0]; + data[1] ^= mask[1]; + data[2] ^= mask[2]; + data[3] ^= mask[3]; + data[4] ^= mask[4]; + data[5] ^= mask[5]; + data[6] ^= mask[6]; + data[7] ^= mask[7]; + data += 8; + mask += 8; + length -= 8; + } + for (u32bit j = 0; j != length; ++j) + data[j] ^= mask[j]; +} + +void xor_buf(byte out[], const byte in[], const byte mask[], u32bit length) +{ + while (length >= 8) { + out[0] = in[0] ^ mask[0]; + out[1] = in[1] ^ mask[1]; + out[2] = in[2] ^ mask[2]; + out[3] = in[3] ^ mask[3]; + out[4] = in[4] ^ mask[4]; + out[5] = in[5] ^ mask[5]; + out[6] = in[6] ^ mask[6]; + out[7] = in[7] ^ mask[7]; + in += 8; + out += 8; + mask += 8; + length -= 8; + } + for (u32bit j = 0; j != length; ++j) + out[j] = in[j] ^ mask[j]; +} + +/************************************************* + * Return true iff arg is 2**n for some n > 0 * + *************************************************/ +bool power_of_2(u64bit arg) +{ + if (arg == 0 || arg == 1) + return false; + if ((arg & (arg - 1)) == 0) + return true; + return false; +} + +/************************************************* + * Return the index of the highest set bit * + *************************************************/ +u32bit high_bit(u64bit n) +{ + for (u32bit count = 64; count > 0; --count) + if ((n >> (count - 1)) & 0x01) + return count; + return 0; +} + +/************************************************* + * Return the index of the lowest set bit * + *************************************************/ +u32bit low_bit(u64bit n) +{ + for (u32bit count = 0; count != 64; ++count) + if ((n >> count) & 0x01) + return (count + 1); + return 0; +} + +/************************************************* + * Return the number of significant bytes in n * + *************************************************/ +u32bit significant_bytes(u64bit n) +{ + for (u32bit j = 0; j != 8; ++j) + if (get_byte(j, n)) + return 8 - j; + return 0; +} + +/************************************************* + * Return the Hamming weight of n * + *************************************************/ +u32bit hamming_weight(u64bit n) +{ + u32bit weight = 0; + for (u32bit j = 0; j != 64; ++j) + if ((n >> j) & 0x01) + ++weight; + return weight; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/allocate.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/allocate.h new file mode 100644 index 0000000000..53c01f6548 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/allocate.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Allocator Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_ALLOCATOR_H__ +#define BOTAN_ALLOCATOR_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +#if __cplusplus >= 201103L +#define QCA_NOEXCEPT(x) noexcept(x) +#else +#define QCA_NOEXCEPT(x) +#endif + +namespace Botan { + +/************************************************* + * Allocator * + *************************************************/ +class Allocator +{ +public: + static Allocator *get(bool); + + virtual void *allocate(u32bit) = 0; + virtual void deallocate(void *, u32bit) = 0; + + virtual std::string type() const = 0; + + virtual void init() + { + } + virtual void destroy() + { + } + + virtual ~Allocator() QCA_NOEXCEPT(false) + { + } +}; + +/************************************************* + * Get an allocator * + *************************************************/ + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/bigint.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/bigint.h new file mode 100644 index 0000000000..0d5a47ca0f --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/bigint.h @@ -0,0 +1,304 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * BigInt Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_BIGINT_H__ +#define BOTAN_BIGINT_H__ + +#ifdef BOTAN_MINIMAL_BIGINT +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#else +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * BigInt * + *************************************************/ +class BigInt // clazy:exclude=rule-of-three TODO Needs checking if a real bug or not +{ +public: + enum Base + { + Octal = 8, + Decimal = 10, + Hexadecimal = 16, + Binary = 256 + }; + enum Sign + { + Negative = 0, + Positive = 1 + }; + enum NumberType + { + Random, + Power2 + }; + + struct DivideByZero : public Exception + { + DivideByZero() + : Exception("BigInt divide by zero") + { + } + }; + + BigInt &operator+=(const BigInt &); + BigInt &operator-=(const BigInt &); + + BigInt &operator*=(const BigInt &); + BigInt &operator/=(const BigInt &); + BigInt &operator%=(const BigInt &); + word operator%=(word); + BigInt &operator<<=(u32bit); + BigInt &operator>>=(u32bit); + + BigInt &operator++() + { + return (*this += 1); + } + BigInt &operator--() + { + return (*this -= 1); + } + BigInt operator++(int) + { + BigInt x = (*this); + ++(*this); + return x; + } + BigInt operator--(int) + { + BigInt x = (*this); + --(*this); + return x; + } + + BigInt operator-() const; + bool operator!() const + { + return (!is_nonzero()); + } + + s32bit cmp(const BigInt &, bool = true) const; + bool is_even() const + { + return (get_bit(0) == 0); + } + bool is_odd() const + { + return (get_bit(0) == 1); + } + bool is_nonzero() const + { + return (!is_zero()); + } + bool is_zero() const; + + void set_bit(u32bit); + void clear_bit(u32bit); + void mask_bits(u32bit); + + bool get_bit(u32bit) const; + u32bit get_substring(u32bit, u32bit) const; + byte byte_at(u32bit) const; + word word_at(u32bit n) const + { + return ((n < size()) ? reg[n] : 0); + } + + u32bit to_u32bit() const; + + bool is_negative() const + { + return (sign() == Negative); + } + bool is_positive() const + { + return (sign() == Positive); + } + Sign sign() const + { + return (signedness); + } + Sign reverse_sign() const; + void flip_sign(); + void set_sign(Sign); + BigInt abs() const; + + u32bit size() const + { + return reg.size(); + } + u32bit sig_words() const; + u32bit bytes() const; + u32bit bits() const; + + const word *data() const + { + return reg.begin(); + } + SecureVector &get_reg() + { + return reg; + } + void grow_reg(u32bit) const; + + word &operator[](u32bit index) + { + return reg[index]; + } + word operator[](u32bit index) const + { + return reg[index]; + } + void clear() + { + reg.clear(); + } + +#ifndef BOTAN_MINIMAL_BIGINT + void randomize(u32bit = 0); +#endif + + void binary_encode(byte[]) const; + void binary_decode(const byte[], u32bit); + u32bit encoded_size(Base = Binary) const; + + static SecureVector encode(const BigInt &, Base = Binary); + static void encode(byte[], const BigInt &, Base = Binary); + static BigInt decode(const byte[], u32bit, Base = Binary); + static BigInt decode(const MemoryRegion &, Base = Binary); + static SecureVector encode_1363(const BigInt &, u32bit); + + void swap(BigInt &); + + BigInt() + { + signedness = Positive; + } + BigInt(u64bit); + BigInt(const BigInt &); + BigInt(const std::string &); + BigInt(const byte[], u32bit, Base = Binary); + BigInt(Sign, u32bit); +#ifndef BOTAN_MINIMAL_BIGINT + BigInt(NumberType, u32bit); +#endif + BigInt &operator=(const BigInt &); + +private: + void grow_to(u32bit) const; + SecureVector reg; + Sign signedness; +}; + +/************************************************* + * Arithmetic Operators * + *************************************************/ +BigInt operator+(const BigInt &, const BigInt &); +BigInt operator-(const BigInt &, const BigInt &); +BigInt operator*(const BigInt &, const BigInt &); +BigInt operator/(const BigInt &, const BigInt &); +BigInt operator%(const BigInt &, const BigInt &); +word operator%(const BigInt &, word); +BigInt operator<<(const BigInt &, u32bit); +BigInt operator>>(const BigInt &, u32bit); + +/************************************************* + * Comparison Operators * + *************************************************/ +inline bool operator==(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) == 0); +} +inline bool operator!=(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) != 0); +} +inline bool operator<=(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) <= 0); +} +inline bool operator>=(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) >= 0); +} +inline bool operator<(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) < 0); +} +inline bool operator>(const BigInt &a, const BigInt &b) +{ + return (a.cmp(b) > 0); +} + +/************************************************* + * I/O Operators * + *************************************************/ +#ifndef BOTAN_MINIMAL_BIGINT +std::ostream &operator<<(std::ostream &, const BigInt &); +std::istream &operator>>(std::istream &, BigInt &); +#endif + +} + +#ifndef BOTAN_MINIMAL_BIGINT +} // WRAPNS_LINE +namespace std { + +inline void swap(Botan::BigInt &a, Botan::BigInt &b) +{ + a.swap(b); +} + +} +namespace QCA { // WRAPNS_LINE +#endif + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/bit_ops.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/bit_ops.h new file mode 100644 index 0000000000..64b319206c --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/bit_ops.h @@ -0,0 +1,101 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Bit/Word Operations Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_BIT_OPS_H__ +#define BOTAN_BIT_OPS_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Rotation Functions * + *************************************************/ +template inline T rotate_left(T input, u32bit rot) +{ + return (T)((input << rot) | (input >> (8 * sizeof(T) - rot))); +} + +template inline T rotate_right(T input, u32bit rot) +{ + return (T)((input >> rot) | (input << (8 * sizeof(T) - rot))); +} + +/************************************************* + * Byte Extraction Function * + *************************************************/ +template inline byte get_byte(u32bit byte_num, T input) +{ + return (byte)(input >> ((sizeof(T) - 1 - (byte_num & (sizeof(T) - 1))) << 3)); +} + +/************************************************* + * Byte to Word Conversions * + *************************************************/ +inline u16bit make_u16bit(byte input0, byte input1) +{ + return (u16bit)(((u16bit)input0 << 8) | input1); +} + +inline u32bit make_u32bit(byte input0, byte input1, byte input2, byte input3) +{ + return (u32bit)(((u32bit)input0 << 24) | ((u32bit)input1 << 16) | ((u32bit)input2 << 8) | input3); +} + +inline u64bit +make_u64bit(byte input0, byte input1, byte input2, byte input3, byte input4, byte input5, byte input6, byte input7) +{ + return (u64bit)(((u64bit)input0 << 56) | ((u64bit)input1 << 48) | ((u64bit)input2 << 40) | ((u64bit)input3 << 32) | + ((u64bit)input4 << 24) | ((u64bit)input5 << 16) | ((u64bit)input6 << 8) | input7); +} + +/************************************************* + * XOR Functions * + *************************************************/ +void xor_buf(byte[], const byte[], u32bit); +void xor_buf(byte[], const byte[], const byte[], u32bit); + +/************************************************* + * Misc Utility Functions * + *************************************************/ +bool power_of_2(u64bit); +u32bit high_bit(u64bit); +u32bit low_bit(u64bit); +u32bit significant_bytes(u64bit); +u32bit hamming_weight(u64bit); + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/charset.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/charset.h new file mode 100644 index 0000000000..84665fa4c4 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/charset.h @@ -0,0 +1,86 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Character Set Handling Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_CHARSET_H__ +#define BOTAN_CHARSET_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Character Set Transcoder Interface * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +class Charset_Transcoder +{ +public: + virtual std::string transcode(const std::string &, Character_Set, Character_Set) const = 0; + + virtual ~Charset_Transcoder() + { + } +}; +#endif + +namespace Charset { + +/************************************************* + * Character Set Handling * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +std::string transcode(const std::string &, Character_Set, Character_Set); +#endif + +bool is_digit(char); +bool is_space(char); +bool caseless_cmp(char, char); + +byte char2digit(char); +char digit2char(byte); + +} + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/defalloc.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/defalloc.h new file mode 100644 index 0000000000..b6bcddaeab --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/defalloc.h @@ -0,0 +1,85 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Basic Allocators Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_BASIC_ALLOC_H__ +#define BOTAN_BASIC_ALLOC_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Malloc Allocator * + *************************************************/ +class Malloc_Allocator : public Pooling_Allocator +{ +public: + Malloc_Allocator() + : Pooling_Allocator(64 * 1024, false) + { + } + std::string type() const override + { + return "malloc"; + } + +private: + void *alloc_block(u32bit) override; + void dealloc_block(void *, u32bit) override; +}; + +/************************************************* + * Locking Allocator * + *************************************************/ +class Locking_Allocator : public Pooling_Allocator +{ +public: + Locking_Allocator() + : Pooling_Allocator(64 * 1024, true) + { + } + std::string type() const override + { + return "locking"; + } + +private: + void *alloc_block(u32bit) override; + void dealloc_block(void *, u32bit) override; +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/exceptn.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/exceptn.h new file mode 100644 index 0000000000..fac1a8c37b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/exceptn.h @@ -0,0 +1,293 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Exceptions Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_EXCEPTION_H__ +#define BOTAN_EXCEPTION_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Exception Base Class * + *************************************************/ +class Exception : public std::exception +{ +public: + const char *what() const throw() override + { + return msg.c_str(); + } + Exception(const std::string &m = "Unknown error") + { + set_msg(m); + } + ~Exception() throw() override + { + } + +protected: + void set_msg(const std::string &m) + { + msg = "Botan: " + m; + } + +private: + std::string msg; +}; + +/************************************************* + * Invalid_Argument Exception * + *************************************************/ +struct Invalid_Argument : public Exception +{ + Invalid_Argument(const std::string &err = "") + : Exception(err) + { + } +}; + +/************************************************* + * Invalid_Key_Length Exception * + *************************************************/ +struct Invalid_Key_Length : public Invalid_Argument +{ + Invalid_Key_Length(const std::string &, u32bit); +}; + +/************************************************* + * Invalid_Block_Size Exception * + *************************************************/ +struct Invalid_Block_Size : public Invalid_Argument +{ + Invalid_Block_Size(const std::string &, const std::string &); +}; + +/************************************************* + * Invalid_IV_Length Exception * + *************************************************/ +struct Invalid_IV_Length : public Invalid_Argument +{ + Invalid_IV_Length(const std::string &, u32bit); +}; + +/************************************************* + * Invalid_Message_Number Exception * + *************************************************/ +struct Invalid_Message_Number : public Invalid_Argument +{ + Invalid_Message_Number(const std::string &, u32bit); +}; + +/************************************************* + * Invalid_State Exception * + *************************************************/ +struct Invalid_State : public Exception +{ + Invalid_State(const std::string &err) + : Exception(err) + { + } +}; + +/************************************************* + * PRNG_Unseeded Exception * + *************************************************/ +struct PRNG_Unseeded : public Invalid_State +{ + PRNG_Unseeded(const std::string &algo) + : Invalid_State("PRNG not seeded: " + algo) + { + } +}; + +/************************************************* + * Policy_Violation Exception * + *************************************************/ +struct Policy_Violation : public Invalid_State +{ + Policy_Violation(const std::string &err) + : Invalid_State("Policy violation: " + err) + { + } +}; + +/************************************************* + * Lookup_Error Exception * + *************************************************/ +struct Lookup_Error : public Exception +{ + Lookup_Error(const std::string &err) + : Exception(err) + { + } +}; + +/************************************************* + * Algorithm_Not_Found Exception * + *************************************************/ +struct Algorithm_Not_Found : public Exception +{ + Algorithm_Not_Found(const std::string &); +}; + +/************************************************* + * Format_Error Exception * + *************************************************/ +struct Format_Error : public Exception +{ + Format_Error(const std::string &err = "") + : Exception(err) + { + } +}; + +/************************************************* + * Invalid_Algorithm_Name Exception * + *************************************************/ +struct Invalid_Algorithm_Name : public Format_Error +{ + Invalid_Algorithm_Name(const std::string &); +}; + +/************************************************* + * Encoding_Error Exception * + *************************************************/ +struct Encoding_Error : public Format_Error +{ + Encoding_Error(const std::string &name) + : Format_Error("Encoding error: " + name) + { + } +}; + +/************************************************* + * Decoding_Error Exception * + *************************************************/ +struct Decoding_Error : public Format_Error +{ + Decoding_Error(const std::string &name) + : Format_Error("Decoding error: " + name) + { + } +}; + +/************************************************* + * Invalid_OID Exception * + *************************************************/ +struct Invalid_OID : public Decoding_Error +{ + Invalid_OID(const std::string &oid) + : Decoding_Error("Invalid ASN.1 OID: " + oid) + { + } +}; + +/************************************************* + * Stream_IO_Error Exception * + *************************************************/ +struct Stream_IO_Error : public Exception +{ + Stream_IO_Error(const std::string &err) + : Exception("I/O error: " + err) + { + } +}; + +/************************************************* + * Configuration Error Exception * + *************************************************/ +struct Config_Error : public Format_Error +{ + Config_Error(const std::string &err) + : Format_Error("Config error: " + err) + { + } + Config_Error(const std::string &, u32bit); +}; + +/************************************************* + * Integrity Failure Exception * + *************************************************/ +struct Integrity_Failure : public Exception +{ + Integrity_Failure(const std::string &err) + : Exception("Integrity failure: " + err) + { + } +}; + +/************************************************* + * Internal_Error Exception * + *************************************************/ +struct Internal_Error : public Exception +{ + Internal_Error(const std::string &err) + : Exception("Internal error: " + err) + { + } +}; + +/************************************************* + * Self Test Failure Exception * + *************************************************/ +struct Self_Test_Failure : public Internal_Error +{ + Self_Test_Failure(const std::string &err) + : Internal_Error("Self test failed: " + err) + { + } +}; + +/************************************************* + * Memory Allocation Exception * + *************************************************/ +struct Memory_Exhaustion : public Exception +{ + Memory_Exhaustion() + : Exception("Ran out of memory, allocation failed") + { + } +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/libstate.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/libstate.h new file mode 100644 index 0000000000..040a17c31d --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/libstate.h @@ -0,0 +1,198 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Library Internal/Global State Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_LIB_STATE_H__ +#define BOTAN_LIB_STATE_H__ + +#ifdef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#else +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Global State Container Base * + *************************************************/ +class Library_State +{ +public: +#ifndef BOTAN_TOOLS_ONLY + class Engine_Iterator + { + public: + class Engine *next(); + Engine_Iterator(const Library_State &l) + : lib(l) + { + n = 0; + } + + private: + const Library_State &lib; + u32bit n; + }; + friend class Engine_Iterator; + + class UI + { + public: + virtual void pulse(Pulse_Type) + { + } + virtual ~UI() + { + } + }; +#endif + + int prealloc_size; + Allocator *get_allocator(const std::string & = "") const; + void add_allocator(Allocator *); +#ifdef BOTAN_TOOLS_ONLY + void set_default_allocator(const std::string &); +#else + void set_default_allocator(const std::string &) const; +#endif + +#ifndef BOTAN_TOOLS_ONLY + bool rng_is_seeded() const + { + return rng->is_seeded(); + } + void randomize(byte[], u32bit); + + void set_prng(RandomNumberGenerator *); + void add_entropy_source(EntropySource *, bool = true); + void add_entropy(const byte[], u32bit); + void add_entropy(EntropySource &, bool); + u32bit seed_prng(bool, u32bit); +#endif + + void load(class Modules &); + +#ifndef BOTAN_TOOLS_ONLY + void set_timer(class Timer *); + u64bit system_clock() const; + + class Config &config() const; + + void add_engine(class Engine *); +#endif + + class Mutex *get_mutex() const; + class Mutex *get_named_mutex(const std::string &); + +#ifndef BOTAN_TOOLS_ONLY + void set_x509_state(class X509_GlobalState *); + class X509_GlobalState &x509_state(); + + void pulse(Pulse_Type) const; + void set_ui(UI *); + + void set_transcoder(class Charset_Transcoder *); + std::string transcode(const std::string, Character_Set, Character_Set) const; +#endif + + Library_State(class Mutex_Factory *); + ~Library_State(); + +private: + Library_State(const Library_State &) + { + } + Library_State &operator=(const Library_State &) + { + return (*this); + } + +#ifndef BOTAN_TOOLS_ONLY + class Engine *get_engine_n(u32bit) const; +#endif + + class Mutex_Factory *mutex_factory; +#ifndef BOTAN_TOOLS_ONLY + class Timer *timer; + class Config *config_obj; + class X509_GlobalState *x509_state_obj; +#endif + + std::map locks; + std::map alloc_factory; + mutable Allocator *cached_default_allocator; +#ifdef BOTAN_TOOLS_ONLY + std::string default_allocator_type; +#endif + +#ifndef BOTAN_TOOLS_ONLY + UI *ui; + class Charset_Transcoder *transcoder; + RandomNumberGenerator *rng; +#endif + std::vector allocators; +#ifndef BOTAN_TOOLS_ONLY + std::vector entropy_sources; + std::vector engines; +#endif +}; + +/************************************************* + * Global State * + *************************************************/ +Library_State &global_state(); +void set_global_state(Library_State *); +Library_State *swap_global_state(Library_State *); + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_ops.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_ops.h new file mode 100644 index 0000000000..be5ba3e3a7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_ops.h @@ -0,0 +1,74 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Operations Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MEMORY_OPS_H__ +#define BOTAN_MEMORY_OPS_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Memory Manipulation Functions * + *************************************************/ +template inline void copy_mem(T *out, const T *in, u32bit n) +{ + memmove(out, in, sizeof(T) * n); +} + +template inline void clear_mem(T *ptr, u32bit n) +{ + memset(ptr, 0, sizeof(T) * n); +} + +template inline void set_mem(T *ptr, u32bit n, byte val) +{ + memset(ptr, val, sizeof(T) * n); +} + +template inline bool same_mem(const T *p1, const T *p2, u32bit n) +{ + return (memcmp(p1, p2, sizeof(T) * n) == 0); +} + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_pool.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_pool.h new file mode 100644 index 0000000000..1decf59d2e --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mem_pool.h @@ -0,0 +1,120 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Pooling Allocator Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_POOLING_ALLOCATOR_H__ +#define BOTAN_POOLING_ALLOCATOR_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Pooling Allocator * + *************************************************/ +class Pooling_Allocator : public Allocator +{ +public: + void *allocate(u32bit) override; + void deallocate(void *, u32bit) override; + + void destroy() override; + + Pooling_Allocator(u32bit, bool); + ~Pooling_Allocator() QCA_NOEXCEPT(false) override; + +private: + void get_more_core(u32bit); + byte *allocate_blocks(u32bit); + + virtual void *alloc_block(u32bit) = 0; + virtual void dealloc_block(void *, u32bit) = 0; + + class Memory_Block + { + public: + Memory_Block(void *); + + static u32bit bitmap_size() + { + return BITMAP_SIZE; + } + static u32bit block_size() + { + return BLOCK_SIZE; + } + + bool contains(void *, u32bit) const throw(); + byte *alloc(u32bit) throw(); + void free(void *, u32bit) throw(); + + bool operator<(const Memory_Block &other) const + { + if (buffer < other.buffer && other.buffer < buffer_end) + return false; + return (buffer < other.buffer); + } + + private: + typedef u64bit bitmap_type; + static const u32bit BITMAP_SIZE; + static const u32bit BLOCK_SIZE; + + bitmap_type bitmap; + byte *buffer, *buffer_end; + }; + + const u32bit PREF_SIZE; + + std::vector blocks; + std::vector::iterator last_used; + std::vector> allocated; + Mutex *mutex; +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mmap_mem.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mmap_mem.h new file mode 100644 index 0000000000..cf74424b54 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mmap_mem.h @@ -0,0 +1,65 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Mapping Allocator Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_EXT_MMAP_ALLOCATOR_H__ +#define BOTAN_EXT_MMAP_ALLOCATOR_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Memory Mapping Allocator * + *************************************************/ +class MemoryMapping_Allocator : public Pooling_Allocator +{ +public: + MemoryMapping_Allocator() + : Pooling_Allocator(64 * 1024, false) + { + } + std::string type() const override + { + return "mmap"; + } + +private: + void *alloc_block(u32bit) override; + void dealloc_block(void *, u32bit) override; +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/modules.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/modules.h new file mode 100644 index 0000000000..23339a15eb --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/modules.h @@ -0,0 +1,111 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Module Factory Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MODULE_FACTORIES_H__ +#define BOTAN_MODULE_FACTORIES_H__ + +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Module Builder Interface * + *************************************************/ +class Modules +{ +public: + virtual class Mutex_Factory *mutex_factory() const = 0; +#ifndef BOTAN_TOOLS_ONLY + virtual class Timer *timer() const = 0; + virtual class Charset_Transcoder *transcoder() const = 0; +#endif + + virtual std::string default_allocator() const = 0; + + virtual std::vector allocators() const = 0; +#ifndef BOTAN_TOOLS_ONLY + virtual std::vector entropy_sources() const = 0; + virtual std::vector engines() const = 0; +#endif + + virtual ~Modules() + { + } +}; + +/************************************************* + * Built In Modules * + *************************************************/ +class Builtin_Modules : public Modules +{ +public: + class Mutex_Factory *mutex_factory() const override; +#ifndef BOTAN_TOOLS_ONLY + class Timer *timer() const; + class Charset_Transcoder *transcoder() const; +#endif + + std::string default_allocator() const override; + + std::vector allocators() const override; +#ifndef BOTAN_TOOLS_ONLY + std::vector entropy_sources() const; + std::vector engines() const; +#endif + +#ifdef BOTAN_TOOLS_ONLY + Builtin_Modules(); +#else + Builtin_Modules(const InitializerOptions &); +#endif +private: +#ifdef BOTAN_TOOLS_ONLY + const bool should_lock; +#else + const bool should_lock, use_engines; +#endif +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asm.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asm.h new file mode 100644 index 0000000000..7734023b8b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asm.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Lowest Level MPI Algorithms Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MP_ASM_H__ +#define BOTAN_MP_ASM_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +#if (BOTAN_MP_WORD_BITS == 8) +typedef Botan::u16bit dword; +#elif (BOTAN_MP_WORD_BITS == 16) +typedef Botan::u32bit dword; +#elif (BOTAN_MP_WORD_BITS == 32) +typedef Botan::u64bit dword; +#elif (BOTAN_MP_WORD_BITS == 64) +#error BOTAN_MP_WORD_BITS can be 64 only with assembly support +#else +#error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +namespace Botan { + +extern "C" { + +/************************************************* + * Word Multiply/Add * + *************************************************/ +inline word word_madd2(word a, word b, word c, word *carry) +{ + dword z = (dword)a * b + c; + *carry = (word)(z >> BOTAN_MP_WORD_BITS); + return (word)z; +} + +/************************************************* + * Word Multiply/Add * + *************************************************/ +inline word word_madd3(word a, word b, word c, word d, word *carry) +{ + dword z = (dword)a * b + c + d; + *carry = (word)(z >> BOTAN_MP_WORD_BITS); + return (word)z; +} +} + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asmi.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asmi.h new file mode 100644 index 0000000000..3318864a22 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_asmi.h @@ -0,0 +1,212 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Lowest Level MPI Algorithms Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MP_ASM_INTERNAL_H__ +#define BOTAN_MP_ASM_INTERNAL_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Word Addition * + *************************************************/ +inline word word_add(word x, word y, word *carry) +{ + word z = x + y; + word c1 = (z < x); + z += *carry; + *carry = c1 | (z < *carry); + return z; +} + +/************************************************* + * Eight Word Block Addition, Two Argument * + *************************************************/ +inline word word8_add2(word x[8], const word y[8], word carry) +{ + x[0] = word_add(x[0], y[0], &carry); + x[1] = word_add(x[1], y[1], &carry); + x[2] = word_add(x[2], y[2], &carry); + x[3] = word_add(x[3], y[3], &carry); + x[4] = word_add(x[4], y[4], &carry); + x[5] = word_add(x[5], y[5], &carry); + x[6] = word_add(x[6], y[6], &carry); + x[7] = word_add(x[7], y[7], &carry); + return carry; +} + +/************************************************* + * Eight Word Block Addition, Three Argument * + *************************************************/ +inline word word8_add3(word z[8], const word x[8], const word y[8], word carry) +{ + z[0] = word_add(x[0], y[0], &carry); + z[1] = word_add(x[1], y[1], &carry); + z[2] = word_add(x[2], y[2], &carry); + z[3] = word_add(x[3], y[3], &carry); + z[4] = word_add(x[4], y[4], &carry); + z[5] = word_add(x[5], y[5], &carry); + z[6] = word_add(x[6], y[6], &carry); + z[7] = word_add(x[7], y[7], &carry); + return carry; +} + +/************************************************* + * Word Subtraction * + *************************************************/ +inline word word_sub(word x, word y, word *carry) +{ + word t0 = x - y; + word c1 = (t0 > x); + word z = t0 - *carry; + *carry = c1 | (z > t0); + return z; +} + +/************************************************* + * Eight Word Block Subtraction, Two Argument * + *************************************************/ +inline word word8_sub2(word x[4], const word y[4], word carry) +{ + x[0] = word_sub(x[0], y[0], &carry); + x[1] = word_sub(x[1], y[1], &carry); + x[2] = word_sub(x[2], y[2], &carry); + x[3] = word_sub(x[3], y[3], &carry); + x[4] = word_sub(x[4], y[4], &carry); + x[5] = word_sub(x[5], y[5], &carry); + x[6] = word_sub(x[6], y[6], &carry); + x[7] = word_sub(x[7], y[7], &carry); + return carry; +} + +/************************************************* + * Eight Word Block Subtraction, Three Argument * + *************************************************/ +inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry) +{ + z[0] = word_sub(x[0], y[0], &carry); + z[1] = word_sub(x[1], y[1], &carry); + z[2] = word_sub(x[2], y[2], &carry); + z[3] = word_sub(x[3], y[3], &carry); + z[4] = word_sub(x[4], y[4], &carry); + z[5] = word_sub(x[5], y[5], &carry); + z[6] = word_sub(x[6], y[6], &carry); + z[7] = word_sub(x[7], y[7], &carry); + return carry; +} + +/************************************************* + * Eight Word Block Linear Multiplication * + *************************************************/ +inline word word8_linmul2(word x[4], word y, word carry) +{ + x[0] = word_madd2(x[0], y, carry, &carry); + x[1] = word_madd2(x[1], y, carry, &carry); + x[2] = word_madd2(x[2], y, carry, &carry); + x[3] = word_madd2(x[3], y, carry, &carry); + x[4] = word_madd2(x[4], y, carry, &carry); + x[5] = word_madd2(x[5], y, carry, &carry); + x[6] = word_madd2(x[6], y, carry, &carry); + x[7] = word_madd2(x[7], y, carry, &carry); + return carry; +} + +/************************************************* + * Eight Word Block Linear Multiplication * + *************************************************/ +inline word word8_linmul3(word z[8], const word x[8], word y, word carry) +{ + z[0] = word_madd2(x[0], y, carry, &carry); + z[1] = word_madd2(x[1], y, carry, &carry); + z[2] = word_madd2(x[2], y, carry, &carry); + z[3] = word_madd2(x[3], y, carry, &carry); + z[4] = word_madd2(x[4], y, carry, &carry); + z[5] = word_madd2(x[5], y, carry, &carry); + z[6] = word_madd2(x[6], y, carry, &carry); + z[7] = word_madd2(x[7], y, carry, &carry); + return carry; +} + +/************************************************* + * Eight Word Block Multiply/Add * + *************************************************/ +inline word word8_madd3(word z[8], const word x[8], word y, word carry) +{ + z[0] = word_madd3(x[0], y, z[0], carry, &carry); + z[1] = word_madd3(x[1], y, z[1], carry, &carry); + z[2] = word_madd3(x[2], y, z[2], carry, &carry); + z[3] = word_madd3(x[3], y, z[3], carry, &carry); + z[4] = word_madd3(x[4], y, z[4], carry, &carry); + z[5] = word_madd3(x[5], y, z[5], carry, &carry); + z[6] = word_madd3(x[6], y, z[6], carry, &carry); + z[7] = word_madd3(x[7], y, z[7], carry, &carry); + return carry; +} + +/************************************************* + * Multiply-Add Accumulator * + *************************************************/ +inline void word3_muladd(word *w2, word *w1, word *w0, word a, word b) +{ + *w0 = word_madd2(a, b, *w0, &b); + *w1 += b; + *w2 += (*w1 < b) ? 1 : 0; +} + +/************************************************* + * Multiply-Add Accumulator * + *************************************************/ +inline void word3_muladd_2(word *w2, word *w1, word *w0, word a, word b) +{ + a = word_madd2(a, b, 0, &b); + + word top = (b >> (BOTAN_MP_WORD_BITS - 1)); + b <<= 1; + b |= (a >> (BOTAN_MP_WORD_BITS - 1)); + a <<= 1; + + word carry = 0; + *w0 = word_add(*w0, a, &carry); + *w1 = word_add(*w1, b, &carry); + *w2 = word_add(*w2, top, &carry); +} +} + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_core.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_core.h new file mode 100644 index 0000000000..a3f9d8f83c --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_core.h @@ -0,0 +1,114 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * MPI Algorithms Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MP_CORE_H__ +#define BOTAN_MP_CORE_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * The size of the word type, in bits * + *************************************************/ +const u32bit MP_WORD_BITS = BOTAN_MP_WORD_BITS; + +extern "C" { + +/************************************************* + * Addition/Subtraction Operations * + *************************************************/ +void bigint_add2(word[], u32bit, const word[], u32bit); +void bigint_add3(word[], const word[], u32bit, const word[], u32bit); + +word bigint_add2_nc(word[], u32bit, const word[], u32bit); +word bigint_add3_nc(word[], const word[], u32bit, const word[], u32bit); + +void bigint_sub2(word[], u32bit, const word[], u32bit); +void bigint_sub3(word[], const word[], u32bit, const word[], u32bit); + +/************************************************* + * Shift Operations * + *************************************************/ +void bigint_shl1(word[], u32bit, u32bit, u32bit); +void bigint_shl2(word[], const word[], u32bit, u32bit, u32bit); +void bigint_shr1(word[], u32bit, u32bit, u32bit); +void bigint_shr2(word[], const word[], u32bit, u32bit, u32bit); + +/************************************************* + * Multiplication and Squaring Operations * + *************************************************/ +word bigint_mul_add_words(word[], const word[], u32bit, word); + +void bigint_linmul2(word[], u32bit, word); +void bigint_linmul3(word[], const word[], u32bit, word); +void bigint_linmul_add(word[], u32bit, const word[], u32bit, word); + +/************************************************* + * Montgomery Reduction * + *************************************************/ +void bigint_monty_redc(word[], u32bit, const word[], u32bit, word); + +/************************************************* + * Misc Utility Operations * + *************************************************/ +u32bit bigint_divcore(word, word, word, word, word, word); +s32bit bigint_cmp(const word[], u32bit, const word[], u32bit); +word bigint_divop(word, word, word); +word bigint_modop(word, word, word); +void bigint_wordmul(word, word, word *, word *); + +/************************************************* + * Comba Multiplication / Squaring * + *************************************************/ +void bigint_comba_mul4(word[8], const word[4], const word[4]); +void bigint_comba_mul6(word[12], const word[6], const word[6]); +void bigint_comba_mul8(word[16], const word[8], const word[8]); + +void bigint_comba_sqr4(word[8], const word[4]); +void bigint_comba_sqr6(word[12], const word[6]); +void bigint_comba_sqr8(word[16], const word[8]); +} + +/************************************************* + * High Level Multiplication/Squaring Interfaces * + *************************************************/ +void bigint_mul(word[], u32bit, word[], const word[], u32bit, u32bit, const word[], u32bit, u32bit); + +void bigint_sqr(word[], u32bit, word[], const word[], u32bit, u32bit); + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_types.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_types.h new file mode 100644 index 0000000000..2aa808c9c9 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mp_types.h @@ -0,0 +1,61 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Low Level MPI Types Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MPI_TYPES_H__ +#define BOTAN_MPI_TYPES_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +#if (BOTAN_MP_WORD_BITS == 8) +typedef byte word; +#elif (BOTAN_MP_WORD_BITS == 16) +typedef u16bit word; +#elif (BOTAN_MP_WORD_BITS == 32) +typedef u32bit word; +#elif (BOTAN_MP_WORD_BITS == 64) +typedef u64bit word; +#else +#error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 +#endif + +const word MP_WORD_MASK = ~((word)0); +const word MP_WORD_TOP_BIT = (word)1 << (8 * sizeof(word) - 1); +const word MP_WORD_MAX = MP_WORD_MASK; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mutex.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mutex.h new file mode 100644 index 0000000000..1667667447 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mutex.h @@ -0,0 +1,110 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Mutex Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_MUTEX_H__ +#define BOTAN_MUTEX_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Mutex Base Class * + *************************************************/ +class Mutex +{ +public: + virtual void lock() = 0; + virtual void unlock() = 0; + virtual ~Mutex() + { + } +}; + +/************************************************* + * Mutex Factory * + *************************************************/ +class Mutex_Factory +{ +public: + virtual Mutex *make() = 0; + virtual ~Mutex_Factory() + { + } +}; + +/************************************************* + * Default Mutex Factory * + *************************************************/ +class Default_Mutex_Factory : public Mutex_Factory +{ +public: + Mutex *make() override; +}; + +/************************************************* + * Mutex Holding Class * + *************************************************/ +class Mutex_Holder +{ +public: + Mutex_Holder(Mutex *); + ~Mutex_Holder(); + + Mutex_Holder(const Mutex_Holder &) = delete; + Mutex_Holder &operator=(const Mutex_Holder &) = delete; + +private: + Mutex *mux; +}; + +/************************************************* + * Named Mutex Holder * + *************************************************/ +#ifndef BOTAN_NO_LIBSTATE +class Named_Mutex_Holder +{ +public: + Named_Mutex_Holder(const std::string &); + ~Named_Mutex_Holder(); + +private: + const std::string mutex_name; +}; +#endif + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/mux_qt.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/mux_qt.h new file mode 100644 index 0000000000..963bb9f11c --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/mux_qt.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Qt Mutex Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_EXT_MUTEX_QT_H__ +#define BOTAN_EXT_MUTEX_QT_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Qt Mutex * + *************************************************/ +class Qt_Mutex_Factory : public Mutex_Factory +{ +public: + Mutex *make() override; +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/numthry.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/numthry.h new file mode 100644 index 0000000000..8798a416d5 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/numthry.h @@ -0,0 +1,134 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Number Theory Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_NUMBTHRY_H__ +#define BOTAN_NUMBTHRY_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_MINIMAL_BIGINT +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +namespace Botan { + +#ifndef BOTAN_MINIMAL_BIGINT +/************************************************* + * Fused Arithmetic Operations * + *************************************************/ +BigInt mul_add(const BigInt &, const BigInt &, const BigInt &); +BigInt sub_mul(const BigInt &, const BigInt &, const BigInt &); + +/************************************************* + * Number Theory Functions * + *************************************************/ +inline BigInt abs(const BigInt &n) +{ + return n.abs(); +} +#endif + +void divide(const BigInt &, const BigInt &, BigInt &, BigInt &); + +#ifndef BOTAN_MINIMAL_BIGINT +BigInt gcd(const BigInt &, const BigInt &); +BigInt lcm(const BigInt &, const BigInt &); + +BigInt square(const BigInt &); +BigInt inverse_mod(const BigInt &, const BigInt &); +s32bit jacobi(const BigInt &, const BigInt &); + +BigInt power_mod(const BigInt &, const BigInt &, const BigInt &); + +/************************************************* + * Utility Functions * + *************************************************/ +u32bit low_zero_bits(const BigInt &); + +/************************************************* + * Primality Testing * + *************************************************/ +bool check_prime(const BigInt &); +bool is_prime(const BigInt &); +bool verify_prime(const BigInt &); + +s32bit simple_primality_tests(const BigInt &); +bool passes_mr_tests(const BigInt &, u32bit = 1); +bool run_primality_tests(const BigInt &, u32bit = 1); + +/************************************************* + * Random Number Generation * + *************************************************/ +BigInt random_integer(u32bit); +BigInt random_integer(const BigInt &, const BigInt &); +BigInt random_prime(u32bit, const BigInt & = 1, u32bit = 1, u32bit = 2); +BigInt random_safe_prime(u32bit); + +SecureVector generate_dsa_primes(BigInt &, BigInt &, u32bit); +bool generate_dsa_primes(BigInt &, BigInt &, const byte[], u32bit, u32bit, u32bit = 0); + +/************************************************* + * Prime Numbers * + *************************************************/ +const u32bit PRIME_TABLE_SIZE = 6541; +const u32bit PRIME_PRODUCTS_TABLE_SIZE = 256; + +extern const u16bit PRIMES[]; +extern const u64bit PRIME_PRODUCTS[]; + +/************************************************* + * Miller-Rabin Primality Tester * + *************************************************/ +class MillerRabin_Test +{ +public: + bool passes_test(const BigInt &); + MillerRabin_Test(const BigInt &); + +private: + BigInt n, r, n_minus_1; + u32bit s; + Fixed_Exponent_Power_Mod pow_mod; + Modular_Reducer reducer; +}; +#endif + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/parsing.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/parsing.h new file mode 100644 index 0000000000..da9b08df5b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/parsing.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Parser Functions Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_PARSER_H__ +#define BOTAN_PARSER_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * String Parsing Functions * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +std::vector parse_algorithm_name(const std::string &); +std::vector split_on(const std::string &, char); +std::vector parse_asn1_oid(const std::string &); +bool x500_name_cmp(const std::string &, const std::string &); +u32bit parse_expr(const std::string &); +#endif + +/************************************************* + * String/Integer Conversions * + *************************************************/ +std::string to_string(u64bit, u32bit = 0); +#ifndef BOTAN_TOOLS_ONLY +u32bit to_u32bit(const std::string &); +#endif + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/secmem.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/secmem.h new file mode 100644 index 0000000000..5579b077cc --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/secmem.h @@ -0,0 +1,367 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Secure Memory Buffers Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__ +#define BOTAN_SECURE_MEMORY_BUFFERS_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Variable Length Memory Buffer * + *************************************************/ +template class MemoryRegion +{ +public: + u32bit size() const + { + return used; + } + u32bit is_empty() const + { + return (used == 0); + } + u32bit has_items() const + { + return (used != 0); + } + + operator T *() + { + return buf; + } + operator const T *() const + { + return buf; + } + + T *begin() + { + return buf; + } + const T *begin() const + { + return buf; + } + + T *end() + { + return (buf + size()); + } + const T *end() const + { + return (buf + size()); + } + + bool operator==(const MemoryRegion &other) const + { + return (size() == other.size() && same_mem(buf, other.buf, size())); + } + + bool operator<(const MemoryRegion &) const; + + bool operator!=(const MemoryRegion &in) const + { + return (!(*this == in)); + } + MemoryRegion &operator=(const MemoryRegion &in) + { + if (this != &in) + set(in); + return (*this); + } + + void copy(const T in[], u32bit n) + { + copy(0, in, n); + } + void copy(u32bit off, const T in[], u32bit n) + { + copy_mem(buf + off, in, (n > size() - off) ? (size() - off) : n); + } + + void set(const T in[], u32bit n) + { + create(n); + copy(in, n); + } + void set(const MemoryRegion &in) + { + set(in.begin(), in.size()); + } + + void append(const T data[], u32bit n) + { + grow_to(size() + n); + copy(size() - n, data, n); + } + void append(T x) + { + append(&x, 1); + } + void append(const MemoryRegion &x) + { + append(x.begin(), x.size()); + } + + void clear() + { + clear_mem(buf, allocated); + } + void destroy() + { + create(0); + } + + void create(u32bit); + void grow_to(u32bit) const; + void swap(MemoryRegion &); + + ~MemoryRegion() + { + deallocate(buf, allocated); + } + +protected: + MemoryRegion() + { + buf = nullptr; + alloc = nullptr; + used = allocated = 0; + } + MemoryRegion(const MemoryRegion ©) + { + buf = nullptr; + used = allocated = 0; + alloc = copy.alloc; + set(copy.buf, copy.used); + } + + void init(bool locking, u32bit size = 0) + { + alloc = Allocator::get(locking); + create(size); + } + +private: + T *allocate(u32bit n) const + { + return (T *)alloc->allocate(sizeof(T) * n); + } + void deallocate(T *p, u32bit n) const + { + alloc->deallocate(p, sizeof(T) * n); + } + + mutable T *buf; + mutable u32bit used; + mutable u32bit allocated; + mutable Allocator *alloc; +}; + +/************************************************* + * Create a new buffer * + *************************************************/ +template void MemoryRegion::create(u32bit n) +{ + if (n <= allocated) { + clear(); + used = n; + return; + } + deallocate(buf, allocated); + buf = allocate(n); + allocated = used = n; +} + +/************************************************* + * Increase the size of the buffer * + *************************************************/ +template void MemoryRegion::grow_to(u32bit n) const +{ + if (n > used && n <= allocated) { + clear_mem(buf + used, n - used); + used = n; + return; + } else if (n > allocated) { + T *new_buf = allocate(n); + copy_mem(new_buf, buf, used); + deallocate(buf, allocated); + buf = new_buf; + allocated = used = n; + } +} + +/************************************************* + * Compare this buffer with another one * + *************************************************/ +template bool MemoryRegion::operator<(const MemoryRegion &in) const +{ + if (size() < in.size()) + return true; + if (size() > in.size()) + return false; + + for (u32bit j = 0; j != size(); j++) { + if (buf[j] < in[j]) + return true; + if (buf[j] > in[j]) + return false; + } + + return false; +} + +/************************************************* + * Swap this buffer with another one * + *************************************************/ +template void MemoryRegion::swap(MemoryRegion &x) +{ + std::swap(buf, x.buf); + std::swap(used, x.used); + std::swap(allocated, x.allocated); + std::swap(alloc, x.alloc); +} + +/************************************************* + * Unlocked Variable Length Buffer * + *************************************************/ +template class MemoryVector : public MemoryRegion +{ +public: + MemoryVector &operator=(const MemoryRegion &in) + { + if (this != &in) + this->set(in); + return (*this); + } + + MemoryVector(u32bit n = 0) + { + MemoryRegion::init(false, n); + } + MemoryVector(const T in[], u32bit n) + { + MemoryRegion::init(false); + this->set(in, n); + } + MemoryVector(const MemoryRegion &in) + { + MemoryRegion::init(false); + this->set(in); + } + MemoryVector(const MemoryRegion &in1, const MemoryRegion &in2) + { + MemoryRegion::init(false); + this->set(in1); + append(in2); + } +}; + +/************************************************* + * Locked Variable Length Buffer * + *************************************************/ +template class SecureVector : public MemoryRegion +{ +public: + SecureVector &operator=(const MemoryRegion &in) + { + if (this != &in) + this->set(in); + return (*this); + } + + SecureVector(u32bit n = 0) + { + MemoryRegion::init(true, n); + } + SecureVector(const T in[], u32bit n) + { + MemoryRegion::init(true); + this->set(in, n); + } + SecureVector(const MemoryRegion &in) + { + MemoryRegion::init(true); + this->set(in); + } + SecureVector(const MemoryRegion &in1, const MemoryRegion &in2) + { + MemoryRegion::init(true); + this->set(in1); + append(in2); + } +}; + +/************************************************* + * Locked Fixed Length Buffer * + *************************************************/ +template +class SecureBuffer : public MemoryRegion // clazy:exclude=rule-of-three TODO Needs checking if a real bug or not +{ +public: + SecureBuffer &operator=(const SecureBuffer &in) + { + if (this != &in) + this->set(in); + return (*this); + } + + SecureBuffer() + { + MemoryRegion::init(true, L); + } + SecureBuffer(const T in[], u32bit n) + { + MemoryRegion::init(true, L); + copy(in, n); + } + +private: + SecureBuffer &operator=(const MemoryRegion &in) + { + if (this != &in) + this->set(in); + return (*this); + } +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/stl_util.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/stl_util.h new file mode 100644 index 0000000000..60a2f73db9 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/stl_util.h @@ -0,0 +1,108 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * STL Utility Functions Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_STL_UTIL_H__ +#define BOTAN_STL_UTIL_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Copy-on-Predicate Algorithm * + *************************************************/ +template +OutputIterator copy_if(InputIterator current, InputIterator end, OutputIterator dest, Predicate copy_p) +{ + while (current != end) { + if (copy_p(*current)) + *dest++ = *current; + ++current; + } + return dest; +} + +/************************************************* + * Searching through a std::map * + *************************************************/ +template +inline V search_map(const std::map &mapping, const K &key, const V &null_result = V()) +{ + typename std::map::const_iterator i = mapping.find(key); + if (i == mapping.end()) + return null_result; + return i->second; +} + +template +inline R search_map(const std::map &mapping, const K &key, const R &null_result, const R &found_result) +{ + typename std::map::const_iterator i = mapping.find(key); + if (i == mapping.end()) + return null_result; + return found_result; +} + +/************************************************* + * Function adaptor for delete operation * + *************************************************/ +template class del_fun +{ +public: + void operator()(T *ptr) + { + delete ptr; + } +}; + +/************************************************* + * Delete the second half of a pair of objects * + *************************************************/ +template void delete2nd(Pair &pair) +{ + delete pair.second; +} + +/************************************************* + * Insert a key/value pair into a multimap * + *************************************************/ +template void multimap_insert(std::multimap &multimap, const K &key, const V &value) +{ + multimap.insert(std::make_pair(key, value)); +} + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/types.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/types.h new file mode 100644 index 0000000000..058736bb15 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/types.h @@ -0,0 +1,86 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Low Level Types Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_TYPES_H__ +#define BOTAN_TYPES_H__ + +#ifdef BOTAN_TYPES_QT +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#else +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +namespace Botan { + +#ifdef BOTAN_TYPES_QT + +typedef quint8 byte; +typedef quint16 u16bit; +typedef quint32 u32bit; +typedef qint32 s32bit; +typedef quint64 u64bit; + +#else + +typedef unsigned char byte; +typedef unsigned short u16bit; +typedef unsigned int u32bit; + +typedef signed int s32bit; + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 u64bit; +#elif defined(__KCC) +typedef unsigned __long_long u64bit; +#elif defined(__GNUG__) +__extension__ typedef unsigned long long u64bit; +#else +typedef unsigned long long u64bit; +#endif + +#endif // BOTAN_TYPES_QT + +} + +namespace Botan_types { + +typedef Botan::byte byte; +typedef Botan::u32bit u32bit; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/botan/util.h b/local/recipes/libs/qca/source/src/botantools/botan/botan/util.h new file mode 100644 index 0000000000..4747e5ef64 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/botan/util.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Utility Functions Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_UTIL_H__ +#define BOTAN_UTIL_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Timer Access Functions * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +u64bit system_time(); +u64bit system_clock(); +#endif + +/************************************************* + * Memory Locking Functions * + *************************************************/ +void lock_mem(void *, u32bit); +void unlock_mem(void *, u32bit); + +/************************************************* + * Misc Utility Functions * + *************************************************/ +u32bit round_up(u32bit, u32bit); +u32bit round_down(u32bit, u32bit); +#ifndef BOTAN_TOOLS_ONLY +u64bit combine_timers(u32bit, u32bit, u32bit); +#endif + +/************************************************* + * Work Factor Estimates * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +u32bit entropy_estimate(const byte[], u32bit); +u32bit dl_work_factor(u32bit); +#endif + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/charset.cpp b/local/recipes/libs/qca/source/src/botantools/botan/charset.cpp new file mode 100644 index 0000000000..af6319f71d --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/charset.cpp @@ -0,0 +1,226 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Character Set Handling Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifdef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#else +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +namespace Charset { + +/************************************************* + * Perform character set transcoding * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +std::string transcode(const std::string &str, Character_Set to, Character_Set from) +{ + return global_state().transcode(str, to, from); +} +#endif + +/************************************************* + * Check if a character represents a digit * + *************************************************/ +bool is_digit(char c) +{ + if (c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || + c == '9') + return true; + return false; +} + +/************************************************* + * Check if a character represents whitespace * + *************************************************/ +bool is_space(char c) +{ + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + return true; + return false; +} + +/************************************************* + * Convert a character to a digit * + *************************************************/ +byte char2digit(char c) +{ + switch (c) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + } + + throw Invalid_Argument("char2digit: Input is not a digit character"); +} + +/************************************************* + * Convert a digit to a character * + *************************************************/ +char digit2char(byte b) +{ + switch (b) { + case 0: + return '0'; + case 1: + return '1'; + case 2: + return '2'; + case 3: + return '3'; + case 4: + return '4'; + case 5: + return '5'; + case 6: + return '6'; + case 7: + return '7'; + case 8: + return '8'; + case 9: + return '9'; + } + + throw Invalid_Argument("digit2char: Input is not a digit"); +} + +/************************************************* + * Case-insensitive character comparison * + *************************************************/ +bool caseless_cmp(char a, char b) +{ + return (tolower((unsigned char)a) == tolower((unsigned char)b)); +} + +} + +#ifndef BOTAN_TOOLS_ONLY + +/************************************************* + * Hex Encoder Lookup Tables * + *************************************************/ +const byte Hex_Encoder::BIN_TO_HEX_UPPER[16] = + {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46}; + +const byte Hex_Encoder::BIN_TO_HEX_LOWER[16] = + {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; + +/************************************************* + * Base64 Encoder Lookup Table * + *************************************************/ +const byte Base64_Encoder::BIN_TO_BASE64[64] = { + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F}; + +/************************************************* + * Hex Decoder Lookup Table * + *************************************************/ +const byte Hex_Decoder::HEX_TO_BIN[256] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + +/************************************************* + * Base64 Decoder Lookup Table * + *************************************************/ +const byte Base64_Decoder::BASE64_TO_BIN[256] = { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x3E, 0x80, 0x80, 0x80, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, + 0x3D, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + +#endif + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/defalloc.cpp b/local/recipes/libs/qca/source/src/botantools/botan/defalloc.cpp new file mode 100644 index 0000000000..2386a4b3d3 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/defalloc.cpp @@ -0,0 +1,142 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Basic Allocators Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +namespace { + +/************************************************* + * Perform Memory Allocation * + *************************************************/ +void *do_malloc(u32bit n, bool do_lock) +{ + void *ptr = malloc(n); + + if (!ptr) + return nullptr; + + if (do_lock) + lock_mem(ptr, n); + + memset(ptr, 0, n); + return ptr; +} + +/************************************************* + * Perform Memory Deallocation * + *************************************************/ +void do_free(void *ptr, u32bit n, bool do_lock) +{ + if (!ptr) + return; + + memset(ptr, 0, n); + if (do_lock) + unlock_mem(ptr, n); + + free(ptr); +} + +} + +/************************************************* + * Malloc_Allocator's Allocation * + *************************************************/ +void *Malloc_Allocator::alloc_block(u32bit n) +{ + return do_malloc(n, false); +} + +/************************************************* + * Malloc_Allocator's Deallocation * + *************************************************/ +void Malloc_Allocator::dealloc_block(void *ptr, u32bit n) +{ + do_free(ptr, n, false); +} + +/************************************************* + * Locking_Allocator's Allocation * + *************************************************/ +void *Locking_Allocator::alloc_block(u32bit n) +{ + return do_malloc(n, true); +} + +/************************************************* + * Locking_Allocator's Deallocation * + *************************************************/ +void Locking_Allocator::dealloc_block(void *ptr, u32bit n) +{ + do_free(ptr, n, true); +} + +/************************************************* + * Get an allocator * + *************************************************/ +Allocator *Allocator::get(bool locking) +{ + std::string type = ""; + if (!locking) + type = "malloc"; + + Allocator *alloc = global_state().get_allocator(type); + if (alloc) + return alloc; + + throw Exception("Couldn't find an allocator to use in get_allocator"); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/divide.cpp b/local/recipes/libs/qca/source/src/botantools/botan/divide.cpp new file mode 100644 index 0000000000..ef6c80e6d3 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/divide.cpp @@ -0,0 +1,140 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Division Algorithm Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +namespace { + +/************************************************* + * Handle signed operands, if necessary * + *************************************************/ +void sign_fixup(const BigInt &x, const BigInt &y, BigInt &q, BigInt &r) +{ + if (x.sign() == BigInt::Negative) { + q.flip_sign(); + if (r.is_nonzero()) { + --q; + r = y.abs() - r; + } + } + if (y.sign() == BigInt::Negative) + q.flip_sign(); +} + +} + +/************************************************* + * Solve x = q * y + r * + *************************************************/ +void divide(const BigInt &x, const BigInt &y_arg, BigInt &q, BigInt &r) +{ + if (y_arg.is_zero()) + throw BigInt::DivideByZero(); + + BigInt y = y_arg; + const u32bit y_words = y.sig_words(); + r = x; + + r.set_sign(BigInt::Positive); + y.set_sign(BigInt::Positive); + + s32bit compare = r.cmp(y); + + if (compare < 0) + q = 0; + else if (compare == 0) { + q = 1; + r = 0; + } else { + u32bit shifts = 0; + word y_top = y[y.sig_words() - 1]; + while (y_top < MP_WORD_TOP_BIT) { + y_top <<= 1; + ++shifts; + } + y <<= shifts; + r <<= shifts; + + const u32bit n = r.sig_words() - 1, t = y_words - 1; + + q.get_reg().create(n - t + 1); + if (n <= t) { + while (r > y) { + r -= y; + q++; + } + r >>= shifts; + sign_fixup(x, y_arg, q, r); + return; + } + + BigInt temp = y << (MP_WORD_BITS * (n - t)); + + while (r >= temp) { + r -= temp; + ++q[n - t]; + } + + for (u32bit j = n; j != t; --j) { + const word x_j0 = r.word_at(j); + const word x_j1 = r.word_at(j - 1); + const word y_t = y.word_at(t); + + if (x_j0 == y_t) + q[j - t - 1] = MP_WORD_MAX; + else + q[j - t - 1] = bigint_divop(x_j0, x_j1, y_t); + + while (bigint_divcore(q[j - t - 1], y_t, y.word_at(t - 1), x_j0, x_j1, r.word_at(j - 2))) + --q[j - t - 1]; + + r -= (q[j - t - 1] * y) << (MP_WORD_BITS * (j - t - 1)); + if (r.is_negative()) { + r += y << (MP_WORD_BITS * (j - t - 1)); + --q[j - t - 1]; + } + } + r >>= shifts; + } + + sign_fixup(x, y_arg, q, r); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/exceptn.cpp b/local/recipes/libs/qca/source/src/botantools/botan/exceptn.cpp new file mode 100644 index 0000000000..d7ea1e6bd6 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/exceptn.cpp @@ -0,0 +1,99 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Exceptions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Constructor for Invalid_Key_Length * + *************************************************/ +Invalid_Key_Length::Invalid_Key_Length(const std::string &name, u32bit length) +{ + set_msg(name + " cannot accept a key of length " + to_string(length)); +} + +/************************************************* + * Constructor for Invalid_Block_Size * + *************************************************/ +Invalid_Block_Size::Invalid_Block_Size(const std::string &mode, const std::string &pad) +{ + set_msg("Padding method " + pad + " cannot be used with " + mode); +} + +/************************************************* + * Constructor for Invalid_IV_Length * + *************************************************/ +Invalid_IV_Length::Invalid_IV_Length(const std::string &mode, u32bit bad_len) +{ + set_msg("IV length " + to_string(bad_len) + " is invalid for " + mode); +} + +/************************************************* + * Constructor for Invalid_Message_Number * + *************************************************/ +Invalid_Message_Number::Invalid_Message_Number(const std::string &where, u32bit message_no) +{ + set_msg("Pipe::" + where + ": Invalid message number " + to_string(message_no)); +} + +/************************************************* + * Constructor for Algorithm_Not_Found * + *************************************************/ +Algorithm_Not_Found::Algorithm_Not_Found(const std::string &name) +{ + set_msg("Could not find any algorithm named \"" + name + "\""); +} + +/************************************************* + * Constructor for Invalid_Algorithm_Name * + *************************************************/ +Invalid_Algorithm_Name::Invalid_Algorithm_Name(const std::string &name) +{ + set_msg("Invalid algorithm name: " + name); +} + +/************************************************* + * Constructor for Config_Error * + *************************************************/ +Config_Error::Config_Error(const std::string &err, u32bit line) +{ + set_msg("Config error at line " + to_string(line) + ": " + err); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/libstate.cpp b/local/recipes/libs/qca/source/src/botantools/botan/libstate.cpp new file mode 100644 index 0000000000..632f1af8e4 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/libstate.cpp @@ -0,0 +1,478 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Library Internal/Global State Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Botan's global state * + *************************************************/ +namespace { + +Library_State *global_lib_state = nullptr; + +} + +/************************************************* + * Access the global state object * + *************************************************/ +Library_State &global_state() +{ + if (!global_lib_state) + throw Invalid_State("Library was not initialized correctly"); + return (*global_lib_state); +} + +/************************************************* + * Set a new global state object * + *************************************************/ +void set_global_state(Library_State *new_state) +{ + delete swap_global_state(new_state); +} + +/************************************************* + * Swap two global state objects * + *************************************************/ +Library_State *swap_global_state(Library_State *new_state) +{ + Library_State *old_state = global_lib_state; + global_lib_state = new_state; + return old_state; +} + +/************************************************* + * Increment the Engine iterator * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +Engine *Library_State::Engine_Iterator::next() +{ + return lib.get_engine_n(n++); +} +#endif + +/************************************************* + * Get a new mutex object * + *************************************************/ +Mutex *Library_State::get_mutex() const +{ + return mutex_factory->make(); +} + +/************************************************* + * Get a persistent named mutex object * + *************************************************/ +Mutex *Library_State::get_named_mutex(const std::string &name) +{ + Mutex *mux = search_map(locks, name, 0); + if (mux) + return mux; + return (locks[name] = get_mutex()); +} + +/************************************************* + * Get an allocator by its name * + *************************************************/ +Allocator *Library_State::get_allocator(const std::string &type) const +{ + Named_Mutex_Holder lock("allocator"); + + if (type != "") + return search_map(alloc_factory, type, 0); + + if (!cached_default_allocator) { +#ifdef BOTAN_TOOLS_ONLY + std::string chosen = default_allocator_type; +#else + std::string chosen = config().option("base/default_allocator"); +#endif + if (chosen == "") + chosen = "malloc"; + + cached_default_allocator = search_map(alloc_factory, chosen, 0); + } + + return cached_default_allocator; +} + +/************************************************* + * Create a new name to object mapping * + *************************************************/ +void Library_State::add_allocator(Allocator *allocator) +{ + Named_Mutex_Holder lock("allocator"); + + allocator->init(); + + allocators.push_back(allocator); + alloc_factory[allocator->type()] = allocator; +} + +/************************************************* + * Set the default allocator type * + *************************************************/ +#ifdef BOTAN_TOOLS_ONLY +void Library_State::set_default_allocator(const std::string &type) +#else +void Library_State::set_default_allocator(const std::string &type) const +#endif +{ + Named_Mutex_Holder lock("allocator"); + + if (type == "") + return; + +#ifdef BOTAN_TOOLS_ONLY + default_allocator_type = type; +#else + config().set("conf", "base/default_allocator", type); +#endif + cached_default_allocator = nullptr; +} + +#ifndef BOTAN_TOOLS_ONLY +/************************************************* + * Set the high resolution clock implementation * + *************************************************/ +void Library_State::set_timer(Timer *new_timer) +{ + if (new_timer) { + delete timer; + timer = new_timer; + } +} + +/************************************************* + * Read a high resolution clock * + *************************************************/ +u64bit Library_State::system_clock() const +{ + return (timer) ? timer->clock() : 0; +} + +/************************************************* + * Set the global PRNG * + *************************************************/ +void Library_State::set_prng(RandomNumberGenerator *new_rng) +{ + Named_Mutex_Holder lock("rng"); + + delete rng; + rng = new_rng; +} + +/************************************************* + * Get bytes from the global PRNG * + *************************************************/ +void Library_State::randomize(byte out[], u32bit length) +{ + Named_Mutex_Holder lock("rng"); + + rng->randomize(out, length); +} + +/************************************************* + * Add a new entropy source to use * + *************************************************/ +void Library_State::add_entropy_source(EntropySource *src, bool last_in_list) +{ + Named_Mutex_Holder lock("rng"); + + if (last_in_list) + entropy_sources.push_back(src); + else + entropy_sources.insert(entropy_sources.begin(), src); +} + +/************************************************* + * Add some bytes of entropy to the global PRNG * + *************************************************/ +void Library_State::add_entropy(const byte in[], u32bit length) +{ + Named_Mutex_Holder lock("rng"); + + rng->add_entropy(in, length); +} + +/************************************************* + * Add some bytes of entropy to the global PRNG * + *************************************************/ +void Library_State::add_entropy(EntropySource &source, bool slow_poll) +{ + Named_Mutex_Holder lock("rng"); + + rng->add_entropy(source, slow_poll); +} + +/************************************************* + * Gather entropy for our PRNG object * + *************************************************/ +u32bit Library_State::seed_prng(bool slow_poll, u32bit bits_to_get) +{ + Named_Mutex_Holder lock("rng"); + + u32bit bits = 0; + for (u32bit j = 0; j != entropy_sources.size(); ++j) { + bits += rng->add_entropy(*(entropy_sources[j]), slow_poll); + + if (bits_to_get && bits >= bits_to_get) + return bits; + } + + return bits; +} + +/************************************************* + * Get an engine out of the list * + *************************************************/ +Engine *Library_State::get_engine_n(u32bit n) const +{ + Named_Mutex_Holder lock("engine"); + + if (n >= engines.size()) + return 0; + return engines[n]; +} + +/************************************************* + * Add a new engine to the list * + *************************************************/ +void Library_State::add_engine(Engine *engine) +{ + Named_Mutex_Holder lock("engine"); + engines.insert(engines.begin(), engine); +} + +/************************************************* + * Set the character set transcoder object * + *************************************************/ +void Library_State::set_transcoder(class Charset_Transcoder *transcoder) +{ + if (this->transcoder) + delete this->transcoder; + this->transcoder = transcoder; +} + +/************************************************* + * Transcode a string from one charset to another * + *************************************************/ +std::string Library_State::transcode(const std::string str, Character_Set to, Character_Set from) const +{ + if (!transcoder) + throw Invalid_State("Library_State::transcode: No transcoder set"); + + return transcoder->transcode(str, to, from); +} + +/************************************************* + * Set the X509 global state class * + *************************************************/ +void Library_State::set_x509_state(X509_GlobalState *new_x509_state_obj) +{ + delete x509_state_obj; + x509_state_obj = new_x509_state_obj; +} + +/************************************************* + * Get the X509 global state class * + *************************************************/ +X509_GlobalState &Library_State::x509_state() +{ + if (!x509_state_obj) + x509_state_obj = new X509_GlobalState(); + + return (*x509_state_obj); +} + +/************************************************* + * Set the UI object state * + *************************************************/ +void Library_State::set_ui(UI *new_ui) +{ + delete ui; + ui = new_ui; +} + +/************************************************* + * Send a pulse to the UI object * + *************************************************/ +void Library_State::pulse(Pulse_Type pulse_type) const +{ + if (ui) + ui->pulse(pulse_type); +} + +/************************************************* + * Set the configuration object * + *************************************************/ +Config &Library_State::config() const +{ + if (!config_obj) + throw Invalid_State("Library_State::config(): No config set"); + + return (*config_obj); +} + +#endif + +/************************************************* + * Load modules * + *************************************************/ +void Library_State::load(Modules &modules) +{ +#ifndef BOTAN_TOOLS_ONLY + set_timer(modules.timer()); + set_transcoder(modules.transcoder()); +#endif + + std::vector mod_allocs = modules.allocators(); + for (Allocator *mod_alloc : mod_allocs) + add_allocator(mod_alloc); + + set_default_allocator(modules.default_allocator()); + +#ifndef BOTAN_TOOLS_ONLY + std::vector mod_engines = modules.engines(); + for (u32bit j = 0; j != mod_engines.size(); ++j) { + Named_Mutex_Holder lock("engine"); + engines.push_back(mod_engines[j]); + } + + std::vector sources = modules.entropy_sources(); + for (u32bit j = 0; j != sources.size(); ++j) + add_entropy_source(sources[j]); +#endif +} + +/************************************************* + * Library_State Constructor * + *************************************************/ +Library_State::Library_State(Mutex_Factory *mutex_factory) +{ + if (!mutex_factory) + throw Exception("Library_State: no mutex found"); + + this->mutex_factory = mutex_factory; +#ifndef BOTAN_TOOLS_ONLY + this->timer = new Timer(); + this->transcoder = 0; + this->config_obj = new Config(); +#endif + +#ifndef BOTAN_TOOLS_ONLY + locks["settings"] = get_mutex(); +#endif + locks["allocator"] = get_mutex(); +#ifndef BOTAN_TOOLS_ONLY + locks["rng"] = get_mutex(); + locks["engine"] = get_mutex(); + rng = 0; +#endif + cached_default_allocator = nullptr; +#ifndef BOTAN_TOOLS_ONLY + x509_state_obj = 0; + ui = 0; +#endif +} + +/************************************************* + * Library_State Destructor * + *************************************************/ +static void delete_lock(std::pair &pair) +{ + delete pair.second; +} + +Library_State::~Library_State() +{ +#ifndef BOTAN_TOOLS_ONLY + delete x509_state_obj; + delete transcoder; + delete rng; + delete timer; + delete config_obj; + delete ui; + + std::for_each(entropy_sources.begin(), entropy_sources.end(), del_fun()); + std::for_each(engines.begin(), engines.end(), del_fun()); +#endif + + cached_default_allocator = nullptr; + + for (Allocator *allocator : allocators) { + allocator->destroy(); + delete allocator; + } + + std::for_each(locks.begin(), locks.end(), delete_lock); + + delete mutex_factory; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/license.txt b/local/recipes/libs/qca/source/src/botantools/botan/license.txt new file mode 100644 index 0000000000..0fd6217219 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/license.txt @@ -0,0 +1,23 @@ +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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/local/recipes/libs/qca/source/src/botantools/botan/mem_pool.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mem_pool.cpp new file mode 100644 index 0000000000..7660789c6b --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mem_pool.cpp @@ -0,0 +1,306 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Pooling Allocator Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifdef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#else +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +namespace { + +/************************************************* + * Decide how much memory to allocate at once * + *************************************************/ +u32bit choose_pref_size(u32bit provided) +{ + if (provided) + return provided; + +#ifdef BOTAN_TOOLS_ONLY + u32bit result = (u32bit)global_state().prealloc_size; +#else + u32bit result = global_config().option_as_u32bit("base/memory_chunk"); +#endif + if (result) + return result; + + return 16 * 1024; +} + +} + +/************************************************* + * Memory_Block Constructor * + *************************************************/ +Pooling_Allocator::Memory_Block::Memory_Block(void *buf) +{ + buffer = static_cast(buf); + bitmap = 0; + buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE); +} + +/************************************************* + * See if ptr is contained by this block * + *************************************************/ +bool Pooling_Allocator::Memory_Block::contains(void *ptr, u32bit length) const throw() +{ + return ((buffer <= ptr) && (buffer_end >= (byte *)ptr + length * BLOCK_SIZE)); +} + +/************************************************* + * Allocate some memory, if possible * + *************************************************/ +byte *Pooling_Allocator::Memory_Block::alloc(u32bit n) throw() +{ + if (n == 0 || n > BITMAP_SIZE) + return nullptr; + + if (n == BITMAP_SIZE) { + if (bitmap) + return nullptr; + else { + bitmap = ~bitmap; + return buffer; + } + } + + bitmap_type mask = ((bitmap_type)1 << n) - 1; + u32bit offset = 0; + + while (bitmap & mask) { + mask <<= 1; + ++offset; + + if ((bitmap & mask) == 0) + break; + if (mask >> 63) + break; + } + + if (bitmap & mask) + return nullptr; + + bitmap |= mask; + return buffer + offset * BLOCK_SIZE; +} + +/************************************************* + * Mark this memory as free, if we own it * + *************************************************/ +void Pooling_Allocator::Memory_Block::free(void *ptr, u32bit blocks) throw() +{ + clear_mem((byte *)ptr, blocks * BLOCK_SIZE); + + const u32bit offset = ((byte *)ptr - buffer) / BLOCK_SIZE; + + if (offset == 0 && blocks == BITMAP_SIZE) + bitmap = ~bitmap; + else { + for (u32bit j = 0; j != blocks; ++j) + bitmap &= ~((bitmap_type)1 << (j + offset)); + } +} + +/************************************************* + * Pooling_Allocator Constructor * + *************************************************/ +Pooling_Allocator::Pooling_Allocator(u32bit p_size, bool) + : PREF_SIZE(choose_pref_size(p_size)) +{ + mutex = global_state().get_mutex(); + last_used = blocks.begin(); +} + +/************************************************* + * Pooling_Allocator Destructor * + *************************************************/ +Pooling_Allocator::~Pooling_Allocator() QCA_NOEXCEPT(false) +{ + delete mutex; + if (blocks.size()) + throw Invalid_State("Pooling_Allocator: Never released memory"); +} + +/************************************************* + * Free all remaining memory * + *************************************************/ +void Pooling_Allocator::destroy() +{ + Mutex_Holder lock(mutex); + + blocks.clear(); + + for (const std::pair &p : allocated) + dealloc_block(p.first, p.second); + allocated.clear(); +} + +/************************************************* + * Allocation * + *************************************************/ +void *Pooling_Allocator::allocate(u32bit n) +{ + const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); + const u32bit BLOCK_SIZE = Memory_Block::block_size(); + + Mutex_Holder lock(mutex); + + if (n <= BITMAP_SIZE * BLOCK_SIZE) { + const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; + + byte *mem = allocate_blocks(block_no); + if (mem) + return mem; + + get_more_core(PREF_SIZE); + + mem = allocate_blocks(block_no); + if (mem) + return mem; + + throw Memory_Exhaustion(); + } + + void *new_buf = alloc_block(n); + if (new_buf) + return new_buf; + + throw Memory_Exhaustion(); +} + +/************************************************* + * Deallocation * + *************************************************/ +void Pooling_Allocator::deallocate(void *ptr, u32bit n) +{ + const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); + const u32bit BLOCK_SIZE = Memory_Block::block_size(); + + if (ptr == nullptr || n == 0) + return; + + Mutex_Holder lock(mutex); + + if (n > BITMAP_SIZE * BLOCK_SIZE) + dealloc_block(ptr, n); + else { + const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; + + std::vector::iterator i = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); + + if (i == blocks.end() || !i->contains(ptr, block_no)) + throw Invalid_State("Pointer released to the wrong allocator"); + + i->free(ptr, block_no); + } +} + +/************************************************* + * Try to get some memory from an existing block * + *************************************************/ +byte *Pooling_Allocator::allocate_blocks(u32bit n) +{ + if (blocks.empty()) + return nullptr; + + std::vector::iterator i = last_used; + + do { + byte *mem = i->alloc(n); + if (mem) { + last_used = i; + return mem; + } + + ++i; + if (i == blocks.end()) + i = blocks.begin(); + } while (i != last_used); + + return nullptr; +} + +/************************************************* + * Allocate more memory for the pool * + *************************************************/ +void Pooling_Allocator::get_more_core(u32bit in_bytes) +{ + const u32bit BITMAP_SIZE = Memory_Block::bitmap_size(); + const u32bit BLOCK_SIZE = Memory_Block::block_size(); + + const u32bit TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE; + + const u32bit in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE; + const u32bit to_allocate = in_blocks * TOTAL_BLOCK_SIZE; + + void *ptr = alloc_block(to_allocate); + if (ptr == nullptr) + throw Memory_Exhaustion(); + + allocated.emplace_back(ptr, to_allocate); + + for (u32bit j = 0; j != in_blocks; ++j) { + byte *byte_ptr = static_cast(ptr); + blocks.emplace_back(byte_ptr + j * TOTAL_BLOCK_SIZE); + } + + std::sort(blocks.begin(), blocks.end()); + last_used = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); +} + +const u32bit Pooling_Allocator::Memory_Block::BITMAP_SIZE = 8 * sizeof(Pooling_Allocator::Memory_Block::bitmap_type); +const u32bit Pooling_Allocator::Memory_Block::BLOCK_SIZE = 64; + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/ml_unix/mlock.cpp b/local/recipes/libs/qca/source/src/botantools/botan/ml_unix/mlock.cpp new file mode 100644 index 0000000000..c260726412 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/ml_unix/mlock.cpp @@ -0,0 +1,67 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Locking Functions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309 +#endif + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Lock an area of memory into RAM * + *************************************************/ +void lock_mem(void *ptr, u32bit bytes) +{ + mlock(ptr, bytes); +} + +/************************************************* + * Unlock a previously locked region of memory * + *************************************************/ +void unlock_mem(void *ptr, u32bit bytes) +{ + munlock(ptr, bytes); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/ml_win32/mlock.cpp b/local/recipes/libs/qca/source/src/botantools/botan/ml_win32/mlock.cpp new file mode 100644 index 0000000000..38fe6473f9 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/ml_win32/mlock.cpp @@ -0,0 +1,59 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Memory Locking Functions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Lock an area of memory into RAM * + *************************************************/ +void lock_mem(void *ptr, u32bit bytes) +{ + VirtualLock(ptr, bytes); +} + +/************************************************* + * Unlock a previously locked region of memory * + *************************************************/ +void unlock_mem(void *ptr, u32bit bytes) +{ + VirtualUnlock(ptr, bytes); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/modules.cpp b/local/recipes/libs/qca/source/src/botantools/botan/modules.cpp new file mode 100644 index 0000000000..1581e83b0a --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/modules.cpp @@ -0,0 +1,321 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Module Factory Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_MUTEX_PTHREAD) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#elif defined(BOTAN_EXT_MUTEX_WIN32) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#elif defined(BOTAN_EXT_MUTEX_QT) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ALLOC_MMAP) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#ifndef BOTAN_TOOLS_ONLY + +#if defined(BOTAN_EXT_TIMER_HARDWARE) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#elif defined(BOTAN_EXT_TIMER_POSIX) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#elif defined(BOTAN_EXT_TIMER_UNIX) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#elif defined(BOTAN_EXT_TIMER_WIN32) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENGINE_AEP) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENGINE_GNU_MP) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENGINE_OPENSSL) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_AEP) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_EGD) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_FTW) +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +#endif + +namespace Botan { + +/************************************************* + * Return a mutex factory, if available * + *************************************************/ +Mutex_Factory *Builtin_Modules::mutex_factory() const +{ +#if defined(BOTAN_EXT_MUTEX_PTHREAD) + return new Pthread_Mutex_Factory; +#elif defined(BOTAN_EXT_MUTEX_WIN32) + return new Win32_Mutex_Factory; +#elif defined(BOTAN_EXT_MUTEX_QT) + return new Qt_Mutex_Factory; +#else + return 0; +#endif +} + +/************************************************* + * Find a high resolution timer, if possible * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +Timer *Builtin_Modules::timer() const +{ +#if defined(BOTAN_EXT_TIMER_HARDWARE) + return new Hardware_Timer; +#elif defined(BOTAN_EXT_TIMER_POSIX) + return new POSIX_Timer; +#elif defined(BOTAN_EXT_TIMER_UNIX) + return new Unix_Timer; +#elif defined(BOTAN_EXT_TIMER_WIN32) + return new Win32_Timer; +#else + return new Timer; +#endif +} +#endif + +/************************************************* + * Find any usable allocators * + *************************************************/ +std::vector Builtin_Modules::allocators() const +{ + std::vector allocators; + +#if defined(BOTAN_EXT_ALLOC_MMAP) + allocators.push_back(new MemoryMapping_Allocator); +#endif + + allocators.push_back(new Locking_Allocator); + allocators.push_back(new Malloc_Allocator); + + return allocators; +} + +/************************************************* + * Return the default allocator * + *************************************************/ +std::string Builtin_Modules::default_allocator() const +{ + if (should_lock) { +#if defined(BOTAN_EXT_ALLOC_MMAP) + return "mmap"; +#else + return "locking"; +#endif + } else + return "malloc"; +} + +#ifndef BOTAN_TOOLS_ONLY + +/************************************************* + * Register any usable entropy sources * + *************************************************/ +std::vector Builtin_Modules::entropy_sources() const +{ + std::vector sources; + + sources.push_back(new File_EntropySource); + +#if defined(BOTAN_EXT_ENTROPY_SRC_AEP) + sources.push_back(new AEP_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_EGD) + sources.push_back(new EGD_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) + sources.push_back(new Win32_CAPI_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) + sources.push_back(new Win32_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) + sources.push_back(new Unix_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) + sources.push_back(new BeOS_EntropySource); +#endif + +#if defined(BOTAN_EXT_ENTROPY_SRC_FTW) + sources.push_back(new FTW_EntropySource); +#endif + + return sources; +} + +/************************************************* + * Find any usable engines * + *************************************************/ +std::vector Builtin_Modules::engines() const +{ + std::vector engines; + + if (use_engines) { +#if defined(BOTAN_EXT_ENGINE_AEP) + engines.push_back(new AEP_Engine); +#endif + +#if defined(BOTAN_EXT_ENGINE_GNU_MP) + engines.push_back(new GMP_Engine); +#endif + +#if defined(BOTAN_EXT_ENGINE_OPENSSL) + engines.push_back(new OpenSSL_Engine); +#endif + } + + engines.push_back(new Default_Engine); + + return engines; +} + +/************************************************* + * Find the best transcoder option * + *************************************************/ +Charset_Transcoder *Builtin_Modules::transcoder() const +{ + return new Default_Charset_Transcoder; +} + +#endif + +/************************************************* + * Builtin_Modules Constructor * + *************************************************/ +#ifdef BOTAN_TOOLS_ONLY +Builtin_Modules::Builtin_Modules() + : should_lock(true) +{ +} +#else +Builtin_Modules::Builtin_Modules(const InitializerOptions &args) + : should_lock(args.secure_memory()) + , use_engines(args.use_engines()) +{ +} +#endif + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_asm.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_asm.cpp new file mode 100644 index 0000000000..16f5dae6d7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_asm.cpp @@ -0,0 +1,236 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Lowest Level MPI Algorithms Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Two Operand Addition, No Carry * + *************************************************/ +word bigint_add2_nc(word x[], u32bit x_size, const word y[], u32bit y_size) +{ + word carry = 0; + + const u32bit blocks = y_size - (y_size % 8); + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_add2(x + j, y + j, carry); + + for (u32bit j = blocks; j != y_size; ++j) + x[j] = word_add(x[j], y[j], &carry); + + if (!carry) + return 0; + + for (u32bit j = y_size; j != x_size; ++j) + if (++x[j]) + return 0; + + return 1; +} + +/************************************************* + * Three Operand Addition, No Carry * + *************************************************/ +word bigint_add3_nc(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) +{ + if (x_size < y_size) { + return bigint_add3_nc(z, y, y_size, x, x_size); + } + + word carry = 0; + + const u32bit blocks = y_size - (y_size % 8); + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_add3(z + j, x + j, y + j, carry); + + for (u32bit j = blocks; j != y_size; ++j) + z[j] = word_add(x[j], y[j], &carry); + + for (u32bit j = y_size; j != x_size; ++j) { + word x_j = x[j] + carry; + if (carry && x_j) + carry = 0; + z[j] = x_j; + } + + return carry; +} + +/************************************************* + * Two Operand Addition * + *************************************************/ +void bigint_add2(word x[], u32bit x_size, const word y[], u32bit y_size) +{ + if (bigint_add2_nc(x, x_size, y, y_size)) + ++x[x_size]; +} + +/************************************************* + * Three Operand Addition * + *************************************************/ +void bigint_add3(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) +{ + if (bigint_add3_nc(z, x, x_size, y, y_size)) + ++z[(x_size > y_size ? x_size : y_size)]; +} + +/************************************************* + * Two Operand Subtraction * + *************************************************/ +void bigint_sub2(word x[], u32bit x_size, const word y[], u32bit y_size) +{ + word carry = 0; + + const u32bit blocks = y_size - (y_size % 8); + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_sub2(x + j, y + j, carry); + + for (u32bit j = blocks; j != y_size; ++j) + x[j] = word_sub(x[j], y[j], &carry); + + if (!carry) + return; + + for (u32bit j = y_size; j != x_size; ++j) { + --x[j]; + if (x[j] != MP_WORD_MAX) + return; + } +} + +/************************************************* + * Three Operand Subtraction * + *************************************************/ +void bigint_sub3(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) +{ + word carry = 0; + + const u32bit blocks = y_size - (y_size % 8); + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_sub3(z + j, x + j, y + j, carry); + + for (u32bit j = blocks; j != y_size; ++j) + z[j] = word_sub(x[j], y[j], &carry); + + for (u32bit j = y_size; j != x_size; ++j) { + word x_j = x[j] - carry; + if (carry && x_j != MP_WORD_MAX) + carry = 0; + z[j] = x_j; + } +} + +/************************************************* + * Two Operand Linear Multiply * + *************************************************/ +void bigint_linmul2(word x[], u32bit x_size, word y) +{ + const u32bit blocks = x_size - (x_size % 8); + + word carry = 0; + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_linmul2(x + j, y, carry); + + for (u32bit j = blocks; j != x_size; ++j) + x[j] = word_madd2(x[j], y, carry, &carry); + + x[x_size] = carry; +} + +/************************************************* + * Three Operand Linear Multiply * + *************************************************/ +void bigint_linmul3(word z[], const word x[], u32bit x_size, word y) +{ + const u32bit blocks = x_size - (x_size % 8); + + word carry = 0; + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_linmul3(z + j, x + j, y, carry); + + for (u32bit j = blocks; j != x_size; ++j) + z[j] = word_madd2(x[j], y, carry, &carry); + + z[x_size] = carry; +} + +/************************************************* + * Montgomery Reduction Algorithm * + *************************************************/ +#ifndef BOTAN_MINIMAL_BIGINT +void bigint_monty_redc(word z[], u32bit z_size, const word x[], u32bit x_size, word u) +{ + for (u32bit j = 0; j != x_size; ++j) { + word *z_j = z + j; + + const word y = z_j[0] * u; + + word carry = bigint_mul_add_words(z_j, x, x_size, y); + + word z_sum = z_j[x_size] + carry; + carry = (z_sum < z_j[x_size]); + z_j[x_size] = z_sum; + + for (u32bit k = x_size + 1; carry && k != z_size - j; ++k) { + ++z_j[k]; + carry = !z_j[k]; + } + } + + if (bigint_cmp(z + x_size, x_size + 1, x, x_size) >= 0) + bigint_sub2(z + x_size, x_size + 1, x, x_size); +} +#endif +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_comba.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_comba.cpp new file mode 100644 index 0000000000..90257aab93 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_comba.cpp @@ -0,0 +1,595 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Comba Multiplication and Squaring Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Comba 4x4 Multiplication * + *************************************************/ +void bigint_comba_mul4(word z[8], const word x[4], const word y[4]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[3]); + word3_muladd(&w2, &w1, &w0, x[1], y[2]); + word3_muladd(&w2, &w1, &w0, x[2], y[1]); + word3_muladd(&w2, &w1, &w0, x[3], y[0]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[3]); + z[6] = w0; + z[7] = w1; +} + +/************************************************* + * Comba 6x6 Multiplication * + *************************************************/ +void bigint_comba_mul6(word z[12], const word x[6], const word y[6]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[3]); + word3_muladd(&w2, &w1, &w0, x[1], y[2]); + word3_muladd(&w2, &w1, &w0, x[2], y[1]); + word3_muladd(&w2, &w1, &w0, x[3], y[0]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[4]); + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + word3_muladd(&w2, &w1, &w0, x[4], y[0]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[5]); + word3_muladd(&w2, &w1, &w0, x[1], y[4]); + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + word3_muladd(&w2, &w1, &w0, x[4], y[1]); + word3_muladd(&w2, &w1, &w0, x[5], y[0]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[1], y[5]); + word3_muladd(&w2, &w1, &w0, x[2], y[4]); + word3_muladd(&w2, &w1, &w0, x[3], y[3]); + word3_muladd(&w2, &w1, &w0, x[4], y[2]); + word3_muladd(&w2, &w1, &w0, x[5], y[1]); + z[6] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[2], y[5]); + word3_muladd(&w2, &w1, &w0, x[3], y[4]); + word3_muladd(&w2, &w1, &w0, x[4], y[3]); + word3_muladd(&w2, &w1, &w0, x[5], y[2]); + z[7] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[5]); + word3_muladd(&w2, &w1, &w0, x[4], y[4]); + word3_muladd(&w2, &w1, &w0, x[5], y[3]); + z[8] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[4], y[5]); + word3_muladd(&w2, &w1, &w0, x[5], y[4]); + z[9] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[5], y[5]); + z[10] = w0; + z[11] = w1; +} + +/************************************************* + * Comba 8x8 Multiplication * + *************************************************/ +void bigint_comba_mul8(word z[16], const word x[8], const word y[8]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[1]); + word3_muladd(&w2, &w1, &w0, x[1], y[0]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[2]); + word3_muladd(&w2, &w1, &w0, x[1], y[1]); + word3_muladd(&w2, &w1, &w0, x[2], y[0]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[3]); + word3_muladd(&w2, &w1, &w0, x[1], y[2]); + word3_muladd(&w2, &w1, &w0, x[2], y[1]); + word3_muladd(&w2, &w1, &w0, x[3], y[0]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[4]); + word3_muladd(&w2, &w1, &w0, x[1], y[3]); + word3_muladd(&w2, &w1, &w0, x[2], y[2]); + word3_muladd(&w2, &w1, &w0, x[3], y[1]); + word3_muladd(&w2, &w1, &w0, x[4], y[0]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[5]); + word3_muladd(&w2, &w1, &w0, x[1], y[4]); + word3_muladd(&w2, &w1, &w0, x[2], y[3]); + word3_muladd(&w2, &w1, &w0, x[3], y[2]); + word3_muladd(&w2, &w1, &w0, x[4], y[1]); + word3_muladd(&w2, &w1, &w0, x[5], y[0]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[6]); + word3_muladd(&w2, &w1, &w0, x[1], y[5]); + word3_muladd(&w2, &w1, &w0, x[2], y[4]); + word3_muladd(&w2, &w1, &w0, x[3], y[3]); + word3_muladd(&w2, &w1, &w0, x[4], y[2]); + word3_muladd(&w2, &w1, &w0, x[5], y[1]); + word3_muladd(&w2, &w1, &w0, x[6], y[0]); + z[6] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], y[7]); + word3_muladd(&w2, &w1, &w0, x[1], y[6]); + word3_muladd(&w2, &w1, &w0, x[2], y[5]); + word3_muladd(&w2, &w1, &w0, x[3], y[4]); + word3_muladd(&w2, &w1, &w0, x[4], y[3]); + word3_muladd(&w2, &w1, &w0, x[5], y[2]); + word3_muladd(&w2, &w1, &w0, x[6], y[1]); + word3_muladd(&w2, &w1, &w0, x[7], y[0]); + z[7] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[1], y[7]); + word3_muladd(&w2, &w1, &w0, x[2], y[6]); + word3_muladd(&w2, &w1, &w0, x[3], y[5]); + word3_muladd(&w2, &w1, &w0, x[4], y[4]); + word3_muladd(&w2, &w1, &w0, x[5], y[3]); + word3_muladd(&w2, &w1, &w0, x[6], y[2]); + word3_muladd(&w2, &w1, &w0, x[7], y[1]); + z[8] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[2], y[7]); + word3_muladd(&w2, &w1, &w0, x[3], y[6]); + word3_muladd(&w2, &w1, &w0, x[4], y[5]); + word3_muladd(&w2, &w1, &w0, x[5], y[4]); + word3_muladd(&w2, &w1, &w0, x[6], y[3]); + word3_muladd(&w2, &w1, &w0, x[7], y[2]); + z[9] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], y[7]); + word3_muladd(&w2, &w1, &w0, x[4], y[6]); + word3_muladd(&w2, &w1, &w0, x[5], y[5]); + word3_muladd(&w2, &w1, &w0, x[6], y[4]); + word3_muladd(&w2, &w1, &w0, x[7], y[3]); + z[10] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[4], y[7]); + word3_muladd(&w2, &w1, &w0, x[5], y[6]); + word3_muladd(&w2, &w1, &w0, x[6], y[5]); + word3_muladd(&w2, &w1, &w0, x[7], y[4]); + z[11] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[5], y[7]); + word3_muladd(&w2, &w1, &w0, x[6], y[6]); + word3_muladd(&w2, &w1, &w0, x[7], y[5]); + z[12] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[6], y[7]); + word3_muladd(&w2, &w1, &w0, x[7], y[6]); + z[13] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[7], y[7]); + z[14] = w0; + z[15] = w1; +} + +/************************************************* + * Comba 4x4 Squaring * + *************************************************/ +void bigint_comba_sqr4(word z[8], const word x[4]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], x[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); + word3_muladd(&w2, &w1, &w0, x[1], x[1]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); + word3_muladd(&w2, &w1, &w0, x[2], x[2]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[3], x[3]); + z[6] = w0; + z[7] = w1; +} + +/************************************************* + * Comba 6x6 Squaring * + *************************************************/ +void bigint_comba_sqr6(word z[12], const word x[6]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], x[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); + word3_muladd(&w2, &w1, &w0, x[1], x[1]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[4]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); + word3_muladd(&w2, &w1, &w0, x[2], x[2]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[4]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[1], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[4]); + word3_muladd(&w2, &w1, &w0, x[3], x[3]); + z[6] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[2], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[3], x[4]); + z[7] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[3], x[5]); + word3_muladd(&w2, &w1, &w0, x[4], x[4]); + z[8] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[4], x[5]); + z[9] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[5], x[5]); + z[10] = w0; + z[11] = w1; +} + +/************************************************* + * Comba 8x8 Squaring * + *************************************************/ +void bigint_comba_sqr8(word z[16], const word x[8]) +{ + word w2 = 0, w1 = 0, w0 = 0; + + word3_muladd(&w2, &w1, &w0, x[0], x[0]); + z[0] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[1]); + z[1] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[2]); + word3_muladd(&w2, &w1, &w0, x[1], x[1]); + z[2] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[3]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[2]); + z[3] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[4]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[3]); + word3_muladd(&w2, &w1, &w0, x[2], x[2]); + z[4] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[4]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[3]); + z[5] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[6]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[4]); + word3_muladd(&w2, &w1, &w0, x[3], x[3]); + z[6] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[0], x[7]); + word3_muladd_2(&w2, &w1, &w0, x[1], x[6]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[5]); + word3_muladd_2(&w2, &w1, &w0, x[3], x[4]); + z[7] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[1], x[7]); + word3_muladd_2(&w2, &w1, &w0, x[2], x[6]); + word3_muladd_2(&w2, &w1, &w0, x[3], x[5]); + word3_muladd(&w2, &w1, &w0, x[4], x[4]); + z[8] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[2], x[7]); + word3_muladd_2(&w2, &w1, &w0, x[3], x[6]); + word3_muladd_2(&w2, &w1, &w0, x[4], x[5]); + z[9] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[3], x[7]); + word3_muladd_2(&w2, &w1, &w0, x[4], x[6]); + word3_muladd(&w2, &w1, &w0, x[5], x[5]); + z[10] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[4], x[7]); + word3_muladd_2(&w2, &w1, &w0, x[5], x[6]); + z[11] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[5], x[7]); + word3_muladd(&w2, &w1, &w0, x[6], x[6]); + z[12] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd_2(&w2, &w1, &w0, x[6], x[7]); + z[13] = w0; + w0 = w1; + w1 = w2; + w2 = 0; + + word3_muladd(&w2, &w1, &w0, x[7], x[7]); + z[14] = w0; + z[15] = w1; +} +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_misc.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_misc.cpp new file mode 100644 index 0000000000..8b37cd0aec --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_misc.cpp @@ -0,0 +1,154 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * MP Misc Functions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Core Division Operation * + *************************************************/ +u32bit bigint_divcore(word q, word y1, word y2, word x1, word x2, word x3) +{ + word y0 = 0; + y2 = word_madd2(q, y2, y0, &y0); + y1 = word_madd2(q, y1, y0, &y0); + + if (y0 > x1) + return 1; + if (y0 < x1) + return 0; + if (y1 > x2) + return 1; + if (y1 < x2) + return 0; + if (y2 > x3) + return 1; + if (y2 < x3) + return 0; + return 0; +} + +/************************************************* + * Compare two MP integers * + *************************************************/ +s32bit bigint_cmp(const word x[], u32bit x_size, const word y[], u32bit y_size) +{ + if (x_size < y_size) { + return (-bigint_cmp(y, y_size, x, x_size)); + } + + while (x_size > y_size) { + if (x[x_size - 1]) + return 1; + x_size--; + } + for (u32bit j = x_size; j > 0; --j) { + if (x[j - 1] > y[j - 1]) + return 1; + if (x[j - 1] < y[j - 1]) + return -1; + } + return 0; +} + +/************************************************* + * Do a 2-word/1-word Division * + *************************************************/ +word bigint_divop(word n1, word n0, word d) +{ + word high = n1 % d, quotient = 0; + + for (u32bit j = 0; j != MP_WORD_BITS; ++j) { + word high_top_bit = (high & MP_WORD_TOP_BIT); + + high <<= 1; + high |= (n0 >> (MP_WORD_BITS - 1 - j)) & 1; + quotient <<= 1; + + if (high_top_bit || high >= d) { + high -= d; + quotient |= 1; + } + } + + return quotient; +} + +/************************************************* + * Do a 2-word/1-word Modulo * + *************************************************/ +word bigint_modop(word n1, word n0, word d) +{ + word z = bigint_divop(n1, n0, d); + word dummy = 0; + z = word_madd2(z, d, dummy, &dummy); + return (n0 - z); +} + +/************************************************* + * Do a word*word->2-word Multiply * + *************************************************/ +void bigint_wordmul(word a, word b, word *out_low, word *out_high) +{ + const u32bit MP_HWORD_BITS = MP_WORD_BITS / 2; + const word MP_HWORD_MASK = ((word)1 << MP_HWORD_BITS) - 1; + + const word a_hi = (a >> MP_HWORD_BITS); + const word a_lo = (a & MP_HWORD_MASK); + const word b_hi = (b >> MP_HWORD_BITS); + const word b_lo = (b & MP_HWORD_MASK); + + word x0 = a_hi * b_hi; + word x1 = a_lo * b_hi; + word x2 = a_hi * b_lo; + word x3 = a_lo * b_lo; + + x2 += x3 >> (MP_HWORD_BITS); + x2 += x1; + if (x2 < x1) + x0 += ((word)1 << MP_HWORD_BITS); + + *out_high = x0 + (x2 >> MP_HWORD_BITS); + *out_low = ((x2 & MP_HWORD_MASK) << MP_HWORD_BITS) + (x3 & MP_HWORD_MASK); +} +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_mul.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_mul.cpp new file mode 100644 index 0000000000..6d19637b02 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_mul.cpp @@ -0,0 +1,208 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Karatsuba Multiplication Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +namespace { + +/************************************************* + * Simple O(N^2) Multiplication * + *************************************************/ +void bigint_simple_mul(word z[], const word x[], u32bit x_size, const word y[], u32bit y_size) +{ + clear_mem(z, x_size + y_size); + + for (u32bit j = 0; j != x_size; ++j) + z[j + y_size] = bigint_mul_add_words(z + j, y, y_size, x[j]); +} + +/************************************************* + * Karatsuba Multiplication Operation * + *************************************************/ +void karatsuba_mul(word z[], const word x[], const word y[], u32bit N, word workspace[]) +{ + const u32bit KARATSUBA_MUL_LOWER_SIZE = BOTAN_KARAT_MUL_THRESHOLD; + + if (N == 6) + bigint_comba_mul6(z, x, y); + else if (N == 8) + bigint_comba_mul8(z, x, y); + else if (N < KARATSUBA_MUL_LOWER_SIZE || N % 2) + bigint_simple_mul(z, x, N, y, N); + else { + const u32bit N2 = N / 2; + + const word *x0 = x; + const word *x1 = x + N2; + const word *y0 = y; + const word *y1 = y + N2; + word *z0 = z; + word *z1 = z + N; + + const s32bit cmp0 = bigint_cmp(x0, N2, x1, N2); + const s32bit cmp1 = bigint_cmp(y1, N2, y0, N2); + + clear_mem(workspace, 2 * N); + + if (cmp0 && cmp1) { + if (cmp0 > 0) + bigint_sub3(z0, x0, N2, x1, N2); + else + bigint_sub3(z0, x1, N2, x0, N2); + + if (cmp1 > 0) + bigint_sub3(z1, y1, N2, y0, N2); + else + bigint_sub3(z1, y0, N2, y1, N2); + + karatsuba_mul(workspace, z0, z1, N2, workspace + N); + } + + karatsuba_mul(z0, x0, y0, N2, workspace + N); + karatsuba_mul(z1, x1, y1, N2, workspace + N); + + word carry = bigint_add3_nc(workspace + N, z0, N, z1, N); + carry += bigint_add2_nc(z + N2, N, workspace + N, N); + bigint_add2_nc(z + N + N2, N2, &carry, 1); + + if ((cmp0 == cmp1) || (cmp0 == 0) || (cmp1 == 0)) + bigint_add2(z + N2, 2 * N - N2, workspace, N); + else + bigint_sub2(z + N2, 2 * N - N2, workspace, N); + } +} + +/************************************************* + * Pick a good size for the Karatsuba multiply * + *************************************************/ +u32bit karatsuba_size(u32bit z_size, u32bit x_size, u32bit x_sw, u32bit y_size, u32bit y_sw) +{ + if (x_sw > x_size || x_sw > y_size || y_sw > x_size || y_sw > y_size) + return 0; + + if (((x_size == x_sw) && (x_size % 2)) || ((y_size == y_sw) && (y_size % 2))) + return 0; + + u32bit start = (x_sw > y_sw) ? x_sw : y_sw; + u32bit end = (x_size < y_size) ? x_size : y_size; + + if (start == end) { + if (start % 2) + return 0; + return start; + } + + for (u32bit j = start; j <= end; ++j) { + if (j % 2) + continue; + + if (2 * j > z_size) + return 0; + + if (x_sw <= j && j <= x_size && y_sw <= j && j <= y_size) { + if (j % 4 == 2 && (j + 2) <= x_size && (j + 2) <= y_size && 2 * (j + 2) <= z_size) + return j + 2; + return j; + } + } + + return 0; +} + +/************************************************* + * Handle small operand multiplies * + *************************************************/ +void handle_small_mul(word z[], + u32bit z_size, + const word x[], + u32bit x_size, + u32bit x_sw, + const word y[], + u32bit y_size, + u32bit y_sw) +{ + if (x_sw == 1) + bigint_linmul3(z, y, y_sw, x[0]); + else if (y_sw == 1) + bigint_linmul3(z, x, x_sw, y[0]); + + else if (x_sw <= 4 && x_size >= 4 && y_sw <= 4 && y_size >= 4 && z_size >= 8) + bigint_comba_mul4(z, x, y); + + else if (x_sw <= 6 && x_size >= 6 && y_sw <= 6 && y_size >= 6 && z_size >= 12) + bigint_comba_mul6(z, x, y); + + else if (x_sw <= 8 && x_size >= 8 && y_sw <= 8 && y_size >= 8 && z_size >= 16) + bigint_comba_mul8(z, x, y); + + else + bigint_simple_mul(z, x, x_sw, y, y_sw); +} + +} + +/************************************************* + * Multiplication Algorithm Dispatcher * + *************************************************/ +void bigint_mul(word z[], + u32bit z_size, + word workspace[], + const word x[], + u32bit x_size, + u32bit x_sw, + const word y[], + u32bit y_size, + u32bit y_sw) +{ + if (x_size <= 8 || y_size <= 8) { + handle_small_mul(z, z_size, x, x_size, x_sw, y, y_size, y_sw); + return; + } + + const u32bit N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw); + + if (N) { + clear_mem(workspace, 2 * N); + karatsuba_mul(z, x, y, N, workspace); + } else + bigint_simple_mul(z, x, x_sw, y, y_sw); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_mulop.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_mulop.cpp new file mode 100644 index 0000000000..653267bb7d --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_mulop.cpp @@ -0,0 +1,67 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Multiply/Add Algorithm Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Multiply/Add Words * + *************************************************/ +word bigint_mul_add_words(word z[], const word x[], u32bit x_size, word y) +{ + const u32bit blocks = x_size - (x_size % 8); + + word carry = 0; + + for (u32bit j = 0; j != blocks; j += 8) + carry = word8_madd3(z + j, x + j, y, carry); + + for (u32bit j = blocks; j != x_size; ++j) + z[j] = word_madd3(x[j], y, z[j], carry, &carry); + + return carry; +} +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mp_shift.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mp_shift.cpp new file mode 100644 index 0000000000..ea58d6a073 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mp_shift.cpp @@ -0,0 +1,131 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * MP Shift Algorithms Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +extern "C" { + +/************************************************* + * Single Operand Left Shift * + *************************************************/ +void bigint_shl1(word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) +{ + if (word_shift) { + for (u32bit j = 1; j != x_size + 1; ++j) + x[(x_size - j) + word_shift] = x[x_size - j]; + clear_mem(x, word_shift); + } + + if (bit_shift) { + word carry = 0; + for (u32bit j = word_shift; j != x_size + word_shift + 1; ++j) { + word temp = x[j]; + x[j] = (temp << bit_shift) | carry; + carry = (temp >> (MP_WORD_BITS - bit_shift)); + } + } +} + +/************************************************* + * Single Operand Right Shift * + *************************************************/ +void bigint_shr1(word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) +{ + if (x_size < word_shift) { + clear_mem(x, x_size); + return; + } + + if (word_shift) { + for (u32bit j = 0; j != x_size - word_shift; ++j) + x[j] = x[j + word_shift]; + for (u32bit j = x_size - word_shift; j != x_size; ++j) + x[j] = 0; + } + + if (bit_shift) { + word carry = 0; + for (u32bit j = x_size - word_shift; j > 0; --j) { + word temp = x[j - 1]; + x[j - 1] = (temp >> bit_shift) | carry; + carry = (temp << (MP_WORD_BITS - bit_shift)); + } + } +} + +/************************************************* + * Two Operand Left Shift * + *************************************************/ +void bigint_shl2(word y[], const word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) +{ + for (u32bit j = 0; j != x_size; ++j) + y[j + word_shift] = x[j]; + if (bit_shift) { + word carry = 0; + for (u32bit j = word_shift; j != x_size + word_shift + 1; ++j) { + word temp = y[j]; + y[j] = (temp << bit_shift) | carry; + carry = (temp >> (MP_WORD_BITS - bit_shift)); + } + } +} + +/************************************************* + * Two Operand Right Shift * + *************************************************/ +void bigint_shr2(word y[], const word x[], u32bit x_size, u32bit word_shift, u32bit bit_shift) +{ + if (x_size < word_shift) + return; + + for (u32bit j = 0; j != x_size - word_shift; ++j) + y[j] = x[j + word_shift]; + if (bit_shift) { + word carry = 0; + for (u32bit j = x_size - word_shift; j > 0; --j) { + word temp = y[j - 1]; + y[j - 1] = (temp >> bit_shift) | carry; + carry = (temp << (MP_WORD_BITS - bit_shift)); + } + } +} +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mutex.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mutex.cpp new file mode 100644 index 0000000000..7d0978755f --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mutex.cpp @@ -0,0 +1,139 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Mutex Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_NO_LIBSTATE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif + +namespace Botan { + +/************************************************* + * Mutex_Holder Constructor * + *************************************************/ +Mutex_Holder::Mutex_Holder(Mutex *m) + : mux(m) +{ + if (!mux) + throw Invalid_Argument("Mutex_Holder: Argument was NULL"); + mux->lock(); +} + +/************************************************* + * Mutex_Holder Destructor * + *************************************************/ +Mutex_Holder::~Mutex_Holder() +{ + mux->unlock(); +} + +#ifndef BOTAN_NO_LIBSTATE +/************************************************* + * Named_Mutex_Holder Constructor * + *************************************************/ +Named_Mutex_Holder::Named_Mutex_Holder(const std::string &name) + : mutex_name(name) +{ + global_state().get_named_mutex(mutex_name)->lock(); +} + +/************************************************* + * Named_Mutex_Holder Destructor * + *************************************************/ +Named_Mutex_Holder::~Named_Mutex_Holder() +{ + global_state().get_named_mutex(mutex_name)->unlock(); +} +#endif + +/************************************************* + * Default Mutex Factory * + *************************************************/ +#ifdef BOTAN_FIX_GDB +namespace { +#else +Mutex *Default_Mutex_Factory::make() +{ +#endif +class Default_Mutex : public Mutex +{ +public: + class Mutex_State_Error : public Internal_Error + { + public: + Mutex_State_Error(const std::string &where) + : Internal_Error("Default_Mutex::" + where + ": " + "Mutex is already " + where + "ed") + { + } + }; + + void lock() override + { + if (locked) + throw Mutex_State_Error("lock"); + locked = true; + } + + void unlock() override + { + if (!locked) + throw Mutex_State_Error("unlock"); + locked = false; + } + + Default_Mutex() + { + locked = false; + } + +private: + bool locked; +}; + +#ifdef BOTAN_FIX_GDB +} // end unnamed namespace +Mutex *Default_Mutex_Factory::make() +{ +#endif + + return new Default_Mutex; +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.cpp b/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.cpp new file mode 100644 index 0000000000..c5c6b12732 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.cpp @@ -0,0 +1,67 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Qt Thread Mutex Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Qt Mutex Factory * + *************************************************/ +Mutex *Qt_Mutex_Factory::make() +{ + class Qt_Mutex : public Mutex + { + public: + void lock() override + { + mutex.lock(); + } + void unlock() override + { + mutex.unlock(); + } + + private: + QMutex mutex; + }; + + return new Qt_Mutex(); +} + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.h b/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.h new file mode 100644 index 0000000000..9836526ce7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/mux_qt/mux_qt.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Qt Mutex Header File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +#ifndef BOTAN_EXT_MUTEX_QT_H__ +#define BOTAN_EXT_MUTEX_QT_H__ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Qt Mutex * + *************************************************/ +class Qt_Mutex_Factory : public Mutex_Factory +{ +public: + Mutex *make(); +}; + +} + +#endif +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/parsing.cpp b/local/recipes/libs/qca/source/src/botantools/botan/parsing.cpp new file mode 100644 index 0000000000..6d1e82a9b0 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/parsing.cpp @@ -0,0 +1,263 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Parser Functions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Convert a string into an integer * + *************************************************/ +#ifndef BOTAN_TOOLS_ONLY +u32bit to_u32bit(const std::string &number) +{ + u32bit n = 0; + + for (std::string::const_iterator j = number.begin(); j != number.end(); ++j) { + const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10; + + byte digit = Charset::char2digit(*j); + + if ((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5)) + throw Decoding_Error("to_u32bit: Integer overflow"); + n *= 10; + n += digit; + } + return n; +} +#endif + +/************************************************* + * Convert an integer into a string * + *************************************************/ +std::string to_string(u64bit n, u32bit min_len) +{ + std::string lenstr; + if (n) { + while (n > 0) { + lenstr = Charset::digit2char(n % 10) + lenstr; // NOLINT(performance-inefficient-string-concatenation) + n /= 10; + } + } else + lenstr = "0"; + + while (lenstr.size() < min_len) + lenstr = "0" + lenstr; // NOLINT(performance-inefficient-string-concatenation) + + return lenstr; +} + +#ifndef BOTAN_TOOLS_ONLY +/************************************************* + * Parse a SCAN-style algorithm name * + *************************************************/ +std::vector parse_algorithm_name(const std::string &namex) +{ + if (namex.find('(') == std::string::npos && namex.find(')') == std::string::npos) + return std::vector(1, namex); + + std::string name = namex, substring; + std::vector elems; + u32bit level = 0; + + elems.push_back(name.substr(0, name.find('('))); + name = name.substr(name.find('(')); + + for (std::string::const_iterator j = name.begin(); j != name.end(); ++j) { + char c = *j; + + if (c == '(') + ++level; + if (c == ')') { + if (level == 1 && j == name.end() - 1) { + if (elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + return elems; + } + + if (level == 0 || (level == 1 && j != name.end() - 1)) + throw Invalid_Algorithm_Name(namex); + --level; + } + + if (c == ',' && level == 1) { + if (elems.size() == 1) + elems.push_back(substring.substr(1)); + else + elems.push_back(substring); + substring.clear(); + } else + substring += c; + } + + if (substring != "") + throw Invalid_Algorithm_Name(namex); + + return elems; +} + +/************************************************* + * Split the string on slashes * + *************************************************/ +std::vector split_on(const std::string &str, char delim) +{ + std::vector elems; + if (str == "") + return elems; + + std::string substr; + for (std::string::const_iterator j = str.begin(); j != str.end(); ++j) { + if (*j == delim) { + if (substr != "") + elems.push_back(substr); + substr.clear(); + } else + substr += *j; + } + + if (substr == "") + throw Format_Error("Unable to split string: " + str); + elems.push_back(substr); + + return elems; +} + +/************************************************* + * Parse an ASN.1 OID string * + *************************************************/ +std::vector parse_asn1_oid(const std::string &oid) +{ + std::string substring; + std::vector oid_elems; + + for (std::string::const_iterator j = oid.begin(); j != oid.end(); ++j) { + char c = *j; + + if (c == '.') { + if (substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + substring.clear(); + } else + substring += c; + } + + if (substring == "") + throw Invalid_OID(oid); + oid_elems.push_back(to_u32bit(substring)); + + if (oid_elems.size() < 2) + throw Invalid_OID(oid); + + return oid_elems; +} + +/************************************************* + * X.500 String Comparison * + *************************************************/ +bool x500_name_cmp(const std::string &name1, const std::string &name2) +{ + std::string::const_iterator p1 = name1.begin(); + std::string::const_iterator p2 = name2.begin(); + + while ((p1 != name1.end()) && Charset::is_space(*p1)) + ++p1; + while ((p2 != name2.end()) && Charset::is_space(*p2)) + ++p2; + + while (p1 != name1.end() && p2 != name2.end()) { + if (Charset::is_space(*p1)) { + if (!Charset::is_space(*p2)) + return false; + + while ((p1 != name1.end()) && Charset::is_space(*p1)) + ++p1; + while ((p2 != name2.end()) && Charset::is_space(*p2)) + ++p2; + + if (p1 == name1.end() && p2 == name2.end()) + return true; + } + + if (!Charset::caseless_cmp(*p1, *p2)) + return false; + ++p1; + ++p2; + } + + while ((p1 != name1.end()) && Charset::is_space(*p1)) + ++p1; + while ((p2 != name2.end()) && Charset::is_space(*p2)) + ++p2; + + if ((p1 != name1.end()) || (p2 != name2.end())) + return false; + return true; +} + +/************************************************* + * Parse and compute an arithmetic expression * + *************************************************/ +u32bit parse_expr(const std::string &expr) +{ + const bool have_add = (expr.find('+') != std::string::npos); + const bool have_mul = (expr.find('*') != std::string::npos); + + if (have_add) { + std::vector sub_expr = split_on(expr, '+'); + u32bit result = 0; + for (u32bit j = 0; j != sub_expr.size(); ++j) + result += parse_expr(sub_expr[j]); + return result; + } else if (have_mul) { + std::vector sub_expr = split_on(expr, '*'); + u32bit result = 1; + for (u32bit j = 0; j != sub_expr.size(); ++j) + result *= parse_expr(sub_expr[j]); + return result; + } else + return to_u32bit(expr); +} +#endif + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botan/util.cpp b/local/recipes/libs/qca/source/src/botantools/botan/util.cpp new file mode 100644 index 0000000000..fb4a6005ed --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botan/util.cpp @@ -0,0 +1,121 @@ +/* +Copyright (C) 1999-2007 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "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 AUTHOR(S) OR CONTRIBUTOR(S) 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. +*/ +// LICENSEHEADER_END +namespace QCA { // WRAPNS_LINE +/************************************************* + * Utility Functions Source File * + * (C) 1999-2007 The Botan Project * + *************************************************/ + +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#ifndef BOTAN_TOOLS_ONLY +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +#endif +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE +} // WRAPNS_LINE +#include +namespace QCA { // WRAPNS_LINE + +namespace Botan { + +/************************************************* + * Round up n to multiple of align_to * + *************************************************/ +u32bit round_up(u32bit n, u32bit align_to) +{ + if (n % align_to || n == 0) + n += align_to - (n % align_to); + return n; +} + +/************************************************* + * Round down n to multiple of align_to * + *************************************************/ +u32bit round_down(u32bit n, u32bit align_to) +{ + return (n - (n % align_to)); +} + +#ifndef BOTAN_TOOLS_ONLY +/************************************************* + * Return the work required for solving DL * + *************************************************/ +u32bit dl_work_factor(u32bit n_bits) +{ + const u32bit MIN_ESTIMATE = 64; + + if (n_bits < 32) + return 0; + + const double log_x = n_bits / 1.44; + + u32bit estimate = (u32bit)(2.76 * std::pow(log_x, 1.0 / 3.0) * std::pow(std::log(log_x), 2.0 / 3.0)); + + return std::max(estimate, MIN_ESTIMATE); +} + +/************************************************* + * Estimate the entropy of the buffer * + *************************************************/ +u32bit entropy_estimate(const byte buffer[], u32bit length) +{ + if (length <= 4) + return 0; + + u32bit estimate = 0; + byte last = 0, last_delta = 0, last_delta2 = 0; + + for (u32bit j = 0; j != length; ++j) { + byte delta = last ^ buffer[j]; + last = buffer[j]; + + byte delta2 = delta ^ last_delta; + last_delta = delta; + + byte delta3 = delta2 ^ last_delta2; + last_delta2 = delta2; + + byte min_delta = delta; + if (min_delta > delta2) + min_delta = delta2; + if (min_delta > delta3) + min_delta = delta3; + + estimate += hamming_weight(min_delta); + } + + return (estimate / 2); +} +#endif + +} +} // WRAPNS_LINE diff --git a/local/recipes/libs/qca/source/src/botantools/botantools.diff b/local/recipes/libs/qca/source/src/botantools/botantools.diff new file mode 100644 index 0000000000..e30cacf32d --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botantools.diff @@ -0,0 +1,1276 @@ +diff -ur a/include/bigint.h b/include/bigint.h +--- a/include/bigint.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/bigint.h 2007-06-26 11:31:40.000000000 -0700 +@@ -6,7 +6,13 @@ + #ifndef BOTAN_BIGINT_H__ + #define BOTAN_BIGINT_H__ + +-#include ++#ifdef BOTAN_MINIMAL_BIGINT ++# include ++# include ++#else ++# include ++#endif ++ + #include + #include + +@@ -82,7 +88,9 @@ + word operator[](u32bit index) const { return reg[index]; } + void clear() { reg.clear(); } + ++#ifndef BOTAN_MINIMAL_BIGINT + void randomize(u32bit = 0); ++#endif + + void binary_encode(byte[]) const; + void binary_decode(const byte[], u32bit); +@@ -102,7 +110,9 @@ + BigInt(const std::string&); + BigInt(const byte[], u32bit, Base = Binary); + BigInt(Sign, u32bit); ++#ifndef BOTAN_MINIMAL_BIGINT + BigInt(NumberType, u32bit); ++#endif + private: + void grow_to(u32bit) const; + SecureVector reg; +@@ -140,15 +150,19 @@ + /************************************************* + * I/O Operators * + *************************************************/ ++#ifndef BOTAN_MINIMAL_BIGINT + std::ostream& operator<<(std::ostream&, const BigInt&); + std::istream& operator>>(std::istream&, BigInt&); ++#endif + + } + ++#ifndef BOTAN_MINIMAL_BIGINT + namespace std { + + inline void swap(Botan::BigInt& a, Botan::BigInt& b) { a.swap(b); } + + } ++#endif + + #endif +diff -ur a/include/charset.h b/include/charset.h +--- a/include/charset.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/charset.h 2007-06-26 11:31:40.000000000 -0700 +@@ -7,7 +7,9 @@ + #define BOTAN_CHARSET_H__ + + #include ++#ifndef BOTAN_TOOLS_ONLY + #include ++#endif + #include + + namespace Botan { +@@ -15,6 +17,7 @@ + /************************************************* + * Character Set Transcoder Interface * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + class Charset_Transcoder + { + public: +@@ -23,13 +26,16 @@ + + virtual ~Charset_Transcoder() {} + }; ++#endif + + namespace Charset { + + /************************************************* + * Character Set Handling * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + std::string transcode(const std::string&, Character_Set, Character_Set); ++#endif + + bool is_digit(char); + bool is_space(char); +diff -ur a/include/libstate.h b/include/libstate.h +--- a/include/libstate.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/libstate.h 2007-06-26 11:31:40.000000000 -0700 +@@ -6,9 +6,13 @@ + #ifndef BOTAN_LIB_STATE_H__ + #define BOTAN_LIB_STATE_H__ + ++#ifdef BOTAN_TOOLS_ONLY ++#include ++#else + #include + #include + #include ++#endif + #include + #include + #include +@@ -21,6 +25,7 @@ + class Library_State + { + public: ++#ifndef BOTAN_TOOLS_ONLY + class Engine_Iterator + { + public: +@@ -38,11 +43,18 @@ + virtual void pulse(Pulse_Type) {} + virtual ~UI() {} + }; ++#endif + ++ int prealloc_size; + Allocator* get_allocator(const std::string& = "") const; + void add_allocator(Allocator*); ++#ifdef BOTAN_TOOLS_ONLY ++ void set_default_allocator(const std::string&); ++#else + void set_default_allocator(const std::string&) const; ++#endif + ++#ifndef BOTAN_TOOLS_ONLY + bool rng_is_seeded() const { return rng->is_seeded(); } + void randomize(byte[], u32bit); + +@@ -51,19 +63,23 @@ + void add_entropy(const byte[], u32bit); + void add_entropy(EntropySource&, bool); + u32bit seed_prng(bool, u32bit); ++#endif + + void load(class Modules&); + ++#ifndef BOTAN_TOOLS_ONLY + void set_timer(class Timer*); + u64bit system_clock() const; + + class Config& config() const; + + void add_engine(class Engine*); ++#endif + + class Mutex* get_mutex() const; + class Mutex* get_named_mutex(const std::string&); + ++#ifndef BOTAN_TOOLS_ONLY + void set_x509_state(class X509_GlobalState*); + class X509_GlobalState& x509_state(); + +@@ -73,6 +89,7 @@ + void set_transcoder(class Charset_Transcoder*); + std::string transcode(const std::string, + Character_Set, Character_Set) const; ++#endif + + Library_State(class Mutex_Factory*); + ~Library_State(); +@@ -80,23 +97,34 @@ + Library_State(const Library_State&) {} + Library_State& operator=(const Library_State&) { return (*this); } + ++#ifndef BOTAN_TOOLS_ONLY + class Engine* get_engine_n(u32bit) const; ++#endif + + class Mutex_Factory* mutex_factory; ++#ifndef BOTAN_TOOLS_ONLY + class Timer* timer; + class Config* config_obj; + class X509_GlobalState* x509_state_obj; ++#endif + + std::map locks; + std::map alloc_factory; + mutable Allocator* cached_default_allocator; ++#ifdef BOTAN_TOOLS_ONLY ++ std::string default_allocator_type; ++#endif + ++#ifndef BOTAN_TOOLS_ONLY + UI* ui; + class Charset_Transcoder* transcoder; + RandomNumberGenerator* rng; ++#endif + std::vector allocators; ++#ifndef BOTAN_TOOLS_ONLY + std::vector entropy_sources; + std::vector engines; ++#endif + }; + + /************************************************* +diff -ur a/include/mem_ops.h b/include/mem_ops.h +--- a/include/mem_ops.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/mem_ops.h 2007-06-26 11:31:40.000000000 -0700 +@@ -8,6 +8,7 @@ + + #include + #include ++#include + + namespace Botan { + +@@ -15,16 +16,16 @@ + * Memory Manipulation Functions * + *************************************************/ + template inline void copy_mem(T* out, const T* in, u32bit n) +- { std::memmove(out, in, sizeof(T)*n); } ++ { memmove(out, in, sizeof(T)*n); } + + template inline void clear_mem(T* ptr, u32bit n) +- { std::memset(ptr, 0, sizeof(T)*n); } ++ { memset(ptr, 0, sizeof(T)*n); } + + template inline void set_mem(T* ptr, u32bit n, byte val) +- { std::memset(ptr, val, sizeof(T)*n); } ++ { memset(ptr, val, sizeof(T)*n); } + + template inline bool same_mem(const T* p1, const T* p2, u32bit n) +- { return (std::memcmp(p1, p2, sizeof(T)*n) == 0); } ++ { return (memcmp(p1, p2, sizeof(T)*n) == 0); } + + } + +diff -ur a/include/mem_pool.h b/include/mem_pool.h +--- a/include/mem_pool.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/mem_pool.h 2007-06-26 11:31:40.000000000 -0700 +@@ -46,13 +46,17 @@ + byte* alloc(u32bit) throw(); + void free(void*, u32bit) throw(); + +- bool operator<(const void*) const; + bool operator<(const Memory_Block& other) const +- { return (buffer < other.buffer); } ++ { ++ if(buffer < other.buffer && other.buffer < buffer_end) ++ return false; ++ return (buffer < other.buffer); ++ } ++ + private: + typedef u64bit bitmap_type; +- static const u32bit BITMAP_SIZE = 8 * sizeof(bitmap_type); +- static const u32bit BLOCK_SIZE = 64; ++ static const u32bit BITMAP_SIZE; ++ static const u32bit BLOCK_SIZE; + + bitmap_type bitmap; + byte* buffer, *buffer_end; +Only in b/include: mmap_mem.h +diff -ur a/include/modules.h b/include/modules.h +--- a/include/modules.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/modules.h 2007-06-26 11:31:40.000000000 -0700 +@@ -6,7 +6,9 @@ + #ifndef BOTAN_MODULE_FACTORIES_H__ + #define BOTAN_MODULE_FACTORIES_H__ + ++#ifndef BOTAN_TOOLS_ONLY + #include ++#endif + #include + #include + +@@ -19,14 +21,18 @@ + { + public: + virtual class Mutex_Factory* mutex_factory() const = 0; ++#ifndef BOTAN_TOOLS_ONLY + virtual class Timer* timer() const = 0; + virtual class Charset_Transcoder* transcoder() const = 0; ++#endif + + virtual std::string default_allocator() const = 0; + + virtual std::vector allocators() const = 0; ++#ifndef BOTAN_TOOLS_ONLY + virtual std::vector entropy_sources() const = 0; + virtual std::vector engines() const = 0; ++#endif + + virtual ~Modules() {} + }; +@@ -38,18 +44,30 @@ + { + public: + class Mutex_Factory* mutex_factory() const; ++#ifndef BOTAN_TOOLS_ONLY + class Timer* timer() const; + class Charset_Transcoder* transcoder() const; ++#endif + + std::string default_allocator() const; + + std::vector allocators() const; ++#ifndef BOTAN_TOOLS_ONLY + std::vector entropy_sources() const; + std::vector engines() const; ++#endif + ++#ifdef BOTAN_TOOLS_ONLY ++ Builtin_Modules(); ++#else + Builtin_Modules(const InitializerOptions&); ++#endif + private: ++#ifdef BOTAN_TOOLS_ONLY ++ const bool should_lock; ++#else + const bool should_lock, use_engines; ++#endif + }; + + } +diff -ur a/include/mutex.h b/include/mutex.h +--- a/include/mutex.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/mutex.h 2007-06-26 11:31:40.000000000 -0700 +@@ -55,6 +55,7 @@ + /************************************************* + * Named Mutex Holder * + *************************************************/ ++#ifndef BOTAN_NO_LIBSTATE + class Named_Mutex_Holder + { + public: +@@ -63,6 +64,7 @@ + private: + const std::string mutex_name; + }; ++#endif + + } + +Only in b/include: mux_qt.h +diff -ur a/include/numthry.h b/include/numthry.h +--- a/include/numthry.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/numthry.h 2007-06-26 11:31:40.000000000 -0700 +@@ -7,11 +7,14 @@ + #define BOTAN_NUMBTHRY_H__ + + #include ++#ifndef BOTAN_MINIMAL_BIGINT + #include + #include ++#endif + + namespace Botan { + ++#ifndef BOTAN_MINIMAL_BIGINT + /************************************************* + * Fused Arithmetic Operations * + *************************************************/ +@@ -22,9 +25,11 @@ + * Number Theory Functions * + *************************************************/ + inline BigInt abs(const BigInt& n) { return n.abs(); } ++#endif + + void divide(const BigInt&, const BigInt&, BigInt&, BigInt&); + ++#ifndef BOTAN_MINIMAL_BIGINT + BigInt gcd(const BigInt&, const BigInt&); + BigInt lcm(const BigInt&, const BigInt&); + +@@ -85,6 +90,7 @@ + Fixed_Exponent_Power_Mod pow_mod; + Modular_Reducer reducer; + }; ++#endif + + } + +diff -ur a/include/parsing.h b/include/parsing.h +--- a/include/parsing.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/parsing.h 2007-06-26 11:31:40.000000000 -0700 +@@ -15,17 +15,21 @@ + /************************************************* + * String Parsing Functions * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + std::vector parse_algorithm_name(const std::string&); + std::vector split_on(const std::string&, char); + std::vector parse_asn1_oid(const std::string&); + bool x500_name_cmp(const std::string&, const std::string&); + u32bit parse_expr(const std::string&); ++#endif + + /************************************************* + * String/Integer Conversions * + *************************************************/ + std::string to_string(u64bit, u32bit = 0); ++#ifndef BOTAN_TOOLS_ONLY + u32bit to_u32bit(const std::string&); ++#endif + + } + +diff -ur a/include/types.h b/include/types.h +--- a/include/types.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/types.h 2007-06-26 11:31:40.000000000 -0700 +@@ -6,10 +6,24 @@ + #ifndef BOTAN_TYPES_H__ + #define BOTAN_TYPES_H__ + ++#ifdef BOTAN_TYPES_QT ++#include ++#else + #include ++#endif + + namespace Botan { + ++#ifdef BOTAN_TYPES_QT ++ ++typedef quint8 byte; ++typedef quint16 u16bit; ++typedef quint32 u32bit; ++typedef qint32 s32bit; ++typedef quint64 u64bit; ++ ++#else ++ + typedef unsigned char byte; + typedef unsigned short u16bit; + typedef unsigned int u32bit; +@@ -26,6 +40,8 @@ + typedef unsigned long long u64bit; + #endif + ++#endif // BOTAN_TYPES_QT ++ + } + + namespace Botan_types { +diff -ur a/include/util.h b/include/util.h +--- a/include/util.h 2007-03-24 11:51:37.000000000 -0700 ++++ b/include/util.h 2007-06-26 11:31:40.000000000 -0700 +@@ -13,8 +13,10 @@ + /************************************************* + * Timer Access Functions * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + u64bit system_time(); + u64bit system_clock(); ++#endif + + /************************************************* + * Memory Locking Functions * +@@ -27,13 +29,17 @@ + *************************************************/ + u32bit round_up(u32bit, u32bit); + u32bit round_down(u32bit, u32bit); ++#ifndef BOTAN_TOOLS_ONLY + u64bit combine_timers(u32bit, u32bit, u32bit); ++#endif + + /************************************************* + * Work Factor Estimates * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + u32bit entropy_estimate(const byte[], u32bit); + u32bit dl_work_factor(u32bit); ++#endif + + } + +diff -ur a/modules/alloc_mmap/mmap_mem.cpp b/modules/alloc_mmap/mmap_mem.cpp +--- a/modules/alloc_mmap/mmap_mem.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/modules/alloc_mmap/mmap_mem.cpp 2007-08-20 07:51:08.000000000 -0700 +@@ -102,6 +102,11 @@ + void MemoryMapping_Allocator::dealloc_block(void* ptr, u32bit n) + { + if(ptr == 0) return; ++#ifdef MLOCK_NOT_VOID_PTR ++# define MLOCK_TYPE_CAST (char *) ++#else ++# define MLOCK_TYPE_CAST ++#endif + + const u32bit OVERWRITE_PASSES = 12; + const byte PATTERNS[] = { 0x00, 0xFF, 0xAA, 0x55, 0x73, 0x8C, 0x5F, 0xA0, +@@ -110,14 +115,14 @@ + for(u32bit j = 0; j != OVERWRITE_PASSES; j++) + { + std::memset(ptr, PATTERNS[j % sizeof(PATTERNS)], n); +- if(msync(ptr, n, MS_SYNC)) ++ if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) + throw MemoryMapping_Failed("Sync operation failed"); + } + std::memset(ptr, 0, n); +- if(msync(ptr, n, MS_SYNC)) ++ if(msync(MLOCK_TYPE_CAST ptr, n, MS_SYNC)) + throw MemoryMapping_Failed("Sync operation failed"); + +- if(munmap(ptr, n)) ++ if(munmap(MLOCK_TYPE_CAST ptr, n)) + throw MemoryMapping_Failed("Could not unmap file"); + } + +diff -ur a/modules/mux_qt/mux_qt.cpp b/modules/mux_qt/mux_qt.cpp +--- a/modules/mux_qt/mux_qt.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/modules/mux_qt/mux_qt.cpp 2007-06-26 11:32:30.000000000 -0700 +@@ -6,7 +6,7 @@ + #include + #include + +-#if !defined(QT_THREAD_SUPPORT) ++#if QT_VERSION <= 0x040000 && !defined(QT_THREAD_SUPPORT) + #error Your version of Qt does not support threads or mutexes + #endif + +diff -ur a/src/big_code.cpp b/src/big_code.cpp +--- a/src/big_code.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/big_code.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -6,7 +6,9 @@ + #include + #include + #include ++#ifndef BOTAN_MINIMAL_BIGINT + #include ++#endif + + namespace Botan { + +@@ -17,6 +19,7 @@ + { + if(base == Binary) + n.binary_encode(output); ++#ifndef BOTAN_MINIMAL_BIGINT + else if(base == Hexadecimal) + { + SecureVector binary(n.encoded_size(Binary)); +@@ -24,6 +27,7 @@ + for(u32bit j = 0; j != binary.size(); ++j) + Hex_Encoder::encode(binary[j], output + 2*j); + } ++#endif + else if(base == Octal) + { + BigInt copy = n; +@@ -46,7 +50,15 @@ + output[output_size - 1 - j] = + Charset::digit2char(remainder.word_at(0)); + if(copy.is_zero()) ++ { ++ if(j < output_size - 1) ++ { ++ int extra = output_size - 1 - j; ++ memmove(output, output + extra, output_size - extra); ++ memset(output + output_size - extra, 0, extra); ++ } + break; ++ } + } + } + else +@@ -99,6 +111,7 @@ + BigInt r; + if(base == Binary) + r.binary_decode(buf, length); ++#ifndef BOTAN_MINIMAL_BIGINT + else if(base == Hexadecimal) + { + SecureVector hex; +@@ -119,6 +132,7 @@ + binary[j] = Hex_Decoder::decode(hex+2*j-offset); + r.binary_decode(binary, binary.size()); + } ++#endif + else if(base == Decimal || base == Octal) + { + const u32bit RADIX = ((base == Decimal) ? 10 : 8); +diff -ur a/src/big_io.cpp b/src/big_io.cpp +--- a/src/big_io.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/big_io.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -8,6 +8,8 @@ + + namespace Botan { + ++#ifndef BOTAN_MINIMAL_BIGINT ++ + /************************************************* + * Write the BigInt into a stream * + *************************************************/ +@@ -49,4 +51,6 @@ + return stream; + } + ++#endif ++ + } +diff -ur a/src/big_ops2.cpp b/src/big_ops2.cpp +--- a/src/big_ops2.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/big_ops2.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -19,7 +19,11 @@ + { + const u32bit x_sw = sig_words(), y_sw = y.sig_words(); + ++#ifdef BOTAN_TYPES_QT ++ const u32bit reg_size = qMax(x_sw, y_sw) + 1; ++#else + const u32bit reg_size = std::max(x_sw, y_sw) + 1; ++#endif + grow_to(reg_size); + + if((sign() == y.sign())) +@@ -56,7 +60,11 @@ + + s32bit relative_size = bigint_cmp(data(), x_sw, y.data(), y_sw); + ++#ifdef BOTAN_TYPES_QT ++ const u32bit reg_size = qMax(x_sw, y_sw) + 1; ++#else + const u32bit reg_size = std::max(x_sw, y_sw) + 1; ++#endif + grow_to(reg_size); + + if(relative_size < 0) +diff -ur a/src/big_ops3.cpp b/src/big_ops3.cpp +--- a/src/big_ops3.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/big_ops3.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -18,7 +18,11 @@ + { + const u32bit x_sw = x.sig_words(), y_sw = y.sig_words(); + ++#ifdef BOTAN_TYPES_QT ++ BigInt z(x.sign(), qMax(x_sw, y_sw) + 1); ++#else + BigInt z(x.sign(), std::max(x_sw, y_sw) + 1); ++#endif + + if((x.sign() == y.sign())) + bigint_add3(z.get_reg(), x.data(), x_sw, y.data(), y_sw); +@@ -49,7 +53,11 @@ + + s32bit relative_size = bigint_cmp(x.data(), x_sw, y.data(), y_sw); + ++#ifdef BOTAN_TYPES_QT ++ BigInt z(BigInt::Positive, qMax(x_sw, y_sw) + 1); ++#else + BigInt z(BigInt::Positive, std::max(x_sw, y_sw) + 1); ++#endif + + if(relative_size < 0) + { +diff -ur a/src/charset.cpp b/src/charset.cpp +--- a/src/charset.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/charset.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -4,10 +4,15 @@ + *************************************************/ + + #include ++#ifdef BOTAN_TOOLS_ONLY ++#include ++#else + #include + #include ++#endif + #include + #include ++#include + + namespace Botan { + +@@ -16,11 +21,13 @@ + /************************************************* + * Perform character set transcoding * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + std::string transcode(const std::string& str, + Character_Set to, Character_Set from) + { + return global_state().transcode(str, to, from); + } ++#endif + + /************************************************* + * Check if a character represents a digit * +@@ -92,11 +99,13 @@ + *************************************************/ + bool caseless_cmp(char a, char b) + { +- return (std::tolower((unsigned char)a) == std::tolower((unsigned char)b)); ++ return (tolower((unsigned char)a) == tolower((unsigned char)b)); + } + + } + ++#ifndef BOTAN_TOOLS_ONLY ++ + /************************************************* + * Hex Encoder Lookup Tables * + *************************************************/ +@@ -168,4 +177,6 @@ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; + ++#endif ++ + } +diff -ur a/src/defalloc.cpp b/src/defalloc.cpp +--- a/src/defalloc.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/defalloc.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -8,6 +8,8 @@ + #include + #include + #include ++#include ++#include + + namespace Botan { + +@@ -18,7 +20,7 @@ + *************************************************/ + void* do_malloc(u32bit n, bool do_lock) + { +- void* ptr = std::malloc(n); ++ void* ptr = malloc(n); + + if(!ptr) + return 0; +@@ -26,7 +28,7 @@ + if(do_lock) + lock_mem(ptr, n); + +- std::memset(ptr, 0, n); ++ memset(ptr, 0, n); + return ptr; + } + +@@ -38,11 +40,11 @@ + if(!ptr) + return; + +- std::memset(ptr, 0, n); ++ memset(ptr, 0, n); + if(do_lock) + unlock_mem(ptr, n); + +- std::free(ptr); ++ free(ptr); + } + + } +diff -ur a/src/libstate.cpp b/src/libstate.cpp +--- a/src/libstate.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/libstate.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -4,14 +4,20 @@ + *************************************************/ + + #include ++#ifndef BOTAN_TOOLS_ONLY + #include ++#endif + #include ++#ifndef BOTAN_TOOLS_ONLY + #include + #include ++#endif + #include + #include ++#ifndef BOTAN_TOOLS_ONLY + #include + #include ++#endif + #include + + namespace Botan { +@@ -56,10 +62,12 @@ + /************************************************* + * Increment the Engine iterator * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + Engine* Library_State::Engine_Iterator::next() + { + return lib.get_engine_n(n++); + } ++#endif + + /************************************************* + * Get a new mutex object * +@@ -92,8 +100,11 @@ + + if(!cached_default_allocator) + { ++#ifdef BOTAN_TOOLS_ONLY ++ std::string chosen = default_allocator_type; ++#else + std::string chosen = config().option("base/default_allocator"); +- ++#endif + if(chosen == "") + chosen = "malloc"; + +@@ -120,17 +131,26 @@ + /************************************************* + * Set the default allocator type * + *************************************************/ ++#ifdef BOTAN_TOOLS_ONLY ++void Library_State::set_default_allocator(const std::string& type) ++#else + void Library_State::set_default_allocator(const std::string& type) const ++#endif + { + Named_Mutex_Holder lock("allocator"); + + if(type == "") + return; + ++#ifdef BOTAN_TOOLS_ONLY ++ default_allocator_type = type; ++#else + config().set("conf", "base/default_allocator", type); ++#endif + cached_default_allocator = 0; + } + ++#ifndef BOTAN_TOOLS_ONLY + /************************************************* + * Set the high resolution clock implementation * + *************************************************/ +@@ -317,13 +337,17 @@ + return (*config_obj); + } + ++#endif ++ + /************************************************* + * Load modules * + *************************************************/ + void Library_State::load(Modules& modules) + { ++#ifndef BOTAN_TOOLS_ONLY + set_timer(modules.timer()); + set_transcoder(modules.transcoder()); ++#endif + + std::vector mod_allocs = modules.allocators(); + for(u32bit j = 0; j != mod_allocs.size(); j++) +@@ -331,6 +355,7 @@ + + set_default_allocator(modules.default_allocator()); + ++#ifndef BOTAN_TOOLS_ONLY + std::vector mod_engines = modules.engines(); + for(u32bit j = 0; j != mod_engines.size(); ++j) + { +@@ -341,6 +366,7 @@ + std::vector sources = modules.entropy_sources(); + for(u32bit j = 0; j != sources.size(); ++j) + add_entropy_source(sources[j]); ++#endif + } + + /************************************************* +@@ -352,25 +378,39 @@ + throw Exception("Library_State: no mutex found"); + + this->mutex_factory = mutex_factory; ++#ifndef BOTAN_TOOLS_ONLY + this->timer = new Timer(); + this->transcoder = 0; + this->config_obj = new Config(); ++#endif + ++#ifndef BOTAN_TOOLS_ONLY + locks["settings"] = get_mutex(); ++#endif + locks["allocator"] = get_mutex(); ++#ifndef BOTAN_TOOLS_ONLY + locks["rng"] = get_mutex(); + locks["engine"] = get_mutex(); + rng = 0; ++#endif + cached_default_allocator = 0; ++#ifndef BOTAN_TOOLS_ONLY + x509_state_obj = 0; + ui = 0; ++#endif + } + + /************************************************* + * Library_State Destructor * + *************************************************/ ++static void delete_lock(std::pair &pair) ++ { ++ delete pair.second; ++ } ++ + Library_State::~Library_State() + { ++#ifndef BOTAN_TOOLS_ONLY + delete x509_state_obj; + delete transcoder; + delete rng; +@@ -381,6 +421,7 @@ + std::for_each(entropy_sources.begin(), entropy_sources.end(), + del_fun()); + std::for_each(engines.begin(), engines.end(), del_fun()); ++#endif + + cached_default_allocator = 0; + +@@ -390,8 +431,7 @@ + delete allocators[j]; + } + +- std::for_each(locks.begin(), locks.end(), +- delete2nd::value_type>); ++ std::for_each(locks.begin(), locks.end(), delete_lock); + + delete mutex_factory; + } +diff -ur a/src/mem_pool.cpp b/src/mem_pool.cpp +--- a/src/mem_pool.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/mem_pool.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -5,8 +5,12 @@ + + #include + #include ++#ifdef BOTAN_TOOLS_ONLY ++#include ++#else + #include + #include ++#endif + #include + #include + +@@ -22,7 +26,11 @@ + if(provided) + return provided; + ++#ifdef BOTAN_TOOLS_ONLY ++ u32bit result = (u32bit)global_state().prealloc_size; ++#else + u32bit result = global_config().option_as_u32bit("base/memory_chunk"); ++#endif + if(result) + return result; + +@@ -42,16 +50,6 @@ + } + + /************************************************* +-* Compare a Memory_Block with a void pointer * +-*************************************************/ +-inline bool Pooling_Allocator::Memory_Block::operator<(const void* other) const +- { +- if(buffer <= other && other < buffer_end) +- return false; +- return (buffer < other); +- } +- +-/************************************************* + * See if ptr is contained by this block * + *************************************************/ + bool Pooling_Allocator::Memory_Block::contains(void* ptr, +@@ -207,7 +205,7 @@ + const u32bit block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE; + + std::vector::iterator i = +- std::lower_bound(blocks.begin(), blocks.end(), ptr); ++ std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); + + if(i == blocks.end() || !i->contains(ptr, block_no)) + throw Invalid_State("Pointer released to the wrong allocator"); +@@ -270,7 +268,10 @@ + } + + std::sort(blocks.begin(), blocks.end()); +- last_used = std::lower_bound(blocks.begin(), blocks.end(), ptr); ++ last_used = std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr)); + } + ++const u32bit Pooling_Allocator::Memory_Block::BITMAP_SIZE = 8 * sizeof(Pooling_Allocator::Memory_Block::bitmap_type); ++const u32bit Pooling_Allocator::Memory_Block::BLOCK_SIZE = 64; ++ + } +diff -ur a/src/modules.cpp b/src/modules.cpp +--- a/src/modules.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/modules.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -5,71 +5,77 @@ + + #include + #include ++#ifndef BOTAN_TOOLS_ONLY + #include + #include + #include + #include ++#endif + + #if defined(BOTAN_EXT_MUTEX_PTHREAD) +- #include ++# include + #elif defined(BOTAN_EXT_MUTEX_WIN32) +- #include ++# include + #elif defined(BOTAN_EXT_MUTEX_QT) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ALLOC_MMAP) +- #include ++# include + #endif + ++#ifndef BOTAN_TOOLS_ONLY ++ + #if defined(BOTAN_EXT_TIMER_HARDWARE) +- #include ++# include + #elif defined(BOTAN_EXT_TIMER_POSIX) +- #include ++# include + #elif defined(BOTAN_EXT_TIMER_UNIX) +- #include ++# include + #elif defined(BOTAN_EXT_TIMER_WIN32) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENGINE_AEP) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENGINE_GNU_MP) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENGINE_OPENSSL) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_AEP) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_EGD) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_UNIX) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_BEOS) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_CAPI) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_WIN32) +- #include ++# include + #endif + + #if defined(BOTAN_EXT_ENTROPY_SRC_FTW) +- #include ++# include ++#endif ++ + #endif + + namespace Botan { +@@ -93,6 +99,7 @@ + /************************************************* + * Find a high resolution timer, if possible * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + Timer* Builtin_Modules::timer() const + { + #if defined(BOTAN_EXT_TIMER_HARDWARE) +@@ -107,6 +114,7 @@ + return new Timer; + #endif + } ++#endif + + /************************************************* + * Find any usable allocators * +@@ -142,6 +150,8 @@ + return "malloc"; + } + ++#ifndef BOTAN_TOOLS_ONLY ++ + /************************************************* + * Register any usable entropy sources * + *************************************************/ +@@ -217,13 +227,22 @@ + return new Default_Charset_Transcoder; + } + ++#endif ++ + /************************************************* + * Builtin_Modules Constructor * + *************************************************/ ++#ifdef BOTAN_TOOLS_ONLY ++Builtin_Modules::Builtin_Modules() : ++ should_lock(true) ++ { ++ } ++#else + Builtin_Modules::Builtin_Modules(const InitializerOptions& args) : + should_lock(args.secure_memory()), + use_engines(args.use_engines()) + { + } ++#endif + + } +diff -ur a/src/mp_asm.cpp b/src/mp_asm.cpp +--- a/src/mp_asm.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/mp_asm.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -174,6 +174,7 @@ + /************************************************* + * Montgomery Reduction Algorithm * + *************************************************/ ++#ifndef BOTAN_MINIMAL_BIGINT + void bigint_monty_redc(word z[], u32bit z_size, + const word x[], u32bit x_size, word u) + { +@@ -199,6 +200,7 @@ + if(bigint_cmp(z + x_size, x_size + 1, x, x_size) >= 0) + bigint_sub2(z + x_size, x_size + 1, x, x_size); + } ++#endif + + } + +diff -ur a/src/mutex.cpp b/src/mutex.cpp +--- a/src/mutex.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/mutex.cpp 2007-08-20 07:53:57.000000000 -0700 +@@ -3,8 +3,11 @@ + * (C) 1999-2007 The Botan Project * + *************************************************/ + ++#include + #include ++#ifndef BOTAN_NO_LIBSTATE + #include ++#endif + + namespace Botan { + +@@ -26,6 +29,7 @@ + mux->unlock(); + } + ++#ifndef BOTAN_NO_LIBSTATE + /************************************************* + * Named_Mutex_Holder Constructor * + *************************************************/ +@@ -42,12 +46,17 @@ + { + global_state().get_named_mutex(mutex_name)->unlock(); + } ++#endif + + /************************************************* + * Default Mutex Factory * + *************************************************/ ++#ifdef BOTAN_FIX_GDB ++namespace { ++#else + Mutex* Default_Mutex_Factory::make() + { ++#endif + class Default_Mutex : public Mutex + { + public: +@@ -78,6 +87,12 @@ + bool locked; + }; + ++#ifdef BOTAN_FIX_GDB ++ } // end unnamed namespace ++Mutex* Default_Mutex_Factory::make() ++ { ++#endif ++ + return new Default_Mutex; + } + +diff -ur a/src/parsing.cpp b/src/parsing.cpp +--- a/src/parsing.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/parsing.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -12,6 +12,7 @@ + /************************************************* + * Convert a string into an integer * + *************************************************/ ++#ifndef BOTAN_TOOLS_ONLY + u32bit to_u32bit(const std::string& number) + { + u32bit n = 0; +@@ -29,7 +30,7 @@ + } + return n; + } +- ++#endif + + /************************************************* + * Convert an integer into a string * +@@ -54,6 +55,7 @@ + return lenstr; + } + ++#ifndef BOTAN_TOOLS_ONLY + /************************************************* + * Parse a SCAN-style algorithm name * + *************************************************/ +@@ -237,5 +239,6 @@ + else + return to_u32bit(expr); + } ++#endif + + } +diff -ur a/src/util.cpp b/src/util.cpp +--- a/src/util.cpp 2007-03-24 11:51:37.000000000 -0700 ++++ b/src/util.cpp 2007-06-26 11:31:30.000000000 -0700 +@@ -4,7 +4,9 @@ + *************************************************/ + + #include ++#ifndef BOTAN_TOOLS_ONLY + #include ++#endif + #include + #include + +@@ -28,6 +30,7 @@ + return (n - (n % align_to)); + } + ++#ifndef BOTAN_TOOLS_ONLY + /************************************************* + * Return the work required for solving DL * + *************************************************/ +@@ -77,5 +80,6 @@ + + return (estimate / 2); + } ++#endif + + } diff --git a/local/recipes/libs/qca/source/src/botantools/botantools.h b/local/recipes/libs/qca/source/src/botantools/botantools.h new file mode 100644 index 0000000000..f4cae41228 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/botantools.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2004-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#ifndef BOTANTOOLS_H +#define BOTANTOOLS_H + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/local/recipes/libs/qca/source/src/botantools/btest.cpp b/local/recipes/libs/qca/source/src/botantools/btest.cpp new file mode 100644 index 0000000000..a33cc39cad --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/btest.cpp @@ -0,0 +1,26 @@ +/* + * btest.cpp - test to ensure botantools compiles properly + * Copyright (C) 2004-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "botantools.h" + +int main() +{ + return 0; +} diff --git a/local/recipes/libs/qca/source/src/botantools/removeadded.sh b/local/recipes/libs/qca/source/src/botantools/removeadded.sh new file mode 100755 index 0000000000..973d727759 --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/removeadded.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +for f in `find botan -name \*.cpp -o -name \*.h` ; do + sed -e '1,/LICENSEHEADER_END/d' $f | grep -v WRAPNS_LINE > file.tmp + cp file.tmp $f + rm file.tmp +done + diff --git a/local/recipes/libs/qca/source/src/botantools/wrapns.c b/local/recipes/libs/qca/source/src/botantools/wrapns.c new file mode 100644 index 0000000000..82f355fadc --- /dev/null +++ b/local/recipes/libs/qca/source/src/botantools/wrapns.c @@ -0,0 +1,250 @@ +/* + Copyright (C) 2006 Justin Karneges + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +static char *read_file(const char *fname) +{ + FILE *f; + char *buf; + int size; + + f = fopen(fname, "r"); + if (!f) + return 0; + + fseek(f, 0l, SEEK_END); + size = ftell(f); + rewind(f); + buf = malloc(size + 1); + if (!buf) { + fclose(f); + return 0; + } + + fread(buf, size, 1, f); + buf[size] = 0; + fclose(f); + + return buf; +} + +static void write_file(const char *fname, const char *buf) +{ + FILE *f; + + f = fopen(fname, "w"); + fwrite(buf, strlen(buf), 1, f); + fclose(f); +} + +static char *insert_string(char *buf, char *str, int at) +{ + int bsize, slen; + bsize = strlen(buf) + 1; + slen = strlen(str); + + buf = realloc(buf, bsize + slen); + if (!buf) + return 0; + memmove(buf + at + slen, buf + at, bsize - at); + memcpy(buf + at, str, slen); + return buf; +} + +static int is_include(const char *buf) +{ + char *p, *sub; + int len; + + if (buf[0] != '#') + return 0; + + p = strchr(buf, '\n'); + if (!p) + return 0; + + // take the substring + ++buf; + len = p - buf; + sub = malloc(len + 1); + memcpy(sub, buf, len); + sub[len] = 0; + + if (strstr(sub, "include")) { + free(sub); + return 1; + } + free(sub); + return 0; +} + +static const char *find_include(const char *buf) +{ + const char *p = buf; + + if (p[0] == '#') { + if (is_include(p)) + return p; + } + + while (1) { + p = strstr(p, "\n#"); + if (!p) + break; + ++p; + if (is_include(p)) + return p; + } + + return 0; +} + +static const char *find_std(const char *buf) +{ + const char *p; + p = strstr(buf, "namespace std"); + return p; +} + +static const char *skip_to_next_curly(const char *buf) +{ + int n; + for (n = 0; buf[n]; ++n) { + if (buf[n] == '{' || buf[n] == '}') + return (buf + n); + } + return 0; +} + +static const char *skip_over_curlies(const char *buf) +{ + const char *p; + int opened; + + p = strchr(buf, '{'); + if (!p) + return buf; + + ++p; + opened = 1; + while (opened) { + p = skip_to_next_curly(p); + if (!p) + return 0; + if (*p == '{') + ++opened; + else if (*p == '}') + --opened; + ++p; + } + return p; +} + +void do_it(char *buf, char *ns) +{ + char str[256], str_end[256]; + const char *p, *p2; + int slen, slen_end; + int at; + + sprintf(str, "namespace %s { // WRAPNS_LINE\n", ns); + slen = strlen(str); + + sprintf(str_end, "} // WRAPNS_LINE\n", ns); + slen_end = strlen(str_end); + + at = 0; + while (1) { + // make sure there is a line left + p = strchr(buf + at, '\n'); + if (!p) + break; + + // open the namespace + buf = insert_string(buf, str, at); + at += slen; + + // find an #include, "namespace std", or the end + int f = 0; + p = find_include(buf + at); + p2 = find_std(buf + at); + if (p && (!p2 || p < p2)) { + f = 1; + } else if (p2) { + f = 2; + p = p2; + } + + if (f == 0) { + // point to the end + at = strlen(buf); + } else if (f == 1) { + printf("found include\n"); + at = p - buf; + } else if (f == 2) { + printf("found std\n"); + at = p - buf; + } + + // close it + buf = insert_string(buf, str_end, at); + at += slen_end; + + if (f == 1) { + // go to next line + p = strchr(buf + at, '\n'); + if (!p) + break; + at = p - buf + 1; + } else if (f == 2) { + p = skip_over_curlies(buf + at); + if (!p) + break; + at = p - buf; + + // go to next line + p = strchr(buf + at, '\n'); + if (!p) + break; + at = p - buf + 1; + } + } +} + +int main(int argc, char **argv) +{ + char *buf; + + if (argc < 3) { + printf("usage: wrapns [file] [namespace]\n\n"); + return 1; + } + + buf = read_file(argv[1]); + do_it(buf, argv[2]); + write_file(argv[1], buf); + free(buf); + + return 0; +} diff --git a/local/recipes/libs/qca/source/src/qca_basic.cpp b/local/recipes/libs/qca/source/src/qca_basic.cpp new file mode 100644 index 0000000000..f2694e7eb5 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_basic.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005,2007 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_basic.h" + +#include "qcaprovider.h" + +#include +#include + +namespace QCA { + +// from qca_core.cpp +QMutex *global_random_mutex(); +Random *global_random(); +Provider::Context *getContext(const QString &type, Provider *p); + +// from qca_publickey.cpp +ProviderList allProviders(); +Provider *providerForName(const QString &name); + +static void mergeList(QStringList *a, const QStringList &b) +{ + foreach (const QString &s, b) { + if (!a->contains(s)) + a->append(s); + } +} + +static QStringList get_hash_types(Provider *p) +{ + QStringList out; + InfoContext *c = static_cast(getContext(QStringLiteral("info"), p)); + if (!c) + return out; + out = c->supportedHashTypes(); + delete c; + return out; +} + +static QStringList get_cipher_types(Provider *p) +{ + QStringList out; + InfoContext *c = static_cast(getContext(QStringLiteral("info"), p)); + if (!c) + return out; + out = c->supportedCipherTypes(); + delete c; + return out; +} + +static QStringList get_mac_types(Provider *p) +{ + QStringList out; + InfoContext *c = static_cast(getContext(QStringLiteral("info"), p)); + if (!c) + return out; + out = c->supportedMACTypes(); + delete c; + return out; +} + +static QStringList get_types(QStringList (*get_func)(Provider *p), const QString &provider) +{ + QStringList out; + if (!provider.isEmpty()) { + Provider *p = providerForName(provider); + if (p) + out = get_func(p); + } else { + const ProviderList pl = allProviders(); + foreach (Provider *p, pl) + mergeList(&out, get_func(p)); + } + return out; +} + +static QStringList supportedHashTypes(const QString &provider) +{ + return get_types(get_hash_types, provider); +} + +static QStringList supportedCipherTypes(const QString &provider) +{ + return get_types(get_cipher_types, provider); +} + +static QStringList supportedMACTypes(const QString &provider) +{ + return get_types(get_mac_types, provider); +} + +//---------------------------------------------------------------------------- +// Random +//---------------------------------------------------------------------------- +Random::Random(const QString &provider) + : Algorithm(QStringLiteral("random"), provider) +{ +} + +Random::Random(const Random &from) + : Algorithm(from) +{ +} + +Random::~Random() +{ +} + +Random &Random::operator=(const Random &from) +{ + Algorithm::operator=(from); + return *this; +} + +uchar Random::nextByte() +{ + return (uchar)(nextBytes(1)[0]); +} + +SecureArray Random::nextBytes(int size) +{ + return static_cast(context())->nextBytes(size); +} + +uchar Random::randomChar() +{ + QMutexLocker locker(global_random_mutex()); + return global_random()->nextByte(); +} + +int Random::randomInt() +{ + QMutexLocker locker(global_random_mutex()); + const SecureArray a = global_random()->nextBytes(sizeof(int)); + int x; + memcpy(&x, a.data(), a.size()); + return x; +} + +SecureArray Random::randomArray(int size) +{ + QMutexLocker locker(global_random_mutex()); + return global_random()->nextBytes(size); +} + +//---------------------------------------------------------------------------- +// Hash +//---------------------------------------------------------------------------- +Hash::Hash(const QString &type, const QString &provider) + : Algorithm(type, provider) +{ +} + +Hash::Hash(const Hash &from) + : Algorithm(from) + , BufferedComputation(from) +{ +} + +Hash::~Hash() +{ +} + +Hash &Hash::operator=(const Hash &from) +{ + Algorithm::operator=(from); + return *this; +} + +QStringList Hash::supportedTypes(const QString &provider) +{ + return supportedHashTypes(provider); +} + +QString Hash::type() const +{ + // algorithm type is the same as the hash type + return Algorithm::type(); +} + +void Hash::clear() +{ + static_cast(context())->clear(); +} + +void Hash::update(const MemoryRegion &a) +{ + static_cast(context())->update(a); +} + +void Hash::update(const QByteArray &a) +{ + update(MemoryRegion(a)); +} + +void Hash::update(const char *data, int len) +{ + if (len < 0) + len = qstrlen(data); + if (len == 0) + return; + + update(MemoryRegion(QByteArray::fromRawData(data, len))); +} + +// Reworked from KMD5, from KDE's kdelibs +void Hash::update(QIODevice *file) +{ + char buffer[1024]; + int len; + + while ((len = file->read(reinterpret_cast(buffer), sizeof(buffer))) > 0) + update(buffer, len); +} + +MemoryRegion Hash::final() +{ + return static_cast(context())->final(); +} + +MemoryRegion Hash::hash(const MemoryRegion &a) +{ + return process(a); +} + +QString Hash::hashToString(const MemoryRegion &a) +{ + return arrayToHex(hash(a).toByteArray()); +} + +//---------------------------------------------------------------------------- +// Cipher +//---------------------------------------------------------------------------- +class Cipher::Private +{ +public: + QString type; + Cipher::Mode mode; + Cipher::Padding pad; + Direction dir; + SymmetricKey key; + InitializationVector iv; + AuthTag tag; + + bool ok, done; +}; + +Cipher::Cipher(const QString &type, + Mode mode, + Padding pad, + Direction dir, + const SymmetricKey &key, + const InitializationVector &iv, + const QString &provider) + : Algorithm(withAlgorithms(type, mode, pad), provider) +{ + d = new Private; + d->type = type; + d->mode = mode; + d->pad = pad; + if (!key.isEmpty()) + setup(dir, key, iv); +} + +Cipher::Cipher(const QString &type, + Cipher::Mode mode, + Cipher::Padding pad, + Direction dir, + const SymmetricKey &key, + const InitializationVector &iv, + const AuthTag &tag, + const QString &provider) + : Algorithm(withAlgorithms(type, mode, pad), provider) +{ + d = new Private; + d->type = type; + d->mode = mode; + d->pad = pad; + d->tag = tag; + if (!key.isEmpty()) + setup(dir, key, iv, tag); +} + +Cipher::Cipher(const Cipher &from) + : Algorithm(from) + , Filter(from) +{ + d = new Private(*from.d); +} + +Cipher::~Cipher() +{ + delete d; +} + +Cipher &Cipher::operator=(const Cipher &from) +{ + Algorithm::operator=(from); + *d = *from.d; + return *this; +} + +QStringList Cipher::supportedTypes(const QString &provider) +{ + return supportedCipherTypes(provider); +} + +QString Cipher::type() const +{ + return d->type; +} + +Cipher::Mode Cipher::mode() const +{ + return d->mode; +} + +Cipher::Padding Cipher::padding() const +{ + return d->pad; +} + +Direction Cipher::direction() const +{ + return d->dir; +} + +KeyLength Cipher::keyLength() const +{ + return static_cast(context())->keyLength(); +} + +bool Cipher::validKeyLength(int n) const +{ + const KeyLength len = keyLength(); + return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); +} + +int Cipher::blockSize() const +{ + return static_cast(context())->blockSize(); +} + +AuthTag Cipher::tag() const +{ + return static_cast(context())->tag(); +} + +void Cipher::clear() +{ + d->done = false; + static_cast(context())->setup(d->dir, d->key, d->iv, d->tag); +} + +MemoryRegion Cipher::update(const MemoryRegion &a) +{ + SecureArray out; + if (d->done) + return out; + d->ok = static_cast(context())->update(a, &out); + return out; +} + +MemoryRegion Cipher::final() +{ + SecureArray out; + if (d->done) + return out; + d->done = true; + d->ok = static_cast(context())->final(&out); + return out; +} + +bool Cipher::ok() const +{ + return d->ok; +} + +void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv) +{ + setup(dir, key, iv, AuthTag()); +} + +void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag) +{ + d->dir = dir; + d->key = key; + d->iv = iv; + d->tag = tag; + clear(); +} + +QString Cipher::withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType) +{ + QString mode; + switch (modeType) { + case CBC: + mode = QStringLiteral("cbc"); + break; + case CFB: + mode = QStringLiteral("cfb"); + break; + case OFB: + mode = QStringLiteral("ofb"); + break; + case ECB: + mode = QStringLiteral("ecb"); + break; + case CTR: + mode = QStringLiteral("ctr"); + break; + case GCM: + mode = QStringLiteral("gcm"); + break; + case CCM: + mode = QStringLiteral("ccm"); + break; + default: + Q_ASSERT(0); + } + + // do the default + if (paddingType == DefaultPadding) { + // logic from Botan + if (modeType == CBC) + paddingType = PKCS7; + else + paddingType = NoPadding; + } + + QString pad; + if (paddingType == NoPadding) + pad = QLatin1String(""); + else + pad = QStringLiteral("pkcs7"); + + QString result = cipherType + QLatin1Char('-') + mode; + if (!pad.isEmpty()) + result += QStringLiteral("-") + pad; + + return result; +} + +//---------------------------------------------------------------------------- +// MessageAuthenticationCode +//---------------------------------------------------------------------------- +class MessageAuthenticationCode::Private +{ +public: + SymmetricKey key; + + bool done; + MemoryRegion buf; +}; + +MessageAuthenticationCode::MessageAuthenticationCode(const QString &type, + const SymmetricKey &key, + const QString &provider) + : Algorithm(type, provider) +{ + d = new Private; + setup(key); +} + +MessageAuthenticationCode::MessageAuthenticationCode(const MessageAuthenticationCode &from) + : Algorithm(from) + , BufferedComputation(from) +{ + d = new Private(*from.d); +} + +MessageAuthenticationCode::~MessageAuthenticationCode() +{ + delete d; +} + +MessageAuthenticationCode &MessageAuthenticationCode::operator=(const MessageAuthenticationCode &from) +{ + Algorithm::operator=(from); + *d = *from.d; + return *this; +} + +QStringList MessageAuthenticationCode::supportedTypes(const QString &provider) +{ + return supportedMACTypes(provider); +} + +QString MessageAuthenticationCode::type() const +{ + // algorithm type is the same as the mac type + return Algorithm::type(); +} + +KeyLength MessageAuthenticationCode::keyLength() const +{ + return static_cast(context())->keyLength(); +} + +bool MessageAuthenticationCode::validKeyLength(int n) const +{ + const KeyLength len = keyLength(); + return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); +} + +void MessageAuthenticationCode::clear() +{ + d->done = false; + static_cast(context())->setup(d->key); +} + +void MessageAuthenticationCode::update(const MemoryRegion &a) +{ + if (d->done) + return; + static_cast(context())->update(a); +} + +MemoryRegion MessageAuthenticationCode::final() +{ + if (!d->done) { + d->done = true; + static_cast(context())->final(&d->buf); + } + return d->buf; +} + +void MessageAuthenticationCode::setup(const SymmetricKey &key) +{ + d->key = key; + clear(); +} + +//---------------------------------------------------------------------------- +// Key Derivation Function +//---------------------------------------------------------------------------- +KeyDerivationFunction::KeyDerivationFunction(const QString &type, const QString &provider) + : Algorithm(type, provider) +{ +} + +KeyDerivationFunction::KeyDerivationFunction(const KeyDerivationFunction &from) + : Algorithm(from) +{ +} + +KeyDerivationFunction::~KeyDerivationFunction() +{ +} + +KeyDerivationFunction &KeyDerivationFunction::operator=(const KeyDerivationFunction &from) +{ + Algorithm::operator=(from); + return *this; +} + +SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + unsigned int iterationCount) +{ + return static_cast(context())->makeKey(secret, salt, keyLength, iterationCount); +} + +SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret, + const InitializationVector &salt, + unsigned int keyLength, + int msecInterval, + unsigned int *iterationCount) +{ + return static_cast(context())->makeKey(secret, salt, keyLength, msecInterval, iterationCount); +} + +QString KeyDerivationFunction::withAlgorithm(const QString &kdfType, const QString &algType) +{ + return (kdfType + QLatin1Char('(') + algType + QLatin1Char(')')); +} + +//---------------------------------------------------------------------------- +// HKDF +//---------------------------------------------------------------------------- +HKDF::HKDF(const QString &algorithm, const QString &provider) + : Algorithm(QStringLiteral("hkdf(") + algorithm + QLatin1Char(')'), provider) +{ +} + +HKDF::HKDF(const HKDF &from) + : Algorithm(from) +{ +} + +HKDF::~HKDF() +{ +} + +HKDF &HKDF::operator=(const HKDF &from) +{ + Algorithm::operator=(from); + return *this; +} + +SymmetricKey HKDF::makeKey(const SecureArray &secret, + const InitializationVector &salt, + const InitializationVector &info, + unsigned int keyLength) +{ + return static_cast(context())->makeKey(secret, salt, info, keyLength); +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_cert.cpp b/local/recipes/libs/qca/source/src/qca_cert.cpp new file mode 100644 index 0000000000..06ba5db442 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_cert.cpp @@ -0,0 +1,2995 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004-2006 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_cert.h" + +#include "qca_publickey.h" +#include "qcaprovider.h" + +#include +#include +#include +#include +#include + +#include + +namespace QCA { + +Provider::Context *getContext(const QString &type, const QString &provider); +Provider::Context *getContext(const QString &type, Provider *p); + +// from qca_publickey.cpp +bool stringToFile(const QString &fileName, const QString &content); +bool stringFromFile(const QString &fileName, QString *s); +bool arrayToFile(const QString &fileName, const QByteArray &content); +bool arrayFromFile(const QString &fileName, QByteArray *a); +bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer); +ProviderList allProviders(); +Provider *providerForName(const QString &name); +bool use_asker_fallback(ConvertResult r); + +// last 3 arguments must be valid, and chain must be empty +static bool get_pkcs12_der(const QByteArray &der, + const QString &fileName, + void *ptr, + const SecureArray &passphrase, + ConvertResult *result, + const QString &provider, + QString *name, + CertificateChain *chain, + PrivateKey *key) +{ + QString _name; + QList list; + PKeyContext *kc = nullptr; + + PKCS12Context *pix = static_cast(getContext(QStringLiteral("pkcs12"), provider)); + ConvertResult r = pix->fromPKCS12(der, passphrase, &_name, &list, &kc); + + // error converting without passphrase? maybe a passphrase is needed + if (use_asker_fallback(r) && passphrase.isEmpty()) { + SecureArray pass; + if (ask_passphrase(fileName, ptr, &pass)) + r = pix->fromPKCS12(der, pass, &_name, &list, &kc); + } + delete pix; + + if (result) + *result = r; + + if (r == ConvertGood) { + *name = _name; + for (int n = 0; n < list.count(); ++n) { + Certificate cert; + cert.change(list[n]); + chain->append(cert); + } + key->change(kc); + return true; + } + return false; +} + +static CertificateInfo orderedToMap(const CertificateInfoOrdered &info) +{ + CertificateInfo out; + + // first, do all but EmailLegacy + for (int n = 0; n < info.count(); ++n) { + const CertificateInfoPair &i = info[n]; + if (i.type().known() != EmailLegacy) + out.insert(i.type(), i.value()); + } + + // lastly, apply EmailLegacy + for (int n = 0; n < info.count(); ++n) { + const CertificateInfoPair &i = info[n]; + if (i.type().known() == EmailLegacy) { + // de-dup + const QList emails = out.values(Email); + if (!emails.contains(i.value())) + out.insert(Email, i.value()); + } + } + + return out; +} + +static void moveMapValues(CertificateInfo *from, CertificateInfoOrdered *to, const CertificateInfoType &type) +{ + const QList values = from->values(type); + from->remove(type); + + // multimap values are stored in reverse. we'll insert backwards in + // order to right them. + for (int n = values.count() - 1; n >= 0; --n) + to->append(CertificateInfoPair(type, values[n])); +} + +static CertificateInfoOrdered mapToOrdered(const CertificateInfo &info) +{ + CertificateInfo in = info; + CertificateInfoOrdered out; + + // have a specific order for some types + moveMapValues(&in, &out, CommonName); + moveMapValues(&in, &out, Country); + moveMapValues(&in, &out, Locality); + moveMapValues(&in, &out, State); + moveMapValues(&in, &out, Organization); + moveMapValues(&in, &out, OrganizationalUnit); + moveMapValues(&in, &out, Email); + moveMapValues(&in, &out, URI); + moveMapValues(&in, &out, DNS); + moveMapValues(&in, &out, IPAddress); + moveMapValues(&in, &out, XMPP); + + // get remaining types + const QList typesLeft = in.keys(); + + // dedup + QList types; + for (int n = 0; n < typesLeft.count(); ++n) { + if (!types.contains(typesLeft[n])) + types += typesLeft[n]; + } + + // insert the rest of the types in the order we got them (map order) + for (int n = 0; n < types.count(); ++n) + moveMapValues(&in, &out, types[n]); + + Q_ASSERT(in.isEmpty()); + + return out; +} + +//---------------------------------------------------------------------------- +// Global +//---------------------------------------------------------------------------- +static const char CommonName_id[] = "2.5.4.3"; +static const char Email_id[] = "GeneralName.rfc822Name"; +static const char EmailLegacy_id[] = "1.2.840.113549.1.9.1"; +static const char Organization_id[] = "2.5.4.10"; +static const char OrganizationalUnit_id[] = "2.5.4.11"; +static const char Locality_id[] = "2.5.4.7"; +static const char IncorporationLocality_id[] = "1.3.6.1.4.1.311.60.2.1.1"; +static const char State_id[] = "2.5.4.8"; +static const char IncorporationState_id[] = "1.3.6.1.4.1.311.60.2.1.2"; +static const char Country_id[] = "2.5.4.6"; +static const char IncorporationCountry_id[] = "1.3.6.1.4.1.311.60.2.1.3"; +static const char URI_id[] = "GeneralName.uniformResourceIdentifier"; +static const char DNS_id[] = "GeneralName.dNSName"; +static const char IPAddress_id[] = "GeneralName.iPAddress"; +static const char XMPP_id[] = "1.3.6.1.5.5.7.8.5"; + +static const char DigitalSignature_id[] = "KeyUsage.digitalSignature"; +static const char NonRepudiation_id[] = "KeyUsage.nonRepudiation"; +static const char KeyEncipherment_id[] = "KeyUsage.keyEncipherment"; +static const char DataEncipherment_id[] = "KeyUsage.dataEncipherment"; +static const char KeyAgreement_id[] = "KeyUsage.keyAgreement"; +static const char KeyCertificateSign_id[] = "KeyUsage.keyCertSign"; +static const char CRLSign_id[] = "KeyUsage.crlSign"; +static const char EncipherOnly_id[] = "KeyUsage.encipherOnly"; +static const char DecipherOnly_id[] = "KeyUsage.decipherOnly"; +static const char ServerAuth_id[] = "1.3.6.1.5.5.7.3.1"; +static const char ClientAuth_id[] = "1.3.6.1.5.5.7.3.2"; +static const char CodeSigning_id[] = "1.3.6.1.5.5.7.3.3"; +static const char EmailProtection_id[] = "1.3.6.1.5.5.7.3.4"; +static const char IPSecEndSystem_id[] = "1.3.6.1.5.5.7.3.5"; +static const char IPSecTunnel_id[] = "1.3.6.1.5.5.7.3.6"; +static const char IPSecUser_id[] = "1.3.6.1.5.5.7.3.7"; +static const char TimeStamping_id[] = "1.3.6.1.5.5.7.3.8"; +static const char OCSPSigning_id[] = "1.3.6.1.5.5.7.3.9"; + +static QString knownToId(CertificateInfoTypeKnown k) +{ + const char *out = nullptr; + switch (k) { + case CommonName: + out = CommonName_id; + break; + case Email: + out = Email_id; + break; + case EmailLegacy: + out = EmailLegacy_id; + break; + case Organization: + out = Organization_id; + break; + case OrganizationalUnit: + out = OrganizationalUnit_id; + break; + case Locality: + out = Locality_id; + break; + case IncorporationLocality: + out = IncorporationLocality_id; + break; + case State: + out = State_id; + break; + case IncorporationState: + out = IncorporationState_id; + break; + case Country: + out = Country_id; + break; + case IncorporationCountry: + out = IncorporationCountry_id; + break; + case URI: + out = URI_id; + break; + case DNS: + out = DNS_id; + break; + case IPAddress: + out = IPAddress_id; + break; + case XMPP: + out = XMPP_id; + break; + } + Q_ASSERT(out); + if (!out) + abort(); + return QString::fromLatin1(out); +} + +static int idToKnown(const QString &id) +{ + if (id == QLatin1String(CommonName_id)) + return CommonName; + else if (id == QLatin1String(Email_id)) + return Email; + else if (id == QLatin1String(EmailLegacy_id)) + return EmailLegacy; + else if (id == QLatin1String(Organization_id)) + return Organization; + else if (id == QLatin1String(OrganizationalUnit_id)) + return OrganizationalUnit; + else if (id == QLatin1String(Locality_id)) + return Locality; + else if (id == QLatin1String(IncorporationLocality_id)) + return IncorporationLocality; + else if (id == QLatin1String(State_id)) + return State; + else if (id == QLatin1String(IncorporationState_id)) + return IncorporationState; + else if (id == QLatin1String(Country_id)) + return Country; + else if (id == QLatin1String(IncorporationCountry_id)) + return IncorporationCountry; + else if (id == QLatin1String(URI_id)) + return URI; + else if (id == QLatin1String(DNS_id)) + return DNS; + else if (id == QLatin1String(IPAddress_id)) + return IPAddress; + else if (id == QLatin1String(XMPP_id)) + return XMPP; + else + return -1; +} + +static CertificateInfoType::Section knownToSection(CertificateInfoTypeKnown k) +{ + switch (k) { + case CommonName: + case EmailLegacy: + case Organization: + case OrganizationalUnit: + case Locality: + case IncorporationLocality: + case State: + case IncorporationState: + case Country: + case IncorporationCountry: + return CertificateInfoType::DN; + default: + break; + } + return CertificateInfoType::AlternativeName; +} + +static const char *knownToShortName(CertificateInfoTypeKnown k) +{ + switch (k) { + case CommonName: + return "CN"; + case Locality: + return "L"; + case State: + return "ST"; + case Organization: + return "O"; + case OrganizationalUnit: + return "OU"; + case Country: + return "C"; + case EmailLegacy: + return "emailAddress"; + default: + break; + } + return nullptr; +} + +static QString constraintKnownToId(ConstraintTypeKnown k) +{ + const char *out = nullptr; + switch (k) { + case DigitalSignature: + out = DigitalSignature_id; + break; + case NonRepudiation: + out = NonRepudiation_id; + break; + case KeyEncipherment: + out = KeyEncipherment_id; + break; + case DataEncipherment: + out = DataEncipherment_id; + break; + case KeyAgreement: + out = KeyAgreement_id; + break; + case KeyCertificateSign: + out = KeyCertificateSign_id; + break; + case CRLSign: + out = CRLSign_id; + break; + case EncipherOnly: + out = EncipherOnly_id; + break; + case DecipherOnly: + out = DecipherOnly_id; + break; + case ServerAuth: + out = ServerAuth_id; + break; + case ClientAuth: + out = ClientAuth_id; + break; + case CodeSigning: + out = CodeSigning_id; + break; + case EmailProtection: + out = EmailProtection_id; + break; + case IPSecEndSystem: + out = IPSecEndSystem_id; + break; + case IPSecTunnel: + out = IPSecTunnel_id; + break; + case IPSecUser: + out = IPSecUser_id; + break; + case TimeStamping: + out = TimeStamping_id; + break; + case OCSPSigning: + out = OCSPSigning_id; + break; + } + Q_ASSERT(out); + if (!out) + abort(); + return QString::fromLatin1(out); +} + +static int constraintIdToKnown(const QString &id) +{ + if (id == QLatin1String(DigitalSignature_id)) + return DigitalSignature; + else if (id == QLatin1String(NonRepudiation_id)) + return NonRepudiation; + else if (id == QLatin1String(KeyEncipherment_id)) + return KeyEncipherment; + else if (id == QLatin1String(DataEncipherment_id)) + return DataEncipherment; + else if (id == QLatin1String(KeyAgreement_id)) + return KeyAgreement; + else if (id == QLatin1String(KeyCertificateSign_id)) + return KeyCertificateSign; + else if (id == QLatin1String(CRLSign_id)) + return CRLSign; + else if (id == QLatin1String(EncipherOnly_id)) + return EncipherOnly; + else if (id == QLatin1String(DecipherOnly_id)) + return DecipherOnly; + else if (id == QLatin1String(ServerAuth_id)) + return ServerAuth; + else if (id == QLatin1String(ClientAuth_id)) + return ClientAuth; + else if (id == QLatin1String(CodeSigning_id)) + return CodeSigning; + else if (id == QLatin1String(EmailProtection_id)) + return EmailProtection; + else if (id == QLatin1String(IPSecEndSystem_id)) + return IPSecEndSystem; + else if (id == QLatin1String(IPSecTunnel_id)) + return IPSecTunnel; + else if (id == QLatin1String(IPSecUser_id)) + return IPSecUser; + else if (id == QLatin1String(TimeStamping_id)) + return TimeStamping; + else if (id == QLatin1String(OCSPSigning_id)) + return OCSPSigning; + else + return -1; +} + +static ConstraintType::Section constraintKnownToSection(ConstraintTypeKnown k) +{ + switch (k) { + case DigitalSignature: + case NonRepudiation: + case KeyEncipherment: + case DataEncipherment: + case KeyAgreement: + case KeyCertificateSign: + case CRLSign: + case EncipherOnly: + case DecipherOnly: + return ConstraintType::KeyUsage; + default: + break; + } + return ConstraintType::ExtendedKeyUsage; +} + +static QString dnLabel(const CertificateInfoType &type) +{ + const char *str = knownToShortName(type.known()); + if (str) + return QString::fromLatin1(str); + + const QString id = type.id(); + // is it an oid? + if (id[0].isDigit()) + return QStringLiteral("OID.") + id; + + return QStringLiteral("qca.") + id; +} + +QString orderedToDNString(const CertificateInfoOrdered &in) +{ + QStringList parts; + foreach (const CertificateInfoPair &i, in) { + if (i.type().section() != CertificateInfoType::DN) + continue; + + const QString name = dnLabel(i.type()); + parts += name + QLatin1Char('=') + i.value(); + } + return parts.join(QStringLiteral(", ")); +} + +CertificateInfoOrdered orderedDNOnly(const CertificateInfoOrdered &in) +{ + CertificateInfoOrdered out; + for (int n = 0; n < in.count(); ++n) { + if (in[n].type().section() == CertificateInfoType::DN) + out += in[n]; + } + return out; +} + +static QString baseCertName(const CertificateInfo &info) +{ + QString str = info.value(CommonName); + if (str.isEmpty()) { + str = info.value(Organization); + if (str.isEmpty()) + str = QStringLiteral("Unnamed"); + } + return str; +} + +static QList findSameName(const QString &name, const QStringList &list) +{ + QList out; + for (int n = 0; n < list.count(); ++n) { + if (list[n] == name) + out += n; + } + return out; +} + +static QString +uniqueSubjectValue(const CertificateInfoType &type, const QList &items, const QList &certs, int i) +{ + QStringList vals = certs[items[i]].subjectInfo().values(type); + if (!vals.isEmpty()) { + foreach (int n, items) { + if (n == items[i]) + continue; + + const QStringList other_vals = certs[n].subjectInfo().values(type); + for (int k = 0; k < vals.count(); ++k) { + if (other_vals.contains(vals[k])) { + vals.removeAt(k); + break; + } + } + + if (vals.isEmpty()) + break; + } + + if (!vals.isEmpty()) + return vals[0]; + } + + return QString(); +} + +static QString uniqueIssuerName(const QList &items, const QList &certs, int i) +{ + const QString val = baseCertName(certs[items[i]].issuerInfo()); + + bool found = false; + foreach (int n, items) { + if (n == items[i]) + continue; + + const QString other_val = baseCertName(certs[n].issuerInfo()); + if (other_val == val) { + found = true; + break; + } + } + + if (!found) + return val; + + return QString(); +} + +static const char *constraintToString(const ConstraintType &type) +{ + switch (type.known()) { + case DigitalSignature: + return "DigitalSignature"; + case NonRepudiation: + return "NonRepudiation"; + case KeyEncipherment: + return "KeyEncipherment"; + case DataEncipherment: + return "DataEncipherment"; + case KeyAgreement: + return "KeyAgreement"; + case KeyCertificateSign: + return "KeyCertificateSign"; + case CRLSign: + return "CRLSign"; + case EncipherOnly: + return "EncipherOnly"; + case DecipherOnly: + return "DecipherOnly"; + case ServerAuth: + return "ServerAuth"; + case ClientAuth: + return "ClientAuth"; + case CodeSigning: + return "CodeSigning"; + case EmailProtection: + return "EmailProtection"; + case IPSecEndSystem: + return "IPSecEndSystem"; + case IPSecTunnel: + return "IPSecTunnel"; + case IPSecUser: + return "IPSecUser"; + case TimeStamping: + return "TimeStamping"; + case OCSPSigning: + return "OCSPSigning"; + } + return nullptr; +} + +static QString +uniqueConstraintValue(const ConstraintType &type, const QList &items, const QList &certs, int i) +{ + if (certs[items[i]].constraints().contains(type)) { + bool found = false; + foreach (int n, items) { + if (n == items[i]) + continue; + + Constraints other_vals = certs[n].constraints(); + if (other_vals.contains(type)) { + found = true; + break; + } + } + + if (!found) + return QString::fromLatin1(constraintToString(type)); + } + + return QString(); +} + +static QString makeUniqueName(const QList &items, const QStringList &list, const QList &certs, int i) +{ + QString str, name; + + // different organization? + str = uniqueSubjectValue(Organization, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" of ") + str; + goto end; + } + + // different organizational unit? + str = uniqueSubjectValue(OrganizationalUnit, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" of ") + str; + goto end; + } + + // different email address? + str = uniqueSubjectValue(Email, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" <") + str + QLatin1Char('>'); + goto end; + } + + // different xmpp addresses? + str = uniqueSubjectValue(XMPP, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" '); + goto end; + } + + // different issuers? + str = uniqueIssuerName(items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" by ") + str; + goto end; + } + + // different usages? + + // DigitalSignature + str = uniqueConstraintValue(DigitalSignature, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // ClientAuth + str = uniqueConstraintValue(ClientAuth, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // EmailProtection + str = uniqueConstraintValue(EmailProtection, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // DataEncipherment + str = uniqueConstraintValue(DataEncipherment, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // EncipherOnly + str = uniqueConstraintValue(EncipherOnly, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // DecipherOnly + str = uniqueConstraintValue(DecipherOnly, items, certs, i); + if (!str.isEmpty()) { + name = list[items[i]] + QStringLiteral(" for ") + str; + goto end; + } + + // if there's nothing easily unique, then do a DN string + name = certs[items[i]].subjectInfoOrdered().toString(); + +end: + return name; +} + +QStringList makeFriendlyNames(const QList &list) +{ + QStringList names; + + // give a base name to all certs first + foreach (const Certificate &cert, list) + names += baseCertName(cert.subjectInfo()); + + // come up with a collision list + QList> itemCollisions; + foreach (const QString &name, names) { + // anyone else using this name? + const QList items = findSameName(name, names); + if (items.count() > 1) { + // don't save duplicate collisions + bool haveAlready = false; + foreach (const QList &other, itemCollisions) { + foreach (int n, items) { + if (other.contains(n)) { + haveAlready = true; + break; + } + } + + if (haveAlready) + break; + } + + if (haveAlready) + continue; + + itemCollisions += items; + } + } + + // resolve collisions by providing extra details + foreach (const QList &items, itemCollisions) { + // printf("%d items are using [%s]\n", items.count(), qPrintable(names[items[0]])); + + for (int n = 0; n < items.count(); ++n) { + names[items[n]] = makeUniqueName(items, names, list, n); + // printf(" %d: reassigning: [%s]\n", items[n], qPrintable(names[items[n]])); + } + } + + return names; +} + +//---------------------------------------------------------------------------- +// CertificateInfoType +//---------------------------------------------------------------------------- +class CertificateInfoType::Private : public QSharedData +{ +public: + CertificateInfoType::Section section; + int known; + QString id; + + Private() + : section(CertificateInfoType::DN) + , known(-1) + { + } +}; + +CertificateInfoType::CertificateInfoType() + : d(new Private) +{ +} + +CertificateInfoType::CertificateInfoType(CertificateInfoTypeKnown known) + : d(new Private) +{ + d->section = knownToSection(known); + d->known = known; + d->id = knownToId(known); // always valid +} + +CertificateInfoType::CertificateInfoType(const QString &id, Section section) + : d(new Private) +{ + d->section = section; + d->known = idToKnown(id); // can be -1 for unknown + d->id = id; +} + +CertificateInfoType::CertificateInfoType(const CertificateInfoType &from) + : d(from.d) +{ +} + +CertificateInfoType::~CertificateInfoType() +{ +} + +CertificateInfoType &CertificateInfoType::operator=(const CertificateInfoType &from) +{ + d = from.d; + return *this; +} + +CertificateInfoType::Section CertificateInfoType::section() const +{ + return d->section; +} + +CertificateInfoTypeKnown CertificateInfoType::known() const +{ + return (CertificateInfoTypeKnown)d->known; +} + +QString CertificateInfoType::id() const +{ + return d->id; +} + +bool CertificateInfoType::operator<(const CertificateInfoType &other) const +{ + // sort by knowns (in enum order), then by ids (in string order) + if (d->known != -1) { + if (other.d->known == -1) + return true; + else if (d->known < other.d->known) + return true; + else + return false; + } else { + if (other.d->known != -1) + return false; + else if (d->id < other.d->id) + return true; + else + return false; + } +} + +bool CertificateInfoType::operator==(const CertificateInfoType &other) const +{ + // are both known types? + if (d->known != -1 && other.d->known != -1) { + // if so, compare the ints + if (d->known != other.d->known) + return false; + } else { + // otherwise, compare the string ids + if (d->id != other.d->id) + return false; + } + + if (d->section != other.d->section) + return false; + + return true; +} + +//---------------------------------------------------------------------------- +// CertificateInfoPair +//---------------------------------------------------------------------------- +class CertificateInfoPair::Private : public QSharedData +{ +public: + CertificateInfoType type; + QString value; +}; + +CertificateInfoPair::CertificateInfoPair() + : d(new Private) +{ +} + +CertificateInfoPair::CertificateInfoPair(const CertificateInfoType &type, const QString &value) + : d(new Private) +{ + d->type = type; + d->value = value; +} + +CertificateInfoPair::CertificateInfoPair(const CertificateInfoPair &from) + : d(from.d) +{ +} + +CertificateInfoPair::~CertificateInfoPair() +{ +} + +CertificateInfoPair &CertificateInfoPair::operator=(const CertificateInfoPair &from) +{ + d = from.d; + return *this; +} + +CertificateInfoType CertificateInfoPair::type() const +{ + return d->type; +} + +QString CertificateInfoPair::value() const +{ + return d->value; +} + +bool CertificateInfoPair::operator==(const CertificateInfoPair &other) const +{ + if (d->type == other.d->type && d->value == other.d->value) + return true; + return false; +} + +//---------------------------------------------------------------------------- +// ConstraintType +//---------------------------------------------------------------------------- +class ConstraintType::Private : public QSharedData +{ +public: + ConstraintType::Section section; + int known; + QString id; + + Private() + : section(ConstraintType::KeyUsage) + , known(-1) + { + } +}; + +ConstraintType::ConstraintType() + : d(new Private) +{ +} + +ConstraintType::ConstraintType(ConstraintTypeKnown known) + : d(new Private) +{ + d->section = constraintKnownToSection(known); + d->known = known; + d->id = constraintKnownToId(known); // always valid +} + +ConstraintType::ConstraintType(const QString &id, Section section) + : d(new Private) +{ + d->section = section; + d->known = constraintIdToKnown(id); // can be -1 for unknown + d->id = id; +} + +ConstraintType::ConstraintType(const ConstraintType &from) + : d(from.d) +{ +} + +ConstraintType::~ConstraintType() +{ +} + +ConstraintType &ConstraintType::operator=(const ConstraintType &from) +{ + d = from.d; + return *this; +} + +ConstraintType::Section ConstraintType::section() const +{ + return d->section; +} + +ConstraintTypeKnown ConstraintType::known() const +{ + return (ConstraintTypeKnown)d->known; +} + +QString ConstraintType::id() const +{ + return d->id; +} + +bool ConstraintType::operator<(const ConstraintType &other) const +{ + // sort by knowns (in enum order), then by ids (in string order) + if (d->known != -1) { + if (other.d->known == -1) + return true; + else if (d->known < other.d->known) + return true; + else + return false; + } else { + if (other.d->known != -1) + return false; + else if (d->id < other.d->id) + return true; + else + return false; + } +} + +bool ConstraintType::operator==(const ConstraintType &other) const +{ + // are both known types? + if (d->known != -1 && other.d->known != -1) { + // if so, compare the ints + if (d->known != other.d->known) + return false; + } else { + // otherwise, compare the string ids + if (d->id != other.d->id) + return false; + } + + if (d->section != other.d->section) + return false; + + return true; +} + +//---------------------------------------------------------------------------- +// CertificateOptions +//---------------------------------------------------------------------------- +class CertificateOptions::Private +{ +public: + CertificateRequestFormat format; + + QString challenge; + CertificateInfoOrdered info; + CertificateInfo infoMap; + Constraints constraints; + QStringList policies; + QStringList crlLocations, issuerLocations, ocspLocations; + bool isCA; + int pathLimit; + BigInteger serial; + QDateTime start, end; + + Private() + : isCA(false) + , pathLimit(0) + { + } +}; + +CertificateOptions::CertificateOptions(CertificateRequestFormat f) +{ + d = new Private; + d->format = f; +} + +CertificateOptions::CertificateOptions(const CertificateOptions &from) +{ + d = new Private(*from.d); +} + +CertificateOptions::~CertificateOptions() +{ + delete d; +} + +CertificateOptions &CertificateOptions::operator=(const CertificateOptions &from) +{ + *d = *from.d; + return *this; +} + +CertificateRequestFormat CertificateOptions::format() const +{ + return d->format; +} + +void CertificateOptions::setFormat(CertificateRequestFormat f) +{ + d->format = f; +} + +bool CertificateOptions::isValid() const +{ + // logic from Botan + if (d->infoMap.value(CommonName).isEmpty() || d->infoMap.value(Country).isEmpty()) + return false; + if (d->infoMap.value(Country).length() != 2) + return false; + if (d->start >= d->end) + return false; + return true; +} + +QString CertificateOptions::challenge() const +{ + return d->challenge; +} + +CertificateInfo CertificateOptions::info() const +{ + return d->infoMap; +} + +CertificateInfoOrdered CertificateOptions::infoOrdered() const +{ + return d->info; +} + +Constraints CertificateOptions::constraints() const +{ + return d->constraints; +} + +QStringList CertificateOptions::policies() const +{ + return d->policies; +} + +QStringList CertificateOptions::crlLocations() const +{ + return d->crlLocations; +} + +QStringList CertificateOptions::issuerLocations() const +{ + return d->issuerLocations; +} + +QStringList CertificateOptions::ocspLocations() const +{ + return d->ocspLocations; +} + +bool CertificateOptions::isCA() const +{ + return d->isCA; +} + +int CertificateOptions::pathLimit() const +{ + return d->pathLimit; +} + +BigInteger CertificateOptions::serialNumber() const +{ + return d->serial; +} + +QDateTime CertificateOptions::notValidBefore() const +{ + return d->start; +} + +QDateTime CertificateOptions::notValidAfter() const +{ + return d->end; +} + +void CertificateOptions::setChallenge(const QString &s) +{ + d->challenge = s; +} + +void CertificateOptions::setInfo(const CertificateInfo &info) +{ + d->info = mapToOrdered(info); + d->infoMap = info; +} + +void CertificateOptions::setInfoOrdered(const CertificateInfoOrdered &info) +{ + d->info = info; + d->infoMap = orderedToMap(info); +} + +void CertificateOptions::setConstraints(const Constraints &constraints) +{ + d->constraints = constraints; +} + +void CertificateOptions::setPolicies(const QStringList &policies) +{ + d->policies = policies; +} + +void CertificateOptions::setCRLLocations(const QStringList &locations) +{ + d->crlLocations = locations; +} + +void CertificateOptions::setIssuerLocations(const QStringList &locations) +{ + d->issuerLocations = locations; +} + +void CertificateOptions::setOCSPLocations(const QStringList &locations) +{ + d->ocspLocations = locations; +} + +void CertificateOptions::setAsCA(int pathLimit) +{ + d->isCA = true; + d->pathLimit = pathLimit; +} + +void CertificateOptions::setAsUser() +{ + d->isCA = false; + d->pathLimit = 0; +} + +void CertificateOptions::setSerialNumber(const BigInteger &i) +{ + d->serial = i; +} + +void CertificateOptions::setValidityPeriod(const QDateTime &start, const QDateTime &end) +{ + d->start = start; + d->end = end; +} + +//---------------------------------------------------------------------------- +// Certificate +//---------------------------------------------------------------------------- +// ip address string to binary (msb), adapted from jdns (adapted from qt) +// return: size 4 = ipv4, size 16 = ipv6, size 0 = error +static QByteArray ipaddr_str2bin(const QString &str) +{ + // ipv6 + if (str.contains(QLatin1Char(':'))) { + const QStringList parts = str.split(QLatin1Char(':'), Qt::KeepEmptyParts); + if (parts.count() < 3 || parts.count() > 8) + return QByteArray(); + + QByteArray ipv6(16, 0); + int at = 16; + int fill = 9 - parts.count(); + for (int n = parts.count() - 1; n >= 0; --n) { + if (at <= 0) + return QByteArray(); + + if (parts[n].isEmpty()) { + if (n == parts.count() - 1) { + if (!parts[n - 1].isEmpty()) + return QByteArray(); + ipv6[--at] = 0; + ipv6[--at] = 0; + } else if (n == 0) { + if (!parts[n + 1].isEmpty()) + return QByteArray(); + ipv6[--at] = 0; + ipv6[--at] = 0; + } else { + for (int i = 0; i < fill; ++i) { + if (at <= 0) + return QByteArray(); + ipv6[--at] = 0; + ipv6[--at] = 0; + } + } + } else { + if (parts[n].indexOf(QLatin1Char('.')) == -1) { + bool ok; + int x = parts[n].toInt(&ok, 16); + if (!ok || x < 0 || x > 0xffff) + return QByteArray(); + ipv6[--at] = x & 0xff; + ipv6[--at] = (x >> 8) & 0xff; + } else { + if (n != parts.count() - 1) + return QByteArray(); + + const QByteArray buf = ipaddr_str2bin(parts[n]); + if (buf.isEmpty()) + return QByteArray(); + + ipv6[--at] = buf[3]; + ipv6[--at] = buf[2]; + ipv6[--at] = buf[1]; + ipv6[--at] = buf[0]; + --fill; + } + } + } + + return ipv6; + } else if (str.contains(QLatin1Char('.'))) { + const QStringList parts = str.split(QLatin1Char('.'), Qt::KeepEmptyParts); + if (parts.count() != 4) + return QByteArray(); + + QByteArray out(4, 0); + for (int n = 0; n < 4; ++n) { + bool ok; + int x = parts[n].toInt(&ok); + if (!ok || x < 0 || x > 0xff) + return QByteArray(); + out[n] = (unsigned char)x; + } + return out; + } else + return QByteArray(); +} + +// acedomain must be all lowercase, with no trailing dot or wildcards +static bool cert_match_domain(const QString &certname, const QString &acedomain) +{ + // KSSL strips start/end whitespace, even though such whitespace is + // probably not legal anyway. (compat) + QString name = certname.trimmed(); + + // KSSL strips trailing dot, even though the dot is probably not + // legal anyway. (compat) + if (name.length() > 0 && name[name.length() - 1] == QLatin1Char('.')) + name.truncate(name.length() - 1); + + // after our compatibility modifications, make sure the name isn't + // empty. + if (name.isEmpty()) + return false; + + // lowercase, for later performing case insensitive matching + name = name.toLower(); + + // ensure the cert field contains valid characters only + if (QRegularExpression(QStringLiteral("[^a-z0-9\\.\\*\\-]")).match(name).hasMatch()) + return false; + + // hack into parts, and require at least 1 part + const QStringList parts_name = name.split(QLatin1Char('.'), Qt::KeepEmptyParts); + if (parts_name.isEmpty()) + return false; + + // KSSL checks to make sure the last two parts don't contain + // wildcards. I don't know where it is written that this + // should be done, but for compat sake we'll do it. + if (parts_name[parts_name.count() - 1].contains(QLatin1Char('*'))) + return false; + if (parts_name.count() >= 2 && parts_name[parts_name.count() - 2].contains(QLatin1Char('*'))) + return false; + + const QStringList parts_compare = acedomain.split(QLatin1Char('.'), Qt::KeepEmptyParts); + if (parts_compare.isEmpty()) + return false; + + // don't allow empty parts + foreach (const QString &s, parts_name) { + if (s.isEmpty()) + return false; + } + foreach (const QString &s, parts_compare) { + if (s.isEmpty()) + return false; + } + + // RFC2818: "Names may contain the wildcard character * which is + // considered to match any single domain name component or + // component fragment. E.g., *.a.com matches foo.a.com but not + // bar.foo.a.com. f*.com matches foo.com but not bar.com." + // + // This means that for the domain to match it must have the + // same number of components, wildcards or not. If there are + // wildcards, their scope must only be within the component + // they reside in. + // + // First, make sure the number of parts is equal. + if (parts_name.count() != parts_compare.count()) + return false; + + // Now compare each part + for (int n = 0; n < parts_name.count(); ++n) { + const QString &p1 = parts_name[n]; + const QString &p2 = parts_compare[n]; + + if (!QRegExp(p1, Qt::CaseSensitive, QRegExp::Wildcard).exactMatch(p2)) + return false; + } + + return true; +} + +// ipaddress must be an ipv4 or ipv6 address in binary format +static bool cert_match_ipaddress(const QString &certname, const QByteArray &ipaddress) +{ + // KSSL strips start/end whitespace, even though such whitespace is + // probably not legal anyway. (compat) + QString name = certname.trimmed(); + + // KSSL accepts IPv6 in brackets, which is usually done for URIs, but + // IMO sounds very strange for a certificate. We'll follow this + // behavior anyway. (compat) + if (name.length() >= 2 && name[0] == QLatin1Char('[') && name[name.length() - 1] == QLatin1Char(']')) + name = name.mid(1, name.length() - 2); // chop off brackets + + // after our compatibility modifications, make sure the name isn't + // empty. + if (name.isEmpty()) + return false; + + // convert to binary form + const QByteArray addr = ipaddr_str2bin(name); + if (addr.isEmpty()) + return false; + + // not the same? + if (addr != ipaddress) + return false; + + return true; +} + +class Certificate::Private : public QSharedData +{ +public: + CertificateInfo subjectInfoMap, issuerInfoMap; + + void update(CertContext *c) + { + if (c) { + subjectInfoMap = orderedToMap(c->props()->subject); + issuerInfoMap = orderedToMap(c->props()->issuer); + } else { + subjectInfoMap = CertificateInfo(); + issuerInfoMap = CertificateInfo(); + } + } +}; + +Certificate::Certificate() + : d(new Private) +{ +} + +Certificate::Certificate(const QString &fileName) + : d(new Private) +{ + *this = fromPEMFile(fileName, nullptr, QString()); +} + +Certificate::Certificate(const CertificateOptions &opts, const PrivateKey &key, const QString &provider) + : d(new Private) +{ + CertContext *c = static_cast(getContext(QStringLiteral("cert"), provider)); + if (c->createSelfSigned(opts, *(static_cast(key.context())))) + change(c); + else + delete c; +} + +Certificate::Certificate(const Certificate &from) + : Algorithm(from) + , d(from.d) +{ +} + +Certificate::~Certificate() +{ +} + +Certificate &Certificate::operator=(const Certificate &from) +{ + Algorithm::operator=(from); + d = from.d; + return *this; +} + +bool Certificate::isNull() const +{ + return (!context() ? true : false); +} + +QDateTime Certificate::notValidBefore() const +{ + return static_cast(context())->props()->start; +} + +QDateTime Certificate::notValidAfter() const +{ + return static_cast(context())->props()->end; +} + +CertificateInfo Certificate::subjectInfo() const +{ + return d->subjectInfoMap; +} + +CertificateInfoOrdered Certificate::subjectInfoOrdered() const +{ + return static_cast(context())->props()->subject; +} + +CertificateInfo Certificate::issuerInfo() const +{ + return d->issuerInfoMap; +} + +CertificateInfoOrdered Certificate::issuerInfoOrdered() const +{ + return static_cast(context())->props()->issuer; +} + +Constraints Certificate::constraints() const +{ + return static_cast(context())->props()->constraints; +} + +QStringList Certificate::policies() const +{ + return static_cast(context())->props()->policies; +} + +QStringList Certificate::crlLocations() const +{ + return static_cast(context())->props()->crlLocations; +} + +QStringList Certificate::issuerLocations() const +{ + return static_cast(context())->props()->issuerLocations; +} + +QStringList Certificate::ocspLocations() const +{ + return static_cast(context())->props()->ocspLocations; +} + +QString Certificate::commonName() const +{ + return d->subjectInfoMap.value(CommonName); +} + +BigInteger Certificate::serialNumber() const +{ + return static_cast(context())->props()->serial; +} + +PublicKey Certificate::subjectPublicKey() const +{ + PKeyContext *c = static_cast(context())->subjectPublicKey(); + PublicKey key; + key.change(c); + return key; +} + +bool Certificate::isCA() const +{ + return static_cast(context())->props()->isCA; +} + +bool Certificate::isSelfSigned() const +{ + return static_cast(context())->props()->isSelfSigned; +} + +bool Certificate::isIssuerOf(const Certificate &other) const +{ + const CertContext *cc = static_cast(other.context()); + return static_cast(context())->isIssuerOf(cc); +} + +int Certificate::pathLimit() const +{ + return static_cast(context())->props()->pathLimit; +} + +SignatureAlgorithm Certificate::signatureAlgorithm() const +{ + return static_cast(context())->props()->sigalgo; +} + +QByteArray Certificate::subjectKeyId() const +{ + return static_cast(context())->props()->subjectId; +} + +QByteArray Certificate::issuerKeyId() const +{ + return static_cast(context())->props()->issuerId; +} + +Validity Certificate::validate(const CertificateCollection &trusted, + const CertificateCollection &untrusted, + UsageMode u, + ValidateFlags vf) const +{ + const QList issuers = trusted.certificates() + untrusted.certificates(); + CertificateChain chain; + chain += *this; + Validity result; + chain = chain.complete(issuers, &result); + if (result != ValidityGood) + return result; + return chain.validate(trusted, untrusted.crls(), u, vf); +} + +QByteArray Certificate::toDER() const +{ + return static_cast(context())->toDER(); +} + +QString Certificate::toPEM() const +{ + return static_cast(context())->toPEM(); +} + +bool Certificate::toPEMFile(const QString &fileName) const +{ + return stringToFile(fileName, toPEM()); +} + +Certificate Certificate::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) +{ + Certificate c; + CertContext *cc = static_cast(getContext(QStringLiteral("cert"), provider)); + ConvertResult r = cc->fromDER(a); + if (result) + *result = r; + if (r == ConvertGood) + c.change(cc); + else + delete cc; + return c; +} + +Certificate Certificate::fromPEM(const QString &s, ConvertResult *result, const QString &provider) +{ + Certificate c; + CertContext *cc = static_cast(getContext(QStringLiteral("cert"), provider)); + ConvertResult r = cc->fromPEM(s); + if (result) + *result = r; + if (r == ConvertGood) + c.change(cc); + else + delete cc; + return c; +} + +Certificate Certificate::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QString pem; + if (!stringFromFile(fileName, &pem)) { + if (result) + *result = ErrorFile; + return Certificate(); + } + return fromPEM(pem, result, provider); +} + +// check for ip addresses in iPAddress, dNSName, then commonName +// for all else, check in dNSName, then commonName +bool Certificate::matchesHostName(const QString &host) const +{ + const QByteArray ipaddr = ipaddr_str2bin(host); + if (!ipaddr.isEmpty()) // ip address + { + // check iPAddress, dNSName, commonName + const CertificateInfoOrdered subjectInfo = subjectInfoOrdered(); + for (const CertificateInfoPair &p : subjectInfo) { + const CertificateInfoType type = p.type(); + if (type == IPAddress || type == DNS || type == CommonName) { + if (cert_match_ipaddress(p.value(), ipaddr)) + return true; + } + } + } else // domain + { + // lowercase + QString name = host.toLower(); + + // ACE + name = QString::fromLatin1(QUrl::toAce(name)); + + // don't allow wildcards in the comparison host + if (name.contains(QLatin1Char('*'))) + return false; + + // strip out trailing dot + if (name.length() > 0 && name[name.length() - 1] == QLatin1Char('.')) + name.truncate(name.length() - 1); + + // make sure the name is not empty after our modifications + if (name.isEmpty()) + return false; + + // check dNSName, commonName + const CertificateInfoOrdered subjectInfo = subjectInfoOrdered(); + for (const CertificateInfoPair &p : subjectInfo) { + const CertificateInfoType type = p.type(); + if (type == DNS || type == CommonName) { + if (cert_match_domain(p.value(), name)) + return true; + } + } + } + + return false; +} + +bool Certificate::operator==(const Certificate &otherCert) const +{ + if (isNull()) { + if (otherCert.isNull()) + return true; + else + return false; + } else if (otherCert.isNull()) + return false; + + const CertContext *other = static_cast(otherCert.context()); + return static_cast(context())->compare(other); +} + +void Certificate::change(CertContext *c) +{ + Algorithm::change(c); + d->update(static_cast(context())); +} + +Validity Certificate::chain_validate(const CertificateChain &chain, + const CertificateCollection &trusted, + const QList &untrusted_crls, + UsageMode u, + ValidateFlags vf) const +{ + QList chain_list; + QList trusted_list; + QList crl_list; + + QList chain_certs = chain; + QList trusted_certs = trusted.certificates(); + QList crls = trusted.crls() + untrusted_crls; + + for (int n = 0; n < chain_certs.count(); ++n) { + CertContext *c = static_cast(chain_certs[n].context()); + chain_list += c; + } + for (int n = 0; n < trusted_certs.count(); ++n) { + CertContext *c = static_cast(trusted_certs[n].context()); + trusted_list += c; + } + for (int n = 0; n < crls.count(); ++n) { + CRLContext *c = static_cast(crls[n].context()); + crl_list += c; + } + + return static_cast(context())->validate_chain(chain_list, trusted_list, crl_list, u, vf); +} + +CertificateChain +Certificate::chain_complete(const CertificateChain &chain, const QList &issuers, Validity *result) const +{ + CertificateChain out; + QList pool = issuers + chain.mid(1); + out += chain.first(); + if (result) + *result = ValidityGood; + while (!out.last().isSelfSigned()) { + // try to get next in chain + int at = -1; + for (int n = 0; n < pool.count(); ++n) { + // QString str = QString("[%1] issued by [%2] ? ").arg(out.last().commonName()).arg(pool[n].commonName()); + if (pool[n].isIssuerOf(out.last())) { + // printf("%s yes\n", qPrintable(str)); + at = n; + break; + } + // printf("%s no\n", qPrintable(str)); + } + if (at == -1) { + if (result) + *result = ErrorInvalidCA; + break; + } + + // take it out of the pool + Certificate next = pool.takeAt(at); + + // make sure it isn't in the chain already (avoid loops) + if (out.contains(next)) + break; + + // append to the chain + out += next; + } + return out; +} + +//---------------------------------------------------------------------------- +// CertificateRequest +//---------------------------------------------------------------------------- +class CertificateRequest::Private : public QSharedData +{ +public: + CertificateInfo subjectInfoMap; + + void update(CSRContext *c) + { + if (c) + subjectInfoMap = orderedToMap(c->props()->subject); + else + subjectInfoMap = CertificateInfo(); + } +}; + +CertificateRequest::CertificateRequest() + : d(new Private) +{ +} + +CertificateRequest::CertificateRequest(const QString &fileName) + : d(new Private) +{ + *this = fromPEMFile(fileName, nullptr, QString()); +} + +CertificateRequest::CertificateRequest(const CertificateOptions &opts, const PrivateKey &key, const QString &provider) + : d(new Private) +{ + CSRContext *c = static_cast(getContext(QStringLiteral("csr"), provider)); + if (c->createRequest(opts, *(static_cast(key.context())))) + change(c); + else + delete c; +} + +CertificateRequest::CertificateRequest(const CertificateRequest &from) + : Algorithm(from) + , d(from.d) +{ +} + +CertificateRequest::~CertificateRequest() +{ +} + +CertificateRequest &CertificateRequest::operator=(const CertificateRequest &from) +{ + Algorithm::operator=(from); + d = from.d; + return *this; +} + +bool CertificateRequest::isNull() const +{ + return (!context() ? true : false); +} + +bool CertificateRequest::canUseFormat(CertificateRequestFormat f, const QString &provider) +{ + CSRContext *c = static_cast(getContext(QStringLiteral("csr"), provider)); + bool ok = c->canUseFormat(f); + delete c; + return ok; +} + +CertificateRequestFormat CertificateRequest::format() const +{ + if (isNull()) + return PKCS10; // some default so we don't explode + return static_cast(context())->props()->format; +} + +CertificateInfo CertificateRequest::subjectInfo() const +{ + return d->subjectInfoMap; +} + +CertificateInfoOrdered CertificateRequest::subjectInfoOrdered() const +{ + return static_cast(context())->props()->subject; +} + +Constraints CertificateRequest::constraints() const +{ + return static_cast(context())->props()->constraints; +} + +QStringList CertificateRequest::policies() const +{ + return static_cast(context())->props()->policies; +} + +PublicKey CertificateRequest::subjectPublicKey() const +{ + PKeyContext *c = static_cast(context())->subjectPublicKey(); + PublicKey key; + key.change(c); + return key; +} + +bool CertificateRequest::isCA() const +{ + return static_cast(context())->props()->isCA; +} + +int CertificateRequest::pathLimit() const +{ + return static_cast(context())->props()->pathLimit; +} + +QString CertificateRequest::challenge() const +{ + return static_cast(context())->props()->challenge; +} + +SignatureAlgorithm CertificateRequest::signatureAlgorithm() const +{ + return static_cast(context())->props()->sigalgo; +} + +bool CertificateRequest::operator==(const CertificateRequest &otherCsr) const +{ + if (isNull()) { + if (otherCsr.isNull()) + return true; + else + return false; + } else if (otherCsr.isNull()) + return false; + + const CSRContext *other = static_cast(otherCsr.context()); + return static_cast(context())->compare(other); +} + +QByteArray CertificateRequest::toDER() const +{ + return static_cast(context())->toDER(); +} + +QString CertificateRequest::toPEM() const +{ + return static_cast(context())->toPEM(); +} + +bool CertificateRequest::toPEMFile(const QString &fileName) const +{ + return stringToFile(fileName, toPEM()); +} + +CertificateRequest CertificateRequest::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) +{ + CertificateRequest c; + CSRContext *csr = static_cast(getContext(QStringLiteral("csr"), provider)); + ConvertResult r = csr->fromDER(a); + if (result) + *result = r; + if (r == ConvertGood) + c.change(csr); + else + delete csr; + return c; +} + +CertificateRequest CertificateRequest::fromPEM(const QString &s, ConvertResult *result, const QString &provider) +{ + CertificateRequest c; + CSRContext *csr = static_cast(getContext(QStringLiteral("csr"), provider)); + ConvertResult r = csr->fromPEM(s); + if (result) + *result = r; + if (r == ConvertGood) + c.change(csr); + else + delete csr; + return c; +} + +CertificateRequest +CertificateRequest::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QString pem; + if (!stringFromFile(fileName, &pem)) { + if (result) + *result = ErrorFile; + return CertificateRequest(); + } + return fromPEM(pem, result, provider); +} + +QString CertificateRequest::toString() const +{ + return static_cast(context())->toSPKAC(); +} + +CertificateRequest CertificateRequest::fromString(const QString &s, ConvertResult *result, const QString &provider) +{ + CertificateRequest c; + CSRContext *csr = static_cast(getContext(QStringLiteral("csr"), provider)); + ConvertResult r = csr->fromSPKAC(s); + if (result) + *result = r; + if (r == ConvertGood) + c.change(csr); + else + delete csr; + return c; +} + +void CertificateRequest::change(CSRContext *c) +{ + Algorithm::change(c); + d->update(static_cast(context())); +} + +//---------------------------------------------------------------------------- +// CRLEntry +//---------------------------------------------------------------------------- +CRLEntry::CRLEntry() +{ + _reason = Unspecified; +} + +CRLEntry::CRLEntry(const Certificate &c, Reason r) +{ + _serial = c.serialNumber(); + _time = QDateTime::currentDateTime(); + _reason = r; +} + +// TODO make serial const & when we break ABI +CRLEntry::CRLEntry( + const BigInteger serial, // clazy:exclude=function-args-by-ref NOLINT(performance-unnecessary-value-param) + const QDateTime &time, + Reason r) +{ + _serial = serial; + _time = time; + _reason = r; +} + +CRLEntry::CRLEntry(const CRLEntry &from) + : _serial(from._serial) + , _time(from._time) + , _reason(from._reason) +{ +} + +CRLEntry::~CRLEntry() +{ +} + +CRLEntry &CRLEntry::operator=(const CRLEntry &from) +{ + _serial = from._serial; + _time = from._time; + _reason = from._reason; + return *this; +} + +bool CRLEntry::isNull() const +{ + return (_time.isNull()); +} + +BigInteger CRLEntry::serialNumber() const +{ + return _serial; +} + +QDateTime CRLEntry::time() const +{ + return _time; +} + +CRLEntry::Reason CRLEntry::reason() const +{ + return _reason; +} + +bool CRLEntry::operator==(const CRLEntry &otherEntry) const +{ + if (isNull()) { + if (otherEntry.isNull()) + return true; + else + return false; + } else if (otherEntry.isNull()) + return false; + + if ((_serial != otherEntry._serial) || (_time != otherEntry._time) || (_reason != otherEntry._reason)) { + return false; + } + return true; +} + +bool CRLEntry::operator<(const CRLEntry &otherEntry) const +{ + if (isNull() || otherEntry.isNull()) + return false; + + if (_serial < otherEntry._serial) + return true; + + return false; +} + +//---------------------------------------------------------------------------- +// CRL +//---------------------------------------------------------------------------- +class CRL::Private : public QSharedData +{ +public: + CertificateInfo issuerInfoMap; + + void update(CRLContext *c) + { + if (c) + issuerInfoMap = orderedToMap(c->props()->issuer); + else + issuerInfoMap = CertificateInfo(); + } +}; + +CRL::CRL() + : d(new Private) +{ +} + +CRL::CRL(const CRL &from) + : Algorithm(from) + , d(from.d) +{ +} + +CRL::~CRL() +{ +} + +CRL &CRL::operator=(const CRL &from) +{ + Algorithm::operator=(from); + d = from.d; + return *this; +} + +bool CRL::isNull() const +{ + return (!context() ? true : false); +} + +CertificateInfo CRL::issuerInfo() const +{ + return d->issuerInfoMap; +} + +CertificateInfoOrdered CRL::issuerInfoOrdered() const +{ + return static_cast(context())->props()->issuer; +} + +int CRL::number() const +{ + return static_cast(context())->props()->number; +} + +QDateTime CRL::thisUpdate() const +{ + return static_cast(context())->props()->thisUpdate; +} + +QDateTime CRL::nextUpdate() const +{ + return static_cast(context())->props()->nextUpdate; +} + +QList CRL::revoked() const +{ + return static_cast(context())->props()->revoked; +} + +SignatureAlgorithm CRL::signatureAlgorithm() const +{ + return static_cast(context())->props()->sigalgo; +} + +QByteArray CRL::issuerKeyId() const +{ + return static_cast(context())->props()->issuerId; +} + +QByteArray CRL::toDER() const +{ + return static_cast(context())->toDER(); +} + +QString CRL::toPEM() const +{ + return static_cast(context())->toPEM(); +} + +bool CRL::operator==(const CRL &otherCrl) const +{ + if (isNull()) { + if (otherCrl.isNull()) + return true; + else + return false; + } else if (otherCrl.isNull()) + return false; + + const CRLContext *other = static_cast(otherCrl.context()); + return static_cast(context())->compare(other); +} + +CRL CRL::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) +{ + CRL c; + CRLContext *cc = static_cast(getContext(QStringLiteral("crl"), provider)); + ConvertResult r = cc->fromDER(a); + if (result) + *result = r; + if (r == ConvertGood) + c.change(cc); + else + delete cc; + return c; +} + +CRL CRL::fromPEM(const QString &s, ConvertResult *result, const QString &provider) +{ + CRL c; + CRLContext *cc = static_cast(getContext(QStringLiteral("crl"), provider)); + ConvertResult r = cc->fromPEM(s); + if (result) + *result = r; + if (r == ConvertGood) + c.change(cc); + else + delete cc; + return c; +} + +CRL CRL::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QString pem; + if (!stringFromFile(fileName, &pem)) { + if (result) + *result = ErrorFile; + return CRL(); + } + return fromPEM(pem, result, provider); +} + +bool CRL::toPEMFile(const QString &fileName) const +{ + return stringToFile(fileName, toPEM()); +} + +void CRL::change(CRLContext *c) +{ + Algorithm::change(c); + d->update(static_cast(context())); +} + +//---------------------------------------------------------------------------- +// Store +//---------------------------------------------------------------------------- +// CRL / X509 CRL +// CERTIFICATE / X509 CERTIFICATE +static QString readNextPem(QTextStream *ts, bool *isCRL) +{ + QString pem; + bool crl = false; + bool found = false; + bool done = false; + while (!ts->atEnd()) { + const QString line = ts->readLine(); + if (!found) { + if (line.startsWith(QLatin1String("-----BEGIN "))) { + if (line.contains(QLatin1String("CERTIFICATE"))) { + found = true; + pem += line + QLatin1Char('\n'); + crl = false; + } else if (line.contains(QLatin1String("CRL"))) { + found = true; + pem += line + QLatin1Char('\n'); + crl = true; + } + } + } else { + pem += line + QLatin1Char('\n'); + if (line.startsWith(QLatin1String("-----END "))) { + done = true; + break; + } + } + } + if (!done) + return QString(); + if (isCRL) + *isCRL = crl; + return pem; +} + +class CertificateCollection::Private : public QSharedData +{ +public: + QList certs; + QList crls; +}; + +CertificateCollection::CertificateCollection() + : d(new Private) +{ +} + +CertificateCollection::CertificateCollection(const CertificateCollection &from) + : d(from.d) +{ +} + +CertificateCollection::~CertificateCollection() +{ +} + +CertificateCollection &CertificateCollection::operator=(const CertificateCollection &from) +{ + d = from.d; + return *this; +} + +void CertificateCollection::addCertificate(const Certificate &cert) +{ + d->certs.append(cert); +} + +void CertificateCollection::addCRL(const CRL &crl) +{ + d->crls.append(crl); +} + +QList CertificateCollection::certificates() const +{ + return d->certs; +} + +QList CertificateCollection::crls() const +{ + return d->crls; +} + +void CertificateCollection::append(const CertificateCollection &other) +{ + d->certs += other.d->certs; + d->crls += other.d->crls; +} + +CertificateCollection CertificateCollection::operator+(const CertificateCollection &other) const +{ + CertificateCollection c = *this; + c.append(other); + return c; +} + +CertificateCollection &CertificateCollection::operator+=(const CertificateCollection &other) +{ + append(other); + return *this; +} + +bool CertificateCollection::canUsePKCS7(const QString &provider) +{ + return isSupported("certcollection", provider); +} + +bool CertificateCollection::toFlatTextFile(const QString &fileName) +{ + QFile f(fileName); + if (!f.open(QFile::WriteOnly)) + return false; + + QTextStream ts(&f); + int n; + for (n = 0; n < d->certs.count(); ++n) + ts << d->certs[n].toPEM(); + for (n = 0; n < d->crls.count(); ++n) + ts << d->crls[n].toPEM(); + return true; +} + +bool CertificateCollection::toPKCS7File(const QString &fileName, const QString &provider) +{ + CertCollectionContext *col = + static_cast(getContext(QStringLiteral("certcollection"), provider)); + + QList cert_list; + QList crl_list; + int n; + for (n = 0; n < d->certs.count(); ++n) { + CertContext *c = static_cast(d->certs[n].context()); + cert_list += c; + } + for (n = 0; n < d->crls.count(); ++n) { + CRLContext *c = static_cast(d->crls[n].context()); + crl_list += c; + } + + const QByteArray result = col->toPKCS7(cert_list, crl_list); + delete col; + + return arrayToFile(fileName, result); +} + +CertificateCollection +CertificateCollection::fromFlatTextFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) { + if (result) + *result = ErrorFile; + return CertificateCollection(); + } + + CertificateCollection certs; + QTextStream ts(&f); + while (true) { + bool isCRL = false; + QString pem = readNextPem(&ts, &isCRL); + if (pem.isNull()) + break; + if (isCRL) { + CRL c = CRL::fromPEM(pem, nullptr, provider); + if (!c.isNull()) + certs.addCRL(c); + } else { + Certificate c = Certificate::fromPEM(pem, nullptr, provider); + if (!c.isNull()) + certs.addCertificate(c); + } + } + + if (result) + *result = ConvertGood; + + return certs; +} + +CertificateCollection +CertificateCollection::fromPKCS7File(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QByteArray der; + if (!arrayFromFile(fileName, &der)) { + if (result) + *result = ErrorFile; + return CertificateCollection(); + } + + CertificateCollection certs; + + QList cert_list; + QList crl_list; + CertCollectionContext *col = + static_cast(getContext(QStringLiteral("certcollection"), provider)); + ConvertResult r = col->fromPKCS7(der, &cert_list, &crl_list); + delete col; + + if (result) + *result = r; + if (r == ConvertGood) { + int n; + for (n = 0; n < cert_list.count(); ++n) { + Certificate c; + c.change(cert_list[n]); + certs.addCertificate(c); + } + for (n = 0; n < crl_list.count(); ++n) { + CRL c; + c.change(crl_list[n]); + certs.addCRL(c); + } + } + return certs; +} + +//---------------------------------------------------------------------------- +// CertificateAuthority +//---------------------------------------------------------------------------- +CertificateAuthority::CertificateAuthority(const Certificate &cert, const PrivateKey &key, const QString &provider) + : Algorithm(QStringLiteral("ca"), provider) +{ + static_cast(context())->setup(*(static_cast(cert.context())), + *(static_cast(key.context()))); +} + +CertificateAuthority::CertificateAuthority(const CertificateAuthority &from) + : Algorithm(from) +{ +} + +CertificateAuthority::~CertificateAuthority() +{ +} + +CertificateAuthority &CertificateAuthority::operator=(const CertificateAuthority &from) +{ + Algorithm::operator=(from); + return *this; +} + +Certificate CertificateAuthority::certificate() const +{ + Certificate c; + c.change(static_cast(context())->certificate()); + return c; +} + +Certificate CertificateAuthority::signRequest(const CertificateRequest &req, const QDateTime ¬ValidAfter) const +{ + Certificate c; + CertContext *cc = static_cast(context())->signRequest( + *(static_cast(req.context())), notValidAfter); + if (cc) + c.change(cc); + return c; +} + +CRL CertificateAuthority::createCRL(const QDateTime &nextUpdate) const +{ + CRL crl; + CRLContext *cc = static_cast(context())->createCRL(nextUpdate); + if (cc) + crl.change(cc); + return crl; +} + +CRL CertificateAuthority::updateCRL(const CRL &crl, const QList &entries, const QDateTime &nextUpdate) const +{ + CRL new_crl; + CRLContext *cc = static_cast(context())->updateCRL( + *(static_cast(crl.context())), entries, nextUpdate); + if (cc) + new_crl.change(cc); + return new_crl; +} + +//---------------------------------------------------------------------------- +// KeyBundle +//---------------------------------------------------------------------------- +class KeyBundle::Private : public QSharedData +{ +public: + QString name; + CertificateChain chain; + PrivateKey key; +}; + +KeyBundle::KeyBundle() + : d(new Private) +{ +} + +KeyBundle::KeyBundle(const QString &fileName, const SecureArray &passphrase) + : d(new Private) +{ + *this = fromFile(fileName, passphrase, nullptr, QString()); +} + +KeyBundle::KeyBundle(const KeyBundle &from) + : d(from.d) +{ +} + +KeyBundle::~KeyBundle() +{ +} + +KeyBundle &KeyBundle::operator=(const KeyBundle &from) +{ + d = from.d; + return *this; +} + +bool KeyBundle::isNull() const +{ + return d->chain.isEmpty(); +} + +QString KeyBundle::name() const +{ + return d->name; +} + +CertificateChain KeyBundle::certificateChain() const +{ + return d->chain; +} + +PrivateKey KeyBundle::privateKey() const +{ + return d->key; +} + +void KeyBundle::setName(const QString &s) +{ + d->name = s; +} + +void KeyBundle::setCertificateChainAndKey(const CertificateChain &c, const PrivateKey &key) +{ + d->chain = c; + d->key = key; +} + +QByteArray KeyBundle::toArray(const SecureArray &passphrase, const QString &provider) const +{ + PKCS12Context *pix = static_cast(getContext(QStringLiteral("pkcs12"), provider)); + + QList list; + for (int n = 0; n < d->chain.count(); ++n) + list.append(static_cast(d->chain[n].context())); + const QByteArray buf = + pix->toPKCS12(d->name, list, *(static_cast(d->key.context())), passphrase); + delete pix; + + return buf; +} + +bool KeyBundle::toFile(const QString &fileName, const SecureArray &passphrase, const QString &provider) const +{ + return arrayToFile(fileName, toArray(passphrase, provider)); +} + +KeyBundle +KeyBundle::fromArray(const QByteArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider) +{ + KeyBundle bundle; + get_pkcs12_der( + a, QString(), (void *)&a, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key); + return bundle; +} + +KeyBundle KeyBundle::fromFile(const QString &fileName, + const SecureArray &passphrase, + ConvertResult *result, + const QString &provider) +{ + QByteArray der; + if (!arrayFromFile(fileName, &der)) { + if (result) + *result = ErrorFile; + return KeyBundle(); + } + + KeyBundle bundle; + get_pkcs12_der( + der, fileName, nullptr, passphrase, result, provider, &bundle.d->name, &bundle.d->chain, &bundle.d->key); + return bundle; +} + +//---------------------------------------------------------------------------- +// PGPKey +//---------------------------------------------------------------------------- +PGPKey::PGPKey() +{ +} + +PGPKey::PGPKey(const QString &fileName) +{ + *this = fromFile(fileName, nullptr, QString()); +} + +PGPKey::PGPKey(const PGPKey &from) + : Algorithm(from) +{ +} + +PGPKey::~PGPKey() +{ +} + +PGPKey &PGPKey::operator=(const PGPKey &from) +{ + Algorithm::operator=(from); + return *this; +} + +bool PGPKey::isNull() const +{ + return (!context() ? true : false); +} + +QString PGPKey::keyId() const +{ + return static_cast(context())->props()->keyId; +} + +QString PGPKey::primaryUserId() const +{ + return static_cast(context())->props()->userIds.first(); +} + +QStringList PGPKey::userIds() const +{ + return static_cast(context())->props()->userIds; +} + +bool PGPKey::isSecret() const +{ + return static_cast(context())->props()->isSecret; +} + +QDateTime PGPKey::creationDate() const +{ + return static_cast(context())->props()->creationDate; +} + +QDateTime PGPKey::expirationDate() const +{ + return static_cast(context())->props()->expirationDate; +} + +QString PGPKey::fingerprint() const +{ + return static_cast(context())->props()->fingerprint; +} + +bool PGPKey::inKeyring() const +{ + return static_cast(context())->props()->inKeyring; +} + +bool PGPKey::isTrusted() const +{ + return static_cast(context())->props()->isTrusted; +} + +QByteArray PGPKey::toArray() const +{ + return static_cast(context())->toBinary(); +} + +QString PGPKey::toString() const +{ + return static_cast(context())->toAscii(); +} + +bool PGPKey::toFile(const QString &fileName) const +{ + return stringToFile(fileName, toString()); +} + +PGPKey PGPKey::fromArray(const QByteArray &a, ConvertResult *result, const QString &provider) +{ + PGPKey k; + PGPKeyContext *kc = static_cast(getContext(QStringLiteral("pgpkey"), provider)); + ConvertResult r = kc->fromBinary(a); + if (result) + *result = r; + if (r == ConvertGood) + k.change(kc); + else + delete kc; + return k; +} + +PGPKey PGPKey::fromString(const QString &s, ConvertResult *result, const QString &provider) +{ + PGPKey k; + PGPKeyContext *kc = static_cast(getContext(QStringLiteral("pgpkey"), provider)); + ConvertResult r = kc->fromAscii(s); + if (result) + *result = r; + if (r == ConvertGood) + k.change(kc); + else + delete kc; + return k; +} + +PGPKey PGPKey::fromFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QString str; + if (!stringFromFile(fileName, &str)) { + if (result) + *result = ErrorFile; + return PGPKey(); + } + return fromString(str, result, provider); +} + +//---------------------------------------------------------------------------- +// KeyLoader +//---------------------------------------------------------------------------- +class KeyLoaderThread : public QThread +{ + Q_OBJECT +public: + enum Type + { + PKPEMFile, + PKPEM, + PKDER, + KBDERFile, + KBDER + }; + + class In + { + public: + Type type; + QString fileName, pem; + SecureArray der; + QByteArray kbder; + }; + + class Out + { + public: + ConvertResult convertResult; + PrivateKey privateKey; + KeyBundle keyBundle; + }; + + In in; + Out out; + + KeyLoaderThread(QObject *parent = nullptr) + : QThread(parent) + { + } + +protected: + void run() override + { + if (in.type == PKPEMFile) + out.privateKey = PrivateKey::fromPEMFile(in.fileName, SecureArray(), &out.convertResult); + else if (in.type == PKPEM) + out.privateKey = PrivateKey::fromPEM(in.pem, SecureArray(), &out.convertResult); + else if (in.type == PKDER) + out.privateKey = PrivateKey::fromDER(in.der, SecureArray(), &out.convertResult); + else if (in.type == KBDERFile) + out.keyBundle = KeyBundle::fromFile(in.fileName, SecureArray(), &out.convertResult); + else if (in.type == KBDER) + out.keyBundle = KeyBundle::fromArray(in.kbder, SecureArray(), &out.convertResult); + } +}; + +class KeyLoader::Private : public QObject +{ + Q_OBJECT +public: + KeyLoader *q; + + bool active; + KeyLoaderThread *thread; + KeyLoaderThread::In in; + KeyLoaderThread::Out out; + + Private(KeyLoader *_q) + : QObject(_q) + , q(_q) + { + active = false; + } + + void reset() + { + in = KeyLoaderThread::In(); + out = KeyLoaderThread::Out(); + } + + void start() + { + active = true; + thread = new KeyLoaderThread(this); + // used queued for signal-safety + connect(thread, &KeyLoaderThread::finished, this, &KeyLoader::Private::thread_finished, Qt::QueuedConnection); + thread->in = in; + thread->start(); + } + +private Q_SLOTS: + void thread_finished() + { + out = thread->out; + delete thread; + thread = nullptr; + active = false; + + emit q->finished(); + } +}; + +KeyLoader::KeyLoader(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +KeyLoader::~KeyLoader() +{ + delete d; +} + +void KeyLoader::loadPrivateKeyFromPEMFile(const QString &fileName) +{ + Q_ASSERT(!d->active); + if (d->active) + return; + + d->reset(); + d->in.type = KeyLoaderThread::PKPEMFile; + d->in.fileName = fileName; + d->start(); +} + +void KeyLoader::loadPrivateKeyFromPEM(const QString &s) +{ + Q_ASSERT(!d->active); + if (d->active) + return; + + d->reset(); + d->in.type = KeyLoaderThread::PKPEM; + d->in.pem = s; + d->start(); +} + +void KeyLoader::loadPrivateKeyFromDER(const SecureArray &a) +{ + Q_ASSERT(!d->active); + if (d->active) + return; + + d->reset(); + d->in.type = KeyLoaderThread::PKDER; + d->in.der = a; + d->start(); +} + +void KeyLoader::loadKeyBundleFromFile(const QString &fileName) +{ + Q_ASSERT(!d->active); + if (d->active) + return; + + d->reset(); + d->in.type = KeyLoaderThread::KBDERFile; + d->in.fileName = fileName; + d->start(); +} + +void KeyLoader::loadKeyBundleFromArray(const QByteArray &a) +{ + Q_ASSERT(!d->active); + if (d->active) + return; + + d->reset(); + d->in.type = KeyLoaderThread::KBDERFile; + d->in.kbder = a; + d->start(); +} + +ConvertResult KeyLoader::convertResult() const +{ + return d->out.convertResult; +} + +PrivateKey KeyLoader::privateKey() const +{ + return d->out.privateKey; +} + +KeyBundle KeyLoader::keyBundle() const +{ + return d->out.keyBundle; +} + +} + +#include "qca_cert.moc" diff --git a/local/recipes/libs/qca/source/src/qca_core.cpp b/local/recipes/libs/qca/source/src/qca_core.cpp new file mode 100644 index 0000000000..b0e9f47044 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_core.cpp @@ -0,0 +1,2186 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * Copyright (C) 2014-2016 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_core.h" + +#include "qca_cert.h" +#include "qca_keystore.h" +#include "qca_plugin.h" +#include "qca_textfilter.h" +#include "qcaprovider.h" + +// for qAddPostRoutine +#include + +#include +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +#include +#endif + +int qcaVersion() +{ + return QCA_VERSION; +} + +const char *qcaVersionStr() +{ + return QCA_VERSION_STR; +} + +int qcaMajorVersion() +{ + return QCA_MAJOR_VERSION; +} + +int qcaMinorVersion() +{ + return QCA_MINOR_VERSION; +} + +int qcaPatchVersion() +{ + return QCA_PATCH_VERSION; +} + +namespace QCA { + +// from qca_tools +bool botan_init(int prealloc, bool mmap); +void botan_deinit(); + +// from qca_default +Provider *create_default_provider(); + +//---------------------------------------------------------------------------- +// Global +//---------------------------------------------------------------------------- +class Global +{ +public: + int refs; + bool secmem; + bool loaded; + bool first_scan; + QString app_name; + QMutex name_mutex; + ProviderManager *manager; + QMutex scan_mutex; + Random *rng; + QMutex rng_mutex; + Logger *logger; + QVariantMap properties; + QMutex prop_mutex; + QMap config; + QMutex config_mutex; + QMutex logger_mutex; + + Global() + { + refs = 0; + secmem = false; + loaded = false; + first_scan = false; + rng = nullptr; + logger = nullptr; + manager = new ProviderManager; + } + + ~Global() + { + KeyStoreManager::shutdown(); + delete rng; + rng = nullptr; + delete manager; + manager = nullptr; + delete logger; + logger = nullptr; + } + + void ensure_loaded() + { + // probably we shouldn't overload scan mutex, or else rename it + QMutexLocker locker(&scan_mutex); + if (!loaded) { + loaded = true; + manager->setDefault(create_default_provider()); // manager owns it + } + } + + bool ensure_first_scan() + { + scan_mutex.lock(); + if (!first_scan) { + first_scan = true; + manager->scan(); + scan_mutex.unlock(); + return true; + } + scan_mutex.unlock(); + return false; + } + + void scan() + { + scan_mutex.lock(); + first_scan = true; + manager->scan(); + scan_mutex.unlock(); + } + + void ksm_scan() + { + KeyStoreManager::scan(); + } + + Logger *get_logger() + { + QMutexLocker locker(&logger_mutex); + if (!logger) { + logger = new Logger; + + // needed so deinit may delete the logger regardless + // of what thread the logger was created from + logger->moveToThread(nullptr); + } + return logger; + } + + void unloadAllPlugins() + { + KeyStoreManager::shutdown(); + + // if the global_rng was owned by a plugin, then delete it + rng_mutex.lock(); + if (rng && (rng->provider() != manager->find(QStringLiteral("default")))) { + delete rng; + rng = nullptr; + } + rng_mutex.unlock(); + + manager->unloadAll(); + } +}; + +Q_GLOBAL_STATIC(QMutex, global_mutex) +static Global *global = nullptr; + +static bool features_have(const QStringList &have, const QStringList &want) +{ + foreach (const QString &i, want) { + if (!have.contains(i)) + return false; + } + return true; +} + +void init(MemoryMode mode, int prealloc) +{ + QMutexLocker locker(global_mutex()); + if (global) { + ++(global->refs); + return; + } + + bool allow_mmap_fallback = false; + bool drop_root = false; + if (mode == Practical) { + allow_mmap_fallback = true; + drop_root = true; + } else if (mode == Locking) + drop_root = true; + + bool secmem = botan_init(prealloc, allow_mmap_fallback); + +#if defined(Q_OS_UNIX) + if ((geteuid() == 0) && drop_root) { + setuid(getuid()); + } +#endif + + global = new Global; + global->secmem = secmem; + ++(global->refs); + + // for maximum setuid safety, qca should be initialized before qapp: + // + // int main(int argc, char **argv) + // { + // QCA::Initializer init; + // QCoreApplication app(argc, argv); + // return 0; + // } + // + // however, the above code has the unfortunate side-effect of causing + // qapp to deinit before qca, which can cause problems with any + // plugins that have active objects (notably KeyStore). we'll use a + // post routine to force qca to deinit first. + qAddPostRoutine(deinit); +} + +void init() +{ + init(Practical, 64); +} + +void deinit() +{ + QMutexLocker locker(global_mutex()); + if (!global) + return; + --(global->refs); + if (global->refs == 0) { + // In order to maintain symmetry with the init() function, remove the + // post routine from QCoreApplication. This is needed in case when the + // QCA library is unloaded before QCoreApplication instance completes: + // QCoreApplication d-tor would try to execute the deinit() function, + // which would no longer be there. + // Note that this function is documented only in Qt 5.3 and later, but + // it has been present since ancient times with the same semantics. + qRemovePostRoutine(deinit); + + delete global; + global = nullptr; + botan_deinit(); + } +} + +static bool global_check() +{ + Q_ASSERT(global); + if (!global) + return false; + return true; +} + +static bool global_check_load() +{ + Q_ASSERT(global); + if (!global) + return false; + global->ensure_loaded(); + return true; +} + +QMutex *global_random_mutex() +{ + return &global->rng_mutex; +} + +Random *global_random() +{ + if (!global->rng) + global->rng = new Random; + return global->rng; +} + +bool haveSecureMemory() +{ + if (!global_check()) + return false; + + return global->secmem; +} + +bool haveSecureRandom() +{ + if (!global_check_load()) + return false; + + QMutexLocker locker(global_random_mutex()); + if (global_random()->provider()->name() != QLatin1String("default")) + return true; + + return false; +} + +bool isSupported(const QStringList &features, const QString &provider) +{ + if (!global_check_load()) + return false; + + // single + if (!provider.isEmpty()) { + Provider *p = global->manager->find(provider); + if (!p) { + // ok, try scanning for new stuff + global->scan(); + p = global->manager->find(provider); + } + + if (p && features_have(p->features(), features)) + return true; + } + // all + else { + if (features_have(global->manager->allFeatures(), features)) + return true; + + global->manager->appendDiagnosticText( + QStringLiteral("Scanning to find features: %1\n").arg(features.join(QStringLiteral(" ")))); + + // ok, try scanning for new stuff + global->scan(); + + if (features_have(global->manager->allFeatures(), features)) + return true; + } + return false; +} + +bool isSupported(const char *features, const QString &provider) +{ + return isSupported(QString::fromLatin1(features).split(QLatin1Char(','), Qt::SkipEmptyParts), provider); +} + +QStringList supportedFeatures() +{ + if (!global_check_load()) + return QStringList(); + + // query all features + global->scan(); + return global->manager->allFeatures(); +} + +QStringList defaultFeatures() +{ + if (!global_check_load()) + return QStringList(); + + return global->manager->find(QStringLiteral("default"))->features(); +} + +ProviderList providers() +{ + if (!global_check_load()) + return ProviderList(); + + global->ensure_first_scan(); + + return global->manager->providers(); +} + +bool insertProvider(Provider *p, int priority) +{ + if (!global_check_load()) + return false; + + global->ensure_first_scan(); + + return global->manager->add(p, priority); +} + +bool unloadProvider(const QString &name) +{ + if (!global_check_load()) + return false; + + global->ensure_first_scan(); + + return global->manager->unload(name); +} + +void setProviderPriority(const QString &name, int priority) +{ + if (!global_check_load()) + return; + + global->ensure_first_scan(); + + global->manager->changePriority(name, priority); +} + +int providerPriority(const QString &name) +{ + if (!global_check_load()) + return -1; + + global->ensure_first_scan(); + + return global->manager->getPriority(name); +} + +Provider *findProvider(const QString &name) +{ + if (!global_check_load()) + return nullptr; + + global->ensure_first_scan(); + + return global->manager->find(name); +} + +Provider *defaultProvider() +{ + if (!global_check_load()) + return nullptr; + + return global->manager->find(QStringLiteral("default")); +} + +QStringList pluginPaths() +{ + QStringList paths; +#ifndef DEVELOPER_MODE + const QByteArray qcaPluginPath = qgetenv("QCA_PLUGIN_PATH"); + if (!qcaPluginPath.isEmpty()) { +#ifdef Q_OS_WIN + char pathSep(';'); +#else + char pathSep(':'); +#endif + foreach (const QByteArray &path, qcaPluginPath.split(pathSep)) { + const QString canonicalPath = QDir(QFile::decodeName(path)).canonicalPath(); + if (!canonicalPath.isEmpty()) + paths << canonicalPath; + } + } + paths += QCoreApplication::libraryPaths(); +#endif + // In developer mode load plugins only from buildtree. + // In regular mode QCA_PLUGIN_PATH is path where plugins was installed + paths << QDir(QStringLiteral(QCA_PLUGIN_PATH)).canonicalPath(); +#ifndef DEVELOPER_MODE + paths.removeDuplicates(); +#endif + // No empty strings + paths.removeAll(QString()); + return paths; +} + +void scanForPlugins() +{ + if (!global_check_load()) + return; + + global->scan(); + global->ksm_scan(); +} + +void unloadAllPlugins() +{ + if (!global_check_load()) + return; + + global->unloadAllPlugins(); +} + +QString pluginDiagnosticText() +{ + if (!global_check_load()) + return QString(); + + return global->manager->diagnosticText(); +} + +void clearPluginDiagnosticText() +{ + if (!global_check_load()) + return; + + global->manager->clearDiagnosticText(); +} + +void appendPluginDiagnosticText(const QString &text) +{ + if (!global_check_load()) + return; + + global->manager->appendDiagnosticText(text); +} + +void setProperty(const QString &name, const QVariant &value) +{ + if (!global_check_load()) + return; + + QMutexLocker locker(&global->prop_mutex); + + global->properties[name] = value; +} + +QVariant getProperty(const QString &name) +{ + if (!global_check_load()) + return QVariant(); + + QMutexLocker locker(&global->prop_mutex); + + return global->properties.value(name); +} + +static bool configIsValid(const QVariantMap &config) +{ + if (!config.contains(QStringLiteral("formtype"))) + return false; + QMapIterator it(config); + while (it.hasNext()) { + it.next(); + const QVariant &v = it.value(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (v.typeId() != QMetaType::QString && v.typeId() != QMetaType::Int && v.typeId() != QMetaType::Bool) +#else + if (v.type() != QVariant::String && v.type() != QVariant::Int && v.type() != QVariant::Bool) + +#endif + return false; + } + return true; +} + +static QVariantMap readConfig(const QString &name) +{ + QSettings settings(QStringLiteral("Affinix"), QStringLiteral("QCA2")); + settings.beginGroup(QStringLiteral("ProviderConfig")); + const QStringList providerNames = settings.value(QStringLiteral("providerNames")).toStringList(); + if (!providerNames.contains(name)) + return QVariantMap(); + + settings.beginGroup(name); + const QStringList keys = settings.childKeys(); + QVariantMap map; + foreach (const QString &key, keys) + map[key] = settings.value(key); + settings.endGroup(); + + if (!configIsValid(map)) + return QVariantMap(); + return map; +} + +static bool writeConfig(const QString &name, const QVariantMap &config, bool systemWide = false) +{ + QSettings settings(QSettings::NativeFormat, + systemWide ? QSettings::SystemScope : QSettings::UserScope, + QStringLiteral("Affinix"), + QStringLiteral("QCA2")); + settings.beginGroup(QStringLiteral("ProviderConfig")); + + // version + settings.setValue(QStringLiteral("version"), 2); + + // add the entry if needed + QStringList providerNames = settings.value(QStringLiteral("providerNames")).toStringList(); + if (!providerNames.contains(name)) + providerNames += name; + settings.setValue(QStringLiteral("providerNames"), providerNames); + + settings.beginGroup(name); + QMapIterator it(config); + while (it.hasNext()) { + it.next(); + settings.setValue(it.key(), it.value()); + } + settings.endGroup(); + + if (settings.status() == QSettings::NoError) + return true; + return false; +} + +void setProviderConfig(const QString &name, const QVariantMap &config) +{ + if (!global_check_load()) + return; + + if (!configIsValid(config)) + return; + + global->config_mutex.lock(); + global->config[name] = config; + global->config_mutex.unlock(); + + Provider *p = findProvider(name); + if (p) + p->configChanged(config); +} + +QVariantMap getProviderConfig(const QString &name) +{ + if (!global_check_load()) + return QVariantMap(); + + QVariantMap conf; + + global->config_mutex.lock(); + + // try loading from persistent storage + conf = readConfig(name); + + // if not, load the one from memory + if (conf.isEmpty()) + conf = global->config.value(name); + + global->config_mutex.unlock(); + + // if provider doesn't exist or doesn't have a valid config form, + // use the config we loaded + Provider *p = findProvider(name); + if (!p) + return conf; + const QVariantMap pconf = p->defaultConfig(); + if (!configIsValid(pconf)) + return conf; + + // if the config loaded was empty, use the provider's config + if (conf.isEmpty()) + return pconf; + + // if the config formtype doesn't match the provider's formtype, + // then use the provider's + if (pconf[QStringLiteral("formtype")] != conf[QStringLiteral("formtype")]) + return pconf; + + // otherwise, use the config loaded + return conf; +} + +void saveProviderConfig(const QString &name) +{ + if (!global_check_load()) + return; + + QMutexLocker locker(&global->config_mutex); + + QVariantMap conf = global->config.value(name); + if (conf.isEmpty()) + return; + + writeConfig(name, conf); +} + +QVariantMap getProviderConfig_internal(Provider *p) +{ + QVariantMap conf; + const QString name = p->name(); + + global->config_mutex.lock(); + + // try loading from persistent storage + conf = readConfig(name); + + // if not, load the one from memory + if (conf.isEmpty()) + conf = global->config.value(name); + + global->config_mutex.unlock(); + + // if provider doesn't exist or doesn't have a valid config form, + // use the config we loaded + const QVariantMap pconf = p->defaultConfig(); + if (!configIsValid(pconf)) + return conf; + + // if the config loaded was empty, use the provider's config + if (conf.isEmpty()) + return pconf; + + // if the config formtype doesn't match the provider's formtype, + // then use the provider's + if (pconf[QStringLiteral("formtype")] != conf[QStringLiteral("formtype")]) + return pconf; + + // otherwise, use the config loaded + return conf; +} + +QString globalRandomProvider() +{ + QMutexLocker locker(global_random_mutex()); + return global_random()->provider()->name(); +} + +void setGlobalRandomProvider(const QString &provider) +{ + QMutexLocker locker(global_random_mutex()); + delete global->rng; + global->rng = new Random(provider); +} + +Logger *logger() +{ + return global->get_logger(); +} + +bool haveSystemStore() +{ + // ensure the system store is loaded + KeyStoreManager::start(QStringLiteral("default")); + KeyStoreManager ksm; + ksm.waitForBusyFinished(); + + const QStringList list = ksm.keyStores(); + for (int n = 0; n < list.count(); ++n) { + KeyStore ks(list[n], &ksm); + if (ks.type() == KeyStore::System && ks.holdsTrustedCertificates()) + return true; + } + return false; +} + +CertificateCollection systemStore() +{ + // ensure the system store is loaded + KeyStoreManager::start(QStringLiteral("default")); + KeyStoreManager ksm; + ksm.waitForBusyFinished(); + + CertificateCollection col; + const QStringList list = ksm.keyStores(); + for (int n = 0; n < list.count(); ++n) { + KeyStore ks(list[n], &ksm); + + // system store + if (ks.type() == KeyStore::System && ks.holdsTrustedCertificates()) { + // extract contents + const QList entries = ks.entryList(); + for (int i = 0; i < entries.count(); ++i) { + if (entries[i].type() == KeyStoreEntry::TypeCertificate) + col.addCertificate(entries[i].certificate()); + else if (entries[i].type() == KeyStoreEntry::TypeCRL) + col.addCRL(entries[i].crl()); + } + break; + } + } + return col; +} + +QString appName() +{ + if (!global_check()) + return QString(); + + QMutexLocker locker(&global->name_mutex); + + return global->app_name; +} + +void setAppName(const QString &s) +{ + if (!global_check()) + return; + + QMutexLocker locker(&global->name_mutex); + + global->app_name = s; +} + +QString arrayToHex(const QByteArray &a) +{ + return Hex().arrayToString(a); +} + +QByteArray hexToArray(const QString &str) +{ + return Hex().stringToArray(str).toByteArray(); +} + +QString arrayToBase64(const QByteArray &a) +{ + return Base64().arrayToString(a); +} + +QByteArray base64ToArray(const QString &base64String) +{ + return Base64().stringToArray(base64String).toByteArray(); +} + +static Provider *getProviderForType(const QString &type, const QString &provider) +{ + Provider *p = nullptr; + bool scanned = global->ensure_first_scan(); + if (!provider.isEmpty()) { + // try using specific provider + p = global->manager->findFor(provider, type); + if (!p && !scanned) { + // maybe this provider is new, so scan and try again + global->scan(); + scanned = true; + p = global->manager->findFor(provider, type); + } + } + if (!p) { + // try using some other provider + p = global->manager->findFor(QString(), type); + + // note: we used to rescan if no provider was found or if + // the only found provider was 'default'. now we only + // rescan if no provider was found. this optimizes lookups + // for features that are in the default provider (such as + // 'sha1') when no other plugin is available. the drawback + // is that if a plugin is installed later during runtime, + // then it won't be picked up without restarting the + // application or manually calling QCA::scanForPlugins. + // if((!p || p->name() == "default") && !scanned) + if (!p && !scanned) { + // maybe there are new providers, so scan and try again + // before giving up or using default + global->scan(); + scanned = true; + p = global->manager->findFor(QString(), type); + } + } + + return p; +} + +static inline Provider::Context *doCreateContext(Provider *p, const QString &type) +{ + return p->createContext(type); +} + +Provider::Context *getContext(const QString &type, const QString &provider) +{ + if (!global_check_load()) + return nullptr; + + Provider *p; + { + p = getProviderForType(type, provider); + if (!p) + return nullptr; + } + + return doCreateContext(p, type); +} + +Provider::Context *getContext(const QString &type, Provider *_p) +{ + if (!global_check_load()) + return nullptr; + + Provider *p; + { + p = global->manager->find(_p); + if (!p) + return nullptr; + } + + return doCreateContext(p, type); +} + +//---------------------------------------------------------------------------- +// Initializer +//---------------------------------------------------------------------------- +Initializer::Initializer(MemoryMode m, int prealloc) +{ + init(m, prealloc); +} + +Initializer::~Initializer() +{ + deinit(); +} + +//---------------------------------------------------------------------------- +// Provider +//---------------------------------------------------------------------------- +Provider::~Provider() +{ +} + +void Provider::init() +{ +} + +void Provider::deinit() +{ +} + +int Provider::version() const +{ + return 0; +} + +QString Provider::credit() const +{ + return QString(); +} + +QVariantMap Provider::defaultConfig() const +{ + return QVariantMap(); +} + +void Provider::configChanged(const QVariantMap &) +{ +} + +Provider::Context::Context(Provider *parent, const QString &type) + : QObject() +{ + _provider = parent; + _type = type; +} + +Provider::Context::Context(const Context &from) + : QObject() +{ + _provider = from._provider; + _type = from._type; +} + +Provider::Context::~Context() +{ +} + +Provider *Provider::Context::provider() const +{ + return _provider; +} + +QString Provider::Context::type() const +{ + return _type; +} + +bool Provider::Context::sameProvider(const Context *c) const +{ + return (c->provider() == _provider); +} + +//---------------------------------------------------------------------------- +// BasicContext +//---------------------------------------------------------------------------- +BasicContext::BasicContext(Provider *parent, const QString &type) + : Context(parent, type) +{ + moveToThread(nullptr); // no thread association +} + +BasicContext::BasicContext(const BasicContext &from) + : Context(from) +{ + moveToThread(nullptr); // no thread association +} + +BasicContext::~BasicContext() +{ +} + +//---------------------------------------------------------------------------- +// InfoContext +//---------------------------------------------------------------------------- +QStringList InfoContext::supportedHashTypes() const +{ + return QStringList(); +} + +QStringList InfoContext::supportedCipherTypes() const +{ + return QStringList(); +} + +QStringList InfoContext::supportedMACTypes() const +{ + return QStringList(); +} + +//---------------------------------------------------------------------------- +// PKeyBase +//---------------------------------------------------------------------------- +PKeyBase::PKeyBase(Provider *p, const QString &type) + : BasicContext(p, type) +{ +} + +int PKeyBase::maximumEncryptSize(EncryptionAlgorithm) const +{ + return 0; +} + +SecureArray PKeyBase::encrypt(const SecureArray &, EncryptionAlgorithm) +{ + return SecureArray(); +} + +bool PKeyBase::decrypt(const SecureArray &, SecureArray *, EncryptionAlgorithm) +{ + return false; +} + +void PKeyBase::startSign(SignatureAlgorithm, SignatureFormat) +{ +} + +void PKeyBase::startVerify(SignatureAlgorithm, SignatureFormat) +{ +} + +void PKeyBase::update(const MemoryRegion &) +{ +} + +QByteArray PKeyBase::endSign() +{ + return QByteArray(); +} + +bool PKeyBase::endVerify(const QByteArray &) +{ + return false; +} + +SymmetricKey PKeyBase::deriveKey(const PKeyBase &) +{ + return SymmetricKey(); +} + +//---------------------------------------------------------------------------- +// PKeyContext +//---------------------------------------------------------------------------- +QByteArray PKeyContext::publicToDER() const +{ + return QByteArray(); +} + +QString PKeyContext::publicToPEM() const +{ + return QString(); +} + +ConvertResult PKeyContext::publicFromDER(const QByteArray &) +{ + return ErrorDecode; +} + +ConvertResult PKeyContext::publicFromPEM(const QString &) +{ + return ErrorDecode; +} + +SecureArray PKeyContext::privateToDER(const SecureArray &, PBEAlgorithm) const +{ + return SecureArray(); +} + +QString PKeyContext::privateToPEM(const SecureArray &, PBEAlgorithm) const +{ + return QString(); +} + +ConvertResult PKeyContext::privateFromDER(const SecureArray &, const SecureArray &) +{ + return ErrorDecode; +} + +ConvertResult PKeyContext::privateFromPEM(const QString &, const SecureArray &) +{ + return ErrorDecode; +} + +//---------------------------------------------------------------------------- +// KeyStoreEntryContext +//---------------------------------------------------------------------------- +bool KeyStoreEntryContext::isAvailable() const +{ + return true; +} + +KeyBundle KeyStoreEntryContext::keyBundle() const +{ + return KeyBundle(); +} + +Certificate KeyStoreEntryContext::certificate() const +{ + return Certificate(); +} + +CRL KeyStoreEntryContext::crl() const +{ + return CRL(); +} + +PGPKey KeyStoreEntryContext::pgpSecretKey() const +{ + return PGPKey(); +} + +PGPKey KeyStoreEntryContext::pgpPublicKey() const +{ + return PGPKey(); +} + +bool KeyStoreEntryContext::ensureAccess() +{ + return true; +} + +//---------------------------------------------------------------------------- +// KeyStoreListContext +//---------------------------------------------------------------------------- +void KeyStoreListContext::start() +{ + QMetaObject::invokeMethod(this, "busyEnd", Qt::QueuedConnection); +} + +void KeyStoreListContext::setUpdatesEnabled(bool) +{ +} + +bool KeyStoreListContext::isReadOnly(int) const +{ + return true; +} + +KeyStoreEntryContext *KeyStoreListContext::entry(int id, const QString &entryId) +{ + KeyStoreEntryContext *out = nullptr; + QList list = entryList(id); + for (int n = 0; n < list.count(); ++n) { + if (list[n]->id() == entryId) { + out = list.takeAt(n); + break; + } + } + qDeleteAll(list); + return out; +} + +KeyStoreEntryContext *KeyStoreListContext::entryPassive(const QString &serialized) +{ + Q_UNUSED(serialized); + return nullptr; +} + +QString KeyStoreListContext::writeEntry(int, const KeyBundle &) +{ + return QString(); +} + +QString KeyStoreListContext::writeEntry(int, const Certificate &) +{ + return QString(); +} + +QString KeyStoreListContext::writeEntry(int, const CRL &) +{ + return QString(); +} + +QString KeyStoreListContext::writeEntry(int, const PGPKey &) +{ + return QString(); +} + +bool KeyStoreListContext::removeEntry(int, const QString &) +{ + return false; +} + +//---------------------------------------------------------------------------- +// TLSContext +//---------------------------------------------------------------------------- +void TLSContext::setMTU(int) +{ +} + +//---------------------------------------------------------------------------- +// MessageContext +//---------------------------------------------------------------------------- +QString MessageContext::diagnosticText() const +{ + return QString(); +} + +//---------------------------------------------------------------------------- +// SMSContext +//---------------------------------------------------------------------------- +void SMSContext::setTrustedCertificates(const CertificateCollection &) +{ +} + +void SMSContext::setUntrustedCertificates(const CertificateCollection &) +{ +} + +void SMSContext::setPrivateKeys(const QList &) +{ +} + +//---------------------------------------------------------------------------- +// BufferedComputation +//---------------------------------------------------------------------------- +BufferedComputation::~BufferedComputation() +{ +} + +MemoryRegion BufferedComputation::process(const MemoryRegion &a) +{ + clear(); + update(a); + return final(); +} + +//---------------------------------------------------------------------------- +// Filter +//---------------------------------------------------------------------------- +Filter::~Filter() +{ +} + +MemoryRegion Filter::process(const MemoryRegion &a) +{ + clear(); + MemoryRegion buf = update(a); + if (!ok()) + return MemoryRegion(); + const MemoryRegion fin = final(); + if (!ok()) + return MemoryRegion(); + if (buf.isSecure() || fin.isSecure()) + return (SecureArray(buf) + SecureArray(fin)); + else + return QByteArray(buf.toByteArray() + fin.toByteArray()); +} + +//---------------------------------------------------------------------------- +// Algorithm +//---------------------------------------------------------------------------- +class Algorithm::Private : public QSharedData +{ +public: + Provider::Context *c; + + Private(Provider::Context *context) + { + c = context; + // printf("** [%p] Algorithm Created\n", c); + } + + Private(const Private &from) + : QSharedData(from) + { + c = from.c->clone(); + // printf("** [%p] Algorithm Copied (to [%p])\n", from.c, c); + } + + ~Private() + { + // printf("** [%p] Algorithm Destroyed\n", c); + delete c; + } +}; + +Algorithm::Algorithm() +{ +} + +Algorithm::Algorithm(const QString &type, const QString &provider) +{ + change(type, provider); +} + +Algorithm::Algorithm(const Algorithm &from) +{ + *this = from; +} + +Algorithm::~Algorithm() +{ +} + +Algorithm &Algorithm::operator=(const Algorithm &from) +{ + d = from.d; + return *this; +} + +QString Algorithm::type() const +{ + if (d) + return d->c->type(); + else + return QString(); +} + +Provider *Algorithm::provider() const +{ + if (d) + return d->c->provider(); + else + return nullptr; +} + +Provider::Context *Algorithm::context() +{ + if (d) + return d->c; + else + return nullptr; +} + +const Provider::Context *Algorithm::context() const +{ + if (d) + return d->c; + else + return nullptr; +} + +void Algorithm::change(Provider::Context *c) +{ + if (c) + d = new Private(c); + else + d = nullptr; +} + +void Algorithm::change(const QString &type, const QString &provider) +{ + if (!type.isEmpty()) + change(getContext(type, provider)); + else + change(nullptr); +} + +Provider::Context *Algorithm::takeContext() +{ + if (d) { + Provider::Context *c = d->c; // should cause a detach + d->c = nullptr; + d = nullptr; + return c; + } else + return nullptr; +} + +//---------------------------------------------------------------------------- +// SymmetricKey +//---------------------------------------------------------------------------- +SymmetricKey::SymmetricKey() +{ +} + +SymmetricKey::SymmetricKey(int size) +{ + set(Random::randomArray(size)); +} + +SymmetricKey::SymmetricKey(const SecureArray &a) +{ + set(a); +} + +SymmetricKey::SymmetricKey(const QByteArray &a) +{ + set(SecureArray(a)); +} + +/* from libgcrypt-1.2.0 */ +static const unsigned char desWeakKeyTable[64][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*w*/ + {0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e}, {0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0}, + {0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe}, {0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e}, /*sw*/ + {0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00}, {0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe}, + {0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0}, {0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0}, /*sw*/ + {0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe}, {0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00}, + {0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e}, {0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe}, /*sw*/ + {0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0}, {0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e}, + {0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00}, {0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e}, + {0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00}, /*sw*/ + {0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe}, {0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0}, + {0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00}, {0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e}, /*w*/ + {0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0}, {0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe}, + {0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe}, {0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0}, /*sw*/ + {0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e}, {0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00}, + {0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0}, {0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe}, /*sw*/ + {0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00}, {0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e}, + {0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0}, {0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe}, + {0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00}, /*sw*/ + {0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e}, {0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe}, + {0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0}, {0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e}, /*sw*/ + {0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00}, {0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00}, + {0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e}, {0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0}, /*w*/ + {0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe}, {0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e}, + {0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00}, {0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe}, /*sw*/ + {0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0}, {0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe}, + {0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0}, {0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e}, + {0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00}, /*sw*/ + {0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0}, {0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe}, + {0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00}, {0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e}, /*sw*/ + {0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e}, {0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00}, + {0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe}, {0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0}, /*sw*/ + {0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00}, {0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e}, + {0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0}, {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe} /*w*/ +}; + +bool SymmetricKey::isWeakDESKey() +{ + if (size() != 8) + return false; // dubious + SecureArray workingCopy(8); + // clear parity bits + for (uint i = 0; i < 8; i++) + workingCopy[i] = (data()[i]) & 0xfe; + + for (auto n : desWeakKeyTable) { + if (memcmp(workingCopy.data(), n, 8) == 0) + return true; + } + return false; +} + +//---------------------------------------------------------------------------- +// InitializationVector +//---------------------------------------------------------------------------- +InitializationVector::InitializationVector() +{ +} + +InitializationVector::InitializationVector(int size) +{ + set(Random::randomArray(size)); +} + +InitializationVector::InitializationVector(const SecureArray &a) +{ + set(a); +} + +InitializationVector::InitializationVector(const QByteArray &a) +{ + set(SecureArray(a)); +} + +//---------------------------------------------------------------------------- +// AuthTag +//---------------------------------------------------------------------------- +AuthTag::AuthTag() +{ +} + +AuthTag::AuthTag(int size) +{ + resize(size); +} + +AuthTag::AuthTag(const SecureArray &a) +{ + set(a); +} + +AuthTag::AuthTag(const QByteArray &a) +{ + set(SecureArray(a)); +} + +//---------------------------------------------------------------------------- +// Event +//---------------------------------------------------------------------------- +class Event::Private : public QSharedData +{ +public: + Type type; + Source source; + PasswordStyle style; + KeyStoreInfo ksi; + KeyStoreEntry kse; + QString fname; + void *ptr; +}; + +Event::Event() +{ +} + +Event::Event(const Event &from) + : d(from.d) +{ +} + +Event::~Event() +{ +} + +Event &Event::operator=(const Event &from) +{ + d = from.d; + return *this; +} + +bool Event::isNull() const +{ + return (d ? false : true); +} + +Event::Type Event::type() const +{ + return d->type; +} + +Event::Source Event::source() const +{ + return d->source; +} + +Event::PasswordStyle Event::passwordStyle() const +{ + return d->style; +} + +KeyStoreInfo Event::keyStoreInfo() const +{ + return d->ksi; +} + +KeyStoreEntry Event::keyStoreEntry() const +{ + return d->kse; +} + +QString Event::fileName() const +{ + return d->fname; +} + +void *Event::ptr() const +{ + return d->ptr; +} + +void Event::setPasswordKeyStore(PasswordStyle pstyle, + const KeyStoreInfo &keyStoreInfo, + const KeyStoreEntry &keyStoreEntry, + void *ptr) +{ + if (!d) + d = new Private; + d->type = Password; + d->source = KeyStore; + d->style = pstyle; + d->ksi = keyStoreInfo; + d->kse = keyStoreEntry; + d->fname = QString(); + d->ptr = ptr; +} + +void Event::setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr) +{ + if (!d) + d = new Private; + d->type = Password; + d->source = Data; + d->style = pstyle; + d->ksi = KeyStoreInfo(); + d->kse = KeyStoreEntry(); + d->fname = fileName; + d->ptr = ptr; +} + +void Event::setToken(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) +{ + if (!d) + d = new Private; + d->type = Token; + d->source = KeyStore; + d->style = StylePassword; + d->ksi = keyStoreInfo; + d->kse = keyStoreEntry; + d->fname = QString(); + d->ptr = ptr; +} + +//---------------------------------------------------------------------------- +// EventGlobal +//---------------------------------------------------------------------------- +class HandlerBase : public QObject +{ + Q_OBJECT +public: + HandlerBase(QObject *parent = nullptr) + : QObject(parent) + { + } + +protected Q_SLOTS: + virtual void ask(int id, const QCA::Event &e) = 0; +}; + +class AskerBase : public QObject +{ + Q_OBJECT +public: + AskerBase(QObject *parent = nullptr) + : QObject(parent) + { + } + + virtual void set_accepted(const SecureArray &password) = 0; + virtual void set_rejected() = 0; +}; + +static void handler_add(HandlerBase *h, int pos = -1); +static void handler_remove(HandlerBase *h); +static void handler_accept(HandlerBase *h, int id, const SecureArray &password); +static void handler_reject(HandlerBase *h, int id); +static bool asker_ask(AskerBase *a, const Event &e); +static void asker_cancel(AskerBase *a); + +Q_GLOBAL_STATIC(QMutex, g_event_mutex) + +class EventGlobal; +static EventGlobal *g_event = nullptr; + +class EventGlobal +{ +public: + class HandlerItem + { + public: + HandlerBase *h; + QList ids; + }; + + class AskerItem + { + public: + AskerBase *a; + int id; + Event event; + int handler_pos; + }; + + QList handlers; + QList askers; + + int next_id; + + EventGlobal() + { + qRegisterMetaType("QCA::Event"); + qRegisterMetaType("QCA::SecureArray"); + next_id = 0; + } + + int findHandlerItem(HandlerBase *h) + { + for (int n = 0; n < handlers.count(); ++n) { + if (handlers[n].h == h) + return n; + } + return -1; + } + + int findAskerItem(AskerBase *a) + { + for (int n = 0; n < askers.count(); ++n) { + if (askers[n].a == a) + return n; + } + return -1; + } + + int findAskerItemById(int id) + { + for (int n = 0; n < askers.count(); ++n) { + if (askers[n].id == id) + return n; + } + return -1; + } + + void ask(int asker_at) + { + AskerItem &i = askers[asker_at]; + + g_event->handlers[i.handler_pos].ids += i.id; + QMetaObject::invokeMethod( + handlers[i.handler_pos].h, "ask", Qt::QueuedConnection, Q_ARG(int, i.id), Q_ARG(QCA::Event, i.event)); + } + + void reject(int asker_at) + { + AskerItem &i = askers[asker_at]; + + // look for the next usable handler + int pos = -1; + for (int n = i.handler_pos + 1; n < g_event->handlers.count(); ++n) { + // handler and asker can't be in the same thread + // Q_ASSERT(g_event->handlers[n].h->thread() != i.a->thread()); + // if(g_event->handlers[n].h->thread() != i.a->thread()) + //{ + pos = n; + break; + //} + } + + // if there is one, try it + if (pos != -1) { + i.handler_pos = pos; + ask(asker_at); + } + // if not, send official reject + else { + AskerBase *asker = i.a; + askers.removeAt(asker_at); + + asker->set_rejected(); + } + } +}; + +void handler_add(HandlerBase *h, int pos) +{ + QMutexLocker locker(g_event_mutex()); + if (!g_event) + g_event = new EventGlobal; + + EventGlobal::HandlerItem i; + i.h = h; + + if (pos != -1) { + g_event->handlers.insert(pos, i); + + // adjust handler positions + for (int n = 0; n < g_event->askers.count(); ++n) { + if (g_event->askers[n].handler_pos >= pos) + g_event->askers[n].handler_pos++; + } + } else + g_event->handlers += i; +} + +void handler_remove(HandlerBase *h) +{ + QMutexLocker locker(g_event_mutex()); + Q_ASSERT(g_event); + if (!g_event) + return; + int at = g_event->findHandlerItem(h); + Q_ASSERT(at != -1); + if (at == -1) + return; + + const QList ids = g_event->handlers[at].ids; + g_event->handlers.removeAt(at); + + // adjust handler positions within askers + for (int n = 0; n < g_event->askers.count(); ++n) { + if (g_event->askers[n].handler_pos >= at) + g_event->askers[n].handler_pos--; + } + + // reject all askers + foreach (int id, ids) { + int asker_at = g_event->findAskerItemById(id); + Q_ASSERT(asker_at != -1); + + g_event->reject(asker_at); + } + + if (g_event->handlers.isEmpty()) { + delete g_event; + g_event = nullptr; + } +} + +void handler_accept(HandlerBase *h, int id, const SecureArray &password) +{ + QMutexLocker locker(g_event_mutex()); + Q_ASSERT(g_event); + if (!g_event) + return; + int at = g_event->findHandlerItem(h); + Q_ASSERT(at != -1); + if (at == -1) + return; + int asker_at = g_event->findAskerItemById(id); + Q_ASSERT(asker_at != -1); + if (asker_at == -1) + return; + + g_event->handlers[at].ids.removeAll(g_event->askers[asker_at].id); + + AskerBase *asker = g_event->askers[asker_at].a; + asker->set_accepted(password); +} + +void handler_reject(HandlerBase *h, int id) +{ + QMutexLocker locker(g_event_mutex()); + Q_ASSERT(g_event); + if (!g_event) + return; + int at = g_event->findHandlerItem(h); + Q_ASSERT(at != -1); + if (at == -1) + return; + int asker_at = g_event->findAskerItemById(id); + Q_ASSERT(asker_at != -1); + if (asker_at == -1) + return; + + g_event->handlers[at].ids.removeAll(g_event->askers[asker_at].id); + + g_event->reject(asker_at); +} + +bool asker_ask(AskerBase *a, const Event &e) +{ + QMutexLocker locker(g_event_mutex()); + if (!g_event) + return false; + + int pos = -1; + for (int n = 0; n < g_event->handlers.count(); ++n) { + // handler and asker can't be in the same thread + // Q_ASSERT(g_event->handlers[n].h->thread() != a->thread()); + // if(g_event->handlers[n].h->thread() != a->thread()) + //{ + pos = n; + break; + //} + } + if (pos == -1) + return false; + + EventGlobal::AskerItem i; + i.a = a; + i.id = g_event->next_id++; + i.event = e; + i.handler_pos = pos; + g_event->askers += i; + const int asker_at = g_event->askers.count() - 1; + + g_event->ask(asker_at); + return true; +} + +void asker_cancel(AskerBase *a) +{ + QMutexLocker locker(g_event_mutex()); + if (!g_event) + return; + int at = g_event->findAskerItem(a); + if (at == -1) + return; + + for (int n = 0; n < g_event->handlers.count(); ++n) + g_event->handlers[n].ids.removeAll(g_event->askers[at].id); + + g_event->askers.removeAt(at); +} + +//---------------------------------------------------------------------------- +// EventHandler +//---------------------------------------------------------------------------- +class EventHandler::Private : public HandlerBase +{ + Q_OBJECT +public: + EventHandler *q; + bool started; + QList activeIds; + + Private(EventHandler *_q) + : HandlerBase(_q) + , q(_q) + { + started = false; + } + +public Q_SLOTS: + void ask(int id, const QCA::Event &e) override + { + activeIds += id; + emit q->eventReady(id, e); + } +}; + +EventHandler::EventHandler(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +EventHandler::~EventHandler() +{ + if (d->started) { + foreach (int id, d->activeIds) + handler_reject(d, id); + + handler_remove(d); + } + + delete d; +} + +void EventHandler::start() +{ + d->started = true; + handler_add(d); +} + +void EventHandler::submitPassword(int id, const SecureArray &password) +{ + if (!d->activeIds.contains(id)) + return; + + d->activeIds.removeAll(id); + handler_accept(d, id, password); +} + +void EventHandler::tokenOkay(int id) +{ + if (!d->activeIds.contains(id)) + return; + + d->activeIds.removeAll(id); + handler_accept(d, id, SecureArray()); +} + +void EventHandler::reject(int id) +{ + if (!d->activeIds.contains(id)) + return; + + d->activeIds.removeAll(id); + handler_reject(d, id); +} + +//---------------------------------------------------------------------------- +// PasswordAsker +//---------------------------------------------------------------------------- +class AskerPrivate : public AskerBase +{ + Q_OBJECT +public: + enum Type + { + Password, + Token + }; + + Type type; + PasswordAsker *passwordAsker; + TokenAsker *tokenAsker; + + QMutex m; + QWaitCondition w; + + bool accepted; + SecureArray password; + bool waiting; + bool done; + + AskerPrivate(PasswordAsker *parent) + : AskerBase(parent) + { + passwordAsker = parent; + tokenAsker = nullptr; + type = Password; + accepted = false; + waiting = false; + done = true; + } + + AskerPrivate(TokenAsker *parent) + : AskerBase(parent) + { + passwordAsker = nullptr; + tokenAsker = parent; + type = Token; + accepted = false; + waiting = false; + done = true; + } + + void ask(const Event &e) + { + accepted = false; + waiting = false; + done = false; + password.clear(); + + if (!asker_ask(this, e)) { + done = true; + QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); + } + } + + void cancel() + { + if (!done) + asker_cancel(this); + } + + void set_accepted(const SecureArray &_password) override + { + QMutexLocker locker(&m); + accepted = true; + password = _password; + done = true; + if (waiting) + w.wakeOne(); + else + QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); + } + + void set_rejected() override + { + QMutexLocker locker(&m); + done = true; + if (waiting) + w.wakeOne(); + else + QMetaObject::invokeMethod(this, "emitResponseReady", Qt::QueuedConnection); + } + + void waitForResponse() + { + QMutexLocker locker(&m); + if (done) + return; + waiting = true; + w.wait(&m); + waiting = false; + } + +public Q_SLOTS: + virtual void emitResponseReady() = 0; +}; + +class PasswordAsker::Private : public AskerPrivate +{ + Q_OBJECT +public: + Private(PasswordAsker *_q) + : AskerPrivate(_q) + { + } + + void emitResponseReady() override + { + emit passwordAsker->responseReady(); + } +}; + +PasswordAsker::PasswordAsker(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +PasswordAsker::~PasswordAsker() +{ + delete d; +} + +void PasswordAsker::ask(Event::PasswordStyle pstyle, + const KeyStoreInfo &keyStoreInfo, + const KeyStoreEntry &keyStoreEntry, + void *ptr) +{ + Event e; + e.setPasswordKeyStore(pstyle, keyStoreInfo, keyStoreEntry, ptr); + d->ask(e); +} + +void PasswordAsker::ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr) +{ + Event e; + e.setPasswordData(pstyle, fileName, ptr); + d->ask(e); +} + +void PasswordAsker::cancel() +{ + d->cancel(); +} + +void PasswordAsker::waitForResponse() +{ + d->waitForResponse(); +} + +bool PasswordAsker::accepted() const +{ + return d->accepted; +} + +SecureArray PasswordAsker::password() const +{ + return d->password; +} + +//---------------------------------------------------------------------------- +// TokenAsker +//---------------------------------------------------------------------------- +class TokenAsker::Private : public AskerPrivate +{ + Q_OBJECT +public: + Private(TokenAsker *_q) + : AskerPrivate(_q) + { + } + + void emitResponseReady() override + { + emit tokenAsker->responseReady(); + } +}; + +TokenAsker::TokenAsker(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +TokenAsker::~TokenAsker() +{ + delete d; +} + +void TokenAsker::ask(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr) +{ + Event e; + e.setToken(keyStoreInfo, keyStoreEntry, ptr); + d->ask(e); +} + +void TokenAsker::cancel() +{ + d->cancel(); +} + +void TokenAsker::waitForResponse() +{ + d->waitForResponse(); +} + +bool TokenAsker::accepted() const +{ + return d->accepted; +} + +} + +#include "qca_core.moc" diff --git a/local/recipes/libs/qca/source/src/qca_default.cpp b/local/recipes/libs/qca/source/src/qca_default.cpp new file mode 100644 index 0000000000..72752be0a9 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_default.cpp @@ -0,0 +1,1369 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_core.h" + +#include "qca_cert.h" +#include "qca_textfilter.h" +#include "qcaprovider.h" +#include + +#ifndef QCA_NO_SYSTEMSTORE +#include "qca_systemstore.h" +#endif + +#include + +#define FRIENDLY_NAMES + +namespace QCA { + +class DefaultShared +{ +private: + mutable QMutex m; + bool _use_system; + QString _roots_file; + QStringList _skip_plugins; + QStringList _plugin_priorities; + +public: + DefaultShared() + : _use_system(true) + { + } + + bool use_system() const + { + QMutexLocker locker(&m); + return _use_system; + } + + QString roots_file() const + { + QMutexLocker locker(&m); + return _roots_file; + } + + QStringList skip_plugins() const + { + QMutexLocker locker(&m); + return _skip_plugins; + } + + QStringList plugin_priorities() const + { + QMutexLocker locker(&m); + return _plugin_priorities; + } + + void set(bool use_system, + const QString &roots_file, + const QStringList &skip_plugins, + const QStringList &plugin_priorities) + { + QMutexLocker locker(&m); + _use_system = use_system; + _roots_file = roots_file; + _skip_plugins = skip_plugins; + _plugin_priorities = plugin_priorities; + } +}; + +//---------------------------------------------------------------------------- +// DefaultRandomContext +//---------------------------------------------------------------------------- +class DefaultRandomContext : public RandomContext +{ + Q_OBJECT +public: + DefaultRandomContext(Provider *p) + : RandomContext(p) + { + } + + Provider::Context *clone() const override + { + return new DefaultRandomContext(provider()); + } + + SecureArray nextBytes(int size) override + { + SecureArray buf(size); + for (int n = 0; n < (int)buf.size(); ++n) + buf[n] = (char)std::rand(); + return buf; + } +}; + +//---------------------------------------------------------------------------- +// DefaultMD5Context +//---------------------------------------------------------------------------- + +/* NOTE: the following code was modified to not need BYTE_ORDER -- Justin */ + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef quint8 md5_byte_t; /* 8-bit byte */ +typedef quint32 md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +struct md5_state_t +{ + md5_word_t count[2]; // 2 /* message length in bits, lsw first */ + md5_word_t abcd[4]; // 4 /* digest buffer */ + md5_byte_t buf[64]; // 64 /* accumulate block */ + + md5_state_t() + { + memset(count, 0, sizeof(count)); + memset(abcd, 0, sizeof(abcd)); + memset(buf, 0, sizeof(buf)); + } +}; + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + { + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + + X = xbuf; /* (dynamic only) */ + + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } else /* dynamic big-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. On arm do copying always + */ +#ifndef Q_PROCESSOR_ARM + if (!(reinterpret_cast(data) & 3)) { + /* data are properly aligned */ + X = reinterpret_cast(data); + } else +#endif + { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + F(b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + G(b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + H(b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti) \ + t = a + I(b, c, d) + X[k] + Ti; \ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +class DefaultMD5Context : public HashContext +{ + Q_OBJECT +public: + DefaultMD5Context(Provider *p) + : HashContext(p, QStringLiteral("md5")) + { + clear(); + } + + Provider::Context *clone() const override + { + return new DefaultMD5Context(*this); + } + + void clear() override + { + secure = true; + md5_init(&md5); + } + + void update(const MemoryRegion &in) override + { + if (!in.isSecure()) + secure = false; + md5_append(&md5, (const md5_byte_t *)in.data(), in.size()); + } + + MemoryRegion final() override + { + if (secure) { + SecureArray b(16, 0); + md5_finish(&md5, (md5_byte_t *)b.data()); + return b; + } else { + QByteArray b(16, 0); + md5_finish(&md5, (md5_byte_t *)b.data()); + return b; + } + } + + bool secure; + md5_state_t md5; +}; + +//---------------------------------------------------------------------------- +// DefaultSHA1Context +//---------------------------------------------------------------------------- + +// SHA1 - from a public domain implementation by Steve Reid (steve@edmweb.com) + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#ifdef Q_PROCESSOR_ARM +#define blk(i) \ + (block.l[i & 15] = rol(block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^ block.l[i & 15], 1)) +#else +#define blk(i) \ + (block->l[i & 15] = \ + rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) +#endif + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +struct SHA1_CONTEXT +{ + quint32 state[5]; // 5 + quint32 count[2]; // 2 + unsigned char buffer[64]; // 64 + + SHA1_CONTEXT() + { + memset(state, 0, sizeof(state)); + memset(count, 0, sizeof(count)); + memset(buffer, 0, sizeof(buffer)); + } +}; + +typedef union { + unsigned char c[64]; + quint32 l[16]; +} CHAR64LONG16; + +class DefaultSHA1Context : public HashContext +{ + Q_OBJECT +public: + SHA1_CONTEXT _context; +#ifdef Q_PROCESSOR_ARM + CHAR64LONG16 block; +#else + CHAR64LONG16 *block; +#endif + bool secure; + + DefaultSHA1Context(Provider *p) + : HashContext(p, QStringLiteral("sha1")) + { + clear(); + } + + Provider::Context *clone() const override + { + return new DefaultSHA1Context(*this); + } + + void clear() override + { + secure = true; + sha1_init(&_context); + } + + void update(const MemoryRegion &in) override + { + if (!in.isSecure()) + secure = false; + sha1_update(&_context, (unsigned char *)in.data(), (unsigned int)in.size()); + } + + MemoryRegion final() override + { + if (secure) { + SecureArray b(20, 0); + sha1_final((unsigned char *)b.data(), &_context); + return b; + } else { + QByteArray b(20, 0); + sha1_final((unsigned char *)b.data(), &_context); + return b; + } + } + + inline unsigned long blk0(quint32 i) + { + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) +#ifdef Q_PROCESSOR_ARM + return block.l[i]; +#else + return block->l[i]; +#endif + else +#ifdef Q_PROCESSOR_ARM + return (block.l[i] = (rol(block.l[i], 24) & 0xFF00FF00) | (rol(block.l[i], 8) & 0x00FF00FF)); +#else + return (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF)); +#endif + } + + // Hash a single 512-bit block. This is the core of the algorithm. + void transform(quint32 state[5], unsigned char buffer[64]) + { + quint32 a, b, c, d, e; + +#ifdef Q_PROCESSOR_ARM + memcpy(&block, buffer, sizeof(block)); +#else + block = reinterpret_cast(buffer); +#endif + // Copy context->state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + // 4 rounds of 20 operations each. Loop unrolled. + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + + // Add the working vars back into context.state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + // Wipe variables + a = b = c = d = e = 0; + } + + // SHA1Init - Initialize new context + void sha1_init(SHA1_CONTEXT *context) + { + // SHA1 initialization constants + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; + } + + // Run your data through this + void sha1_update(SHA1_CONTEXT *context, unsigned char *data, quint32 len) + { + quint32 i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + + context->count[1] += (len >> 29); + + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + transform(context->state, &data[i]); + } + j = 0; + } else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); + } + + // Add padding and return the message digest + void sha1_final(unsigned char digest[20], SHA1_CONTEXT *context) + { + quint32 i; + unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = + (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent + } + sha1_update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + sha1_update(context, (unsigned char *)"\0", 1); + } + sha1_update(context, finalcount, 8); // Should cause a transform() + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + + // Wipe variables + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); + } +}; + +//---------------------------------------------------------------------------- +// DefaultKeyStoreEntry +//---------------------------------------------------------------------------- + +// this escapes colons, commas, and newlines. colons and commas so that they +// are available as delimiters, and newlines so that our output can be a +// single line of text. +static QString escape_string(const QString &in) +{ + QString out; + for (const QChar &c : in) { + if (c == QLatin1Char('\\')) + out += QLatin1String("\\\\"); + else if (c == QLatin1Char(':')) + out += QLatin1String("\\c"); + else if (c == QLatin1Char(',')) + out += QLatin1String("\\o"); + else if (c == QLatin1Char('\n')) + out += QLatin1String("\\n"); + else + out += c; + } + return out; +} + +static bool unescape_string(const QString &in, QString *_out) +{ + QString out; + for (int n = 0; n < in.length(); ++n) { + if (in[n] == QLatin1Char('\\')) { + if (n + 1 >= in.length()) + return false; + + if (in[n + 1] == QLatin1Char('\\')) + out += QLatin1Char('\\'); + else if (in[n + 1] == QLatin1Char('c')) + out += QLatin1Char(':'); + else if (in[n + 1] == QLatin1Char('o')) + out += QLatin1Char(','); + else if (in[n + 1] == QLatin1Char('n')) + out += QLatin1Char('\n'); + else + return false; + ++n; + } else + out += in[n]; + } + *_out = out; + return true; +} + +static QString escape_stringlist(const QStringList &in) +{ + QStringList list; + for (int n = 0; n < in.count(); ++n) + list += escape_string(in[n]); + return list.join(QStringLiteral(":")); +} + +static bool unescape_stringlist(const QString &in, QStringList *_out) +{ + QStringList out; + const QStringList list = in.split(QLatin1Char(':')); + for (int n = 0; n < list.count(); ++n) { + QString str; + if (!unescape_string(list[n], &str)) + return false; + out += str; + } + *_out = out; + return true; +} + +// serialization format is a colon separated list of 7 escaped strings +// 0 - "qca_def_1" (header) +// 1 - store id +// 2 - store name +// 3 - entry id +// 4 - entry name +// 5 - entry type (e.g. "cert") +// 6 - string encoding of object (e.g. DER encoded in Base64) +static QString entry_serialize(const QString &storeId, + const QString &storeName, + const QString &entryId, + const QString &entryName, + const QString &entryType, + const QString &data) +{ + QStringList out; + out += QStringLiteral("qca_def"); + out += storeId; + out += storeName; + out += entryId; + out += entryName; + out += entryType; + out += data; + return escape_stringlist(out); +} + +static bool entry_deserialize(const QString &in, + QString *storeId, + QString *storeName, + QString *entryId, + QString *entryName, + QString *entryType, + QString *data) +{ + QStringList list; + if (!unescape_stringlist(in, &list)) + return false; + if (list.count() != 7) + return false; + if (list[0] != QLatin1String("qca_def")) + return false; + *storeId = list[1]; + *storeName = list[2]; + *entryId = list[3]; + *entryName = list[4]; + *entryType = list[5]; + *data = list[6]; + return true; +} + +class DefaultKeyStoreEntry : public KeyStoreEntryContext +{ + Q_OBJECT +public: + KeyStoreEntry::Type _type; + QString _id, _name, _storeId, _storeName; + Certificate _cert; + CRL _crl; + mutable QString _serialized; + + DefaultKeyStoreEntry(const Certificate &cert, const QString &storeId, const QString &storeName, Provider *p) + : KeyStoreEntryContext(p) + { + _type = KeyStoreEntry::TypeCertificate; + _storeId = storeId; + _storeName = storeName; + _cert = cert; + } + + DefaultKeyStoreEntry(const CRL &crl, const QString &storeId, const QString &storeName, Provider *p) + : KeyStoreEntryContext(p) + { + _type = KeyStoreEntry::TypeCRL; + _storeId = storeId; + _storeName = storeName; + _crl = crl; + } + + Provider::Context *clone() const override + { + return new DefaultKeyStoreEntry(*this); + } + + KeyStoreEntry::Type type() const override + { + return _type; + } + + QString id() const override + { + return _id; + } + + QString name() const override + { + return _name; + } + + QString storeId() const override + { + return _storeId; + } + + QString storeName() const override + { + return _storeName; + } + + Certificate certificate() const override + { + return _cert; + } + + CRL crl() const override + { + return _crl; + } + + QString serialize() const override + { + if (_serialized.isEmpty()) { + QString typestr; + QString datastr; + + if (_type == KeyStoreEntry::TypeCertificate) { + typestr = QStringLiteral("cert"); + datastr = Base64().arrayToString(_cert.toDER()); + } else { + typestr = QStringLiteral("crl"); + datastr = Base64().arrayToString(_crl.toDER()); + } + + _serialized = entry_serialize(_storeId, _storeName, _id, _name, typestr, datastr); + } + + return _serialized; + } + + static DefaultKeyStoreEntry *deserialize(const QString &in, Provider *provider) + { + QString storeId, storeName, id, name, typestr, datastr; + + if (entry_deserialize(in, &storeId, &storeName, &id, &name, &typestr, &datastr)) { + const QByteArray data = Base64().stringToArray(datastr).toByteArray(); + DefaultKeyStoreEntry *c; + + if (typestr == QLatin1String("cert")) { + Certificate cert = Certificate::fromDER(data); + if (cert.isNull()) + return nullptr; + c = new DefaultKeyStoreEntry(cert, storeId, storeName, provider); + } else if (typestr == QLatin1String("crl")) { + CRL crl = CRL::fromDER(data); + if (crl.isNull()) + return nullptr; + c = new DefaultKeyStoreEntry(crl, storeId, storeName, provider); + } else + return nullptr; + + c->_id = id; + c->_name = name; + c->_serialized = in; + return c; + } + return nullptr; + } + + QString simpleId() const + { + if (_type == KeyStoreEntry::TypeCertificate) + return QString::number(qHash(_cert.toDER())); + else + return QString::number(qHash(_crl.toDER())); + } + + QString simpleName() const + { + // use the common name, else orgname + if (_type == KeyStoreEntry::TypeCertificate) { + QString str = _cert.commonName(); + if (str.isEmpty()) + str = _cert.subjectInfo().value(Organization); + return str; + } else + return _crl.issuerInfo().value(CommonName); + } +}; + +//---------------------------------------------------------------------------- +// DefaultKeyStoreList +//---------------------------------------------------------------------------- +class DefaultKeyStoreList : public KeyStoreListContext +{ + Q_OBJECT +public: + bool x509_supported; + DefaultShared *shared; + + DefaultKeyStoreList(Provider *p, DefaultShared *_shared) + : KeyStoreListContext(p) + , shared(_shared) + { + } + + ~DefaultKeyStoreList() override + { + } + + Provider::Context *clone() const override + { + return nullptr; + } + + void start() override + { + x509_supported = false; + + QMetaObject::invokeMethod(this, "busyEnd", Qt::QueuedConnection); + } + + QList keyStores() override + { + if (!x509_supported) { + if (isSupported("cert") && isSupported("crl")) + x509_supported = true; + } + + bool have_systemstore = false; +#ifndef QCA_NO_SYSTEMSTORE + if (shared->use_system()) + have_systemstore = qca_have_systemstore(); +#endif + + QList list; + + // system store only shows up if the OS store is available or + // there is a configured store file + if (x509_supported && (have_systemstore || !shared->roots_file().isEmpty())) + list += 0; + + return list; + } + + KeyStore::Type type(int) const override + { + return KeyStore::System; + } + + QString storeId(int) const override + { + return QStringLiteral("qca-default-systemstore"); + } + + QString name(int) const override + { + return QStringLiteral("System Trusted Certificates"); + } + + QList entryTypes(int) const override + { + QList list; + list += KeyStoreEntry::TypeCertificate; + list += KeyStoreEntry::TypeCRL; + return list; + } + + QList entryList(int) override + { + QList out; + + QList certs; + QList crls; + + if (shared->use_system()) { + CertificateCollection col; +#ifndef QCA_NO_SYSTEMSTORE + col = qca_get_systemstore(QString()); +#endif + certs += col.certificates(); + crls += col.crls(); + } + + const QString roots = shared->roots_file(); + if (!roots.isEmpty()) { + CertificateCollection col = CertificateCollection::fromFlatTextFile(roots); + certs += col.certificates(); + crls += col.crls(); + } + +#ifdef FRIENDLY_NAMES + const QStringList names = makeFriendlyNames(certs); +#endif + for (int n = 0; n < certs.count(); ++n) { + DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(certs[n], storeId(0), name(0), provider()); + c->_id = c->simpleId(); +#ifdef FRIENDLY_NAMES + c->_name = names[n]; +#else + c->_name = c->simpleName(); +#endif + out.append(c); + } + + for (int n = 0; n < crls.count(); ++n) { + DefaultKeyStoreEntry *c = new DefaultKeyStoreEntry(crls[n], storeId(0), name(0), provider()); + c->_id = c->simpleId(); + c->_name = c->simpleName(); + out.append(c); + } + + return out; + } + + KeyStoreEntryContext *entryPassive(const QString &serialized) override + { + return DefaultKeyStoreEntry::deserialize(serialized, provider()); + } +}; + +//---------------------------------------------------------------------------- +// DefaultProvider +//---------------------------------------------------------------------------- +static bool unescape_config_stringlist(const QString &in, QStringList *_out) +{ + QStringList out; + const QStringList list = in.split(QLatin1Char(',')); + for (int n = 0; n < list.count(); ++n) { + QString str; + if (!unescape_string(list[n], &str)) + return false; + out += str.trimmed(); + } + *_out = out; + return true; +} + +class DefaultProvider : public Provider +{ +public: + DefaultShared shared; + + void init() override + { + const QDateTime now = QDateTime::currentDateTime(); + + uint t = now.toSecsSinceEpoch(); + if (now.time().msec() > 0) + t /= now.time().msec(); + std::srand(t); + } + + int version() const override + { + return QCA_VERSION; + } + + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return QStringLiteral("default"); + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("random"); + list += QStringLiteral("md5"); + list += QStringLiteral("sha1"); + list += QStringLiteral("keystorelist"); + return list; + } + + Provider::Context *createContext(const QString &type) override + { + if (type == QLatin1String("random")) + return new DefaultRandomContext(this); + else if (type == QLatin1String("md5")) + return new DefaultMD5Context(this); + else if (type == QLatin1String("sha1")) + return new DefaultSHA1Context(this); + else if (type == QLatin1String("keystorelist")) + return new DefaultKeyStoreList(this, &shared); + else + return nullptr; + } + + QVariantMap defaultConfig() const override + { + QVariantMap config; + config[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/default#1.0"); + config[QStringLiteral("use_system")] = true; + config[QStringLiteral("roots_file")] = QString(); + config[QStringLiteral("skip_plugins")] = QString(); + config[QStringLiteral("plugin_priorities")] = QString(); + return config; + } + + void configChanged(const QVariantMap &config) override + { + const bool use_system = config[QStringLiteral("use_system")].toBool(); + const QString roots_file = config[QStringLiteral("roots_file")].toString(); + const QString skip_plugins_str = config[QStringLiteral("skip_plugins")].toString(); + const QString plugin_priorities_str = config[QStringLiteral("plugin_priorities")].toString(); + + QStringList tmp; + + QStringList skip_plugins; + if (unescape_config_stringlist(skip_plugins_str, &tmp)) + skip_plugins = tmp; + + QStringList plugin_priorities; + if (unescape_config_stringlist(plugin_priorities_str, &tmp)) + plugin_priorities = tmp; + + for (int n = 0; n < plugin_priorities.count(); ++n) { + QString &s = plugin_priorities[n]; + + // make sure the entry ends with ":number" + int x = s.indexOf(QLatin1Char(':')); + bool ok = false; + if (x != -1) +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + (void)QStringView(s).mid(x + 1).toInt(&ok); +#else + s.midRef(x + 1).toInt(&ok); +#endif + if (!ok) { + plugin_priorities.removeAt(n); + --n; + } + } + + shared.set(use_system, roots_file, skip_plugins, plugin_priorities); + } +}; + +Provider *create_default_provider() +{ + return new DefaultProvider; +} + +QStringList skip_plugins(Provider *defaultProvider) +{ + DefaultProvider *that = (DefaultProvider *)defaultProvider; + return that->shared.skip_plugins(); +} + +QStringList plugin_priorities(Provider *defaultProvider) +{ + DefaultProvider *that = (DefaultProvider *)defaultProvider; + return that->shared.plugin_priorities(); +} + +} + +#include "qca_default.moc" diff --git a/local/recipes/libs/qca/source/src/qca_keystore.cpp b/local/recipes/libs/qca/source/src/qca_keystore.cpp new file mode 100644 index 0000000000..ef232b5bd3 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_keystore.cpp @@ -0,0 +1,1679 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_keystore.h" + +#include +#include +#include +#include +#include +#include + +#include // fprintf +#include // abort + +#include "qcaprovider.h" + +Q_DECLARE_METATYPE(QCA::KeyStoreEntry) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QCA::KeyBundle) +Q_DECLARE_METATYPE(QCA::Certificate) +Q_DECLARE_METATYPE(QCA::CRL) +Q_DECLARE_METATYPE(QCA::PGPKey) + +namespace QCA { + +Provider::Context *getContext(const QString &type, Provider *p); + +// from qca_plugin.cpp +QString truncate_log(const QString &in, int size); + +/* + How this stuff works: + + KeyStoreListContext is queried for a list of store context ids. A signal + is used to indicate when the list may have changed, so polling for changes + is not necessary. Context ids change for every new presence of a store. + Even if a user removes and inserts the same smart card device, which has + the same storeId, the context id will ALWAYS be different. If a previously + known context id is missing from a later queried list, then it means the + associated store is unavailable. It is recommended that the provider just + use a counter for the contextId, incrementing the value anytime a new + context is made. + + KeyStoreTracker manages all of the keystore stuff, and exists in its own + thread (called the tracker thread). All of the KeyStoreListContext + objects exist in the tracker thread. +*/ + +/* + scenarios to handle: + - ksm.start shouldn't block + - keystore in available list, but gone by the time it is requested + - keystore is unavailable during a call to a keystoreentry method + - keystore/keystoreentry methods called simultaneously from different threads + - and of course, objects from keystores should work, despite being created + in the keystore thread +*/ + +//---------------------------------------------------------------------------- +// KeyStoreTracker +//---------------------------------------------------------------------------- +static int tracker_id_at = 0; + +class KeyStoreTracker : public QObject +{ + Q_OBJECT +public: + static KeyStoreTracker *self; + + class Item + { + public: + // combine keystore owner and contextid into a single id + int trackerId; + + // number of times the keystore has been updated + int updateCount; + + // keystore context + KeyStoreListContext *owner; + int storeContextId; + + // properties + QString storeId; + QString name; + KeyStore::Type type; + bool isReadOnly; + + Item() + : trackerId(-1) + , updateCount(0) + , owner(nullptr) + , storeContextId(-1) + , storeId(QLatin1String("")) + , name(QLatin1String("")) + , type(KeyStore::System) + , isReadOnly(false) + { + } + }; + + QMutex m; + QSet sources; + QSet busySources; + QList items; + QString dtext; + bool startedAll; + bool busy; + + QMutex updateMutex; + + KeyStoreTracker() + { + self = this; + + qRegisterMetaType(); + qRegisterMetaType>(); + qRegisterMetaType>(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + + connect(this, &KeyStoreTracker::updated_p, this, &KeyStoreTracker::updated_locked, Qt::QueuedConnection); + + startedAll = false; + busy = true; // we start out busy + } + + ~KeyStoreTracker() override + { + qDeleteAll(sources); + self = nullptr; + } + + static KeyStoreTracker *instance() + { + return self; + } + + // thread-safe + bool isBusy() + { + QMutexLocker locker(&m); + return busy; + } + + // thread-safe + QList getItems() + { + QMutexLocker locker(&m); + return items; + } + + // thread-safe + QString getDText() + { + QMutexLocker locker(&m); + return dtext; + } + + // thread-safe + void clearDText() + { + QMutexLocker locker(&m); + dtext.clear(); + } + + // thread-safe + void addTarget(KeyStoreManagerPrivate *ksm); + + // thread-safe + void removeTarget(QObject *ksm) + { + QMutexLocker locker(&updateMutex); + disconnect(ksm); + } + +public Q_SLOTS: + void spinEventLoop() + { + QAbstractEventDispatcher::instance()->processEvents(QEventLoop::AllEvents); + } + + void start() + { + // grab providers (and default) + ProviderList list = providers(); + list.append(defaultProvider()); + + for (int n = 0; n < list.count(); ++n) { + Provider *p = list[n]; + if (p->features().contains(QStringLiteral("keystorelist")) && !haveProviderSource(p)) + startProvider(p); + } + + startedAll = true; + } + + void start(const QString &provider) + { + // grab providers (and default) + ProviderList list = providers(); + list.append(defaultProvider()); + + Provider *p = nullptr; + for (int n = 0; n < list.count(); ++n) { + if (list[n]->name() == provider) { + p = list[n]; + break; + } + } + + if (p && p->features().contains(QStringLiteral("keystorelist")) && !haveProviderSource(p)) + startProvider(p); + } + + void scan() + { + if (startedAll) + start(); + } + + QList entryList(int trackerId) + { + QList out; + int at = findItem(trackerId); + if (at == -1) + return out; + Item &i = items[at]; + const QList list = i.owner->entryList(i.storeContextId); + for (int n = 0; n < list.count(); ++n) { + KeyStoreEntry entry; + entry.change(list[n]); + out.append(entry); + } + return out; + } + + QList entryTypes(int trackerId) + { + QList out; + int at = findItem(trackerId); + if (at == -1) + return out; + Item &i = items[at]; + return i.owner->entryTypes(i.storeContextId); + } + + // hack with void * + void *entry(const QString &storeId, const QString &entryId) + { + KeyStoreListContext *c = nullptr; + int contextId = -1; + m.lock(); + foreach (const Item &i, items) { + if (i.storeId == storeId) { + c = i.owner; + contextId = i.storeContextId; + break; + } + } + m.unlock(); + if (!c) + return nullptr; + + return c->entry(contextId, entryId); + } + + // hack with void * + void *entryPassive(const QString &serialized) + { + foreach (KeyStoreListContext *ksl, sources) { + // "is this yours?" + KeyStoreEntryContext *e = ksl->entryPassive(serialized); + if (e) + return e; + } + return nullptr; + } + + QString writeEntry(int trackerId, const QVariant &v) + { + int at = findItem(trackerId); + if (at == -1) + return QString(); + Item &i = items[at]; + if (v.canConvert()) + return i.owner->writeEntry(i.storeContextId, v.value()); + else if (v.canConvert()) + return i.owner->writeEntry(i.storeContextId, v.value()); + else if (v.canConvert()) + return i.owner->writeEntry(i.storeContextId, v.value()); + else if (v.canConvert()) + return i.owner->writeEntry(i.storeContextId, v.value()); + else + return QString(); + } + + QString writeEntry(int trackerId, const QCA::KeyBundle &v) + { + int at = findItem(trackerId); + if (at == -1) + return QString(); + Item &i = items[at]; + + return i.owner->writeEntry(i.storeContextId, v); + } + + QString writeEntry(int trackerId, const QCA::Certificate &v) + { + int at = findItem(trackerId); + if (at == -1) + return QString(); + Item &i = items[at]; + + return i.owner->writeEntry(i.storeContextId, v); + } + + QString writeEntry(int trackerId, const QCA::CRL &v) + { + int at = findItem(trackerId); + if (at == -1) + return QString(); + Item &i = items[at]; + + return i.owner->writeEntry(i.storeContextId, v); + } + + QString writeEntry(int trackerId, const QCA::PGPKey &v) + { + int at = findItem(trackerId); + if (at == -1) + return QString(); + Item &i = items[at]; + + return i.owner->writeEntry(i.storeContextId, v); + } + + bool removeEntry(int trackerId, const QString &entryId) + { + int at = findItem(trackerId); + if (at == -1) + return false; + Item &i = items[at]; + return i.owner->removeEntry(i.storeContextId, entryId); + } + +Q_SIGNALS: + // emit this when items or busy state changes + void updated(); + void updated_p(); + +private Q_SLOTS: + void updated_locked() + { + QMutexLocker locker(&updateMutex); + emit updated(); + } + +private: + bool haveProviderSource(Provider *p) const + { + foreach (KeyStoreListContext *ksl, sources) { + if (ksl->provider() == p) + return true; + } + return false; + } + + int findItem(int trackerId) + { + for (int n = 0; n < items.count(); ++n) { + if (items[n].trackerId == trackerId) + return n; + } + return -1; + } + + void startProvider(Provider *p) + { + KeyStoreListContext *c = static_cast(getContext(QStringLiteral("keystorelist"), p)); + if (!c) + return; + + sources += c; + busySources += c; + connect(c, &KeyStoreListContext::busyStart, this, &KeyStoreTracker::ksl_busyStart); + connect(c, &KeyStoreListContext::busyEnd, this, &KeyStoreTracker::ksl_busyEnd); + connect(c, &KeyStoreListContext::updated, this, &KeyStoreTracker::ksl_updated); + connect(c, &KeyStoreListContext::diagnosticText, this, &KeyStoreTracker::ksl_diagnosticText); + connect(c, &KeyStoreListContext::storeUpdated, this, &KeyStoreTracker::ksl_storeUpdated); + c->start(); + c->setUpdatesEnabled(true); + + QCA_logTextMessage(QStringLiteral("keystore: startProvider %1").arg(p->name()), Logger::Information); + } + + bool updateStores(KeyStoreListContext *c) + { + bool changed = false; + + QMutexLocker locker(&m); + + const QList keyStores = c->keyStores(); + + // remove any contexts that are gone + for (int n = 0; n < items.count(); ++n) { + if (items[n].owner == c && !keyStores.contains(items[n].storeContextId)) { + QCA_logTextMessage(QStringLiteral("keystore: updateStores remove %1").arg(items[n].storeContextId), + Logger::Information); + + items.removeAt(n); + --n; // adjust position + + changed = true; + } + } + + // handle add/updates + foreach (int id, keyStores) { + // do we have it already? + int at = -1; + for (int n = 0; n < items.count(); ++n) { + if (items[n].owner == c && items[n].storeContextId == id) { + at = n; + break; + } + } + + // if so, update it + if (at != -1) { + Item &i = items[at]; + + QString name = c->name(id); + bool isReadOnly = c->isReadOnly(id); + if (i.name != name || i.isReadOnly != isReadOnly) { + QCA_logTextMessage(QStringLiteral("keystore: updateStores update %1").arg(id), Logger::Information); + i.name = name; + i.isReadOnly = isReadOnly; + changed = true; + } + } + // otherwise, add it + else { + QCA_logTextMessage(QStringLiteral("keystore: updateStores add %1").arg(id), Logger::Information); + + Item i; + i.trackerId = tracker_id_at++; + i.updateCount = 0; + i.owner = c; + i.storeContextId = id; + i.storeId = c->storeId(id); + i.name = c->name(id); + i.type = c->type(id); + i.isReadOnly = c->isReadOnly(id); + items += i; + + changed = true; + } + } + + return changed; + } + +private Q_SLOTS: + void ksl_busyStart() + { + KeyStoreListContext *c = (KeyStoreListContext *)sender(); + + QCA_logTextMessage(QStringLiteral("keystore: ksl_busyStart %1").arg(c->provider()->name()), + Logger::Information); + + if (!busySources.contains(c)) { + busySources += c; + + QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); + emit updated_p(); + } + } + + void ksl_busyEnd() + { + KeyStoreListContext *c = (KeyStoreListContext *)sender(); + + QCA_logTextMessage(QStringLiteral("keystore: ksl_busyEnd %1").arg(c->provider()->name()), Logger::Information); + + busySources.remove(c); + bool changed = updateStores(c); + const bool any_busy = !busySources.isEmpty(); + + if (!any_busy) { + m.lock(); + busy = false; + m.unlock(); + } + + if (!any_busy || changed) { + QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); + emit updated_p(); + } + } + + void ksl_updated() + { + KeyStoreListContext *c = (KeyStoreListContext *)sender(); + + QCA_logTextMessage(QStringLiteral("keystore: ksl_updated %1").arg(c->provider()->name()), Logger::Information); + + bool changed = updateStores(c); + if (changed) { + QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); + emit updated_p(); + } + } + + void ksl_diagnosticText(const QString &str) + { + QMutexLocker locker(&m); + dtext += str; + dtext = truncate_log(dtext, 100000); + } + + void ksl_storeUpdated(int id) + { + KeyStoreListContext *c = (KeyStoreListContext *)sender(); + + QCA_logTextMessage( + QStringLiteral("keystore: ksl_storeUpdated %1 %2").arg(c->provider()->name(), QString::number(id)), + Logger::Information); + + QMutexLocker locker(&m); + for (int n = 0; n < items.count(); ++n) { + Item &i = items[n]; + if (i.owner == c && i.storeContextId == id) { + ++i.updateCount; + + QCA_logTextMessage( + QStringLiteral("keystore: %1 updateCount = %2").arg(i.name, QString::number(i.updateCount)), + Logger::Information); + + QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); + emit updated_p(); + return; + } + } + } +}; + +KeyStoreTracker *KeyStoreTracker::self = nullptr; + +//---------------------------------------------------------------------------- +// KeyStoreThread +//---------------------------------------------------------------------------- +class KeyStoreThread : public SyncThread +{ + Q_OBJECT +public: + KeyStoreTracker *tracker; + QMutex call_mutex; + + KeyStoreThread(QObject *parent = nullptr) + : SyncThread(parent) + { + } + + ~KeyStoreThread() override + { + stop(); + } + + void atStart() override + { + tracker = new KeyStoreTracker; + } + + void atEnd() override + { + delete tracker; + } +}; + +//---------------------------------------------------------------------------- +// KeyStoreGlobal +//---------------------------------------------------------------------------- +class KeyStoreManagerGlobal; + +Q_GLOBAL_STATIC(QMutex, ksm_mutex) +static KeyStoreManagerGlobal *g_ksm = nullptr; + +class KeyStoreManagerGlobal +{ +public: + KeyStoreThread *thread; + + KeyStoreManagerGlobal() + { + thread = new KeyStoreThread; + thread->moveToThread(QCoreApplication::instance()->thread()); + thread->start(); + } + + ~KeyStoreManagerGlobal() + { + delete thread; + } + + KeyStoreManagerGlobal(const KeyStoreManagerGlobal &) = delete; + KeyStoreManagerGlobal &operator=(const KeyStoreManagerGlobal &) = delete; +}; + +// this function is thread-safe +static QVariant trackercall(const char *method, const QVariantList &args = QVariantList()) +{ + QVariant ret; + bool ok; + + g_ksm->thread->call_mutex.lock(); + ret = g_ksm->thread->call(KeyStoreTracker::instance(), method, args, &ok); + g_ksm->thread->call_mutex.unlock(); + + Q_ASSERT(ok); + if (!ok) { + fprintf(stderr, "QCA: KeyStoreTracker call [%s] failed.\n", method); + abort(); + return QVariant(); + } + return ret; +} + +//---------------------------------------------------------------------------- +// KeyStoreEntry +//---------------------------------------------------------------------------- +class KeyStoreEntry::Private +{ +public: + bool accessible; + + Private() + { + accessible = false; + } +}; + +KeyStoreEntry::KeyStoreEntry() + : d(new Private) +{ +} + +KeyStoreEntry::KeyStoreEntry(const QString &serialized) + : d(new Private) +{ + *this = fromString(serialized); +} + +KeyStoreEntry::KeyStoreEntry(const KeyStoreEntry &from) + : Algorithm(from) + , d(new Private(*from.d)) +{ +} + +KeyStoreEntry::~KeyStoreEntry() +{ + delete d; +} + +KeyStoreEntry &KeyStoreEntry::operator=(const KeyStoreEntry &from) +{ + Algorithm::operator=(from); + *d = *from.d; + return *this; +} + +bool KeyStoreEntry::isNull() const +{ + return (!context() ? true : false); +} + +bool KeyStoreEntry::isAvailable() const +{ + return static_cast(context())->isAvailable(); +} + +bool KeyStoreEntry::isAccessible() const +{ + return d->accessible; +} + +KeyStoreEntry::Type KeyStoreEntry::type() const +{ + return static_cast(context())->type(); +} + +QString KeyStoreEntry::name() const +{ + return static_cast(context())->name(); +} + +QString KeyStoreEntry::id() const +{ + return static_cast(context())->id(); +} + +QString KeyStoreEntry::storeName() const +{ + return static_cast(context())->storeName(); +} + +QString KeyStoreEntry::storeId() const +{ + return static_cast(context())->storeId(); +} + +QString KeyStoreEntry::toString() const +{ + return static_cast(context())->serialize(); +} + +KeyStoreEntry KeyStoreEntry::fromString(const QString &serialized) +{ + KeyStoreEntry e; + KeyStoreEntryContext *c = (KeyStoreEntryContext *)KeyStoreTracker::instance()->entryPassive(serialized); + if (c) + e.change(c); + return e; +} + +KeyBundle KeyStoreEntry::keyBundle() const +{ + return static_cast(context())->keyBundle(); +} + +Certificate KeyStoreEntry::certificate() const +{ + return static_cast(context())->certificate(); +} + +CRL KeyStoreEntry::crl() const +{ + return static_cast(context())->crl(); +} + +PGPKey KeyStoreEntry::pgpSecretKey() const +{ + return static_cast(context())->pgpSecretKey(); +} + +PGPKey KeyStoreEntry::pgpPublicKey() const +{ + return static_cast(context())->pgpPublicKey(); +} + +bool KeyStoreEntry::ensureAvailable() +{ + const QString storeId = this->storeId(); + const QString entryId = id(); + KeyStoreEntryContext *c = + (KeyStoreEntryContext *)trackercall("entry", QVariantList() << storeId << entryId).value(); + if (c) + change(c); + return isAvailable(); +} + +bool KeyStoreEntry::ensureAccess() +{ + if (!ensureAvailable()) { + d->accessible = false; + return false; + } + const bool ok = static_cast(context())->ensureAccess(); + d->accessible = ok; + return d->accessible; +} + +//---------------------------------------------------------------------------- +// KeyStoreEntryWatcher +//---------------------------------------------------------------------------- +class KeyStoreEntryWatcher::Private : public QObject +{ + Q_OBJECT +public: + KeyStoreEntryWatcher *q; + KeyStoreManager ksm; + KeyStoreEntry entry; + QString storeId, entryId; + KeyStore *ks; + bool avail; + + Private(KeyStoreEntryWatcher *_q) + : QObject(_q) + , q(_q) + , ksm(this) + { + ks = nullptr; + avail = false; + connect(&ksm, &KeyStoreManager::keyStoreAvailable, this, &KeyStoreEntryWatcher::Private::ksm_available); + } + + ~Private() override + { + delete ks; + } + + void start() + { + const QStringList list = ksm.keyStores(); + foreach (const QString &storeId, list) + ksm_available(storeId); + } + +private Q_SLOTS: + void ksm_available(const QString &_storeId) + { + // we only care about one store + if (_storeId == storeId) { + ks = new KeyStore(storeId, &ksm); + connect(ks, &KeyStore::updated, this, &Private::ks_updated); + ks->startAsynchronousMode(); + } + } + + void ks_updated() + { + bool found = false; + const QList list = ks->entryList(); + foreach (const KeyStoreEntry &e, list) { + if (e.id() == entryId && e.isAvailable()) { + found = true; + if (!avail) + entry = e; + break; + } + } + + if (found && !avail) { + avail = true; + emit q->available(); + } else if (!found && avail) { + avail = false; + emit q->unavailable(); + } + } + + void ks_unavailable() + { + delete ks; + ks = nullptr; + + if (avail) { + avail = false; + emit q->unavailable(); + } + } +}; + +KeyStoreEntryWatcher::KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent) + : QObject(parent) +{ + d = new Private(this); + if (!e.isNull()) { + d->entry = e; + d->storeId = e.storeId(); + d->entryId = e.id(); + d->start(); + } +} + +KeyStoreEntryWatcher::~KeyStoreEntryWatcher() +{ + delete d; +} + +KeyStoreEntry KeyStoreEntryWatcher::entry() const +{ + return d->entry; +} + +//---------------------------------------------------------------------------- +// KeyStore +//---------------------------------------------------------------------------- +// union thingy +class KeyStoreWriteEntry +{ +public: + enum Type + { + TypeKeyBundle, + TypeCertificate, + TypeCRL, + TypePGPKey + }; + + Type type; + KeyBundle keyBundle; + Certificate cert; + CRL crl; + PGPKey pgpKey; + + KeyStoreWriteEntry() + { + } + + KeyStoreWriteEntry(const KeyBundle &_keyBundle) + : type(TypeKeyBundle) + , keyBundle(_keyBundle) + { + } + + KeyStoreWriteEntry(const Certificate &_cert) + : type(TypeCertificate) + , cert(_cert) + { + } + + KeyStoreWriteEntry(const CRL &_crl) + : type(TypeCRL) + , crl(_crl) + { + } + + KeyStoreWriteEntry(const PGPKey &_pgpKey) + : type(TypePGPKey) + , pgpKey(_pgpKey) + { + } +}; + +class KeyStoreOperation : public QThread +{ + Q_OBJECT +public: + enum Type + { + EntryList, + WriteEntry, + RemoveEntry + }; + + Type type; + int trackerId; + + KeyStoreWriteEntry wentry; // in: WriteEntry + QList entryList; // out: EntryList + QString entryId; // in: RemoveEntry, out: WriteEntry + bool success; // out: RemoveEntry + + KeyStoreOperation(QObject *parent = nullptr) + : QThread(parent) + { + } + + ~KeyStoreOperation() override + { + wait(); + } + +protected: + void run() override + { + if (type == EntryList) + entryList = trackercall("entryList", QVariantList() << trackerId).value>(); + else if (type == WriteEntry) { + QVariant arg; + if (wentry.type == KeyStoreWriteEntry::TypeKeyBundle) + arg = QVariant::fromValue(wentry.keyBundle); + else if (wentry.type == KeyStoreWriteEntry::TypeCertificate) + arg = QVariant::fromValue(wentry.cert); + else if (wentry.type == KeyStoreWriteEntry::TypeCRL) + arg = QVariant::fromValue(wentry.crl); + else if (wentry.type == KeyStoreWriteEntry::TypePGPKey) + arg = QVariant::fromValue(wentry.pgpKey); + + // note: each variant in the argument list is resolved + // to its native type. so even though it looks like + // we're attempting to call a method named + // writeEntry(QString,QVariant), we're actually + // calling one of many possible methods, such as + // writeEntry(QString,PGPKey) or + // writeEntry(QString,Certificate), etc, depending + // on the type of object we put in the variant. + entryId = trackercall("writeEntry", QVariantList() << trackerId << arg).toString(); + } else // RemoveEntry + { + success = trackercall("removeEntry", QVariantList() << trackerId << entryId).toBool(); + } + } +}; + +class KeyStorePrivate : public QObject +{ + Q_OBJECT +public: + KeyStore *q; + KeyStoreManager *ksm; + int trackerId; + KeyStoreTracker::Item item; + bool async; + bool need_update; + QList latestEntryList; + QList ops; + + KeyStorePrivate(KeyStore *_q) + : QObject(_q) + , q(_q) + , async(false) + { + } + + ~KeyStorePrivate() override + { + qDeleteAll(ops); + } + + // implemented below, after KeyStorePrivate is declared + void reg(); + void unreg(); + KeyStoreTracker::Item *getItem(const QString &storeId); + KeyStoreTracker::Item *getItem(int trackerId); + + void invalidate() + { + trackerId = -1; + unreg(); + } + + bool have_entryList_op() const + { + foreach (KeyStoreOperation *op, ops) { + if (op->type == KeyStoreOperation::EntryList) + return true; + } + return false; + } + + void handle_updated() + { + if (async) { + if (!have_entryList_op()) + async_entryList(); + else + need_update = true; + } else + emit q->updated(); + } + + void async_entryList() + { + KeyStoreOperation *op = new KeyStoreOperation(this); + // use queued for signal-safety + connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); + op->type = KeyStoreOperation::EntryList; + op->trackerId = trackerId; + ops += op; + op->start(); + } + + void async_writeEntry(const KeyStoreWriteEntry &wentry) + { + KeyStoreOperation *op = new KeyStoreOperation(this); + // use queued for signal-safety + connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); + op->type = KeyStoreOperation::WriteEntry; + op->trackerId = trackerId; + op->wentry = wentry; + ops += op; + op->start(); + } + + void async_removeEntry(const QString &entryId) + { + KeyStoreOperation *op = new KeyStoreOperation(this); + // use queued for signal-safety + connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); + op->type = KeyStoreOperation::RemoveEntry; + op->trackerId = trackerId; + op->entryId = entryId; + ops += op; + op->start(); + } + +private Q_SLOTS: + void op_finished() + { + KeyStoreOperation *op = (KeyStoreOperation *)sender(); + + if (op->type == KeyStoreOperation::EntryList) { + latestEntryList = op->entryList; + ops.removeAll(op); + delete op; + + if (need_update) { + need_update = false; + async_entryList(); + } + + emit q->updated(); + } else if (op->type == KeyStoreOperation::WriteEntry) { + QString entryId = op->entryId; + ops.removeAll(op); + delete op; + + emit q->entryWritten(entryId); + } else // RemoveEntry + { + bool success = op->success; + ops.removeAll(op); + delete op; + + emit q->entryRemoved(success); + } + } +}; + +KeyStore::KeyStore(const QString &id, KeyStoreManager *keyStoreManager) + : QObject(keyStoreManager) +{ + d = new KeyStorePrivate(this); + d->ksm = keyStoreManager; + + KeyStoreTracker::Item *i = d->getItem(id); + if (i) { + d->trackerId = i->trackerId; + d->item = *i; + d->reg(); + } else + d->trackerId = -1; +} + +KeyStore::~KeyStore() +{ + if (d->trackerId != -1) + d->unreg(); + delete d; +} + +bool KeyStore::isValid() const +{ + return (d->getItem(d->trackerId) ? true : false); +} + +KeyStore::Type KeyStore::type() const +{ + return d->item.type; +} + +QString KeyStore::name() const +{ + return d->item.name; +} + +QString KeyStore::id() const +{ + return d->item.storeId; +} + +bool KeyStore::isReadOnly() const +{ + return d->item.isReadOnly; +} + +void KeyStore::startAsynchronousMode() +{ + if (d->async) + return; + + d->async = true; + + // initial entrylist + d->need_update = false; + d->async_entryList(); +} + +QList KeyStore::entryList() const +{ + if (d->async) + return d->latestEntryList; + + if (d->trackerId == -1) + return QList(); + return trackercall("entryList", QVariantList() << d->trackerId).value>(); +} + +bool KeyStore::holdsTrustedCertificates() const +{ + QList list; + if (d->trackerId == -1) + return false; + list = trackercall("entryTypes", QVariantList() << d->trackerId).value>(); + if (list.contains(KeyStoreEntry::TypeCertificate) || list.contains(KeyStoreEntry::TypeCRL)) + return true; + return false; +} + +bool KeyStore::holdsIdentities() const +{ + QList list; + if (d->trackerId == -1) + return false; + list = trackercall("entryTypes", QVariantList() << d->trackerId).value>(); + if (list.contains(KeyStoreEntry::TypeKeyBundle) || list.contains(KeyStoreEntry::TypePGPSecretKey)) + return true; + return false; +} + +bool KeyStore::holdsPGPPublicKeys() const +{ + QList list; + if (d->trackerId == -1) + return false; + list = trackercall("entryTypes", QVariantList() << d->trackerId).value>(); + if (list.contains(KeyStoreEntry::TypePGPPublicKey)) + return true; + return false; +} + +QString KeyStore::writeEntry(const KeyBundle &kb) +{ + if (d->async) { + d->async_writeEntry(KeyStoreWriteEntry(kb)); + return QString(); + } else { + const auto arg = QVariant::fromValue(kb); + return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); + } +} + +QString KeyStore::writeEntry(const Certificate &cert) +{ + if (d->async) { + d->async_writeEntry(KeyStoreWriteEntry(cert)); + return QString(); + } else { + const auto arg = QVariant::fromValue(cert); + return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); + } +} + +QString KeyStore::writeEntry(const CRL &crl) +{ + if (d->async) { + d->async_writeEntry(KeyStoreWriteEntry(crl)); + return QString(); + } else { + const auto arg = QVariant::fromValue(crl); + return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); + } +} + +QString KeyStore::writeEntry(const PGPKey &key) +{ + if (d->async) { + d->async_writeEntry(KeyStoreWriteEntry(key)); + return QString(); + } else { + const auto arg = QVariant::fromValue(key); + return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); + } +} + +bool KeyStore::removeEntry(const QString &id) +{ + if (d->async) { + d->async_removeEntry(id); + return false; + } else { + return trackercall("removeEntry", QVariantList() << d->trackerId << id).toBool(); + } +} + +//---------------------------------------------------------------------------- +// KeyStoreManager +//---------------------------------------------------------------------------- +static void ensure_init() +{ + QMutexLocker locker(ksm_mutex()); + if (!g_ksm) + g_ksm = new KeyStoreManagerGlobal; +} + +// static functions +void KeyStoreManager::start() +{ + ensure_init(); + QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection); + trackercall("spinEventLoop"); +} + +void KeyStoreManager::start(const QString &provider) +{ + ensure_init(); + QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection, Q_ARG(QString, provider)); + trackercall("spinEventLoop"); +} + +QString KeyStoreManager::diagnosticText() +{ + ensure_init(); + + // spin one event cycle in the tracker, to receive any pending text. + // note that since trackercall also goes through the eventloop, + // this may end up doing two rounds. probably no big deal. + trackercall("spinEventLoop"); + + return KeyStoreTracker::instance()->getDText(); +} + +void KeyStoreManager::clearDiagnosticText() +{ + ensure_init(); + KeyStoreTracker::instance()->clearDText(); +} + +void KeyStoreManager::scan() +{ + ensure_init(); + QMetaObject::invokeMethod(KeyStoreTracker::instance(), "scan", Qt::QueuedConnection); +} + +void KeyStoreManager::shutdown() +{ + QMutexLocker locker(ksm_mutex()); + delete g_ksm; + g_ksm = nullptr; +} + +// object +class KeyStoreManagerPrivate : public QObject +{ + Q_OBJECT +public: + KeyStoreManager *q; + + QMutex m; + QWaitCondition w; + bool busy; + QList items; + bool pending, waiting; + + QMultiHash keyStoreForTrackerId; + QHash trackerIdForKeyStore; + + KeyStoreManagerPrivate(KeyStoreManager *_q) + : QObject(_q) + , q(_q) + { + pending = false; + waiting = false; + } + + ~KeyStoreManagerPrivate() override + { + // invalidate registered keystores + QList list; + QHashIterator it(trackerIdForKeyStore); + while (it.hasNext()) { + it.next(); + list += it.key(); + } + foreach (KeyStore *ks, list) + ks->d->invalidate(); + } + + // for keystore + void reg(KeyStore *ks, int trackerId) + { + keyStoreForTrackerId.insert(trackerId, ks); + trackerIdForKeyStore.insert(ks, trackerId); + } + + void unreg(KeyStore *ks) + { + int trackerId = trackerIdForKeyStore.take(ks); + + // this is the only way I know to remove one item from a multihash + QList vals = keyStoreForTrackerId.values(trackerId); + keyStoreForTrackerId.remove(trackerId); + vals.removeAll(ks); + foreach (KeyStore *i, vals) + keyStoreForTrackerId.insert(trackerId, i); + } + + KeyStoreTracker::Item *getItem(const QString &storeId) + { + for (int n = 0; n < items.count(); ++n) { + KeyStoreTracker::Item *i = &items[n]; + if (i->storeId == storeId) + return i; + } + return nullptr; + } + + KeyStoreTracker::Item *getItem(int trackerId) + { + for (int n = 0; n < items.count(); ++n) { + KeyStoreTracker::Item *i = &items[n]; + if (i->trackerId == trackerId) + return i; + } + return nullptr; + } + + void do_update() + { + // ksm doesn't have reset or state changes so we can + // use QPointer here for full SS. + QPointer self(this); + + const bool newbusy = KeyStoreTracker::instance()->isBusy(); + const QList newitems = KeyStoreTracker::instance()->getItems(); + + if (!busy && newbusy) { + emit q->busyStarted(); + if (!self) + return; + } + if (busy && !newbusy) { + emit q->busyFinished(); + if (!self) + return; + } + + QStringList here; + QList changed; + QList gone; + + // removed + for (int n = 0; n < items.count(); ++n) { + KeyStoreTracker::Item &i = items[n]; + bool found = false; + for (int k = 0; k < newitems.count(); ++k) { + if (i.trackerId == newitems[k].trackerId) { + found = true; + break; + } + } + if (!found) + gone += i.trackerId; + } + + // changed + for (int n = 0; n < items.count(); ++n) { + KeyStoreTracker::Item &i = items[n]; + for (int k = 0; k < newitems.count(); ++k) { + if (i.trackerId == newitems[k].trackerId) { + if (i.updateCount < newitems[k].updateCount) + changed += i.trackerId; + break; + } + } + } + + // added + for (int n = 0; n < newitems.count(); ++n) { + const KeyStoreTracker::Item &i = newitems[n]; + bool found = false; + for (int k = 0; k < items.count(); ++k) { + if (i.trackerId == items[k].trackerId) { + found = true; + break; + } + } + if (!found) + here += i.storeId; + } + + busy = newbusy; + items = newitems; + + // signals + foreach (int trackerId, gone) { + KeyStore *ks = keyStoreForTrackerId.value(trackerId); + if (ks) { + ks->d->invalidate(); + emit ks->unavailable(); + if (!self) + return; + } + } + + foreach (int trackerId, changed) { + KeyStore *ks = keyStoreForTrackerId.value(trackerId); + if (ks) { + ks->d->handle_updated(); + if (!self) + return; + } + } + + foreach (const QString &storeId, here) { + emit q->keyStoreAvailable(storeId); + if (!self) + return; + } + } + +public Q_SLOTS: + void tracker_updated() + { + QCA_logTextMessage(QString::asprintf("keystore: %p: tracker_updated start", q), Logger::Information); + + QMutexLocker locker(&m); + if (!pending) { + QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); + pending = true; + } + if (waiting && !KeyStoreTracker::instance()->isBusy()) { + busy = false; + items = KeyStoreTracker::instance()->getItems(); + w.wakeOne(); + } + + QCA_logTextMessage(QString::asprintf("keystore: %p: tracker_updated end", q), Logger::Information); + } + + void update() + { + m.lock(); + pending = false; + m.unlock(); + + do_update(); + } +}; + +// from KeyStoreTracker +void KeyStoreTracker::addTarget(KeyStoreManagerPrivate *ksm) +{ + QMutexLocker locker(&updateMutex); + connect(this, &KeyStoreTracker::updated, ksm, &KeyStoreManagerPrivate::tracker_updated, Qt::DirectConnection); +} + +// from KeyStorePrivate +void KeyStorePrivate::reg() +{ + ksm->d->reg(q, trackerId); +} + +void KeyStorePrivate::unreg() +{ + ksm->d->unreg(q); +} + +KeyStoreTracker::Item *KeyStorePrivate::getItem(const QString &storeId) +{ + return ksm->d->getItem(storeId); +} + +KeyStoreTracker::Item *KeyStorePrivate::getItem(int trackerId) +{ + return ksm->d->getItem(trackerId); +} + +KeyStoreManager::KeyStoreManager(QObject *parent) + : QObject(parent) +{ + ensure_init(); + d = new KeyStoreManagerPrivate(this); + KeyStoreTracker::instance()->addTarget(d); + sync(); +} + +KeyStoreManager::~KeyStoreManager() +{ + Q_ASSERT(KeyStoreTracker::instance()); + KeyStoreTracker::instance()->removeTarget(d); + delete d; +} + +bool KeyStoreManager::isBusy() const +{ + return d->busy; +} + +void KeyStoreManager::waitForBusyFinished() +{ + d->m.lock(); + d->busy = KeyStoreTracker::instance()->isBusy(); + if (d->busy) { + d->waiting = true; + d->w.wait(&d->m); + d->waiting = false; + } + d->m.unlock(); +} + +QStringList KeyStoreManager::keyStores() const +{ + QStringList out; + for (int n = 0; n < d->items.count(); ++n) + out += d->items[n].storeId; + return out; +} + +void KeyStoreManager::sync() +{ + d->busy = KeyStoreTracker::instance()->isBusy(); + d->items = KeyStoreTracker::instance()->getItems(); +} + +//---------------------------------------------------------------------------- +// KeyStoreInfo +//---------------------------------------------------------------------------- +class KeyStoreInfo::Private : public QSharedData +{ +public: + KeyStore::Type type; + QString id, name; +}; + +KeyStoreInfo::KeyStoreInfo() +{ +} + +KeyStoreInfo::KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name) + : d(new Private) +{ + d->type = type; + d->id = id; + d->name = name; +} + +KeyStoreInfo::KeyStoreInfo(const KeyStoreInfo &from) + : d(from.d) +{ +} + +KeyStoreInfo::~KeyStoreInfo() +{ +} + +KeyStoreInfo &KeyStoreInfo::operator=(const KeyStoreInfo &from) +{ + d = from.d; + return *this; +} + +bool KeyStoreInfo::isNull() const +{ + return (d ? false : true); +} + +KeyStore::Type KeyStoreInfo::type() const +{ + return d->type; +} + +QString KeyStoreInfo::id() const +{ + return d->id; +} + +QString KeyStoreInfo::name() const +{ + return d->name; +} + +} + +#include "qca_keystore.moc" diff --git a/local/recipes/libs/qca/source/src/qca_plugin.cpp b/local/recipes/libs/qca/source/src/qca_plugin.cpp new file mode 100644 index 0000000000..9341866da5 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_plugin.cpp @@ -0,0 +1,757 @@ +/* + * Copyright (C) 2004-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +// Note: The basic thread-safety approach with the plugin manager is that +// it is safe to add/get providers, however it is unsafe to remove them. +// The expectation is that providers will almost always be unloaded on +// application shutdown. For safe provider unload, ensure no threads are +// using the manager, the provider in question, nor any sub-objects from +// the provider. + +#include "qca_plugin.h" + +#include "qcaprovider.h" + +#include +#include +#include +#include +#include + +#define PLUGIN_SUBDIR QStringLiteral("crypto") + +namespace QCA { + +// from qca_core.cpp +QVariantMap getProviderConfig_internal(Provider *p); + +// from qca_default.cpp +QStringList skip_plugins(Provider *defaultProvider); +QStringList plugin_priorities(Provider *defaultProvider); + +// stupidly simple log truncation function. if the log exceeds size chars, +// then throw out the top half, to nearest line. +QString truncate_log(const QString &in, int size) +{ + if (size < 2 || in.length() < size) + return in; + + // start by pointing at the last chars + int at = in.length() - (size / 2); + + // if the previous char is a newline, then this is a perfect cut. + // otherwise, we need to skip to after the next newline. + if (in[at - 1] != QLatin1Char('\n')) { + while (at < in.length() && in[at] != QLatin1Char('\n')) { + ++at; + } + + // at this point we either reached a newline, or end of + // the entire buffer + + if (in[at] == QLatin1Char('\n')) + ++at; + } + + return in.mid(at); +} + +static ProviderManager *g_pluginman = nullptr; + +static void logDebug(const QString &str) +{ + if (g_pluginman) + g_pluginman->appendDiagnosticText(str + QLatin1Char('\n')); +} + +static bool validVersion(int ver) +{ + // major version must be equal, minor version must be equal or lesser + if ((ver & 0xff0000) == (QCA_VERSION & 0xff0000) && (ver & 0xff00) <= (QCA_VERSION & 0xff00)) + return true; + return false; +} + +class PluginInstance +{ +private: + QPluginLoader *_loader; + QObject *_instance; + bool _ownInstance; + + PluginInstance() + { + } + +public: + static PluginInstance *fromFile(const QString &fname, QString *errstr = nullptr) + { + QPluginLoader *loader = new QPluginLoader(fname); + if (!loader->load()) { + if (errstr) + *errstr = QStringLiteral("failed to load: %1").arg(loader->errorString()); + delete loader; + return nullptr; + } + QObject *obj = loader->instance(); + if (!obj) { + if (errstr) + *errstr = QStringLiteral("failed to get instance"); + loader->unload(); + delete loader; + return nullptr; + } + PluginInstance *i = new PluginInstance; + i->_loader = loader; + i->_instance = obj; + i->_ownInstance = true; + return i; + } + + static PluginInstance *fromStatic(QObject *obj) + { + PluginInstance *i = new PluginInstance; + i->_loader = nullptr; + i->_instance = obj; + i->_ownInstance = false; + return i; + } + + static PluginInstance *fromInstance(QObject *obj) + { + PluginInstance *i = new PluginInstance; + i->_loader = nullptr; + i->_instance = obj; + i->_ownInstance = true; + return i; + } + + ~PluginInstance() + { + if (_ownInstance) + delete _instance; + + if (_loader) { + _loader->unload(); + delete _loader; + } + } + + PluginInstance(const PluginInstance &) = delete; + PluginInstance &operator=(const PluginInstance &) = delete; + + void claim() + { + if (_loader) + _loader->moveToThread(nullptr); + if (_ownInstance) + _instance->moveToThread(nullptr); + } + + QObject *instance() + { + return _instance; + } +}; + +class ProviderItem +{ +public: + QString fname; + Provider *p; + int priority; + QMutex m; + + static ProviderItem *load(const QString &fname, QString *out_errstr = nullptr) + { + QString errstr; + PluginInstance *i = PluginInstance::fromFile(fname, &errstr); + if (!i) { + if (out_errstr) + *out_errstr = errstr; + return nullptr; + } + QCAPlugin *plugin = qobject_cast(i->instance()); + if (!plugin) { + if (out_errstr) + *out_errstr = QStringLiteral("does not offer QCAPlugin interface"); + delete i; + return nullptr; + } + + Provider *p = plugin->createProvider(); + if (!p) { + if (out_errstr) + *out_errstr = QStringLiteral("unable to create provider"); + delete i; + return nullptr; + } + + ProviderItem *pi = new ProviderItem(i, p); + pi->fname = fname; + return pi; + } + + static ProviderItem *loadStatic(QObject *instance, QString *errstr = nullptr) + { + PluginInstance *i = PluginInstance::fromStatic(instance); + QCAPlugin *plugin = qobject_cast(i->instance()); + if (!plugin) { + if (errstr) + *errstr = QStringLiteral("does not offer QCAPlugin interface"); + delete i; + return nullptr; + } + + Provider *p = plugin->createProvider(); + if (!p) { + if (errstr) + *errstr = QStringLiteral("unable to create provider"); + delete i; + return nullptr; + } + + ProviderItem *pi = new ProviderItem(i, p); + return pi; + } + + static ProviderItem *fromClass(Provider *p) + { + ProviderItem *pi = new ProviderItem(nullptr, p); + return pi; + } + + ~ProviderItem() + { + delete p; + delete instance; + } + + void ensureInit() + { + QMutexLocker locker(&m); + if (init_done) + return; + init_done = true; + + p->init(); + + // load config + QVariantMap conf = getProviderConfig_internal(p); + if (!conf.isEmpty()) + p->configChanged(conf); + } + + bool initted() const + { + return init_done; + } + + // null if not a plugin + QObject *objectInstance() const + { + if (instance) + return instance->instance(); + else + return nullptr; + } + +private: + PluginInstance *instance; + bool init_done; + + ProviderItem(PluginInstance *_instance, Provider *_p) + { + instance = _instance; + p = _p; + init_done = false; + + // disassociate from threads + if (instance) + instance->claim(); + } +}; + +ProviderManager::ProviderManager() +{ + g_pluginman = this; + def = nullptr; + scanned_static = false; +} + +ProviderManager::~ProviderManager() +{ + if (def) + def->deinit(); + unloadAll(); + delete def; + g_pluginman = nullptr; +} + +void ProviderManager::scan() +{ + QMutexLocker locker(&providerMutex); + + // check static first, but only once + if (!scanned_static) { + logDebug(QStringLiteral("Checking Qt static plugins:")); + const QObjectList list = QPluginLoader::staticInstances(); + if (list.isEmpty()) + logDebug(QStringLiteral(" (none)")); + for (int n = 0; n < list.count(); ++n) { + QObject *instance = list[n]; + const QString className = QString::fromLatin1(instance->metaObject()->className()); + + QString errstr; + ProviderItem *i = ProviderItem::loadStatic(instance, &errstr); + if (!i) { + logDebug(QStringLiteral(" %1: %2").arg(className, errstr)); + continue; + } + + const QString providerName = i->p->name(); + if (haveAlready(providerName)) { + logDebug( + QStringLiteral(" %1: (as %2) already loaded provider, skipping").arg(className, providerName)); + delete i; + continue; + } + + const int ver = i->p->qcaVersion(); + if (!validVersion(ver)) { + errstr = QString::asprintf("plugin version 0x%06x is in the future", ver); + logDebug(QStringLiteral(" %1: (as %2) %3").arg(className, providerName, errstr)); + delete i; + continue; + } + + addItem(i, get_default_priority(providerName)); + logDebug(QStringLiteral(" %1: loaded as %2").arg(className, providerName)); + } + scanned_static = true; + } + +#ifndef QCA_NO_PLUGINS + if (qgetenv("QCA_NO_PLUGINS") == "1") + return; + + const QStringList dirs = pluginPaths(); + if (dirs.isEmpty()) + logDebug(QStringLiteral("No Qt Library Paths")); + for (const QString &dirIt : dirs) { +#ifdef DEVELOPER_MODE + logDebug(QStringLiteral("Checking QCA build tree Path: %1").arg(QDir::toNativeSeparators(dirIt))); +#else + logDebug(QStringLiteral("Checking Qt Library Path: %1").arg(QDir::toNativeSeparators(dirIt))); +#endif + QDir libpath(dirIt); + QDir dir(libpath.filePath(PLUGIN_SUBDIR)); + if (!dir.exists()) { + logDebug(QStringLiteral(" (No 'crypto' subdirectory)")); + continue; + } + + const QStringList entryList = dir.entryList(QDir::Files); + if (entryList.isEmpty()) { + logDebug(QStringLiteral(" (No files in 'crypto' subdirectory)")); + continue; + } + + foreach (const QString &maybeFile, entryList) { + const QFileInfo fi(dir.filePath(maybeFile)); + + const QString filePath = fi.filePath(); // file name with path + const QString fileName = fi.fileName(); // just file name + + if (!QLibrary::isLibrary(filePath)) { + logDebug(QStringLiteral(" %1: not a library, skipping").arg(fileName)); + continue; + } + + // make sure we haven't loaded this file before + bool haveFile = false; + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (!pi->fname.isEmpty() && pi->fname == filePath) { + haveFile = true; + break; + } + } + if (haveFile) { + logDebug(QStringLiteral(" %1: already loaded file, skipping").arg(fileName)); + continue; + } + + QString errstr; + ProviderItem *i = ProviderItem::load(filePath, &errstr); + if (!i) { + logDebug(QStringLiteral(" %1: %2").arg(fileName, errstr)); + continue; + } + + const QString className = QString::fromLatin1(i->objectInstance()->metaObject()->className()); + + const QString providerName = i->p->name(); + if (haveAlready(providerName)) { + logDebug(QStringLiteral(" %1: (class: %2, as %3) already loaded provider, skipping") + .arg(fileName, className, providerName)); + delete i; + continue; + } + + const int ver = i->p->qcaVersion(); + if (!validVersion(ver)) { + errstr = QString::asprintf("plugin version 0x%06x is in the future", ver); + logDebug(QStringLiteral(" %1: (class: %2, as %3) %4").arg(fileName, className, providerName, errstr)); + delete i; + continue; + } + + if (skip_plugins(def).contains(providerName)) { + logDebug(QStringLiteral(" %1: (class: %2, as %3) explicitly disabled, skipping") + .arg(fileName, className, providerName)); + delete i; + continue; + } + + addItem(i, get_default_priority(providerName)); + logDebug(QStringLiteral(" %1: (class: %2) loaded as %3").arg(fileName, className, providerName)); + } + } +#endif +} + +bool ProviderManager::add(Provider *p, int priority) +{ + QMutexLocker locker(&providerMutex); + + const QString providerName = p->name(); + + if (haveAlready(providerName)) { + logDebug(QStringLiteral("Directly adding: %1: already loaded provider, skipping").arg(providerName)); + return false; + } + + const int ver = p->qcaVersion(); + if (!validVersion(ver)) { + QString errstr = QString::asprintf("plugin version 0x%06x is in the future", ver); + logDebug(QStringLiteral("Directly adding: %1: %2").arg(providerName, errstr)); + return false; + } + + ProviderItem *i = ProviderItem::fromClass(p); + addItem(i, priority); + logDebug(QStringLiteral("Directly adding: %1: loaded").arg(providerName)); + return true; +} + +bool ProviderManager::unload(const QString &name) +{ + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *i = providerItemList[n]; + if (i->p && i->p->name() == name) { + if (i->initted()) + i->p->deinit(); + + delete i; + providerItemList.removeAt(n); + providerList.removeAt(n); + + logDebug(QStringLiteral("Unloaded: %1").arg(name)); + return true; + } + } + + return false; +} + +void ProviderManager::unloadAll() +{ + foreach (ProviderItem *i, providerItemList) { + if (i->initted()) + i->p->deinit(); + } + + while (!providerItemList.isEmpty()) { + ProviderItem *i = providerItemList.first(); + const QString name = i->p->name(); + delete i; + providerItemList.removeFirst(); + providerList.removeFirst(); + + logDebug(QStringLiteral("Unloaded: %1").arg(name)); + } +} + +void ProviderManager::setDefault(Provider *p) +{ + QMutexLocker locker(&providerMutex); + + if (def) + delete def; + def = p; + if (def) { + def->init(); + QVariantMap conf = getProviderConfig_internal(def); + if (!conf.isEmpty()) + def->configChanged(conf); + } +} + +Provider *ProviderManager::find(Provider *_p) const +{ + ProviderItem *i = nullptr; + Provider *p = nullptr; + + providerMutex.lock(); + if (_p == def) { + p = def; + } else { + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (pi->p && pi->p == _p) { + i = pi; + p = pi->p; + break; + } + } + } + providerMutex.unlock(); + + if (i) + i->ensureInit(); + return p; +} + +Provider *ProviderManager::find(const QString &name) const +{ + ProviderItem *i = nullptr; + Provider *p = nullptr; + + providerMutex.lock(); + if (def && name == def->name()) { + p = def; + } else { + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (pi->p && pi->p->name() == name) { + i = pi; + p = pi->p; + break; + } + } + } + providerMutex.unlock(); + + if (i) + i->ensureInit(); + return p; +} + +Provider *ProviderManager::findFor(const QString &name, const QString &type) const +{ + if (name.isEmpty()) { + providerMutex.lock(); + const QList list = providerItemList; + providerMutex.unlock(); + + // find the first one that can do it + for (int n = 0; n < list.count(); ++n) { + ProviderItem *pi = list[n]; + pi->ensureInit(); + if (pi->p && pi->p->features().contains(type)) + return pi->p; + } + + // try the default provider as a last resort + providerMutex.lock(); + Provider *p = def; + providerMutex.unlock(); + if (p && p->features().contains(type)) + return p; + + return nullptr; + } else { + Provider *p = find(name); + if (p && p->features().contains(type)) + return p; + return nullptr; + } +} + +void ProviderManager::changePriority(const QString &name, int priority) +{ + QMutexLocker locker(&providerMutex); + + ProviderItem *i = nullptr; + int n = 0; + for (; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (pi->p && pi->p->name() == name) { + i = pi; + break; + } + } + if (!i) + return; + + providerItemList.removeAt(n); + providerList.removeAt(n); + + addItem(i, priority); +} + +int ProviderManager::getPriority(const QString &name) +{ + QMutexLocker locker(&providerMutex); + + ProviderItem *i = nullptr; + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (pi->p && pi->p->name() == name) { + i = pi; + break; + } + } + if (!i) + return -1; + + return i->priority; +} + +QStringList ProviderManager::allFeatures() const +{ + QStringList featureList; + + providerMutex.lock(); + Provider *p = def; + providerMutex.unlock(); + if (p) + featureList = p->features(); + + providerMutex.lock(); + const QList list = providerItemList; + providerMutex.unlock(); + for (int n = 0; n < list.count(); ++n) { + ProviderItem *i = list[n]; + if (i->p) + mergeFeatures(&featureList, i->p->features()); + } + + return featureList; +} + +ProviderList ProviderManager::providers() const +{ + QMutexLocker locker(&providerMutex); + + return providerList; +} + +QString ProviderManager::diagnosticText() const +{ + QMutexLocker locker(&logMutex); + + return dtext; +} + +void ProviderManager::appendDiagnosticText(const QString &str) +{ + QMutexLocker locker(&logMutex); + + dtext += str; + dtext = truncate_log(dtext, 20000); +} + +void ProviderManager::clearDiagnosticText() +{ + QMutexLocker locker(&logMutex); + + dtext = QString(); +} + +void ProviderManager::addItem(ProviderItem *item, int priority) +{ + if (priority < 0) { + // for -1, make the priority the same as the last item + if (!providerItemList.isEmpty()) { + const ProviderItem *last = providerItemList.last(); + item->priority = last->priority; + } else + item->priority = 0; + + providerItemList.append(item); + providerList.append(item->p); + } else { + // place the item before any other items with same or greater priority + int n = 0; + for (; n < providerItemList.count(); ++n) { + const ProviderItem *i = providerItemList[n]; + if (i->priority >= priority) + break; + } + + item->priority = priority; + providerItemList.insert(n, item); + providerList.insert(n, item->p); + } +} + +bool ProviderManager::haveAlready(const QString &name) const +{ + if (def && name == def->name()) + return true; + + for (int n = 0; n < providerItemList.count(); ++n) { + ProviderItem *pi = providerItemList[n]; + if (pi->p && pi->p->name() == name) + return true; + } + + return false; +} + +void ProviderManager::mergeFeatures(QStringList *a, const QStringList &b) +{ + for (const QString &s : b) { + if (!a->contains(s)) + a->append(s); + } +} + +int ProviderManager::get_default_priority(const QString &name) const +{ + const QStringList list = plugin_priorities(def); + foreach (const QString &s, list) { + // qca_default already sanity checks the strings + const int n = s.indexOf(QLatin1Char(':')); + const QString sname = s.mid(0, n); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2) + const int spriority = QStringView(s).mid(n + 1).toInt(); +#else + const int spriority = s.midRef(n + 1).toInt(); +#endif + if (sname == name) + return spriority; + } + return -1; +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_plugin.h b/local/recipes/libs/qca/source/src/qca_plugin.h new file mode 100644 index 0000000000..8ce086f9d8 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_plugin.h @@ -0,0 +1,74 @@ +/* + * qca_plugin.h - Qt Cryptographic Architecture + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef QCA_PLUGIN_H +#define QCA_PLUGIN_H + +// NOTE: this API is private to QCA + +#include "qca_core.h" +#include + +namespace QCA { + +class ProviderItem; + +class ProviderManager +{ +public: + ProviderManager(); + ~ProviderManager(); + + void scan(); + bool add(Provider *p, int priority); + bool unload(const QString &name); + void unloadAll(); + void setDefault(Provider *p); + Provider *find(Provider *p) const; + Provider *find(const QString &name) const; + Provider *findFor(const QString &name, const QString &type) const; + void changePriority(const QString &name, int priority); + int getPriority(const QString &name); + QStringList allFeatures() const; + ProviderList providers() const; + + static void mergeFeatures(QStringList *a, const QStringList &b); + + QString diagnosticText() const; + void appendDiagnosticText(const QString &str); + void clearDiagnosticText(); + +private: + mutable QMutex logMutex, providerMutex; + QString dtext; + QList providerItemList; + ProviderList providerList; + Provider *def; + bool scanned_static; + void addItem(ProviderItem *i, int priority); + bool haveAlready(const QString &name) const; + int get_default_priority(const QString &name) const; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/src/qca_publickey.cpp b/local/recipes/libs/qca/source/src/qca_publickey.cpp new file mode 100644 index 0000000000..3e3665b84c --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_publickey.cpp @@ -0,0 +1,1519 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_publickey.h" + +#include "qcaprovider.h" + +#include +#include + +namespace QCA { + +Provider::Context *getContext(const QString &type, const QString &provider); +Provider::Context *getContext(const QString &type, Provider *p); + +bool stringToFile(const QString &fileName, const QString &content) +{ + QFile f(fileName); + if (!f.open(QFile::WriteOnly)) + return false; + QTextStream ts(&f); + ts << content; + return true; +} + +bool stringFromFile(const QString &fileName, QString *s) +{ + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) + return false; + QTextStream ts(&f); + *s = ts.readAll(); + return true; +} + +bool arrayToFile(const QString &fileName, const QByteArray &content) +{ + QFile f(fileName); + if (!f.open(QFile::WriteOnly)) + return false; + f.write(content.data(), content.size()); + return true; +} + +bool arrayFromFile(const QString &fileName, QByteArray *a) +{ + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) + return false; + *a = f.readAll(); + return true; +} + +bool ask_passphrase(const QString &fname, void *ptr, SecureArray *answer) +{ + PasswordAsker asker; + asker.ask(Event::StylePassphrase, fname, ptr); + asker.waitForResponse(); + if (!asker.accepted()) + return false; + *answer = asker.password(); + return true; +} + +ProviderList allProviders() +{ + ProviderList pl = providers(); + pl += defaultProvider(); + return pl; +} + +Provider *providerForName(const QString &name) +{ + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + if (pl[n]->name() == name) + return pl[n]; + } + return nullptr; +} + +bool use_asker_fallback(ConvertResult r) +{ + // FIXME: we should only do this if we get ErrorPassphrase? + // if(r == ErrorPassphrase) + if (r != ConvertGood) + return true; + return false; +} + +class Getter_GroupSet +{ +public: + static QList getList(Provider *p) + { + QList list; + const DLGroupContext *c = static_cast(getContext(QStringLiteral("dlgroup"), p)); + if (!c) + return list; + list = c->supportedGroupSets(); + delete c; + return list; + } +}; + +class Getter_PBE +{ +public: + static QList getList(Provider *p) + { + QList list; + const PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), p)); + if (!c) + return list; + list = c->supportedPBEAlgorithms(); + delete c; + return list; + } +}; + +class Getter_Type +{ +public: + static QList getList(Provider *p) + { + QList list; + const PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), p)); + if (!c) + return list; + list = c->supportedTypes(); + delete c; + return list; + } +}; + +class Getter_IOType +{ +public: + static QList getList(Provider *p) + { + QList list; + const PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), p)); + if (!c) + return list; + list = c->supportedIOTypes(); + delete c; + return list; + } +}; + +template class Getter_PublicKey +{ +public: + // DER + static ConvertResult fromData(PKeyContext *c, const QByteArray &in) + { + return c->publicFromDER(in); + } + + // PEM + static ConvertResult fromData(PKeyContext *c, const QString &in) + { + return c->publicFromPEM(in); + } + + static PublicKey getKey(Provider *p, const I &in, const SecureArray &, ConvertResult *result) + { + PublicKey k; + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), p)); + if (!c) { + if (result) + *result = ErrorDecode; + return k; + } + ConvertResult r = fromData(c, in); + if (result) + *result = r; + if (r == ConvertGood) + k.change(c); + else + delete c; + return k; + } +}; + +template class Getter_PrivateKey +{ +public: + // DER + static ConvertResult fromData(PKeyContext *c, const SecureArray &in, const SecureArray &passphrase) + { + return c->privateFromDER(in, passphrase); + } + + // PEM + static ConvertResult fromData(PKeyContext *c, const QString &in, const SecureArray &passphrase) + { + return c->privateFromPEM(in, passphrase); + } + + static PrivateKey getKey(Provider *p, const I &in, const SecureArray &passphrase, ConvertResult *result) + { + PrivateKey k; + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), p)); + if (!c) { + if (result) + *result = ErrorDecode; + return k; + } + ConvertResult r = fromData(c, in, passphrase); + if (result) + *result = r; + if (r == ConvertGood) + k.change(c); + else + delete c; + return k; + } +}; + +Provider *providerForGroupSet(DLGroupSet set) +{ + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + if (Getter_GroupSet::getList(pl[n]).contains(set)) + return pl[n]; + } + return nullptr; +} + +Provider *providerForPBE(PBEAlgorithm alg, PKey::Type ioType, const PKeyContext *prefer = nullptr) +{ + Provider *preferProvider = nullptr; + if (prefer) { + preferProvider = prefer->provider(); + if (prefer->supportedPBEAlgorithms().contains(alg) && prefer->supportedIOTypes().contains(ioType)) + return preferProvider; + } + + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + if (preferProvider && pl[n] == preferProvider) + continue; + + if (Getter_PBE::getList(pl[n]).contains(alg) && Getter_IOType::getList(pl[n]).contains(ioType)) + return pl[n]; + } + return nullptr; +} + +Provider *providerForIOType(PKey::Type type, const PKeyContext *prefer = nullptr) +{ + Provider *preferProvider = nullptr; + if (prefer) { + preferProvider = prefer->provider(); + if (prefer && prefer->supportedIOTypes().contains(type)) + return preferProvider; + } + + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + if (preferProvider && pl[n] == preferProvider) + continue; + + if (Getter_IOType::getList(pl[n]).contains(type)) + return pl[n]; + } + return nullptr; +} + +template QList getList(const QString &provider) +{ + QList list; + + // single + if (!provider.isEmpty()) { + Provider *p = providerForName(provider); + if (p) + list = G::getList(p); + } + // all + else { + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + const QList other = G::getList(pl[n]); + for (int k = 0; k < other.count(); ++k) { + // only add what we don't have in the list + if (!list.contains(other[k])) + list += other[k]; + } + } + } + + return list; +} + +template +T getKey(const QString &provider, const I &in, const SecureArray &passphrase, ConvertResult *result) +{ + T k; + + // single + if (!provider.isEmpty()) { + Provider *p = providerForName(provider); + if (!p) + return k; + k = G::getKey(p, in, passphrase, result); + } + // all + else { + ProviderList pl = allProviders(); + for (int n = 0; n < pl.count(); ++n) { + ConvertResult r; + k = G::getKey(pl[n], in, passphrase, &r); + if (result) + *result = r; + if (!k.isNull()) + break; + if (r == ErrorPassphrase) // don't loop if we get this + break; + } + } + + return k; +} + +PBEAlgorithm get_pbe_default() +{ + return PBES2_TripleDES_SHA1; +} + +static PrivateKey get_privatekey_der(const SecureArray &der, + const QString &fileName, + void *ptr, + const SecureArray &passphrase, + ConvertResult *result, + const QString &provider) +{ + PrivateKey out; + ConvertResult r; + out = getKey, SecureArray>(provider, der, passphrase, &r); + + // error converting without passphrase? maybe a passphrase is needed + if (use_asker_fallback(r) && passphrase.isEmpty()) { + SecureArray pass; + if (ask_passphrase(fileName, ptr, &pass)) + out = getKey, SecureArray>(provider, der, pass, &r); + } + if (result) + *result = r; + return out; +} + +static PrivateKey get_privatekey_pem(const QString &pem, + const QString &fileName, + void *ptr, + const SecureArray &passphrase, + ConvertResult *result, + const QString &provider) +{ + PrivateKey out; + ConvertResult r; + out = getKey, QString>(provider, pem, passphrase, &r); + + // error converting without passphrase? maybe a passphrase is needed + if (use_asker_fallback(r) && passphrase.isEmpty()) { + SecureArray pass; + if (ask_passphrase(fileName, ptr, &pass)) + out = getKey, QString>(provider, pem, pass, &r); + } + if (result) + *result = r; + return out; +} + +//---------------------------------------------------------------------------- +// Global +//---------------------------------------------------------------------------- + +// adapted from Botan +static const unsigned char pkcs_sha1[] = + {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14}; + +static const unsigned char pkcs_md5[] = + {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}; + +static const unsigned char pkcs_md2[] = + {0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10}; + +static const unsigned char pkcs_ripemd160[] = + {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14}; + +QByteArray get_hash_id(const QString &name) +{ + if (name == QLatin1String("sha1")) + return QByteArray::fromRawData((const char *)pkcs_sha1, sizeof(pkcs_sha1)); + else if (name == QLatin1String("md5")) + return QByteArray::fromRawData((const char *)pkcs_md5, sizeof(pkcs_md5)); + else if (name == QLatin1String("md2")) + return QByteArray::fromRawData((const char *)pkcs_md2, sizeof(pkcs_md2)); + else if (name == QLatin1String("ripemd160")) + return QByteArray::fromRawData((const char *)pkcs_ripemd160, sizeof(pkcs_ripemd160)); + else + return QByteArray(); +} + +QByteArray emsa3Encode(const QString &hashName, const QByteArray &digest, int size) +{ + const QByteArray hash_id = get_hash_id(hashName); + if (hash_id.isEmpty()) + return QByteArray(); + + // logic adapted from Botan + const int basesize = hash_id.size() + digest.size() + 2; + if (size == -1) + size = basesize + 1; // default to 1-byte pad + int padlen = size - basesize; + if (padlen < 1) + return QByteArray(); + + QByteArray out(size, (char)0xff); // pad with 0xff + out[0] = 0x01; + out[padlen + 1] = 0x00; + int at = padlen + 2; + memcpy(out.data() + at, hash_id.data(), hash_id.size()); + at += hash_id.size(); + memcpy(out.data() + at, digest.data(), digest.size()); + return out; +} + +//---------------------------------------------------------------------------- +// DLGroup +//---------------------------------------------------------------------------- +class DLGroup::Private +{ +public: + BigInteger p, q, g; + + Private(const BigInteger &p1, const BigInteger &q1, const BigInteger &g1) + : p(p1) + , q(q1) + , g(g1) + { + } +}; + +DLGroup::DLGroup() +{ + d = nullptr; +} + +DLGroup::DLGroup(const BigInteger &p, const BigInteger &q, const BigInteger &g) +{ + d = new Private(p, q, g); +} + +DLGroup::DLGroup(const BigInteger &p, const BigInteger &g) +{ + d = new Private(p, 0, g); +} + +DLGroup::DLGroup(const DLGroup &from) +{ + d = nullptr; + *this = from; +} + +DLGroup::~DLGroup() +{ + delete d; +} + +DLGroup &DLGroup::operator=(const DLGroup &from) +{ + delete d; + d = nullptr; + + if (from.d) + d = new Private(*from.d); + + return *this; +} + +QList DLGroup::supportedGroupSets(const QString &provider) +{ + return getList(provider); +} + +bool DLGroup::isNull() const +{ + return (d ? false : true); +} + +BigInteger DLGroup::p() const +{ + Q_ASSERT(d); + return d->p; +} + +BigInteger DLGroup::q() const +{ + Q_ASSERT(d); + return d->q; +} + +BigInteger DLGroup::g() const +{ + Q_ASSERT(d); + return d->g; +} + +//---------------------------------------------------------------------------- +// PKey +//---------------------------------------------------------------------------- +class PKey::Private +{ +public: +}; + +PKey::PKey() +{ + d = new Private; +} + +PKey::PKey(const QString &type, const QString &provider) + : Algorithm(type, provider) +{ + d = new Private; +} + +PKey::PKey(const PKey &from) + : Algorithm(from) +{ + d = new Private; + *this = from; +} + +PKey::~PKey() +{ + delete d; +} + +PKey &PKey::operator=(const PKey &from) +{ + Algorithm::operator=(from); + *d = *from.d; + return *this; +} + +void PKey::set(const PKey &k) +{ + *this = k; +} + +void PKey::assignToPublic(PKey *dest) const +{ + dest->set(*this); + + // converting private to public + if (dest->isPrivate()) + static_cast(dest->context())->key()->convertToPublic(); +} + +void PKey::assignToPrivate(PKey *dest) const +{ + dest->set(*this); +} + +QList PKey::supportedTypes(const QString &provider) +{ + return getList(provider); +} + +QList PKey::supportedIOTypes(const QString &provider) +{ + return getList(provider); +} + +bool PKey::isNull() const +{ + return (!context() ? true : false); +} + +PKey::Type PKey::type() const +{ + if (isNull()) + return RSA; // some default so we don't explode + return static_cast(context())->key()->type(); +} + +int PKey::bitSize() const +{ + return static_cast(context())->key()->bits(); +} + +bool PKey::isRSA() const +{ + return (type() == RSA); +} + +bool PKey::isDSA() const +{ + return (type() == DSA); +} + +bool PKey::isDH() const +{ + return (type() == DH); +} + +bool PKey::isPublic() const +{ + if (isNull()) + return false; + return !isPrivate(); +} + +bool PKey::isPrivate() const +{ + if (isNull()) + return false; + return static_cast(context())->key()->isPrivate(); +} + +bool PKey::canExport() const +{ + return static_cast(context())->key()->canExport(); +} + +bool PKey::canKeyAgree() const +{ + return isDH(); +} + +PublicKey PKey::toPublicKey() const +{ + PublicKey k; + if (!isNull()) + assignToPublic(&k); + return k; +} + +PrivateKey PKey::toPrivateKey() const +{ + PrivateKey k; + if (!isNull() && isPrivate()) + assignToPrivate(&k); + return k; +} + +RSAPublicKey PKey::toRSAPublicKey() const +{ + RSAPublicKey k; + if (!isNull() && isRSA()) + assignToPublic(&k); + return k; +} + +RSAPrivateKey PKey::toRSAPrivateKey() const +{ + RSAPrivateKey k; + if (!isNull() && isRSA() && isPrivate()) + assignToPrivate(&k); + return k; +} + +DSAPublicKey PKey::toDSAPublicKey() const +{ + DSAPublicKey k; + if (!isNull() && isDSA()) + assignToPublic(&k); + return k; +} + +DSAPrivateKey PKey::toDSAPrivateKey() const +{ + DSAPrivateKey k; + if (!isNull() && isDSA() && isPrivate()) + assignToPrivate(&k); + return k; +} + +DHPublicKey PKey::toDHPublicKey() const +{ + DHPublicKey k; + if (!isNull() && isDH()) + assignToPublic(&k); + return k; +} + +DHPrivateKey PKey::toDHPrivateKey() const +{ + DHPrivateKey k; + if (!isNull() && isDH() && isPrivate()) + assignToPrivate(&k); + return k; +} + +bool PKey::operator==(const PKey &a) const +{ + if (isNull() || a.isNull() || type() != a.type()) + return false; + + if (a.isPrivate()) + return (toPrivateKey().toDER() == a.toPrivateKey().toDER()); + else + return (toPublicKey().toDER() == a.toPublicKey().toDER()); +} + +bool PKey::operator!=(const PKey &a) const +{ + return !(*this == a); +} + +//---------------------------------------------------------------------------- +// PublicKey +//---------------------------------------------------------------------------- +PublicKey::PublicKey() +{ +} + +PublicKey::PublicKey(const QString &type, const QString &provider) + : PKey(type, provider) +{ +} + +PublicKey::PublicKey(const PrivateKey &k) +{ + set(k.toPublicKey()); +} + +PublicKey::PublicKey(const QString &fileName) +{ + *this = fromPEMFile(fileName, nullptr, QString()); +} + +PublicKey::PublicKey(const PublicKey &from) + : PKey(from) +{ +} + +PublicKey::~PublicKey() +{ +} + +PublicKey &PublicKey::operator=(const PublicKey &from) +{ + PKey::operator=(from); + return *this; +} + +RSAPublicKey PublicKey::toRSA() const +{ + return toRSAPublicKey(); +} + +DSAPublicKey PublicKey::toDSA() const +{ + return toDSAPublicKey(); +} + +DHPublicKey PublicKey::toDH() const +{ + return toDHPublicKey(); +} + +bool PublicKey::canEncrypt() const +{ + return isRSA(); +} + +bool PublicKey::canDecrypt() const +{ + return isRSA(); +} + +bool PublicKey::canVerify() const +{ + return (isRSA() || isDSA()); +} + +int PublicKey::maximumEncryptSize(EncryptionAlgorithm alg) const +{ + const PKeyContext *ctx = qobject_cast(context()); + if (ctx) + return ctx->key()->maximumEncryptSize(alg); + else + return -1; +} + +SecureArray PublicKey::encrypt(const SecureArray &a, EncryptionAlgorithm alg) +{ + PKeyContext *ctx = qobject_cast(context()); + if (ctx) + return ctx->key()->encrypt(a, alg); + else + return SecureArray(); +} + +bool PublicKey::decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) +{ + PKeyContext *ctx = qobject_cast(context()); + if (ctx) + return ctx->key()->decrypt(in, out, alg); + else + return false; +} + +void PublicKey::startVerify(SignatureAlgorithm alg, SignatureFormat format) +{ + if (isDSA() && format == DefaultFormat) + format = IEEE_1363; + PKeyContext *ctx = qobject_cast(context()); + if (ctx) + ctx->key()->startVerify(alg, format); +} + +void PublicKey::update(const MemoryRegion &a) +{ + PKeyContext *ctx = qobject_cast(context()); + if (ctx) { + ctx->key()->update(a); + } +} + +bool PublicKey::validSignature(const QByteArray &sig) +{ + PKeyContext *ctx = qobject_cast(context()); + if (ctx) + return ctx->key()->endVerify(sig); + return false; +} + +bool PublicKey::verifyMessage(const MemoryRegion &a, + const QByteArray &sig, + SignatureAlgorithm alg, + SignatureFormat format) +{ + startVerify(alg, format); + update(a); + return validSignature(sig); +} + +QByteArray PublicKey::toDER() const +{ + QByteArray out; + const PKeyContext *cur = static_cast(context()); + Provider *p = providerForIOType(type(), cur); + if (!p) + return out; + if (cur->provider() == p) { + out = cur->publicToDER(); + } else { + PKeyContext *pk = static_cast(getContext(QStringLiteral("pkey"), p)); + if (pk && pk->importKey(cur->key())) + out = pk->publicToDER(); + delete pk; + } + return out; +} + +QString PublicKey::toPEM() const +{ + QString out; + const PKeyContext *cur = static_cast(context()); + if (!cur) + return out; + Provider *p = providerForIOType(type(), cur); + if (!p) + return out; + if (cur->provider() == p) { + out = cur->publicToPEM(); + } else { + PKeyContext *pk = static_cast(getContext(QStringLiteral("pkey"), p)); + if (pk && pk->importKey(cur->key())) + out = pk->publicToPEM(); + delete pk; + } + return out; +} + +bool PublicKey::toPEMFile(const QString &fileName) const +{ + return stringToFile(fileName, toPEM()); +} + +PublicKey PublicKey::fromDER(const QByteArray &a, ConvertResult *result, const QString &provider) +{ + return getKey, QByteArray>(provider, a, SecureArray(), result); +} + +PublicKey PublicKey::fromPEM(const QString &s, ConvertResult *result, const QString &provider) +{ + return getKey, QString>(provider, s, SecureArray(), result); +} + +PublicKey PublicKey::fromPEMFile(const QString &fileName, ConvertResult *result, const QString &provider) +{ + QString pem; + if (!stringFromFile(fileName, &pem)) { + if (result) + *result = ErrorFile; + return PublicKey(); + } + return fromPEM(pem, result, provider); +} + +//---------------------------------------------------------------------------- +// PrivateKey +//---------------------------------------------------------------------------- +PrivateKey::PrivateKey() +{ +} + +PrivateKey::PrivateKey(const QString &type, const QString &provider) + : PKey(type, provider) +{ +} + +PrivateKey::PrivateKey(const QString &fileName, const SecureArray &passphrase) +{ + *this = fromPEMFile(fileName, passphrase, nullptr, QString()); +} + +PrivateKey::PrivateKey(const PrivateKey &from) + : PKey(from) +{ +} + +PrivateKey::~PrivateKey() +{ +} + +PrivateKey &PrivateKey::operator=(const PrivateKey &from) +{ + PKey::operator=(from); + return *this; +} + +RSAPrivateKey PrivateKey::toRSA() const +{ + return toRSAPrivateKey(); +} + +DSAPrivateKey PrivateKey::toDSA() const +{ + return toDSAPrivateKey(); +} + +DHPrivateKey PrivateKey::toDH() const +{ + return toDHPrivateKey(); +} + +bool PrivateKey::canDecrypt() const +{ + return isRSA(); +} + +bool PrivateKey::canEncrypt() const +{ + return isRSA(); +} + +bool PrivateKey::canSign() const +{ + return (isRSA() || isDSA()); +} + +int PrivateKey::maximumEncryptSize(EncryptionAlgorithm alg) const +{ + return static_cast(context())->key()->maximumEncryptSize(alg); +} + +bool PrivateKey::decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) +{ + return static_cast(context())->key()->decrypt(in, out, alg); +} + +SecureArray PrivateKey::encrypt(const SecureArray &a, EncryptionAlgorithm alg) +{ + return static_cast(context())->key()->encrypt(a, alg); +} + +void PrivateKey::startSign(SignatureAlgorithm alg, SignatureFormat format) +{ + if (isDSA() && format == DefaultFormat) + format = IEEE_1363; + static_cast(context())->key()->startSign(alg, format); +} + +void PrivateKey::update(const MemoryRegion &a) +{ + static_cast(context())->key()->update(a); +} + +QByteArray PrivateKey::signature() +{ + return static_cast(context())->key()->endSign(); +} + +QByteArray PrivateKey::signMessage(const MemoryRegion &a, SignatureAlgorithm alg, SignatureFormat format) +{ + startSign(alg, format); + update(a); + return signature(); +} + +SymmetricKey PrivateKey::deriveKey(const PublicKey &theirs) +{ + const PKeyContext *theirContext = static_cast(theirs.context()); + return static_cast(context())->key()->deriveKey(*(theirContext->key())); +} + +QList PrivateKey::supportedPBEAlgorithms(const QString &provider) +{ + return getList(provider); +} + +SecureArray PrivateKey::toDER(const SecureArray &passphrase, PBEAlgorithm pbe) const +{ + SecureArray out; + if (pbe == PBEDefault) + pbe = get_pbe_default(); + const PKeyContext *cur = static_cast(context()); + Provider *p = providerForPBE(pbe, type(), cur); + if (!p) + return out; + if (cur->provider() == p) { + out = cur->privateToDER(passphrase, pbe); + } else { + PKeyContext *pk = static_cast(getContext(QStringLiteral("pkey"), p)); + if (pk->importKey(cur->key())) + out = pk->privateToDER(passphrase, pbe); + delete pk; + } + return out; +} + +QString PrivateKey::toPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const +{ + QString out; + if (pbe == PBEDefault) + pbe = get_pbe_default(); + const PKeyContext *cur = static_cast(context()); + Provider *p = providerForPBE(pbe, type(), cur); + if (!p) + return out; + if (cur->provider() == p) { + out = cur->privateToPEM(passphrase, pbe); + } else { + PKeyContext *pk = static_cast(getContext(QStringLiteral("pkey"), p)); + if (pk->importKey(cur->key())) + out = pk->privateToPEM(passphrase, pbe); + delete pk; + } + return out; +} + +bool PrivateKey::toPEMFile(const QString &fileName, const SecureArray &passphrase, PBEAlgorithm pbe) const +{ + return stringToFile(fileName, toPEM(passphrase, pbe)); +} + +PrivateKey +PrivateKey::fromDER(const SecureArray &a, const SecureArray &passphrase, ConvertResult *result, const QString &provider) +{ + return get_privatekey_der(a, QString(), (void *)&a, passphrase, result, provider); +} + +PrivateKey +PrivateKey::fromPEM(const QString &s, const SecureArray &passphrase, ConvertResult *result, const QString &provider) +{ + return get_privatekey_pem(s, QString(), (void *)&s, passphrase, result, provider); +} + +PrivateKey PrivateKey::fromPEMFile(const QString &fileName, + const SecureArray &passphrase, + ConvertResult *result, + const QString &provider) +{ + QString pem; + if (!stringFromFile(fileName, &pem)) { + if (result) + *result = ErrorFile; + return PrivateKey(); + } + return get_privatekey_pem(pem, fileName, nullptr, passphrase, result, provider); +} + +//---------------------------------------------------------------------------- +// KeyGenerator +//---------------------------------------------------------------------------- +class KeyGenerator::Private : public QObject +{ + Q_OBJECT +public: + KeyGenerator *parent; + bool blocking, wasBlocking; + PrivateKey key; + DLGroup group; + + PKeyBase *k; + PKeyContext *dest; + DLGroupContext *dc; + + Private(KeyGenerator *_parent) + : QObject(_parent) + , parent(_parent) + { + k = nullptr; + dest = nullptr; + dc = nullptr; + } + + ~Private() override + { + delete k; + delete dest; + delete dc; + } + +public Q_SLOTS: + void done() + { + if (!k->isNull()) { + if (!wasBlocking) { + k->setParent(nullptr); + k->moveToThread(nullptr); + } + dest->setKey(k); + k = nullptr; + + key.change(dest); + dest = nullptr; + } else { + delete k; + k = nullptr; + delete dest; + dest = nullptr; + } + + if (!wasBlocking) + emit parent->finished(); + } + + void done_group() + { + if (!dc->isNull()) { + BigInteger p, q, g; + dc->getResult(&p, &q, &g); + group = DLGroup(p, q, g); + } + delete dc; + dc = nullptr; + + if (!wasBlocking) + emit parent->finished(); + } +}; + +KeyGenerator::KeyGenerator(QObject *parent) + : QObject(parent) +{ + d = new Private(this); + d->blocking = true; +} + +KeyGenerator::~KeyGenerator() +{ + delete d; +} + +bool KeyGenerator::blockingEnabled() const +{ + return d->blocking; +} + +void KeyGenerator::setBlockingEnabled(bool b) +{ + d->blocking = b; +} + +bool KeyGenerator::isBusy() const +{ + return (d->k ? true : false); +} + +PrivateKey KeyGenerator::createRSA(int bits, int exp, const QString &provider) +{ + if (isBusy()) + return PrivateKey(); + + d->key = PrivateKey(); + d->wasBlocking = d->blocking; + d->k = static_cast(getContext(QStringLiteral("rsa"), provider)); + if (!d->k) + return PrivateKey(); + d->dest = static_cast(getContext(QStringLiteral("pkey"), d->k->provider())); + + if (!d->blocking) { + d->k->moveToThread(thread()); + d->k->setParent(d); + connect(d->k, &RSAContext::finished, d, &Private::done); + static_cast(d->k)->createPrivate(bits, exp, false); + } else { + static_cast(d->k)->createPrivate(bits, exp, true); + d->done(); + } + + return d->key; +} + +PrivateKey KeyGenerator::createDSA(const DLGroup &domain, const QString &provider) +{ + if (isBusy()) + return PrivateKey(); + + d->key = PrivateKey(); + d->wasBlocking = d->blocking; + d->k = static_cast(getContext(QStringLiteral("dsa"), provider)); + d->dest = static_cast(getContext(QStringLiteral("pkey"), d->k->provider())); + + if (!d->blocking) { + d->k->moveToThread(thread()); + d->k->setParent(d); + connect(d->k, &DSAContext::finished, d, &Private::done); + static_cast(d->k)->createPrivate(domain, false); + } else { + static_cast(d->k)->createPrivate(domain, true); + d->done(); + } + + return d->key; +} + +PrivateKey KeyGenerator::createDH(const DLGroup &domain, const QString &provider) +{ + if (isBusy()) + return PrivateKey(); + + d->key = PrivateKey(); + d->wasBlocking = d->blocking; + d->k = static_cast(getContext(QStringLiteral("dh"), provider)); + d->dest = static_cast(getContext(QStringLiteral("pkey"), d->k->provider())); + + if (!d->blocking) { + d->k->moveToThread(thread()); + d->k->setParent(d); + connect(d->k, &DHContext::finished, d, &Private::done); + static_cast(d->k)->createPrivate(domain, false); + } else { + static_cast(d->k)->createPrivate(domain, true); + d->done(); + } + + return d->key; +} + +PrivateKey KeyGenerator::key() const +{ + return d->key; +} + +DLGroup KeyGenerator::createDLGroup(QCA::DLGroupSet set, const QString &provider) +{ + if (isBusy()) + return DLGroup(); + + Provider *p; + if (!provider.isEmpty()) + p = providerForName(provider); + else + p = providerForGroupSet(set); + + d->dc = static_cast(getContext(QStringLiteral("dlgroup"), p)); + d->group = DLGroup(); + + if (d->dc) { + d->wasBlocking = d->blocking; + if (!d->blocking) { + connect(d->dc, &DLGroupContext ::finished, d, &Private::done_group); + d->dc->fetchGroup(set, false); + } else { + d->dc->fetchGroup(set, true); + d->done_group(); + } + } + + return d->group; +} + +DLGroup KeyGenerator::dlGroup() const +{ + return d->group; +} + +//---------------------------------------------------------------------------- +// RSAPublicKey +//---------------------------------------------------------------------------- +RSAPublicKey::RSAPublicKey() +{ +} + +RSAPublicKey::RSAPublicKey(const BigInteger &n, const BigInteger &e, const QString &provider) +{ + RSAContext *k = static_cast(getContext(QStringLiteral("rsa"), provider)); + k->createPublic(n, e); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +RSAPublicKey::RSAPublicKey(const RSAPrivateKey &k) + : PublicKey(k) +{ +} + +BigInteger RSAPublicKey::n() const +{ + return static_cast(static_cast(context())->key())->n(); +} + +BigInteger RSAPublicKey::e() const +{ + return static_cast(static_cast(context())->key())->e(); +} + +//---------------------------------------------------------------------------- +// RSAPrivateKey +//---------------------------------------------------------------------------- +RSAPrivateKey::RSAPrivateKey() +{ +} + +RSAPrivateKey::RSAPrivateKey(const BigInteger &n, + const BigInteger &e, + const BigInteger &p, + const BigInteger &q, + const BigInteger &d, + const QString &provider) +{ + RSAContext *k = static_cast(getContext(QStringLiteral("rsa"), provider)); + k->createPrivate(n, e, p, q, d); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +BigInteger RSAPrivateKey::n() const +{ + return static_cast(static_cast(context())->key())->n(); +} + +BigInteger RSAPrivateKey::e() const +{ + return static_cast(static_cast(context())->key())->e(); +} + +BigInteger RSAPrivateKey::p() const +{ + return static_cast(static_cast(context())->key())->p(); +} + +BigInteger RSAPrivateKey::q() const +{ + return static_cast(static_cast(context())->key())->q(); +} + +BigInteger RSAPrivateKey::d() const +{ + return static_cast(static_cast(context())->key())->d(); +} + +//---------------------------------------------------------------------------- +// DSAPublicKey +//---------------------------------------------------------------------------- +DSAPublicKey::DSAPublicKey() +{ +} + +DSAPublicKey::DSAPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider) +{ + DSAContext *k = static_cast(getContext(QStringLiteral("dsa"), provider)); + k->createPublic(domain, y); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +DSAPublicKey::DSAPublicKey(const DSAPrivateKey &k) + : PublicKey(k) +{ +} + +DLGroup DSAPublicKey::domain() const +{ + return static_cast(static_cast(context())->key())->domain(); +} + +BigInteger DSAPublicKey::y() const +{ + return static_cast(static_cast(context())->key())->y(); +} + +//---------------------------------------------------------------------------- +// DSAPrivateKey +//---------------------------------------------------------------------------- +DSAPrivateKey::DSAPrivateKey() +{ +} + +DSAPrivateKey::DSAPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider) +{ + DSAContext *k = static_cast(getContext(QStringLiteral("dsa"), provider)); + k->createPrivate(domain, y, x); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +DLGroup DSAPrivateKey::domain() const +{ + return static_cast(static_cast(context())->key())->domain(); +} + +BigInteger DSAPrivateKey::y() const +{ + return static_cast(static_cast(context())->key())->y(); +} + +BigInteger DSAPrivateKey::x() const +{ + return static_cast(static_cast(context())->key())->x(); +} + +//---------------------------------------------------------------------------- +// DHPublicKey +//---------------------------------------------------------------------------- +DHPublicKey::DHPublicKey() +{ +} + +DHPublicKey::DHPublicKey(const DLGroup &domain, const BigInteger &y, const QString &provider) +{ + DHContext *k = static_cast(getContext(QStringLiteral("dh"), provider)); + k->createPublic(domain, y); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +DHPublicKey::DHPublicKey(const DHPrivateKey &k) + : PublicKey(k) +{ +} + +DLGroup DHPublicKey::domain() const +{ + return static_cast(static_cast(context())->key())->domain(); +} + +BigInteger DHPublicKey::y() const +{ + return static_cast(static_cast(context())->key())->y(); +} + +//---------------------------------------------------------------------------- +// DHPrivateKey +//---------------------------------------------------------------------------- +DHPrivateKey::DHPrivateKey() +{ +} + +DHPrivateKey::DHPrivateKey(const DLGroup &domain, const BigInteger &y, const BigInteger &x, const QString &provider) +{ + DHContext *k = static_cast(getContext(QStringLiteral("dh"), provider)); + k->createPrivate(domain, y, x); + PKeyContext *c = static_cast(getContext(QStringLiteral("pkey"), k->provider())); + c->setKey(k); + change(c); +} + +DLGroup DHPrivateKey::domain() const +{ + return static_cast(static_cast(context())->key())->domain(); +} + +BigInteger DHPrivateKey::y() const +{ + return static_cast(static_cast(context())->key())->y(); +} + +BigInteger DHPrivateKey::x() const +{ + return static_cast(static_cast(context())->key())->x(); +} + +} + +#include "qca_publickey.moc" diff --git a/local/recipes/libs/qca/source/src/qca_safeobj.cpp b/local/recipes/libs/qca/source/src/qca_safeobj.cpp new file mode 100644 index 0000000000..b2ad388837 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_safeobj.cpp @@ -0,0 +1,50 @@ +/* + * qca_safeobj.h - Qt Cryptographic Architecture + * Copyright (C) 2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_safeobj.h" + +namespace QCA { + +// This function performs the following steps: +// obj->disconnect(owner); // to prevent future signals to owner +// obj->setParent(0); // to prevent delete if parent is deleted +// obj->deleteLater(); // now we can forget about the object +inline void releaseAndDeleteLater(QObject *owner, QObject *obj) +{ + obj->disconnect(owner); + obj->setParent(nullptr); + obj->deleteLater(); +} + +SafeSocketNotifier::SafeSocketNotifier(qintptr socket, QSocketNotifier::Type type, QObject *parent) + : QObject(parent) +{ + sn = new QSocketNotifier(socket, type, this); + connect(sn, &QSocketNotifier::activated, this, &SafeSocketNotifier::activated); +} + +SafeSocketNotifier::~SafeSocketNotifier() +{ + sn->setEnabled(false); + releaseAndDeleteLater(this, sn); +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_safeobj.h b/local/recipes/libs/qca/source/src/qca_safeobj.h new file mode 100644 index 0000000000..5c47adad84 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_safeobj.h @@ -0,0 +1,68 @@ +/* + * qca_safeobj.h - Qt Cryptographic Architecture + * Copyright (C) 2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef QCA_SAFEOBJ_H +#define QCA_SAFEOBJ_H + +// NOTE: this API is private to QCA + +#include +#include + +namespace QCA { + +class SafeSocketNotifier : public QObject +{ + Q_OBJECT +public: + SafeSocketNotifier(qintptr socket, QSocketNotifier::Type type, QObject *parent = nullptr); + + ~SafeSocketNotifier() override; + + bool isEnabled() const + { + return sn->isEnabled(); + } + qintptr socket() const + { + return sn->socket(); + } + QSocketNotifier::Type type() const + { + return sn->type(); + } + +public Q_SLOTS: + void setEnabled(bool enable) + { + sn->setEnabled(enable); + } + +Q_SIGNALS: + void activated(); + +private: + QSocketNotifier *sn; +}; + +} + +#endif diff --git a/local/recipes/libs/qca/source/src/qca_safetimer.cpp b/local/recipes/libs/qca/source/src/qca_safetimer.cpp new file mode 100644 index 0000000000..cd687744d7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_safetimer.cpp @@ -0,0 +1,238 @@ +/* + * qca_safetimer.cpp - Qt Cryptographic Architecture + * Copyright (C) 2014 Ivan Romanov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_safetimer.h" +#include +#include +#include + +// #define SAFETIMER_DEBUG + +#ifdef SAFETIMER_DEBUG +#include +#endif + +namespace QCA { + +class SafeTimer::Private : public QObject +{ + Q_OBJECT + friend class SafeTimer; + +public: + Private(QObject *parent = nullptr); + + int timerId; + int fixerTimerId; + bool isSingleShot; + int interval; + bool isActive; + QElapsedTimer elapsedTimer; + +public Q_SLOTS: + void fixTimer(); + +Q_SIGNALS: + void needFix(); + +protected: + bool event(QEvent *event) override; + void timerEvent(QTimerEvent *event) override; +}; + +SafeTimer::Private::Private(QObject *parent) + : QObject(parent) + , timerId(0) + , fixerTimerId(0) + , isSingleShot(false) + , interval(0) + , isActive(false) + , elapsedTimer(QElapsedTimer()) +{ + connect(this, &Private::needFix, this, &Private::fixTimer, Qt::QueuedConnection); +} + +void SafeTimer::Private::fixTimer() +{ + // Start special timer to align ressurected old timer + const int msec = qMax(0, interval - static_cast(elapsedTimer.elapsed())); + + fixerTimerId = startTimer(msec); +#ifdef SAFETIMER_DEBUG + qDebug() << "START FIXTIMER: id =" << fixerTimerId << ", thread =" << thread() << ", interval =" << msec + << parent(); +#endif +} + +bool SafeTimer::Private::event(QEvent *event) +{ + if (event->type() == QEvent::ThreadChange && fixerTimerId /* timer is actived */) { + // Timer dies when an object changes owner thread. This trick + // used to ressurect old timer in the new thread. + // Signal is emited in the old thread but will be gotten in the new one. +#ifdef SAFETIMER_DEBUG + qDebug() << "STOP FIXTIMER ON CHANGE THREAD: id =" << fixerTimerId << ", thread =" << thread() << parent(); +#endif + killTimer(fixerTimerId); + fixerTimerId = 0; + emit needFix(); + } + + return QObject::event(event); +} + +void SafeTimer::Private::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == fixerTimerId) { +#ifdef SAFETIMER_DEBUG + qDebug() << "STOP FIXTIMER ON TIMEOUT: id =" << fixerTimerId << ", thread =" << thread() << parent(); +#endif + killTimer(fixerTimerId); + fixerTimerId = 0; + + SafeTimer *safeTimer = qobject_cast(parent()); + // Emulate timeout signal of not yet ressurected timer + emit safeTimer->timeout(); + // Ressurect timer here if not a singleshot + if (!isSingleShot) + safeTimer->start(); + else + isActive = false; + } else { +#ifdef SAFETIMER_DEBUG + qDebug() << "BAD PRIVATE TIME EVENT: id =" << timerId << ", thread =" << thread() << this + << ", badId =" << event->timerId() << parent(); +#endif + } +} + +SafeTimer::SafeTimer(QObject *parent) + : QObject() + , d(new Private()) +{ + // It must be done here. Initialization list can't be used. + // Need to have proper class name. Look at TimerFixer::hook. + setParent(parent); + d->setParent(this); +} + +SafeTimer::~SafeTimer() +{ +} + +int SafeTimer::interval() const +{ + return d->interval; +} + +bool SafeTimer::isActive() const +{ + return d->isActive; +} + +bool SafeTimer::isSingleShot() const +{ + return d->isSingleShot; +} + +void SafeTimer::setInterval(int msec) +{ + d->interval = msec; +} + +void SafeTimer::setSingleShot(bool singleShot) +{ + d->isSingleShot = singleShot; +} + +void SafeTimer::start(int msec) +{ + d->interval = msec; + start(); +} + +void SafeTimer::start() +{ + stop(); + + d->elapsedTimer.start(); + d->timerId = QObject::startTimer(d->interval); + d->isActive = d->timerId > 0; + +#ifdef SAFETIMER_DEBUG + qDebug() << "START TIMER: id =" << d->timerId << ", thread =" << thread() << ", interval =" << d->interval << this; +#endif +} + +void SafeTimer::stop() +{ + if (d->timerId) { + QObject::killTimer(d->timerId); +#ifdef SAFETIMER_DEBUG + qDebug() << "STOP TIMER: id =" << d->timerId << ", thread =" << thread() << this; +#endif + d->timerId = 0; + } + + if (d->fixerTimerId) { +#ifdef SAFETIMER_DEBUG + qDebug() << "STOP FIXER TIMER: id =" << d->fixerTimerId << ", thread =" << thread() << this; +#endif + d->killTimer(d->fixerTimerId); + d->fixerTimerId = 0; + } + d->isActive = false; +} + +bool SafeTimer::event(QEvent *event) +{ + if (event->type() == QEvent::ThreadChange && d->timerId /* timer is actived */) { + // Timer dies when an object changes owner thread. This trick + // used to ressurect old timer in the new thread. + // Signal is emited in the old thread but will be gotten in the new one. +#ifdef SAFETIMER_DEBUG + qDebug() << "CHANGE THREAD: id =" << d->timerId << ", thread =" << thread() << this; +#endif + killTimer(d->timerId); + d->timerId = 0; + emit d->needFix(); + } + + return QObject::event(event); +} + +void SafeTimer::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == d->timerId) { + if (d->isSingleShot) + stop(); + emit timeout(); + } else { +#ifdef SAFETIMER_DEBUG + qDebug() << "BAD TIME EVENT: id =" << d->timerId << ", thread =" << thread() << this + << ", badId =" << event->timerId() << this; +#endif + } +} + +} // end namespace QCA + +#include "qca_safetimer.moc" diff --git a/local/recipes/libs/qca/source/src/qca_securelayer.cpp b/local/recipes/libs/qca/source/src/qca_securelayer.cpp new file mode 100644 index 0000000000..bd1e9d1de2 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_securelayer.cpp @@ -0,0 +1,1891 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_securelayer.h" + +#include "qca_safeobj.h" +#include "qca_safetimer.h" +#include "qcaprovider.h" + +#include +#include + +namespace QCA { + +Provider::Context *getContext(const QString &type, const QString &provider); + +enum ResetMode +{ + ResetSession = 0, + ResetSessionAndData = 1, + ResetAll = 2 +}; + +//---------------------------------------------------------------------------- +// LayerTracker +//---------------------------------------------------------------------------- +class LayerTracker +{ +private: + struct Item + { + int plain; + qint64 encoded; + }; + + int p; + QList list; + +public: + LayerTracker() + { + p = 0; + } + + void reset() + { + p = 0; + list.clear(); + } + + void addPlain(int plain) + { + p += plain; + } + + void specifyEncoded(int encoded, int plain) + { + // can't specify more bytes than we have + if (plain > p) + plain = p; + p -= plain; + Item i; + i.plain = plain; + i.encoded = encoded; + list += i; + } + + int finished(qint64 encoded) + { + int plain = 0; + for (QList::Iterator it = list.begin(); it != list.end();) { + Item &i = *it; + + // not enough? + if (encoded < i.encoded) { + i.encoded -= encoded; + break; + } + + encoded -= i.encoded; + plain += i.plain; + it = list.erase(it); + } + return plain; + } +}; + +//---------------------------------------------------------------------------- +// SecureLayer +//---------------------------------------------------------------------------- +SecureLayer::SecureLayer(QObject *parent) + : QObject(parent) +{ +} + +bool SecureLayer::isClosable() const +{ + return false; +} + +void SecureLayer::close() +{ +} + +QByteArray SecureLayer::readUnprocessed() +{ + return QByteArray(); +} + +//---------------------------------------------------------------------------- +// TLSSession +//---------------------------------------------------------------------------- +TLSSession::TLSSession() +{ +} + +TLSSession::TLSSession(const TLSSession &from) + : Algorithm(from) +{ +} + +TLSSession::~TLSSession() +{ +} + +TLSSession &TLSSession::operator=(const TLSSession &from) +{ + Algorithm::operator=(from); + return *this; +} + +bool TLSSession::isNull() const +{ + return (!context() ? true : false); +} + +//---------------------------------------------------------------------------- +// TLS +//---------------------------------------------------------------------------- +class TLS::Private : public QObject +{ + Q_OBJECT +public: + enum + { + OpStart, + OpUpdate + }; + + enum State + { + Inactive, + Initializing, + Handshaking, + Connected, + Closing + }; + + class Action + { + public: + enum Type + { + ReadyRead, + ReadyReadOutgoing, + Handshaken, + Close, + CheckPeerCertificate, + CertificateRequested, + HostNameReceived + }; + + int type; + + Action(int _type) + : type(_type) + { + } + }; + + TLS *q; + TLSContext *c; + TLS::Mode mode; + + // signal connected flags + bool connect_hostNameReceived; + bool connect_certificateRequested; + bool connect_peerCertificateAvailable; + bool connect_handshaken; + + // persistent settings (survives ResetSessionAndData) + CertificateChain localCert; + PrivateKey localKey; + CertificateCollection trusted; + bool con_ssfMode; + int con_minSSF, con_maxSSF; + QStringList con_cipherSuites; + bool tryCompress; + int packet_mtu; + QList issuerList; + TLSSession session; + + // session + State state; + bool blocked; + bool server; + QString host; + TLSContext::SessionInfo sessionInfo; + SafeTimer actionTrigger; + int op; + QList actionQueue; + bool need_update; + bool maybe_input; + bool emitted_hostNameReceived; + bool emitted_certificateRequested; + bool emitted_peerCertificateAvailable; + + // data (survives ResetSession) + CertificateChain peerCert; + Validity peerValidity; + bool hostMismatch; + Error errorCode; + + // stream i/o + QByteArray in, out; + QByteArray to_net, from_net; + QByteArray unprocessed; + int out_pending; + int to_net_encoded; + LayerTracker layer; + + // datagram i/o + QList packet_in, packet_out; + QList packet_to_net, packet_from_net; + int packet_out_pending; // packet count + QList packet_to_net_encoded; + + Private(TLS *_q, TLS::Mode _mode) + : QObject(_q) + , q(_q) + , mode(_mode) + , actionTrigger(this) + { + // c is 0 during initial reset, so we don't redundantly reset it + c = nullptr; + connect_hostNameReceived = false; + connect_certificateRequested = false; + connect_peerCertificateAvailable = false; + connect_handshaken = false; + server = false; + + connect(&actionTrigger, &SafeTimer::timeout, this, &Private::doNextAction); + actionTrigger.setSingleShot(true); + + reset(ResetAll); + + c = static_cast(q->context()); + + // parent the context to us, so that moveToThread works + c->setParent(this); + + connect(c, &TLSContext::resultsReady, this, &Private::tls_resultsReady); + connect(c, &TLSContext::dtlsTimeout, this, &Private::tls_dtlsTimeout); + } + + ~Private() override + { + // context is owned by Algorithm, unparent so we don't double-delete + c->setParent(nullptr); + } + + void reset(ResetMode mode) + { + if (c) + c->reset(); + + // if we reset while in client mode, then clear this list + // (it should only persist when used for server mode) + if (!server) + issuerList.clear(); + + state = Inactive; + blocked = false; + server = false; + host = QString(); + sessionInfo = TLSContext::SessionInfo(); + actionTrigger.stop(); + op = -1; + actionQueue.clear(); + need_update = false; + maybe_input = false; + emitted_hostNameReceived = false; + emitted_certificateRequested = false; + emitted_peerCertificateAvailable = false; + + out.clear(); + out_pending = 0; + packet_out.clear(); + packet_out_pending = 0; + + if (mode >= ResetSessionAndData) { + peerCert = CertificateChain(); + peerValidity = ErrorValidityUnknown; + hostMismatch = false; + errorCode = (TLS::Error)-1; + + in.clear(); + to_net.clear(); + from_net.clear(); + unprocessed.clear(); + to_net_encoded = 0; + layer.reset(); + + packet_in.clear(); + packet_to_net.clear(); + packet_from_net.clear(); + packet_to_net_encoded.clear(); + } + + if (mode >= ResetAll) { + localCert = CertificateChain(); + localKey = PrivateKey(); + trusted = CertificateCollection(); + con_ssfMode = true; + con_minSSF = 128; + con_maxSSF = -1; + con_cipherSuites = QStringList(); + tryCompress = false; + packet_mtu = -1; + issuerList.clear(); + session = TLSSession(); + } + } + + void start(bool serverMode) + { + state = Initializing; + server = serverMode; + + c->setup(serverMode, host, tryCompress); + + if (con_ssfMode) + c->setConstraints(con_minSSF, con_maxSSF); + else + c->setConstraints(con_cipherSuites); + + c->setCertificate(localCert, localKey); + c->setTrustedCertificates(trusted); + if (serverMode) + c->setIssuerList(issuerList); + if (!session.isNull()) { + TLSSessionContext *sc = static_cast(session.context()); + c->setSessionId(*sc); + } + c->setMTU(packet_mtu); + + QCA_logTextMessage(QStringLiteral("tls[%1]: c->start()").arg(q->objectName()), Logger::Information); + op = OpStart; + c->start(); + } + + void close() + { + QCA_logTextMessage(QStringLiteral("tls[%1]: close").arg(q->objectName()), Logger::Information); + + if (state != Connected) + return; + + state = Closing; + c->shutdown(); + } + + void continueAfterStep() + { + QCA_logTextMessage(QStringLiteral("tls[%1]: continueAfterStep").arg(q->objectName()), Logger::Information); + + if (!blocked) + return; + + blocked = false; + update(); + } + + void processNextAction() + { + if (actionQueue.isEmpty()) { + if (need_update) { + QCA_logTextMessage(QStringLiteral("tls[%1]: need_update").arg(q->objectName()), Logger::Information); + update(); + } + return; + } + + const Action a = actionQueue.takeFirst(); + + // set up for the next one, if necessary + if (!actionQueue.isEmpty() || need_update) { + if (!actionTrigger.isActive()) + actionTrigger.start(); + } + + if (a.type == Action::ReadyRead) { + emit q->readyRead(); + } else if (a.type == Action::ReadyReadOutgoing) { + emit q->readyReadOutgoing(); + } else if (a.type == Action::Handshaken) { + state = Connected; + + // write any app data waiting during handshake + if (!out.isEmpty()) { + need_update = true; + if (!actionTrigger.isActive()) + actionTrigger.start(); + } + + QCA_logTextMessage(QStringLiteral("tls[%1]: handshaken").arg(q->objectName()), Logger::Information); + + if (connect_handshaken) { + blocked = true; + emit q->handshaken(); + } + } else if (a.type == Action::Close) { + unprocessed = c->unprocessed(); + reset(ResetSession); + emit q->closed(); + } else if (a.type == Action::CheckPeerCertificate) { + peerCert = c->peerCertificateChain(); + if (!peerCert.isEmpty()) { + peerValidity = c->peerCertificateValidity(); + if (peerValidity == ValidityGood && !host.isEmpty() && !peerCert.primary().matchesHostName(host)) + hostMismatch = true; + } + + if (connect_peerCertificateAvailable) { + blocked = true; + emitted_peerCertificateAvailable = true; + emit q->peerCertificateAvailable(); + } + } else if (a.type == Action::CertificateRequested) { + issuerList = c->issuerList(); + if (connect_certificateRequested) { + blocked = true; + emitted_certificateRequested = true; + emit q->certificateRequested(); + } + } else if (a.type == Action::HostNameReceived) { + if (connect_hostNameReceived) { + blocked = true; + emitted_hostNameReceived = true; + emit q->hostNameReceived(); + } + } + } + + void update() + { + QCA_logTextMessage(QStringLiteral("tls[%1]: update").arg(q->objectName()), Logger::Information); + + if (blocked) { + QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while blocked").arg(q->objectName()), + Logger::Information); + return; + } + + if (!actionQueue.isEmpty()) { + QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while processing actions").arg(q->objectName()), + Logger::Information); + need_update = true; + return; + } + + // only allow one operation at a time + if (op != -1) { + QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while operation active").arg(q->objectName()), + Logger::Information); + need_update = true; + return; + } + + need_update = false; + + QByteArray arg_from_net, arg_from_app; + + if (state == Handshaking) { + // during handshake, only send from_net (no app data) + + if (mode == TLS::Stream) { + arg_from_net = from_net; + from_net.clear(); + } else { + // note: there may not be a packet + if (!packet_from_net.isEmpty()) + arg_from_net = packet_from_net.takeFirst(); + } + } else { + if (mode == TLS::Stream) { + if (!from_net.isEmpty()) { + arg_from_net = from_net; + from_net.clear(); + } + + if (!out.isEmpty()) { + out_pending += out.size(); + arg_from_app = out; + out.clear(); + } + } else { + if (!packet_from_net.isEmpty()) + arg_from_net = packet_from_net.takeFirst(); + + if (!packet_out.isEmpty()) { + arg_from_app = packet_out.takeFirst(); + ++packet_out_pending; + } + } + } + + if (arg_from_net.isEmpty() && arg_from_app.isEmpty() && !maybe_input) { + QCA_logTextMessage( + QStringLiteral("tls[%1]: ignoring update: no output and no expected input").arg(q->objectName()), + Logger::Information); + return; + } + + // clear this flag + maybe_input = false; + + QCA_logTextMessage(QStringLiteral("tls[%1]: c->update").arg(q->objectName()), Logger::Information); + op = OpUpdate; + c->update(arg_from_net, arg_from_app); + } + + void start_finished() + { + const bool ok = c->result() == TLSContext::Success; + if (!ok) { + reset(ResetSession); + errorCode = TLS::ErrorInit; + emit q->error(); + return; + } + + state = Handshaking; + + // immediately update so we can get the first packet to send + maybe_input = true; + update(); + } + + void update_finished() + { + const TLSContext::Result r = c->result(); + if (r == TLSContext::Error) { + if (state == Handshaking || state == Closing) { + reset(ResetSession); + errorCode = ErrorHandshake; + } else { + reset(ResetSession); + errorCode = ErrorCrypt; + } + + emit q->error(); + return; + } + + const QByteArray c_to_net = c->to_net(); + if (!c_to_net.isEmpty()) { + QCA_logTextMessage( + QStringLiteral("tls[%1]: to_net %2").arg(q->objectName(), QString::number(c_to_net.size())), + Logger::Information); + } + + if (state == Closing) { + if (mode == TLS::Stream) + to_net += c_to_net; + else + packet_to_net += c_to_net; + + if (!c_to_net.isEmpty()) + actionQueue += Action(Action::ReadyReadOutgoing); + + if (r == TLSContext::Success) + actionQueue += Action(Action::Close); + + processNextAction(); + return; + } else if (state == Handshaking) { + if (mode == TLS::Stream) + to_net += c_to_net; + else + packet_to_net += c_to_net; + + if (!c_to_net.isEmpty()) + actionQueue += Action(Action::ReadyReadOutgoing); + + bool clientHello = false; + bool serverHello = false; + if (server) + clientHello = c->clientHelloReceived(); + else + serverHello = c->serverHelloReceived(); + + // client specifies a host? + if (!emitted_hostNameReceived && clientHello) { + host = c->hostName(); + if (!host.isEmpty()) + actionQueue += Action(Action::HostNameReceived); + } + + // successful handshake or server hello means there might be a peer cert + if (!emitted_peerCertificateAvailable && (r == TLSContext::Success || (!server && serverHello))) + actionQueue += Action(Action::CheckPeerCertificate); + + // server requests a cert from us? + if (!emitted_certificateRequested && (serverHello && c->certificateRequested())) + actionQueue += Action(Action::CertificateRequested); + + if (r == TLSContext::Success) { + sessionInfo = c->sessionInfo(); + if (sessionInfo.id) { + TLSSessionContext *sc = static_cast(sessionInfo.id->clone()); + session.change(sc); + } + + actionQueue += Action(Action::Handshaken); + } + + processNextAction(); + return; + } else // Connected + { + const QByteArray c_to_app = c->to_app(); + if (!c_to_app.isEmpty()) { + QCA_logTextMessage( + QStringLiteral("tls[%1]: to_app %2").arg(q->objectName(), QString::number(c_to_app.size())), + Logger::Information); + } + + const bool eof = c->eof(); + int enc = -1; + if (!c_to_net.isEmpty()) + enc = c->encoded(); + + bool io_pending = false; + if (mode == TLS::Stream) { + if (!c_to_net.isEmpty()) + out_pending -= enc; + + if (out_pending > 0) { + maybe_input = true; + io_pending = true; + } + + if (!out.isEmpty()) + io_pending = true; + } else { + if (!c_to_net.isEmpty()) + --packet_out_pending; + + if (packet_out_pending > 0) { + maybe_input = true; + io_pending = true; + } + + if (!packet_out.isEmpty()) + io_pending = true; + } + + if (mode == TLS::Stream) { + to_net += c_to_net; + in += c_to_app; + to_net_encoded += enc; + } else { + packet_to_net += c_to_net; + packet_in += c_to_app; + } + + if (!c_to_net.isEmpty()) + actionQueue += Action(Action::ReadyReadOutgoing); + + if (!c_to_app.isEmpty()) + actionQueue += Action(Action::ReadyRead); + + if (eof) { + close(); + maybe_input = true; + } + + if (eof || io_pending) { + QCA_logTextMessage(QStringLiteral("tls[%1]: eof || io_pending").arg(q->objectName()), + Logger::Information); + update(); + } + + processNextAction(); + return; + } + } + +private Q_SLOTS: + void tls_resultsReady() + { + QCA_logTextMessage(QStringLiteral("tls[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information); + + Q_ASSERT(op != -1); + + int last_op = op; + op = -1; + + if (last_op == OpStart) + start_finished(); + else // OpUpdate + update_finished(); + } + + void tls_dtlsTimeout() + { + QCA_logTextMessage(QStringLiteral("tls[%1]: c->dtlsTimeout()").arg(q->objectName()), Logger::Information); + + maybe_input = true; + update(); + } + + void doNextAction() + { + processNextAction(); + } +}; + +TLS::TLS(QObject *parent, const QString &provider) + : SecureLayer(parent) + , Algorithm(QStringLiteral("tls"), provider) +{ + d = new Private(this, TLS::Stream); +} + +TLS::TLS(Mode mode, QObject *parent, const QString &provider) + : SecureLayer(parent) + , Algorithm(mode == Stream ? QStringLiteral("tls") : QStringLiteral("dtls"), provider) +{ + d = new Private(this, mode); +} + +TLS::~TLS() +{ + delete d; +} + +void TLS::reset() +{ + d->reset(ResetAll); +} + +QStringList TLS::supportedCipherSuites( + const Version &version) const // clazy:exclude=function-args-by-value TODO make it remove the & when we break ABI +{ + return d->c->supportedCipherSuites(version); +} + +void TLS::setCertificate(const CertificateChain &cert, const PrivateKey &key) +{ + d->localCert = cert; + d->localKey = key; + if (d->state != TLS::Private::Inactive) + d->c->setCertificate(cert, key); +} + +void TLS::setCertificate(const KeyBundle &kb) +{ + setCertificate(kb.certificateChain(), kb.privateKey()); +} + +CertificateCollection TLS::trustedCertificates() const +{ + return d->trusted; +} + +void TLS::setTrustedCertificates(const CertificateCollection &trusted) +{ + d->trusted = trusted; + if (d->state != TLS::Private::Inactive) + d->c->setTrustedCertificates(trusted); +} + +void TLS::setConstraints(SecurityLevel s) +{ + int min = 128; + switch (s) { + case SL_None: + min = 0; + break; + case SL_Integrity: + min = 1; + break; + case SL_Export: + min = 40; + break; + case SL_Baseline: + min = 128; + break; + case SL_High: + min = 129; + break; + case SL_Highest: + min = qMax(129, d->c->maxSSF()); + break; + } + + d->con_ssfMode = true; + d->con_minSSF = min; + d->con_maxSSF = -1; + + if (d->state != TLS::Private::Inactive) + d->c->setConstraints(d->con_minSSF, d->con_maxSSF); +} + +void TLS::setConstraints(int minSSF, int maxSSF) +{ + d->con_ssfMode = true; + d->con_minSSF = minSSF; + d->con_maxSSF = maxSSF; + + if (d->state != TLS::Private::Inactive) + d->c->setConstraints(d->con_minSSF, d->con_maxSSF); +} + +void TLS::setConstraints(const QStringList &cipherSuiteList) +{ + d->con_ssfMode = false; + d->con_cipherSuites = cipherSuiteList; + + if (d->state != TLS::Private::Inactive) + d->c->setConstraints(d->con_cipherSuites); +} + +QList TLS::issuerList() const +{ + return d->issuerList; +} + +void TLS::setIssuerList(const QList &issuers) +{ + d->issuerList = issuers; + if (d->state != TLS::Private::Inactive) + d->c->setIssuerList(issuers); +} + +void TLS::setSession(const TLSSession &session) +{ + d->session = session; +} + +bool TLS::canCompress() const +{ + return d->c->canCompress(); +} + +bool TLS::canSetHostName() const +{ + return d->c->canSetHostName(); +} + +bool TLS::compressionEnabled() const +{ + return d->tryCompress; +} + +void TLS::setCompressionEnabled(bool b) +{ + d->tryCompress = b; +} + +void TLS::startClient(const QString &host) +{ + d->reset(ResetSessionAndData); + d->host = host; + d->issuerList.clear(); + + // client mode + d->start(false); +} + +void TLS::startServer() +{ + d->reset(ResetSessionAndData); + + // server mode + d->start(true); +} + +void TLS::continueAfterStep() +{ + d->continueAfterStep(); +} + +bool TLS::isHandshaken() const +{ + if (d->state == TLS::Private::Connected || d->state == TLS::Private::Closing) + return true; + else + return false; +} + +bool TLS::isCompressed() const +{ + return d->sessionInfo.isCompressed; +} + +TLS::Version TLS::version() const +{ + return d->sessionInfo.version; +} + +QString TLS::cipherSuite() const +{ + return d->sessionInfo.cipherSuite; +} + +int TLS::cipherBits() const +{ + return d->sessionInfo.cipherBits; +} + +int TLS::cipherMaxBits() const +{ + return d->sessionInfo.cipherMaxBits; +} + +TLSSession TLS::session() const +{ + return d->session; +} + +TLS::Error TLS::errorCode() const +{ + return d->errorCode; +} + +TLS::IdentityResult TLS::peerIdentityResult() const +{ + if (d->peerCert.isEmpty()) + return NoCertificate; + + if (d->peerValidity != ValidityGood) + return InvalidCertificate; + + if (d->hostMismatch) + return HostMismatch; + + return Valid; +} + +Validity TLS::peerCertificateValidity() const +{ + return d->peerValidity; +} + +CertificateChain TLS::localCertificateChain() const +{ + return d->localCert; +} + +PrivateKey TLS::localPrivateKey() const +{ + return d->localKey; +} + +CertificateChain TLS::peerCertificateChain() const +{ + return d->peerCert; +} + +bool TLS::isClosable() const +{ + return true; +} + +int TLS::bytesAvailable() const +{ + if (d->mode == Stream) + return d->in.size(); + else + return 0; +} + +int TLS::bytesOutgoingAvailable() const +{ + if (d->mode == Stream) + return d->to_net.size(); + else + return 0; +} + +void TLS::close() +{ + d->close(); + d->update(); +} + +void TLS::write(const QByteArray &a) +{ + if (d->mode == Stream) { + d->out.append(a); + d->layer.addPlain(a.size()); + } else + d->packet_out.append(a); + QCA_logTextMessage(QStringLiteral("tls[%1]: write").arg(objectName()), Logger::Information); + d->update(); +} + +QByteArray TLS::read() +{ + if (d->mode == Stream) { + const QByteArray a = d->in; + d->in.clear(); + return a; + } else { + if (!d->packet_in.isEmpty()) + return d->packet_in.takeFirst(); + else + return QByteArray(); + } +} + +void TLS::writeIncoming(const QByteArray &a) +{ + if (d->mode == Stream) + d->from_net.append(a); + else + d->packet_from_net.append(a); + QCA_logTextMessage(QStringLiteral("tls[%1]: writeIncoming %2").arg(objectName(), QString::number(a.size())), + Logger::Information); + d->update(); +} + +QByteArray TLS::readOutgoing(int *plainBytes) +{ + if (d->mode == Stream) { + const QByteArray a = d->to_net; + d->to_net.clear(); + if (plainBytes) + *plainBytes = d->to_net_encoded; + d->layer.specifyEncoded(a.size(), d->to_net_encoded); + d->to_net_encoded = 0; + return a; + } else { + if (!d->packet_to_net.isEmpty()) { + const QByteArray a = d->packet_to_net.takeFirst(); + const int x = d->packet_to_net_encoded.takeFirst(); + if (plainBytes) + *plainBytes = x; + return a; + } else { + if (plainBytes) + *plainBytes = 0; + return QByteArray(); + } + } +} + +QByteArray TLS::readUnprocessed() +{ + if (d->mode == Stream) { + const QByteArray a = d->unprocessed; + d->unprocessed.clear(); + return a; + } else + return QByteArray(); +} + +int TLS::convertBytesWritten(qint64 bytes) +{ + return d->layer.finished(bytes); +} + +int TLS::packetsAvailable() const +{ + return d->packet_in.count(); +} + +int TLS::packetsOutgoingAvailable() const +{ + return d->packet_to_net.count(); +} + +int TLS::packetMTU() const +{ + return d->packet_mtu; +} + +void TLS::setPacketMTU(int size) const +{ + d->packet_mtu = size; + if (d->state != TLS::Private::Inactive) + d->c->setMTU(size); +} + +void TLS::connectNotify(const QMetaMethod &signal) +{ + if (signal == QMetaMethod::fromSignal(&TLS::hostNameReceived)) + d->connect_hostNameReceived = true; + else if (signal == QMetaMethod::fromSignal(&TLS::certificateRequested)) + d->connect_certificateRequested = true; + else if (signal == QMetaMethod::fromSignal(&TLS::peerCertificateAvailable)) + d->connect_peerCertificateAvailable = true; + else if (signal == QMetaMethod::fromSignal(&TLS::handshaken)) + d->connect_handshaken = true; +} + +void TLS::disconnectNotify(const QMetaMethod &signal) +{ + if (signal == QMetaMethod::fromSignal(&TLS::hostNameReceived)) + d->connect_hostNameReceived = false; + else if (signal == QMetaMethod::fromSignal(&TLS::certificateRequested)) + d->connect_certificateRequested = false; + else if (signal == QMetaMethod::fromSignal(&TLS::peerCertificateAvailable)) + d->connect_peerCertificateAvailable = false; + else if (signal == QMetaMethod::fromSignal(&TLS::handshaken)) + d->connect_handshaken = false; +} + +//---------------------------------------------------------------------------- +// SASL::Params +//---------------------------------------------------------------------------- +class SASL::Params::Private +{ +public: + bool needUsername, canSendAuthzid, needPassword, canSendRealm; +}; + +SASL::Params::Params() + : d(new Private) +{ +} + +SASL::Params::Params(bool user, bool authzid, bool pass, bool realm) + : d(new Private) +{ + d->needUsername = user; + d->canSendAuthzid = authzid; + d->needPassword = pass; + d->canSendRealm = realm; +} + +SASL::Params::Params(const SASL::Params &from) + : d(new Private(*from.d)) +{ +} + +SASL::Params::~Params() +{ + delete d; +} + +SASL::Params &SASL::Params::operator=(const SASL::Params &from) +{ + *d = *from.d; + return *this; +} + +bool SASL::Params::needUsername() const +{ + return d->needUsername; +} + +bool SASL::Params::canSendAuthzid() const +{ + return d->canSendAuthzid; +} + +bool SASL::Params::needPassword() const +{ + return d->needPassword; +} + +bool SASL::Params::canSendRealm() const +{ + return d->canSendRealm; +} + +//---------------------------------------------------------------------------- +// SASL +//---------------------------------------------------------------------------- +/* + These don't map, but I don't think it matters much.. + SASL_TRYAGAIN (-8) transient failure (e.g., weak key) + SASL_BADMAC (-9) integrity check failed + -- client only codes -- + SASL_WRONGMECH (-11) mechanism doesn't support requested feature + SASL_NEWSECRET (-12) new secret needed + -- server only codes -- + SASL_TRANS (-17) One time use of a plaintext password will + enable requested mechanism for user + SASL_PWLOCK (-21) password locked + SASL_NOCHANGE (-22) requested change was not needed +*/ + +class SASL::Private : public QObject +{ + Q_OBJECT +public: + enum + { + OpStart, + OpServerFirstStep, + OpNextStep, + OpTryAgain, + OpUpdate + }; + + class Action + { + public: + enum Type + { + ClientStarted, + NextStep, + Authenticated, + ReadyRead, + ReadyReadOutgoing + }; + + int type; + QByteArray stepData; + bool haveInit; + + Action(int _type) + : type(_type) + { + } + + Action(int _type, const QByteArray &_stepData) + : type(_type) + , stepData(_stepData) + { + } + + Action(int _type, bool _haveInit, const QByteArray &_stepData) + : type(_type) + , stepData(_stepData) + , haveInit(_haveInit) + { + } + }; + + SASL *q; + SASLContext *c; + + // persistent settings (survives ResetSessionAndData) + AuthFlags auth_flags; + int ssfmin, ssfmax; + QString ext_authid; + int ext_ssf; + bool localSet, remoteSet; + SASLContext::HostPort local, remote; + bool set_username, set_authzid, set_password, set_realm; + QString username, authzid, realm; + SecureArray password; + + // session + bool server; + QStringList mechlist; + QString server_realm; + bool allowClientSendFirst; + bool disableServerSendLast; + SafeTimer actionTrigger; + int op; + QList actionQueue; + bool need_update; + bool first; + bool authed; + + // data (survives ResetSession) + QString mech; // selected mech + Error errorCode; + + // stream i/o + QByteArray in, out; + QByteArray to_net, from_net; + int out_pending; + int to_net_encoded; + LayerTracker layer; + + Private(SASL *_q) + : QObject(_q) + , q(_q) + , actionTrigger(this) + { + c = nullptr; + set_username = false; + set_authzid = false; + set_password = false; + set_realm = false; + + connect(&actionTrigger, &SafeTimer::timeout, this, &Private::doNextAction); + actionTrigger.setSingleShot(true); + + reset(ResetAll); + + c = static_cast(q->context()); + + // parent the context to us, so that moveToThread works + c->setParent(this); + + connect(c, &SASLContext::resultsReady, this, &Private::sasl_resultsReady); + } + + ~Private() override + { + // context is owned by Algorithm, unparent so we don't double-delete + c->setParent(nullptr); + } + + void reset(ResetMode mode) + { + if (c) + c->reset(); + + server = false; + mechlist.clear(); + server_realm = QString(); + allowClientSendFirst = false; + disableServerSendLast = true; + actionTrigger.stop(); + op = -1; + actionQueue.clear(); + need_update = false; + first = false; + authed = false; + + out.clear(); + out_pending = 0; + + if (mode >= ResetSessionAndData) { + mech = QString(); + errorCode = (SASL::Error)-1; + + in.clear(); + to_net.clear(); + from_net.clear(); + to_net_encoded = 0; + layer.reset(); + } + + if (mode >= ResetAll) { + auth_flags = SASL::AuthFlagsNone; + ssfmin = 0; + ssfmax = 0; + ext_authid = QString(); + ext_ssf = 0; + localSet = false; + remoteSet = false; + local = SASLContext::HostPort(); + remote = SASLContext::HostPort(); + + set_username = false; + username = QString(); + set_authzid = false; + authzid = QString(); + set_password = false; + password = SecureArray(); + set_realm = false; + realm = QString(); + } + } + + void setup(const QString &service, const QString &host) + { + c->setup(service, host, localSet ? &local : nullptr, remoteSet ? &remote : nullptr, ext_authid, ext_ssf); + c->setConstraints(auth_flags, ssfmin, ssfmax); + + QString *p_username = nullptr; + QString *p_authzid = nullptr; + SecureArray *p_password = nullptr; + QString *p_realm = nullptr; + + if (set_username) + p_username = &username; + if (set_authzid) + p_authzid = &authzid; + if (set_password) + p_password = &password; + if (set_realm) + p_realm = &realm; + + c->setClientParams(p_username, p_authzid, p_password, p_realm); + } + + void start() + { + op = OpStart; + first = true; + + if (server) { + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->startServer()").arg(q->objectName()), Logger::Information); + c->startServer(server_realm, disableServerSendLast); + } else { + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->startClient()").arg(q->objectName()), Logger::Information); + c->startClient(mechlist, allowClientSendFirst); + } + } + + void putServerFirstStep(const QString &mech, const QByteArray *clientInit) + { + if (op != -1) + return; + + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->serverFirstStep()").arg(q->objectName()), Logger::Information); + op = OpServerFirstStep; + c->serverFirstStep(mech, clientInit); + } + + void putStep(const QByteArray &stepData) + { + if (op != -1) + return; + + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->nextStep()").arg(q->objectName()), Logger::Information); + op = OpNextStep; + c->nextStep(stepData); + } + + void tryAgain() + { + if (op != -1) + return; + + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->tryAgain()").arg(q->objectName()), Logger::Information); + op = OpTryAgain; + c->tryAgain(); + } + + void processNextAction() + { + if (actionQueue.isEmpty()) { + if (need_update) + update(); + return; + } + + const Action a = actionQueue.takeFirst(); + + // set up for the next one, if necessary + if (!actionQueue.isEmpty() || need_update) { + if (!actionTrigger.isActive()) + actionTrigger.start(); + } + + if (a.type == Action::ClientStarted) { + emit q->clientStarted(a.haveInit, a.stepData); + } else if (a.type == Action::NextStep) { + emit q->nextStep(a.stepData); + } else if (a.type == Action::Authenticated) { + authed = true; + + // write any app data waiting during authentication + if (!out.isEmpty()) { + need_update = true; + if (!actionTrigger.isActive()) + actionTrigger.start(); + } + + QCA_logTextMessage(QStringLiteral("sasl[%1]: authenticated").arg(q->objectName()), Logger::Information); + emit q->authenticated(); + } else if (a.type == Action::ReadyRead) { + emit q->readyRead(); + } else if (a.type == Action::ReadyReadOutgoing) { + emit q->readyReadOutgoing(); + } + } + + void update() + { + // defer writes while authenticating + if (!authed) { + QCA_logTextMessage( + QStringLiteral("sasl[%1]: ignoring update while not yet authenticated").arg(q->objectName()), + Logger::Information); + return; + } + + if (!actionQueue.isEmpty()) { + QCA_logTextMessage( + QStringLiteral("sasl[%1]: ignoring update while processing actions").arg(q->objectName()), + Logger::Information); + need_update = true; + return; + } + + // only allow one operation at a time + if (op != -1) { + QCA_logTextMessage(QStringLiteral("sasl[%1]: ignoring update while operation active").arg(q->objectName()), + Logger::Information); + need_update = true; + return; + } + + need_update = false; + + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->update()").arg(q->objectName()), Logger::Information); + op = OpUpdate; + out_pending += out.size(); + c->update(from_net, out); + from_net.clear(); + out.clear(); + } + +private Q_SLOTS: + void sasl_resultsReady() + { + QCA_logTextMessage(QStringLiteral("sasl[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information); + + int last_op = op; + op = -1; + + const SASLContext::Result r = c->result(); + + if (last_op == OpStart) { + if (server) { + if (r != SASLContext::Success) { + errorCode = SASL::ErrorInit; + emit q->error(); + return; + } + + emit q->serverStarted(); + return; + } else // client + { + mech = c->mech(); + + // fall into this logic + last_op = OpTryAgain; + } + } else if (last_op == OpServerFirstStep) { + // fall into this logic + last_op = OpTryAgain; + } else if (last_op == OpNextStep) { + // fall into this logic + last_op = OpTryAgain; + } + + if (last_op == OpTryAgain) { + if (server) { + if (r == SASLContext::Continue) { + emit q->nextStep(c->stepData()); + return; + } else if (r == SASLContext::AuthCheck) { + emit q->authCheck(c->username(), c->authzid()); + return; + } else if (r == SASLContext::Success) { + if (!disableServerSendLast) + actionQueue += Action(Action::NextStep, c->stepData()); + + actionQueue += Action(Action::Authenticated); + + processNextAction(); + return; + } else // error + { + errorCode = SASL::ErrorHandshake; + emit q->error(); + return; + } + } else // client + { + if (first) { + if (r == SASLContext::Error) { + if (first) + errorCode = SASL::ErrorInit; + else + errorCode = SASL::ErrorHandshake; + emit q->error(); + return; + } else if (r == SASLContext::Params) { + const Params np = c->clientParams(); + emit q->needParams(np); + return; + } + + first = false; + actionQueue += Action(Action::ClientStarted, c->haveClientInit(), c->stepData()); + if (r == SASLContext::Success) + actionQueue += Action(Action::Authenticated); + + processNextAction(); + return; + } else { + if (r == SASLContext::Error) { + errorCode = ErrorHandshake; + emit q->error(); + return; + } else if (r == SASLContext::Params) { + const Params np = c->clientParams(); + emit q->needParams(np); + return; + } else if (r == SASLContext::Continue) { + emit q->nextStep(c->stepData()); + return; + } else if (r == SASLContext::Success) { + actionQueue += Action(Action::NextStep, c->stepData()); + actionQueue += Action(Action::Authenticated); + + processNextAction(); + return; + } + } + } + } else if (last_op == OpUpdate) { + if (r != SASLContext::Success) { + errorCode = ErrorCrypt; + emit q->error(); + return; + } + + const QByteArray c_to_net = c->to_net(); + const QByteArray c_to_app = c->to_app(); + int enc = -1; + if (!c_to_net.isEmpty()) + enc = c->encoded(); + + bool io_pending = false; + if (!c_to_net.isEmpty()) + out_pending -= enc; + + if (out_pending > 0) + io_pending = true; + + if (!out.isEmpty()) + io_pending = true; + + to_net += c_to_net; + in += c_to_app; + to_net_encoded += enc; + + if (!c_to_net.isEmpty()) + actionQueue += Action(Action::ReadyReadOutgoing); + + if (!c_to_app.isEmpty()) + actionQueue += Action(Action::ReadyRead); + + if (io_pending) + update(); + + processNextAction(); + return; + } + } + + void doNextAction() + { + processNextAction(); + } +}; + +SASL::SASL(QObject *parent, const QString &provider) + : SecureLayer(parent) + , Algorithm(QStringLiteral("sasl"), provider) +{ + d = new Private(this); +} + +SASL::~SASL() +{ + delete d; +} + +void SASL::reset() +{ + d->reset(ResetAll); +} + +SASL::Error SASL::errorCode() const +{ + return d->errorCode; +} + +SASL::AuthCondition SASL::authCondition() const +{ + return d->c->authCondition(); +} + +void SASL::setConstraints(AuthFlags f, SecurityLevel s) +{ + int min = 0; + if (s == SL_Integrity) + min = 1; + else if (s == SL_Export) + min = 56; + else if (s == SL_Baseline) + min = 128; + else if (s == SL_High) + min = 192; + else if (s == SL_Highest) + min = 256; + + setConstraints(f, min, 256); +} + +void SASL::setConstraints(AuthFlags f, int minSSF, int maxSSF) +{ + d->auth_flags = f; + + d->ssfmin = minSSF; + d->ssfmax = maxSSF; +} + +void SASL::setExternalAuthId(const QString &authid) +{ + d->ext_authid = authid; +} + +void SASL::setExternalSSF(int strength) +{ + d->ext_ssf = strength; +} + +void SASL::setLocalAddress(const QString &addr, quint16 port) +{ + d->localSet = true; + d->local.addr = addr; + d->local.port = port; +} + +void SASL::setRemoteAddress(const QString &addr, quint16 port) +{ + d->remoteSet = true; + d->remote.addr = addr; + d->remote.port = port; +} + +void SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, ClientSendMode mode) +{ + d->reset(ResetSessionAndData); + d->setup(service, host); + d->server = false; + d->mechlist = mechlist; + d->allowClientSendFirst = (mode == AllowClientSendFirst); + d->start(); +} + +void SASL::startServer(const QString &service, const QString &host, const QString &realm, ServerSendMode mode) +{ + d->reset(ResetSessionAndData); + d->setup(service, host); + d->server = true; + d->server_realm = realm; + d->disableServerSendLast = (mode == DisableServerSendLast); + d->start(); +} + +void SASL::putServerFirstStep(const QString &mech) +{ + d->putServerFirstStep(mech, nullptr); +} + +void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit) +{ + d->putServerFirstStep(mech, &clientInit); +} + +void SASL::putStep(const QByteArray &stepData) +{ + d->putStep(stepData); +} + +void SASL::setUsername(const QString &user) +{ + d->set_username = true; + d->username = user; + d->c->setClientParams(&user, nullptr, nullptr, nullptr); +} + +void SASL::setAuthzid(const QString &authzid) +{ + d->set_authzid = true; + d->authzid = authzid; + d->c->setClientParams(nullptr, &authzid, nullptr, nullptr); +} + +void SASL::setPassword(const SecureArray &pass) +{ + d->set_password = true; + d->password = pass; + d->c->setClientParams(nullptr, nullptr, &pass, nullptr); +} + +void SASL::setRealm(const QString &realm) +{ + d->set_realm = true; + d->realm = realm; + d->c->setClientParams(nullptr, nullptr, nullptr, &realm); +} + +void SASL::continueAfterParams() +{ + d->tryAgain(); +} + +void SASL::continueAfterAuthCheck() +{ + d->tryAgain(); +} + +QString SASL::mechanism() const +{ + return d->mech; +} + +QStringList SASL::mechanismList() const +{ + return d->c->mechlist(); +} + +QStringList SASL::realmList() const +{ + return d->c->realmlist(); +} + +int SASL::ssf() const +{ + return d->c->ssf(); +} + +int SASL::bytesAvailable() const +{ + return d->in.size(); +} + +int SASL::bytesOutgoingAvailable() const +{ + return d->to_net.size(); +} + +void SASL::write(const QByteArray &a) +{ + d->out.append(a); + d->layer.addPlain(a.size()); + d->update(); +} + +QByteArray SASL::read() +{ + const QByteArray a = d->in; + d->in.clear(); + return a; +} + +void SASL::writeIncoming(const QByteArray &a) +{ + d->from_net.append(a); + d->update(); +} + +QByteArray SASL::readOutgoing(int *plainBytes) +{ + const QByteArray a = d->to_net; + d->to_net.clear(); + if (plainBytes) + *plainBytes = d->to_net_encoded; + d->layer.specifyEncoded(a.size(), d->to_net_encoded); + d->to_net_encoded = 0; + return a; +} + +int SASL::convertBytesWritten(qint64 bytes) +{ + return d->layer.finished(bytes); +} + +} + +#include "qca_securelayer.moc" diff --git a/local/recipes/libs/qca/source/src/qca_securemessage.cpp b/local/recipes/libs/qca/source/src/qca_securemessage.cpp new file mode 100644 index 0000000000..f233986e5c --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_securemessage.cpp @@ -0,0 +1,683 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_securemessage.h" + +#include "qca_safeobj.h" +#include "qca_safetimer.h" +#include "qcaprovider.h" + +namespace QCA { + +Provider::Context *getContext(const QString &type, const QString &provider); + +//---------------------------------------------------------------------------- +// SecureMessageKey +//---------------------------------------------------------------------------- +class SecureMessageKey::Private : public QSharedData +{ +public: + SecureMessageKey::Type type; + PGPKey pgp_pub, pgp_sec; + CertificateChain cert_pub; + PrivateKey cert_sec; + + Private() + { + type = SecureMessageKey::None; + } + + // set the proper type, and reset the opposite data structures if needed + void ensureType(SecureMessageKey::Type t) + { + // if we were non-null and changed, we may need to reset some things + if (type != SecureMessageKey::None && t != type) { + if (type == SecureMessageKey::X509) { + cert_pub = CertificateChain(); + cert_sec = PrivateKey(); + } else if (type == SecureMessageKey::PGP) { + pgp_pub = PGPKey(); + pgp_sec = PGPKey(); + } + } + type = t; + } +}; + +SecureMessageKey::SecureMessageKey() + : d(new Private) +{ +} + +SecureMessageKey::SecureMessageKey(const SecureMessageKey &from) + : d(from.d) +{ +} + +SecureMessageKey::~SecureMessageKey() +{ +} + +SecureMessageKey &SecureMessageKey::operator=(const SecureMessageKey &from) +{ + d = from.d; + return *this; +} + +bool SecureMessageKey::isNull() const +{ + return (d->type == None); +} + +SecureMessageKey::Type SecureMessageKey::type() const +{ + return d->type; +} + +PGPKey SecureMessageKey::pgpPublicKey() const +{ + return d->pgp_pub; +} + +PGPKey SecureMessageKey::pgpSecretKey() const +{ + return d->pgp_sec; +} + +void SecureMessageKey::setPGPPublicKey(const PGPKey &pub) +{ + d->ensureType(SecureMessageKey::PGP); + d->pgp_pub = pub; +} + +void SecureMessageKey::setPGPSecretKey(const PGPKey &sec) +{ + d->ensureType(SecureMessageKey::PGP); + Q_ASSERT(sec.isSecret()); + d->pgp_sec = sec; +} + +CertificateChain SecureMessageKey::x509CertificateChain() const +{ + return d->cert_pub; +} + +PrivateKey SecureMessageKey::x509PrivateKey() const +{ + return d->cert_sec; +} + +void SecureMessageKey::setX509CertificateChain(const CertificateChain &c) +{ + d->ensureType(SecureMessageKey::X509); + d->cert_pub = c; +} + +void SecureMessageKey::setX509PrivateKey(const PrivateKey &k) +{ + d->ensureType(SecureMessageKey::X509); + d->cert_sec = k; +} + +void SecureMessageKey::setX509KeyBundle(const KeyBundle &kb) +{ + setX509CertificateChain(kb.certificateChain()); + setX509PrivateKey(kb.privateKey()); +} + +bool SecureMessageKey::havePrivate() const +{ + if (d->type == SecureMessageKey::PGP && !d->pgp_sec.isNull()) + return true; + else if (d->type == SecureMessageKey::X509 && !d->cert_sec.isNull()) + return true; + return false; +} + +QString SecureMessageKey::name() const +{ + if (d->type == SecureMessageKey::PGP && !d->pgp_pub.isNull()) + return d->pgp_pub.primaryUserId(); + else if (d->type == SecureMessageKey::X509 && !d->cert_pub.isEmpty()) + return d->cert_pub.primary().commonName(); + else + return QString(); +} + +//---------------------------------------------------------------------------- +// SecureMessageSignature +//---------------------------------------------------------------------------- +class SecureMessageSignature::Private : public QSharedData +{ +public: + SecureMessageSignature::IdentityResult r; + Validity v; + SecureMessageKey key; + QDateTime ts; + + Private() + { + r = SecureMessageSignature::NoKey; + v = ErrorValidityUnknown; + } +}; + +SecureMessageSignature::SecureMessageSignature() + : d(new Private) +{ +} + +SecureMessageSignature::SecureMessageSignature(IdentityResult r, + Validity v, + const SecureMessageKey &key, + const QDateTime &ts) + : d(new Private) +{ + d->r = r; + d->v = v; + d->key = key; + d->ts = ts; +} + +SecureMessageSignature::SecureMessageSignature(const SecureMessageSignature &from) + : d(from.d) +{ +} + +SecureMessageSignature::~SecureMessageSignature() +{ +} + +SecureMessageSignature &SecureMessageSignature::operator=(const SecureMessageSignature &from) +{ + d = from.d; + return *this; +} + +SecureMessageSignature::IdentityResult SecureMessageSignature::identityResult() const +{ + return d->r; +} + +Validity SecureMessageSignature::keyValidity() const +{ + return d->v; +} + +SecureMessageKey SecureMessageSignature::key() const +{ + return d->key; +} + +QDateTime SecureMessageSignature::timestamp() const +{ + return d->ts; +} + +//---------------------------------------------------------------------------- +// SecureMessage +//---------------------------------------------------------------------------- +enum ResetMode +{ + ResetSession = 0, + ResetSessionAndData = 1, + ResetAll = 2 +}; + +class SecureMessage::Private : public QObject +{ + Q_OBJECT +public: + SecureMessage *q; + MessageContext *c; + SecureMessageSystem *system; + + bool bundleSigner, smime; + SecureMessage::Format format; + SecureMessageKeyList to; + SecureMessageKeyList from; + + QByteArray in; + bool success; + SecureMessage::Error errorCode; + QByteArray detachedSig; + QString hashName; + SecureMessageSignatureList signers; + QString dtext; + + QList bytesWrittenArgs; + SafeTimer readyReadTrigger, bytesWrittenTrigger, finishedTrigger; + + Private(SecureMessage *_q) + : readyReadTrigger(this) + , bytesWrittenTrigger(this) + , finishedTrigger(this) + { + q = _q; + c = nullptr; + system = nullptr; + + readyReadTrigger.setSingleShot(true); + bytesWrittenTrigger.setSingleShot(true); + finishedTrigger.setSingleShot(true); + connect(&readyReadTrigger, &SafeTimer::timeout, this, &Private::t_readyRead); + connect(&bytesWrittenTrigger, &SafeTimer::timeout, this, &Private::t_bytesWritten); + connect(&finishedTrigger, &SafeTimer::timeout, this, &Private::t_finished); + + reset(ResetAll); + } + + void init() + { + connect(c, &MessageContext::updated, this, &Private::updated); + } + + void reset(ResetMode mode) + { + if (c) + c->reset(); + + bytesWrittenArgs.clear(); + readyReadTrigger.stop(); + bytesWrittenTrigger.stop(); + finishedTrigger.stop(); + + if (mode >= ResetSessionAndData) { + in.clear(); + success = false; + errorCode = SecureMessage::ErrorUnknown; + detachedSig.clear(); + hashName = QString(); + signers.clear(); + } + + if (mode >= ResetAll) { + bundleSigner = true; + format = SecureMessage::Binary; + to.clear(); + from.clear(); + } + } + +public Q_SLOTS: + void updated() + { + bool sig_read = false; + bool sig_written = false; + bool sig_done = false; + int written = 0; + { + const QByteArray a = c->read(); + if (!a.isEmpty()) { + sig_read = true; + in.append(a); + } + + const int x = c->written(); + if (x > 0) { + sig_written = true; + written = x; + } + } + + if (c->finished()) { + sig_done = true; + + success = c->success(); + errorCode = c->errorCode(); + dtext = c->diagnosticText(); + if (success) { + detachedSig = c->signature(); + hashName = c->hashName(); + signers = c->signers(); + } + reset(ResetSession); + } + + if (sig_read) + readyReadTrigger.start(); + if (sig_written) { + bytesWrittenArgs += written; + bytesWrittenTrigger.start(); + } + if (sig_done) + finishedTrigger.start(); + } + + void t_readyRead() + { + emit q->readyRead(); + } + + void t_bytesWritten() + { + emit q->bytesWritten(bytesWrittenArgs.takeFirst()); + } + + void t_finished() + { + emit q->finished(); + } +}; + +SecureMessage::SecureMessage(SecureMessageSystem *system) +{ + d = new Private(this); + d->system = system; + d->c = static_cast(d->system->context())->createMessage(); + change(d->c); + d->init(); +} + +SecureMessage::~SecureMessage() +{ + delete d; +} + +SecureMessage::Type SecureMessage::type() const +{ + return d->c->type(); +} + +bool SecureMessage::canSignMultiple() const +{ + return d->c->canSignMultiple(); +} + +bool SecureMessage::canClearsign() const +{ + return (type() == OpenPGP); +} + +bool SecureMessage::canSignAndEncrypt() const +{ + return (type() == OpenPGP); +} + +void SecureMessage::reset() +{ + d->reset(ResetAll); +} + +bool SecureMessage::bundleSignerEnabled() const +{ + return d->bundleSigner; +} + +bool SecureMessage::smimeAttributesEnabled() const +{ + return d->smime; +} + +SecureMessage::Format SecureMessage::format() const +{ + return d->format; +} + +SecureMessageKeyList SecureMessage::recipientKeys() const +{ + return d->to; +} + +SecureMessageKeyList SecureMessage::signerKeys() const +{ + return d->from; +} + +void SecureMessage::setBundleSignerEnabled(bool b) +{ + d->bundleSigner = b; +} + +void SecureMessage::setSMIMEAttributesEnabled(bool b) +{ + d->smime = b; +} + +void SecureMessage::setFormat(Format f) +{ + d->format = f; +} + +void SecureMessage::setRecipient(const SecureMessageKey &key) +{ + d->to = SecureMessageKeyList() << key; +} + +void SecureMessage::setRecipients(const SecureMessageKeyList &keys) +{ + d->to = keys; +} + +void SecureMessage::setSigner(const SecureMessageKey &key) +{ + d->from = SecureMessageKeyList() << key; +} + +void SecureMessage::setSigners(const SecureMessageKeyList &keys) +{ + d->from = keys; +} + +void SecureMessage::startEncrypt() +{ + d->reset(ResetSessionAndData); + d->c->setupEncrypt(d->to); + d->c->start(d->format, MessageContext::Encrypt); +} + +void SecureMessage::startDecrypt() +{ + d->reset(ResetSessionAndData); + d->c->start(d->format, MessageContext::Decrypt); +} + +void SecureMessage::startSign(SignMode m) +{ + d->reset(ResetSessionAndData); + d->c->setupSign(d->from, m, d->bundleSigner, d->smime); + d->c->start(d->format, MessageContext::Sign); +} + +void SecureMessage::startVerify(const QByteArray &sig) +{ + d->reset(ResetSessionAndData); + if (!sig.isEmpty()) + d->c->setupVerify(sig); + d->c->start(d->format, MessageContext::Verify); +} + +void SecureMessage::startSignAndEncrypt() +{ + d->reset(ResetSessionAndData); + d->c->setupEncrypt(d->to); + d->c->setupSign(d->from, Message, d->bundleSigner, d->smime); + d->c->start(d->format, MessageContext::SignAndEncrypt); +} + +void SecureMessage::update(const QByteArray &in) +{ + d->c->update(in); +} + +QByteArray SecureMessage::read() +{ + const QByteArray a = d->in; + d->in.clear(); + return a; +} + +int SecureMessage::bytesAvailable() const +{ + return d->in.size(); +} + +void SecureMessage::end() +{ + d->c->end(); +} + +bool SecureMessage::waitForFinished(int msecs) +{ + d->c->waitForFinished(msecs); + d->updated(); + return d->success; +} + +bool SecureMessage::success() const +{ + return d->success; +} + +SecureMessage::Error SecureMessage::errorCode() const +{ + return d->errorCode; +} + +QByteArray SecureMessage::signature() const +{ + return d->detachedSig; +} + +QString SecureMessage::hashName() const +{ + return d->hashName; +} + +bool SecureMessage::wasSigned() const +{ + return !d->signers.isEmpty(); +} + +bool SecureMessage::verifySuccess() const +{ + // if we're not done or there were no signers, then return false + if (!d->success || d->signers.isEmpty()) + return false; + + // make sure all signers have a valid signature + for (int n = 0; n < d->signers.count(); ++n) { + if (d->signers[n].identityResult() != SecureMessageSignature::Valid) + return false; + } + return true; +} + +SecureMessageSignature SecureMessage::signer() const +{ + if (d->signers.isEmpty()) + return SecureMessageSignature(); + + return d->signers.first(); +} + +SecureMessageSignatureList SecureMessage::signers() const +{ + return d->signers; +} + +QString SecureMessage::diagnosticText() const +{ + return d->dtext; +} + +//---------------------------------------------------------------------------- +// SecureMessageSystem +//---------------------------------------------------------------------------- +SecureMessageSystem::SecureMessageSystem(QObject *parent, const QString &type, const QString &provider) + : QObject(parent) + , Algorithm(type, provider) +{ +} + +SecureMessageSystem::~SecureMessageSystem() +{ +} + +//---------------------------------------------------------------------------- +// OpenPGP +//---------------------------------------------------------------------------- +OpenPGP::OpenPGP(QObject *parent, const QString &provider) + : SecureMessageSystem(parent, QStringLiteral("openpgp"), provider) +{ +} + +OpenPGP::~OpenPGP() +{ +} + +//---------------------------------------------------------------------------- +// CMS +//---------------------------------------------------------------------------- +class CMS::Private +{ +public: + CertificateCollection trusted, untrusted; + SecureMessageKeyList privateKeys; +}; + +CMS::CMS(QObject *parent, const QString &provider) + : SecureMessageSystem(parent, QStringLiteral("cms"), provider) +{ + d = new Private; +} + +CMS::~CMS() +{ + delete d; +} + +CertificateCollection CMS::trustedCertificates() const +{ + return d->trusted; +} + +CertificateCollection CMS::untrustedCertificates() const +{ + return d->untrusted; +} + +SecureMessageKeyList CMS::privateKeys() const +{ + return d->privateKeys; +} + +void CMS::setTrustedCertificates(const CertificateCollection &trusted) +{ + d->trusted = trusted; + static_cast(context())->setTrustedCertificates(trusted); +} + +void CMS::setUntrustedCertificates(const CertificateCollection &untrusted) +{ + d->untrusted = untrusted; + static_cast(context())->setUntrustedCertificates(untrusted); +} + +void CMS::setPrivateKeys(const SecureMessageKeyList &keys) +{ + d->privateKeys = keys; + static_cast(context())->setPrivateKeys(keys); +} + +} + +#include "qca_securemessage.moc" diff --git a/local/recipes/libs/qca/source/src/qca_systemstore.h b/local/recipes/libs/qca/source/src/qca_systemstore.h new file mode 100644 index 0000000000..cebc50a8ae --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_systemstore.h @@ -0,0 +1,36 @@ +/* + * qca_systemstore.h - Qt Cryptographic Architecture + * Copyright (C) 2004 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef QCA_SYSTEMSTORE_H +#define QCA_SYSTEMSTORE_H + +// NOTE: this API is private to QCA + +#include "qca_cert.h" + +namespace QCA { + +bool qca_have_systemstore(); +CertificateCollection qca_get_systemstore(const QString &provider); + +} + +#endif diff --git a/local/recipes/libs/qca/source/src/qca_systemstore_flatfile.cpp b/local/recipes/libs/qca/source/src/qca_systemstore_flatfile.cpp new file mode 100644 index 0000000000..60b2efa274 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_systemstore_flatfile.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004,2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_systemstore.h" + +#include + +namespace QCA { + +bool qca_have_systemstore() +{ + QFile f(QStringLiteral(QCA_SYSTEMSTORE_PATH)); + return f.open(QFile::ReadOnly); +} + +CertificateCollection qca_get_systemstore(const QString &provider) +{ + return CertificateCollection::fromFlatTextFile(QStringLiteral(QCA_SYSTEMSTORE_PATH), nullptr, provider); +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_systemstore_mac.cpp b/local/recipes/libs/qca/source/src/qca_systemstore_mac.cpp new file mode 100644 index 0000000000..faffc48a4b --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_systemstore_mac.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004,2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_systemstore.h" + +#include +#include + +namespace QCA { + +bool qca_have_systemstore() +{ + return true; +} + +CertificateCollection qca_get_systemstore(const QString &provider) +{ + CertificateCollection col; + CFArrayRef anchors; + if (SecTrustCopyAnchorCertificates(&anchors) != 0) + return col; + for (int n = 0; n < CFArrayGetCount(anchors); ++n) { + SecCertificateRef cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, n); + CFDataRef derRef = SecCertificateCopyData(cr); + QByteArray der((const char *)CFDataGetBytePtr(derRef), CFDataGetLength(derRef)); + CFRelease(derRef); + + Certificate cert = Certificate::fromDER(der, 0, provider); + if (!cert.isNull()) + col.addCertificate(cert); + } + CFRelease(anchors); + return col; +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_systemstore_win.cpp b/local/recipes/libs/qca/source/src/qca_systemstore_win.cpp new file mode 100644 index 0000000000..bab71edf0d --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_systemstore_win.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004,2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +// need to define this immediately +#define _WIN32_WINNT 0x400 + +#include "qca_systemstore.h" + +#include +// do not remove this comment. it keeps windows.h on the top during clang-format phase +#include + +namespace QCA { + +bool qca_have_systemstore() +{ + bool ok = false; + HCERTSTORE hSystemStore; + hSystemStore = CertOpenSystemStoreA(0, "ROOT"); + if (hSystemStore) + ok = true; + CertCloseStore(hSystemStore, 0); + return ok; +} + +CertificateCollection qca_get_systemstore(const QString &provider) +{ + CertificateCollection col; + HCERTSTORE hSystemStore; + hSystemStore = CertOpenSystemStoreA(0, "ROOT"); + if (!hSystemStore) + return col; + PCCERT_CONTEXT pc = NULL; + while (1) { + pc = CertFindCertificateInStore( + hSystemStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pc); + if (!pc) + break; + int size = pc->cbCertEncoded; + QByteArray der(size, 0); + memcpy(der.data(), pc->pbCertEncoded, size); + + Certificate cert = Certificate::fromDER(der, 0, provider); + if (!cert.isNull()) + col.addCertificate(cert); + } + CertCloseStore(hSystemStore, 0); + return col; +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_textfilter.cpp b/local/recipes/libs/qca/source/src/qca_textfilter.cpp new file mode 100644 index 0000000000..ae4c4e75b7 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_textfilter.cpp @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2003-2005 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_textfilter.h" + +namespace QCA { + +//---------------------------------------------------------------------------- +// TextFilter +//---------------------------------------------------------------------------- +TextFilter::TextFilter(Direction dir) +{ + setup(dir); +} + +void TextFilter::setup(Direction dir) +{ + _dir = dir; +} + +Direction TextFilter::direction() const +{ + return _dir; +} + +MemoryRegion TextFilter::encode(const MemoryRegion &a) +{ + setup(Encode); + return process(a); +} + +MemoryRegion TextFilter::decode(const MemoryRegion &a) +{ + setup(Decode); + return process(a); +} + +QString TextFilter::arrayToString(const MemoryRegion &a) +{ + return QString::fromLatin1(encode(a).toByteArray()); +} + +MemoryRegion TextFilter::stringToArray(const QString &s) +{ + if (s.isEmpty()) + return MemoryRegion(); + return decode(s.toLatin1()); +} + +QString TextFilter::encodeString(const QString &s) +{ + return arrayToString(s.toUtf8()); +} + +QString TextFilter::decodeString(const QString &s) +{ + return QString::fromUtf8(stringToArray(s).toByteArray()); +} + +//---------------------------------------------------------------------------- +// Hex +//---------------------------------------------------------------------------- +static int enhex(uchar c) +{ + if (c < 10) + return c + '0'; + else if (c < 16) + return c - 10 + 'a'; + else + return -1; +} + +static int dehex(char c) +{ + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= '0' && c <= '9') + return c - '0'; + else + return -1; +} + +Hex::Hex(Direction dir) + : TextFilter(dir) +{ + clear(); +} + +void Hex::clear() +{ + partial = false; + _ok = true; +} + +MemoryRegion Hex::update(const MemoryRegion &m) +{ + const QByteArray a = m.toByteArray(); + if (_dir == Encode) { + QByteArray out(a.size() * 2, 0); + int at = 0; + int c; + for (const char ac : a) { + uchar lo = (uchar)ac & 0x0f; + uchar hi = (uchar)ac >> 4; + c = enhex(hi); + if (c == -1) { + _ok = false; + break; + } + out[at++] = (char)c; + c = enhex(lo); + if (c == -1) { + _ok = false; + break; + } + out[at++] = (char)c; + } + if (!_ok) + return MemoryRegion(); + + return out; + } else { + uchar lo = 0; + uchar hi = 0; + bool flag = false; + if (partial) { + hi = val; + flag = true; + } + + QByteArray out(a.size() / 2, 0); + int at = 0; + int c; + for (const char ac : a) { + c = dehex(ac); + if (c == -1) { + _ok = false; + break; + } + if (flag) { + lo = (uchar)c; + uchar full = ((hi & 0x0f) << 4) + (lo & 0x0f); + out[at++] = full; + flag = false; + } else { + hi = (uchar)c; + flag = true; + } + } + if (!_ok) + return MemoryRegion(); + + if (flag) { + val = hi; + partial = true; + } + return out; + } +} + +MemoryRegion Hex::final() +{ + if (partial) + _ok = false; + return MemoryRegion(); +} + +bool Hex::ok() const +{ + return _ok; +} + +//---------------------------------------------------------------------------- +// Base64 +//---------------------------------------------------------------------------- +Base64::Base64(Direction dir) + : TextFilter(dir) +{ + _lb_enabled = false; + _lb_column = 76; +} + +void Base64::clear() +{ + partial.resize(0); + _ok = true; + col = 0; +} + +bool Base64::lineBreaksEnabled() const +{ + return _lb_enabled; +} + +int Base64::lineBreaksColumn() const +{ + return _lb_column; +} + +void Base64::setLineBreaksEnabled(bool b) +{ + _lb_enabled = b; +} + +void Base64::setLineBreaksColumn(int column) +{ + if (column > 0) + _lb_column = column; + else + _lb_column = 76; +} + +static QByteArray b64encode(const QByteArray &s) +{ + int i; + const int len = s.size(); + static const char tbl[] = + "ABCDEFGH" + "IJKLMNOP" + "QRSTUVWX" + "YZabcdef" + "ghijklmn" + "opqrstuv" + "wxyz0123" + "456789+/" + "="; + int a, b, c; + + QByteArray p((len + 2) / 3 * 4, 0); + int at = 0; + for (i = 0; i < len; i += 3) { + a = ((unsigned char)s[i] & 3) << 4; + if (i + 1 < len) { + a += (unsigned char)s[i + 1] >> 4; + b = ((unsigned char)s[i + 1] & 0xf) << 2; + if (i + 2 < len) { + b += (unsigned char)s[i + 2] >> 6; + c = (unsigned char)s[i + 2] & 0x3f; + } else + c = 64; + } else + b = c = 64; + + p[at++] = tbl[(unsigned char)s[i] >> 2]; + p[at++] = tbl[a]; + p[at++] = tbl[b]; + p[at++] = tbl[c]; + } + return p; +} + +static QByteArray b64decode(const QByteArray &s, bool *ok) +{ + // -1 specifies invalid + // 64 specifies eof + // everything else specifies data + + static const signed char tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, -1, -1, -1, 64, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + // return value + QByteArray p; + *ok = true; + + // this should be a multiple of 4 + const int len = s.size(); + if (len % 4) { + *ok = false; + return p; + } + + p.resize(len / 4 * 3); + + int i; + int at = 0; + + int a, b, c, d; + c = d = 0; + + for (i = 0; i < len; i += 4) { + a = tbl[(int)s[i]]; + b = tbl[(int)s[i + 1]]; + c = tbl[(int)s[i + 2]]; + d = tbl[(int)s[i + 3]]; + if ((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { + p.resize(0); + *ok = false; + return p; + } + p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); + p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); + p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); + } + + if (c & 64) + p.resize(at - 2); + else if (d & 64) + p.resize(at - 1); + + return p; +} + +static int findLF(const QByteArray &in, int offset) +{ + for (int n = offset; n < in.size(); ++n) { + if (in[n] == '\n') + return n; + } + return -1; +} + +static QByteArray insert_linebreaks(const QByteArray &s, int *col, int lfAt) +{ + QByteArray out = s; + + const int needed = (out.size() + *col) / lfAt; // how many newlines needed? + if (needed > 0) { + const int firstlen = lfAt - *col; // length of first chunk + int at = firstlen + (lfAt * (needed - 1)); // position of last newline + const int lastlen = out.size() - at; // length of last chunk + + // printf("size=%d,needed=%d,firstlen=%d,at=%d,lastlen=%d\n", out.size(), needed, firstlen, at, lastlen); + + // make room + out.resize(out.size() + needed); + + // move backwards + for (int n = 0; n < needed; ++n) { + char *p = out.data() + at; + int len; + if (n == 0) + len = lastlen; + else + len = lfAt; + memmove(p + needed - n, p, len); + p[needed - n - 1] = '\n'; + at -= lfAt; + } + + *col = lastlen; + } else + *col += out.size(); + + return out; +} + +static QByteArray remove_linebreaks(const QByteArray &s) +{ + QByteArray out = s; + + int removed = 0; + int at = findLF(out, 0); + while (at != -1) { + int next = findLF(out, at + 1); + int len; + if (next != -1) + len = next - at; + else + len = out.size() - at; + + if (len > 1) { + char *p = out.data() + at; + memmove(p - removed, p + 1, len - 1); + } + ++removed; + at = next; + } + out.resize(out.size() - removed); + + return out; +} + +static void appendArray(QByteArray *a, const QByteArray &b) +{ + a->append(b); +} + +MemoryRegion Base64::update(const MemoryRegion &m) +{ + QByteArray in; + if (_dir == Decode && _lb_enabled) + in = remove_linebreaks(m.toByteArray()); + else + in = m.toByteArray(); + + if (in.isEmpty()) + return MemoryRegion(); + + int chunk; + if (_dir == Encode) + chunk = 3; + else + chunk = 4; + + const int size = partial.size() + in.size(); + if (size < chunk) { + appendArray(&partial, in); + return MemoryRegion(); + } + + int eat = size % chunk; + + // s = partial + a - eat + QByteArray s(partial.size() + in.size() - eat, 0); + memcpy(s.data(), partial.data(), partial.size()); + memcpy(s.data() + partial.size(), in.data(), in.size() - eat); + + partial.resize(eat); + memcpy(partial.data(), in.data() + in.size() - eat, eat); + + if (_dir == Encode) { + if (_lb_enabled) + return insert_linebreaks(b64encode(s), &col, _lb_column); + else + return b64encode(s); + } else { + bool ok; + const QByteArray out = b64decode(s, &ok); + if (!ok) + _ok = false; + return out; + } +} + +MemoryRegion Base64::final() +{ + if (_dir == Encode) { + if (_lb_enabled) + return insert_linebreaks(b64encode(partial), &col, _lb_column); + else + return b64encode(partial); + } else { + bool ok; + const QByteArray out = b64decode(partial, &ok); + if (!ok) + _ok = false; + return out; + } +} + +bool Base64::ok() const +{ + return _ok; +} + +} diff --git a/local/recipes/libs/qca/source/src/qca_tools.cpp b/local/recipes/libs/qca/source/src/qca_tools.cpp new file mode 100644 index 0000000000..f9cd089486 --- /dev/null +++ b/local/recipes/libs/qca/source/src/qca_tools.cpp @@ -0,0 +1,940 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * Copyright (C) 2004,2005 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_tools.h" + +#include "qdebug.h" + +#ifdef Q_OS_UNIX +#include +#include +#endif +#include "botantools/botantools.h" + +namespace QCA { + +static bool can_lock() +{ +#ifdef Q_OS_UNIX + bool ok = false; +#ifdef MLOCK_NOT_VOID_PTR +#define MLOCK_TYPE char * +#define MLOCK_TYPE_CAST (MLOCK_TYPE) +#else +#define MLOCK_TYPE void * +#define MLOCK_TYPE_CAST +#endif + + MLOCK_TYPE d = MLOCK_TYPE_CAST malloc(256); + if (mlock(d, 256) == 0) { + munlock(d, 256); + ok = true; + } + free(d); + return ok; +#else + return true; +#endif +} + +// Botan shouldn't throw any exceptions in our init/deinit. + +static Botan::Allocator *alloc = nullptr; + +void botan_throw_abort() +{ + fprintf(stderr, "QCA: Exception from internal Botan\n"); + abort(); +} + +bool botan_init(int prealloc, bool mmap) +{ + // 64k minimum + if (prealloc < 64) + prealloc = 64; + + bool secmem = false; + + try { + Botan::Builtin_Modules modules; + Botan::Library_State *libstate = new Botan::Library_State(modules.mutex_factory()); + libstate->prealloc_size = prealloc * 1024; + Botan::set_global_state(libstate); + Botan::global_state().load(modules); + + if (can_lock()) { + Botan::global_state().set_default_allocator("locking"); + secmem = true; + } else if (mmap) { + Botan::global_state().set_default_allocator("mmap"); + secmem = true; + } + alloc = Botan::Allocator::get(true); + } catch (std::exception &) { + fprintf(stderr, "QCA: Error initializing internal Botan\n"); + abort(); + } + + return secmem; +} + +void botan_deinit() +{ + try { + alloc = nullptr; + Botan::set_global_state(nullptr); + } catch (std::exception &) { + botan_throw_abort(); + } +} + +void *botan_secure_alloc(int bytes) +{ + try { + return alloc->allocate((Botan::u32bit)bytes); + } catch (std::exception &) { + botan_throw_abort(); + } + return nullptr; // never get here +} + +void botan_secure_free(void *p, int bytes) +{ + try { + alloc->deallocate(p, (Botan::u32bit)bytes); + } catch (std::exception &) { + botan_throw_abort(); + } +} + +} // end namespace QCA + +void *qca_secure_alloc(int bytes) +{ + // allocate enough room to store a size value in front, return a pointer after it + char *c = (char *)QCA::botan_secure_alloc(bytes + sizeof(int)); + reinterpret_cast(c)[0] = bytes + sizeof(int); + return c + sizeof(int); +} + +void qca_secure_free(void *p) +{ + // backtrack to read the size value + char *c = (char *)p; + c -= sizeof(int); + const int bytes = reinterpret_cast(c)[0]; + QCA::botan_secure_free(c, bytes); +} + +void *qca_secure_realloc(void *p, int bytes) +{ + // if null, do a plain alloc (just like how realloc() works) + if (!p) + return qca_secure_alloc(bytes); + + // backtrack to read the size value + char *c = (char *)p; + c -= sizeof(int); + const int oldsize = reinterpret_cast(c)[0] - sizeof(int); + + // alloc the new chunk + char *new_p = (char *)qca_secure_alloc(bytes); + if (!new_p) + return nullptr; + + // move over the memory from the original block + memmove(new_p, p, qMin(oldsize, bytes)); + + // free the original + qca_secure_free(p); + + // done + return new_p; +} + +namespace QCA { + +// secure or non-secure buffer, with trailing 0-byte. +// buffer size of 0 is okay (sbuf/qbuf will be 0). +struct alloc_info +{ + bool sec; + char *data; + int size; + + // internal + Botan::SecureVector *sbuf; + QByteArray *qbuf; +}; + +// note: these functions don't return error if memory allocation/resizing +// fails.. maybe fix this someday? + +// ai: uninitialized +// size: >= 0 +// note: memory will be initially zero'd out +static bool ai_new(alloc_info *ai, int size, bool sec); + +// ai: uninitialized +// from: initialized +static bool ai_copy(alloc_info *ai, const alloc_info *from); + +// ai: initialized +// new_size: >= 0 +static bool ai_resize(alloc_info *ai, int new_size); + +// ai: initialized +static void ai_delete(alloc_info *ai); + +bool ai_new(alloc_info *ai, int size, bool sec) +{ + if (size < 0) + return false; + + ai->size = size; + ai->sec = sec; + + if (size == 0) { + ai->sbuf = nullptr; + ai->qbuf = nullptr; + ai->data = nullptr; + return true; + } + + if (sec) { + try { + ai->sbuf = new Botan::SecureVector((Botan::u32bit)size + 1); + } catch (std::exception &) { + botan_throw_abort(); + return false; // never get here + } + + (*(ai->sbuf))[size] = 0; + ai->qbuf = nullptr; + Botan::byte *bp = (Botan::byte *)(*(ai->sbuf)); + ai->data = (char *)bp; + } else { + ai->sbuf = nullptr; + ai->qbuf = new QByteArray(size, 0); + ai->data = ai->qbuf->data(); + } + + return true; +} + +bool ai_copy(alloc_info *ai, const alloc_info *from) +{ + ai->size = from->size; + ai->sec = from->sec; + + if (ai->size == 0) { + ai->sbuf = nullptr; + ai->qbuf = nullptr; + ai->data = nullptr; + return true; + } + + if (ai->sec) { + try { + ai->sbuf = new Botan::SecureVector(*(from->sbuf)); + } catch (std::exception &) { + botan_throw_abort(); + return false; // never get here + } + + ai->qbuf = nullptr; + Botan::byte *bp = (Botan::byte *)(*(ai->sbuf)); + ai->data = (char *)bp; + } else { + ai->sbuf = nullptr; + ai->qbuf = new QByteArray(*(from->qbuf)); + ai->data = ai->qbuf->data(); + } + + return true; +} + +bool ai_resize(alloc_info *ai, int new_size) +{ + if (new_size < 0) + return false; + + // new size is empty + if (new_size == 0) { + // we currently aren't empty + if (ai->size > 0) { + if (ai->sec) { + delete ai->sbuf; + ai->sbuf = nullptr; + } else { + delete ai->qbuf; + ai->qbuf = nullptr; + } + + ai->size = 0; + ai->data = nullptr; + } + + return true; + } + + if (ai->sec) { + Botan::SecureVector *new_buf; + try { + new_buf = new Botan::SecureVector((Botan::u32bit)new_size + 1); + } catch (std::exception &) { + botan_throw_abort(); + return false; // never get here + } + + Botan::byte *new_p = (Botan::byte *)(*new_buf); + if (ai->size > 0) { + const Botan::byte *old_p = (const Botan::byte *)(*(ai->sbuf)); + memcpy(new_p, old_p, qMin(new_size, ai->size)); + delete ai->sbuf; + } + ai->sbuf = new_buf; + ai->size = new_size; + (*(ai->sbuf))[new_size] = 0; + ai->data = (char *)new_p; + } else { + if (ai->size > 0) + ai->qbuf->resize(new_size); + else + ai->qbuf = new QByteArray(new_size, 0); + + ai->size = new_size; + ai->data = ai->qbuf->data(); + } + + return true; +} + +void ai_delete(alloc_info *ai) +{ + if (ai->size > 0) { + if (ai->sec) + delete ai->sbuf; + else + delete ai->qbuf; + } +} + +//---------------------------------------------------------------------------- +// MemoryRegion +//---------------------------------------------------------------------------- +static char blank[] = ""; + +class MemoryRegion::Private : public QSharedData +{ +public: + alloc_info ai; + + Private(int size, bool sec) + { + ai_new(&ai, size, sec); + } + + Private(const QByteArray &from, bool sec) + { + ai_new(&ai, from.size(), sec); + memcpy(ai.data, from.data(), ai.size); + } + + Private(const Private &from) + : QSharedData(from) + { + ai_copy(&ai, &from.ai); + } + + ~Private() + { + ai_delete(&ai); + } + + bool resize(int new_size) + { + return ai_resize(&ai, new_size); + } + + void setSecure(bool sec) + { + // if same mode, do nothing + if (ai.sec == sec) + return; + + alloc_info other; + ai_new(&other, ai.size, sec); + memcpy(other.data, ai.data, ai.size); + ai_delete(&ai); + ai = other; + } +}; + +MemoryRegion::MemoryRegion() + : _secure(false) + , d(nullptr) +{ +} + +MemoryRegion::MemoryRegion(const char *str) + : _secure(false) + , d(new Private(QByteArray::fromRawData(str, strlen(str)), false)) +{ +} + +MemoryRegion::MemoryRegion(const QByteArray &from) + : _secure(false) + , d(new Private(from, false)) +{ +} + +MemoryRegion::MemoryRegion(const MemoryRegion &from) + : _secure(from._secure) + , d(from.d) +{ +} + +MemoryRegion::~MemoryRegion() +{ +} + +MemoryRegion &MemoryRegion::operator=(const MemoryRegion &from) +{ + _secure = from._secure; + d = from.d; + return *this; +} + +MemoryRegion &MemoryRegion::operator=(const QByteArray &from) +{ + set(from, false); + return *this; +} + +bool MemoryRegion::isNull() const +{ + return (d ? false : true); +} + +bool MemoryRegion::isSecure() const +{ + return _secure; +} + +QByteArray MemoryRegion::toByteArray() const +{ + if (!d) + return QByteArray(); + + if (d->ai.sec) { + QByteArray buf(d->ai.size, 0); + memcpy(buf.data(), d->ai.data, d->ai.size); + return buf; + } else { + if (d->ai.size > 0) + return *(d->ai.qbuf); + else + return QByteArray((int)0, (char)0); + } +} + +MemoryRegion::MemoryRegion(bool secure) + : _secure(secure) + , d(nullptr) +{ +} + +MemoryRegion::MemoryRegion(int size, bool secure) + : _secure(secure) + , d(new Private(size, secure)) +{ +} + +MemoryRegion::MemoryRegion(const QByteArray &from, bool secure) + : _secure(secure) + , d(new Private(from, secure)) +{ +} + +char *MemoryRegion::data() +{ + if (!d) + return blank; + return d->ai.data; +} + +const char *MemoryRegion::data() const +{ + if (!d) + return blank; + return d->ai.data; +} + +const char *MemoryRegion::constData() const +{ + if (!d) + return blank; + return d->ai.data; +} + +char &MemoryRegion::at(int index) +{ + return *(d->ai.data + index); +} + +const char &MemoryRegion::at(int index) const +{ + return *(d->ai.data + index); +} + +int MemoryRegion::size() const +{ + if (!d) + return 0; + return d->ai.size; +} + +bool MemoryRegion::isEmpty() const +{ + if (!d) + return true; + return (d->ai.size > 0 ? false : true); +} + +bool MemoryRegion::resize(int size) +{ + if (!d) { + d = new Private(size, _secure); + return true; + } + + if (d->ai.size == size) + return true; + + return d->resize(size); +} + +void MemoryRegion::set(const QByteArray &from, bool secure) +{ + _secure = secure; + + if (!from.isEmpty()) + d = new Private(from, secure); + else + d = new Private(0, secure); +} + +void MemoryRegion::setSecure(bool secure) +{ + _secure = secure; + + if (!d) { + d = new Private(0, secure); + return; + } + + d->setSecure(secure); +} + +//---------------------------------------------------------------------------- +// SecureArray +//---------------------------------------------------------------------------- +SecureArray::SecureArray() + : MemoryRegion(true) +{ +} + +SecureArray::SecureArray(int size, char ch) + : MemoryRegion(size, true) +{ + // ai_new fills with zeros for us + if (ch != 0) + fill(ch, size); +} + +SecureArray::SecureArray(const char *str) + : MemoryRegion(QByteArray::fromRawData(str, strlen(str)), true) +{ +} + +SecureArray::SecureArray(const QByteArray &a) + : MemoryRegion(a, true) +{ +} + +SecureArray::SecureArray(const MemoryRegion &a) + : MemoryRegion(a) +{ + setSecure(true); +} + +SecureArray::SecureArray(const SecureArray &from) + : MemoryRegion(from) +{ +} + +SecureArray::~SecureArray() +{ +} + +SecureArray &SecureArray::operator=(const SecureArray &from) +{ + MemoryRegion::operator=(from); + return *this; +} + +SecureArray &SecureArray::operator=(const QByteArray &from) +{ + MemoryRegion::set(from, true); + return *this; +} + +void SecureArray::clear() +{ + MemoryRegion::resize(0); +} + +bool SecureArray::resize(int size) +{ + return MemoryRegion::resize(size); +} + +char &SecureArray::operator[](int index) +{ + return at(index); +} + +const char &SecureArray::operator[](int index) const +{ + return at(index); +} + +char &SecureArray::at(int index) +{ + return MemoryRegion::at(index); +} + +const char &SecureArray::at(int index) const +{ + return MemoryRegion::at(index); +} + +char *SecureArray::data() +{ + return MemoryRegion::data(); +} + +const char *SecureArray::data() const +{ + return MemoryRegion::data(); +} + +const char *SecureArray::constData() const +{ + return MemoryRegion::constData(); +} + +int SecureArray::size() const +{ + return MemoryRegion::size(); +} + +bool SecureArray::isEmpty() const +{ + return MemoryRegion::isEmpty(); +} + +QByteArray SecureArray::toByteArray() const +{ + return MemoryRegion::toByteArray(); +} + +SecureArray &SecureArray::append(const SecureArray &a) +{ + const int oldsize = size(); + resize(oldsize + a.size()); + memcpy(data() + oldsize, a.data(), a.size()); + return *this; +} + +bool SecureArray::operator==(const MemoryRegion &other) const +{ + if (this == &other) + return true; + if (size() == other.size() && memcmp(data(), other.data(), size()) == 0) + return true; + return false; +} + +SecureArray &SecureArray::operator+=(const SecureArray &a) +{ + return append(a); +} + +void SecureArray::fill(char fillChar, int fillToPosition) +{ + const int len = (fillToPosition == -1) ? size() : qMin(fillToPosition, size()); + if (len > 0) + memset(data(), (int)fillChar, len); +} + +void SecureArray::set(const SecureArray &from) +{ + *this = from; +} + +void SecureArray::set(const QByteArray &from) +{ + *this = from; +} + +const SecureArray operator+(const SecureArray &a, const SecureArray &b) +{ + SecureArray c = a; + return c.append(b); +} + +//---------------------------------------------------------------------------- +// BigInteger +//---------------------------------------------------------------------------- +static void negate_binary(char *a, int size) +{ + // negate = two's compliment + 1 + bool done = false; + for (int n = size - 1; n >= 0; --n) { + a[n] = ~a[n]; + if (!done) { + if ((unsigned char)a[n] < 0xff) { + ++a[n]; + done = true; + } else + a[n] = 0; + } + } +} + +class BigInteger::Private : public QSharedData +{ +public: + Botan::BigInt n; +}; + +BigInteger::BigInteger() +{ + d = new Private; +} + +BigInteger::BigInteger(int i) +{ + d = new Private; + if (i < 0) { + d->n = Botan::BigInt(i * (-1)); + d->n.set_sign(Botan::BigInt::Negative); + } else { + d->n = Botan::BigInt(i); + d->n.set_sign(Botan::BigInt::Positive); + } +} + +BigInteger::BigInteger(const char *c) +{ + d = new Private; + fromString(QString::fromLatin1(c)); +} + +BigInteger::BigInteger(const QString &s) +{ + d = new Private; + fromString(s); +} + +BigInteger::BigInteger(const SecureArray &a) +{ + d = new Private; + fromArray(a); +} + +BigInteger::BigInteger(const BigInteger &from) +{ + *this = from; +} + +BigInteger::~BigInteger() +{ +} + +BigInteger &BigInteger::operator=(const BigInteger &from) +{ + d = from.d; + return *this; +} + +BigInteger &BigInteger::operator+=(const BigInteger &i) +{ + d->n += i.d->n; + return *this; +} + +BigInteger &BigInteger::operator-=(const BigInteger &i) +{ + d->n -= i.d->n; + return *this; +} + +BigInteger &BigInteger::operator*=(const BigInteger &i) +{ + d->n *= i.d->n; + return *this; +} + +BigInteger &BigInteger::operator/=(const BigInteger &i) +{ + try { + d->n /= i.d->n; + } catch (std::exception &) { + fprintf(stderr, "QCA: Botan integer division error\n"); + abort(); + } + return *this; +} + +BigInteger &BigInteger::operator%=(const BigInteger &i) +{ + try { + d->n %= i.d->n; + } catch (std::exception &) { + fprintf(stderr, "QCA: Botan integer division error\n"); + abort(); + } + return *this; +} + +BigInteger &BigInteger::operator=(const QString &s) +{ + fromString(s); + return *this; +} + +int BigInteger::compare(const BigInteger &n) const +{ + return ((d->n).cmp(n.d->n, true)); +} + +QTextStream &operator<<(QTextStream &stream, const BigInteger &b) +{ + stream << b.toString(); + return stream; +} + +SecureArray BigInteger::toArray() const +{ + int size = d->n.encoded_size(Botan::BigInt::Binary); + + // return at least 8 bits + if (size == 0) { + SecureArray a(1); + a[0] = 0; + return a; + } + + int offset = 0; + SecureArray a; + + // make room for a sign bit if needed + if (d->n.get_bit((size * 8) - 1)) { + ++size; + a.resize(size); + a[0] = 0; + ++offset; + } else + a.resize(size); + + Botan::BigInt::encode((Botan::byte *)a.data() + offset, d->n, Botan::BigInt::Binary); + + if (d->n.is_negative()) + negate_binary(a.data(), a.size()); + + return a; +} + +void BigInteger::fromArray(const SecureArray &_a) +{ + if (_a.isEmpty()) { + d->n = Botan::BigInt(0); + return; + } + SecureArray a = _a; + + Botan::BigInt::Sign sign = Botan::BigInt::Positive; + if (a[0] & 0x80) + sign = Botan::BigInt::Negative; + + if (sign == Botan::BigInt::Negative) + negate_binary(a.data(), a.size()); + + d->n = Botan::BigInt::decode((const Botan::byte *)a.data(), a.size(), Botan::BigInt::Binary); + d->n.set_sign(sign); +} + +QString BigInteger::toString() const +{ + QByteArray cs; + try { + cs.resize(d->n.encoded_size(Botan::BigInt::Decimal)); + Botan::BigInt::encode((Botan::byte *)cs.data(), d->n, Botan::BigInt::Decimal); + } catch (std::exception &) { + return QString(); + } + + QString str; + if (d->n.is_negative()) + str += QLatin1Char('-'); + str += QString::fromLatin1(cs); + str.remove(QChar::Null); + return str; +} + +bool BigInteger::fromString(const QString &s) +{ + if (s.isEmpty()) + return false; + const QByteArray cs = s.toLatin1(); + + bool neg = false; + if (s[0] == QLatin1Char('-')) + neg = true; + + try { + d->n = Botan::BigInt::decode( + (const Botan::byte *)cs.data() + (neg ? 1 : 0), cs.length() - (neg ? 1 : 0), Botan::BigInt::Decimal); + } catch (std::exception &) { + return false; + } + + if (neg) + d->n.set_sign(Botan::BigInt::Negative); + else + d->n.set_sign(Botan::BigInt::Positive); + return true; +} + +} diff --git a/local/recipes/libs/qca/source/src/support/console.cpp b/local/recipes/libs/qca/source/src/support/console.cpp new file mode 100644 index 0000000000..25d9dcaa74 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/console.cpp @@ -0,0 +1,996 @@ +/* + * Copyright (C) 2006,2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_support.h" + +#include "qca_safeobj.h" +#include "qpipe.h" + +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#else +#include +#include +#include +#endif + +#include +#include + +#define CONSOLEPROMPT_INPUT_MAX 56 + +Q_DECLARE_METATYPE(QCA::SecureArray) + +namespace QCA { + +//---------------------------------------------------------------------------- +// ConsoleWorker +//---------------------------------------------------------------------------- +class ConsoleWorker : public QObject +{ + Q_OBJECT +private: + QPipeEnd in, out; + bool started; + QByteArray in_left, out_left; + +public: + ConsoleWorker(QObject *parent = nullptr) + : QObject(parent) + , in(this) + , out(this) + { + started = false; + } + + ~ConsoleWorker() override + { + stop(); + } + + void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id) + { + Q_ASSERT(!started); + + if (in_id != INVALID_Q_PIPE_ID) { + in.take(in_id, QPipeDevice::Read); + connect(&in, &QPipeEnd::readyRead, this, &ConsoleWorker::in_readyRead); + connect(&in, &QPipeEnd::closed, this, &ConsoleWorker::in_closed); + connect(&in, &QPipeEnd::error, this, &ConsoleWorker::in_error); + in.enable(); + } + + if (out_id != INVALID_Q_PIPE_ID) { + out.take(out_id, QPipeDevice::Write); + connect(&out, &QPipeEnd::bytesWritten, this, &ConsoleWorker::out_bytesWritten); + connect(&out, &QPipeEnd::closed, this, &ConsoleWorker::out_closed); + out.enable(); + } + + started = true; + } + + void stop() + { + if (!started) + return; + + if (in.isValid()) + in.finalizeAndRelease(); + if (out.isValid()) + out.release(); + + in_left = in.read(); + out_left = out.takeBytesToWrite(); + + started = false; + } + + Q_INVOKABLE bool isValid() const + { + return in.isValid(); + } + + Q_INVOKABLE int bytesAvailable() const + { + return in.bytesAvailable(); + } + + Q_INVOKABLE int bytesToWrite() const + { + return in.bytesToWrite(); + } + +public Q_SLOTS: + + void setSecurityEnabled(bool enabled) + { + if (in.isValid()) + in.setSecurityEnabled(enabled); + if (out.isValid()) + out.setSecurityEnabled(enabled); + } + + QByteArray read(int bytes = -1) + { + return in.read(bytes); + } + + void write(const QByteArray &a) + { + out.write(a); + } + + QCA::SecureArray readSecure(int bytes = -1) + { + return in.readSecure(bytes); + } + + void writeSecure(const QCA::SecureArray &a) + { + out.writeSecure(a); + } + + void closeOutput() + { + out.close(); + } + +public: + QByteArray takeBytesToRead() + { + QByteArray a = in_left; + in_left.clear(); + return a; + } + + QByteArray takeBytesToWrite() + { + QByteArray a = out_left; + out_left.clear(); + return a; + } + +Q_SIGNALS: + void readyRead(); + void bytesWritten(int bytes); + void inputClosed(); + void outputClosed(); + +private Q_SLOTS: + void in_readyRead() + { + emit readyRead(); + } + + void out_bytesWritten(int bytes) + { + emit bytesWritten(bytes); + } + + void in_closed() + { + emit inputClosed(); + } + + void in_error(QCA::QPipeEnd::Error) + { + emit inputClosed(); + } + + void out_closed() + { + emit outputClosed(); + } +}; + +//---------------------------------------------------------------------------- +// ConsoleThread +//---------------------------------------------------------------------------- +class ConsoleThread : public SyncThread +{ + Q_OBJECT +public: + ConsoleWorker *worker; + Q_PIPE_ID _in_id, _out_id; + QByteArray in_left, out_left; + QMutex call_mutex; + + ConsoleThread(QObject *parent = nullptr) + : SyncThread(parent) + { + qRegisterMetaType("QCA::SecureArray"); + } + + ~ConsoleThread() override + { + stop(); + } + + void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id) + { + _in_id = in_id; + _out_id = out_id; + SyncThread::start(); + } + + void stop() + { + SyncThread::stop(); + } + + QVariant mycall(QObject *obj, const char *method, const QVariantList &args = QVariantList()) + { + QVariant ret; + bool ok; + + call_mutex.lock(); + ret = call(obj, method, args, &ok); + call_mutex.unlock(); + + Q_ASSERT(ok); + if (!ok) { + fprintf(stderr, "QCA: ConsoleWorker call [%s] failed.\n", method); + abort(); + return QVariant(); + } + return ret; + } + + bool isValid() + { + return mycall(worker, "isValid").toBool(); + } + + void setSecurityEnabled(bool enabled) + { + mycall(worker, "setSecurityEnabled", QVariantList() << enabled); + } + + QByteArray read(int bytes = -1) + { + return mycall(worker, "read", QVariantList() << bytes).toByteArray(); + } + + void write(const QByteArray &a) + { + mycall(worker, "write", QVariantList() << a); + } + + SecureArray readSecure(int bytes = -1) + { + return mycall(worker, "readSecure", QVariantList() << bytes).value(); + } + + void writeSecure(const SecureArray &a) + { + mycall(worker, "writeSecure", QVariantList() << QVariant::fromValue(a)); + } + + void closeOutput() + { + mycall(worker, "closeOutput"); + } + + int bytesAvailable() + { + return mycall(worker, "bytesAvailable").toInt(); + } + + int bytesToWrite() + { + return mycall(worker, "bytesToWrite").toInt(); + } + + QByteArray takeBytesToRead() + { + QByteArray a = in_left; + in_left.clear(); + return a; + } + + QByteArray takeBytesToWrite() + { + QByteArray a = out_left; + out_left.clear(); + return a; + } + +Q_SIGNALS: + void readyRead(); + void bytesWritten(int); + void inputClosed(); + void outputClosed(); + +protected: + void atStart() override + { + worker = new ConsoleWorker; + + // use direct connections here, so that the emits come from + // the other thread. we can also connect to our own + // signals to avoid having to make slots just to emit. + connect(worker, &ConsoleWorker::readyRead, this, &ConsoleThread::readyRead, Qt::DirectConnection); + connect(worker, &ConsoleWorker::bytesWritten, this, &ConsoleThread::bytesWritten, Qt::DirectConnection); + connect(worker, &ConsoleWorker::inputClosed, this, &ConsoleThread::inputClosed, Qt::DirectConnection); + connect(worker, &ConsoleWorker::outputClosed, this, &ConsoleThread::outputClosed, Qt::DirectConnection); + + worker->start(_in_id, _out_id); + } + + void atEnd() override + { + in_left = worker->takeBytesToRead(); + out_left = worker->takeBytesToWrite(); + delete worker; + } +}; + +//---------------------------------------------------------------------------- +// Console +//---------------------------------------------------------------------------- +class ConsolePrivate : public QObject +{ + Q_OBJECT +public: + Console *q; + + bool started; + Console::Type type; + Console::ChannelMode cmode; + Console::TerminalMode mode; + ConsoleThread *thread; + ConsoleReference *ref; + Q_PIPE_ID in_id; + +#ifdef Q_OS_WIN + DWORD old_mode; +#else + struct termios old_term_attr; +#endif + + ConsolePrivate(Console *_q) + : QObject(_q) + , q(_q) + { + started = false; + mode = Console::Default; + thread = new ConsoleThread(this); + ref = nullptr; + } + + ~ConsolePrivate() override + { + delete thread; + setInteractive(Console::Default); + } + + void setInteractive(Console::TerminalMode m) + { + // no change + if (m == mode) + return; + + if (m == Console::Interactive) { +#ifdef Q_OS_WIN + GetConsoleMode(in_id, &old_mode); + SetConsoleMode(in_id, old_mode & (~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT)); +#else + int fd = in_id; + struct termios attr; + tcgetattr(fd, &attr); + old_term_attr = attr; + + attr.c_lflag &= ~(ECHO); // turn off the echo flag + attr.c_lflag &= ~(ICANON); // no wait for a newline + attr.c_cc[VMIN] = 1; // read at least 1 char + attr.c_cc[VTIME] = 0; // set wait time to zero + + // set the new attributes + tcsetattr(fd, TCSAFLUSH, &attr); +#endif + } else { +#ifdef Q_OS_WIN + SetConsoleMode(in_id, old_mode); +#else + int fd = in_id; + tcsetattr(fd, TCSANOW, &old_term_attr); +#endif + } + + mode = m; + } +}; + +static Console *g_tty_console = nullptr, *g_stdio_console = nullptr; + +Console::Console(Type type, ChannelMode cmode, TerminalMode tmode, QObject *parent) + : QObject(parent) +{ + if (type == Tty) { + Q_ASSERT(g_tty_console == nullptr); + g_tty_console = this; + } else { + Q_ASSERT(g_stdio_console == nullptr); + g_stdio_console = this; + } + + d = new ConsolePrivate(this); + d->type = type; + d->cmode = cmode; + + Q_PIPE_ID in = INVALID_Q_PIPE_ID; + Q_PIPE_ID out = INVALID_Q_PIPE_ID; + +#ifdef Q_OS_WIN + if (type == Tty) { + in = CreateFileA( + "CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + } else { + in = GetStdHandle(STD_INPUT_HANDLE); + } +#else + if (type == Tty) { + in = open("/dev/tty", O_RDONLY); + } else { + in = 0; // stdin + } +#endif + if (cmode == ReadWrite) { +#ifdef Q_OS_WIN + if (type == Tty) { + out = CreateFileA("CONOUT$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + } else { + out = GetStdHandle(STD_OUTPUT_HANDLE); + } +#else + if (type == Tty) { + out = open("/dev/tty", O_WRONLY); + } else { + out = 1; // stdout + } +#endif + } + + d->in_id = in; + d->setInteractive(tmode); + d->thread->start(in, out); +} + +Console::~Console() +{ + release(); + Console::Type type = d->type; + delete d; + if (type == Tty) + g_tty_console = nullptr; + else + g_stdio_console = nullptr; +} + +Console::Type Console::type() const +{ + return d->type; +} + +Console::ChannelMode Console::channelMode() const +{ + return d->cmode; +} + +Console::TerminalMode Console::terminalMode() const +{ + return d->mode; +} + +bool Console::isStdinRedirected() +{ +#ifdef Q_OS_WIN + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode; + if (GetConsoleMode(h, &mode)) + return false; + return true; +#else + return (isatty(0) ? false : true); // 0 == stdin +#endif +} + +bool Console::isStdoutRedirected() +{ +#ifdef Q_OS_WIN + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD mode; + if (GetConsoleMode(h, &mode)) + return false; + return true; +#else + return (isatty(1) ? false : true); // 1 == stdout +#endif +} + +Console *Console::ttyInstance() +{ + return g_tty_console; +} + +Console *Console::stdioInstance() +{ + return g_stdio_console; +} + +void Console::release() +{ + d->thread->stop(); +} + +QByteArray Console::bytesLeftToRead() +{ + return d->thread->takeBytesToRead(); +} + +QByteArray Console::bytesLeftToWrite() +{ + return d->thread->takeBytesToWrite(); +} + +//---------------------------------------------------------------------------- +// ConsoleReference +//---------------------------------------------------------------------------- +class ConsoleReferencePrivate : public QObject +{ + Q_OBJECT +public: + ConsoleReference *q; + + Console *console; + ConsoleThread *thread; + ConsoleReference::SecurityMode smode; + SafeTimer lateTrigger; + bool late_read, late_close; + + ConsoleReferencePrivate(ConsoleReference *_q) + : QObject(_q) + , q(_q) + , lateTrigger(this) + { + console = nullptr; + thread = nullptr; + connect(&lateTrigger, &SafeTimer::timeout, this, &ConsoleReferencePrivate::doLate); + lateTrigger.setSingleShot(true); + } + +private Q_SLOTS: + void doLate() + { + QPointer self = this; + if (late_read) + emit q->readyRead(); + if (!self) + return; + if (late_close) + emit q->inputClosed(); + } +}; + +ConsoleReference::ConsoleReference(QObject *parent) + : QObject(parent) +{ + d = new ConsoleReferencePrivate(this); +} + +ConsoleReference::~ConsoleReference() +{ + stop(); + delete d; +} + +bool ConsoleReference::start(Console *console, SecurityMode mode) +{ + // make sure this reference isn't using a console already + Q_ASSERT(!d->console); + + // one console reference at a time + Q_ASSERT(console->d->ref == nullptr); + + // let's take it + d->console = console; + d->thread = d->console->d->thread; + d->console->d->ref = this; + + const bool valid = d->thread->isValid(); + const int avail = d->thread->bytesAvailable(); + + // pipe already closed and no data? consider this an error + if (!valid && avail == 0) { + d->console->d->ref = nullptr; + d->thread = nullptr; + d->console = nullptr; + return false; + } + + // enable security? it will last for this active session only + d->smode = mode; + if (mode == SecurityEnabled) + d->thread->setSecurityEnabled(true); + + connect(d->thread, &ConsoleThread::readyRead, this, &ConsoleReference::readyRead); + connect(d->thread, &ConsoleThread::bytesWritten, this, &ConsoleReference::bytesWritten); + connect(d->thread, &ConsoleThread::inputClosed, this, &ConsoleReference::inputClosed); + connect(d->thread, &ConsoleThread::outputClosed, this, &ConsoleReference::outputClosed); + + d->late_read = false; + d->late_close = false; + + if (avail > 0) + d->late_read = true; + + if (!valid) + d->late_close = true; + + if (d->late_read || d->late_close) + d->lateTrigger.start(); + + return true; +} + +void ConsoleReference::stop() +{ + if (!d->console) + return; + + d->lateTrigger.stop(); + + disconnect(d->thread, nullptr, this, nullptr); + + // automatically disable security when we go inactive + d->thread->setSecurityEnabled(false); + + d->console->d->ref = nullptr; + d->thread = nullptr; + d->console = nullptr; +} + +Console *ConsoleReference::console() const +{ + return d->console; +} + +ConsoleReference::SecurityMode ConsoleReference::securityMode() const +{ + return d->smode; +} + +QByteArray ConsoleReference::read(int bytes) +{ + return d->thread->read(bytes); +} + +void ConsoleReference::write(const QByteArray &a) +{ + d->thread->write(a); +} + +SecureArray ConsoleReference::readSecure(int bytes) +{ + return d->thread->readSecure(bytes); +} + +void ConsoleReference::writeSecure(const SecureArray &a) +{ + d->thread->writeSecure(a); +} + +void ConsoleReference::closeOutput() +{ + d->thread->closeOutput(); +} + +int ConsoleReference::bytesAvailable() const +{ + return d->thread->bytesAvailable(); +} + +int ConsoleReference::bytesToWrite() const +{ + return d->thread->bytesToWrite(); +} + +//---------------------------------------------------------------------------- +// ConsolePrompt +//---------------------------------------------------------------------------- +class ConsolePrompt::Private : public QObject +{ + Q_OBJECT +public: + ConsolePrompt *q; + + Synchronizer sync; + Console *con; + bool own_con; + ConsoleReference console; + QString promptStr; + SecureArray result; + bool waiting; + int at; + bool done; + bool charMode; + QTextCodec *codec; + QTextCodec::ConverterState *encstate, *decstate; + + Private(ConsolePrompt *_q) + : QObject(_q) + , q(_q) + , sync(_q) + , console(this) + { + connect(&console, &ConsoleReference::readyRead, this, &Private::con_readyRead); + connect(&console, &ConsoleReference::inputClosed, this, &Private::con_inputClosed); + + con = nullptr; + own_con = false; + waiting = false; + +#ifdef Q_OS_WIN + codec = QTextCodec::codecForMib(106); // UTF-8 +#else + codec = QTextCodec::codecForLocale(); +#endif + encstate = nullptr; + decstate = nullptr; + } + + ~Private() override + { + reset(); + } + + void reset() + { + delete encstate; + encstate = nullptr; + delete decstate; + decstate = nullptr; + + console.stop(); + if (own_con) { + delete con; + con = nullptr; + own_con = false; + } + } + + bool start(bool _charMode) + { + own_con = false; + con = Console::ttyInstance(); + if (!con) { + con = new Console(Console::Tty, Console::ReadWrite, Console::Interactive); + own_con = true; + } + + result.clear(); + at = 0; + done = false; + charMode = _charMode; + + encstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader); + decstate = new QTextCodec::ConverterState(QTextCodec::IgnoreHeader); + + if (!console.start(con, ConsoleReference::SecurityEnabled)) { + reset(); + fprintf(stderr, "Console input not available or closed\n"); + return false; + } + + if (!charMode) + writeString(promptStr + QStringLiteral(": ")); + + return true; + } + + void writeString(const QString &str) + { + console.writeSecure(codec->fromUnicode(str.unicode(), str.length(), encstate)); + } + + // process each char. internally store the result as utf16, which + // is easier to edit (e.g. backspace) + bool processChar(QChar c) + { + if (charMode) { + appendChar(c); + done = true; + return false; + } + + if (c == QLatin1Char('\r') || c == QLatin1Char('\n')) { + writeString(QStringLiteral("\n")); + done = true; + return false; + } + + if (c == QLatin1Char('\b') || c.unicode() == 0x7f) { + if (at > 0) { + --at; + writeString(QStringLiteral("\b \b")); + result.resize(at * sizeof(ushort)); + } + return true; + } else if (c.unicode() < 0x20) + return true; + + if (at >= CONSOLEPROMPT_INPUT_MAX) + return true; + + appendChar(c); + + writeString(QStringLiteral("*")); + return true; + } + + void appendChar(QChar c) + { + if ((at + 1) * (int)sizeof(ushort) > result.size()) + result.resize((at + 1) * sizeof(ushort)); + ushort *p = reinterpret_cast(result.data()); + p[at++] = c.unicode(); + } + + void convertToUtf8() + { + // convert result from utf16 to utf8, securely + QTextCodec *codec = QTextCodec::codecForMib(106); + QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader); + SecureArray out; + const ushort *ustr = reinterpret_cast(result.data()); + const int len = result.size() / sizeof(ushort); + for (int n = 0; n < len; ++n) { + QChar c(ustr[n]); + out += codec->fromUnicode(&c, 1, &cstate); + } + result = out; + } + +private Q_SLOTS: + void con_readyRead() + { + while (console.bytesAvailable() > 0) { + SecureArray buf = console.readSecure(1); + if (buf.isEmpty()) + break; + + // convert to unicode and process + const QString str = codec->toUnicode(buf.data(), 1, decstate); + bool quit = false; + for (const QChar &c : str) { + if (!processChar(c)) { + quit = true; + break; + } + } + if (quit) + break; + } + + if (done) { + convertToUtf8(); + + reset(); + if (waiting) + sync.conditionMet(); + else + emit q->finished(); + } + } + + void con_inputClosed() + { + fprintf(stderr, "Console input closed\n"); + if (!done) { + done = true; + result.clear(); + + reset(); + if (waiting) + sync.conditionMet(); + else + emit q->finished(); + } + } +}; + +ConsolePrompt::ConsolePrompt(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +ConsolePrompt::~ConsolePrompt() +{ + delete d; +} + +void ConsolePrompt::getHidden(const QString &promptStr) +{ + d->reset(); + + d->promptStr = promptStr; + if (!d->start(false)) { + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + return; + } +} + +void ConsolePrompt::getChar() +{ + d->reset(); + + if (!d->start(true)) { + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + return; + } +} + +void ConsolePrompt::waitForFinished() +{ + // reparent the Console under us (for Synchronizer) + QObject *orig_parent = d->con->parent(); + d->con->setParent(this); + + // block while prompting + d->waiting = true; + d->sync.waitForCondition(); + d->waiting = false; + + // restore parent (if con still exists) + if (d->con) + d->con->setParent(orig_parent); +} + +SecureArray ConsolePrompt::result() const +{ + return d->result; +} + +QChar ConsolePrompt::resultChar() const +{ + const QString str = QString::fromUtf8(d->result.toByteArray()); + + // this will never happen if getChar completes + if (str.isEmpty()) + return QChar(); + + return str[0]; +} + +} + +#include "console.moc" diff --git a/local/recipes/libs/qca/source/src/support/dirwatch.cpp b/local/recipes/libs/qca/source/src/support/dirwatch.cpp new file mode 100644 index 0000000000..016b10bec0 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/dirwatch.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2003-2008 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_support.h" + +#include "qca_safeobj.h" +#include +#include +#include +#include +#include + +namespace QCA { + +// this gets us DOR-SS and SR, provided we delete the object between uses. +// we assume QFileSystemWatcher complies to DS,NE. +class QFileSystemWatcherRelay : public QObject +{ + Q_OBJECT +public: + QFileSystemWatcher *watcher; + + QFileSystemWatcherRelay(QFileSystemWatcher *_watcher, QObject *parent = nullptr) + : QObject(parent) + , watcher(_watcher) + { + connect(watcher, + &QFileSystemWatcher::directoryChanged, + this, + &QFileSystemWatcherRelay::directoryChanged, + Qt::QueuedConnection); + connect(watcher, + &QFileSystemWatcher::fileChanged, + this, + &QFileSystemWatcherRelay::fileChanged, + Qt::QueuedConnection); + } + +Q_SIGNALS: + void directoryChanged(const QString &path); + void fileChanged(const QString &path); +}; + +//---------------------------------------------------------------------------- +// DirWatch +//---------------------------------------------------------------------------- +class DirWatch::Private : public QObject +{ + Q_OBJECT +public: + DirWatch *q; + QFileSystemWatcher *watcher; + QFileSystemWatcherRelay *watcher_relay; + QString dirName; + + Private(DirWatch *_q) + : QObject(_q) + , q(_q) + , watcher(nullptr) + , watcher_relay(nullptr) + { + } + +public Q_SLOTS: + void watcher_changed(const QString &path) + { + Q_UNUSED(path); + emit q->changed(); + } +}; + +DirWatch::DirWatch(const QString &dir, QObject *parent) + : QObject(parent) +{ + d = new Private(this); + setDirName(dir); +} + +DirWatch::~DirWatch() +{ + delete d; +} + +QString DirWatch::dirName() const +{ + return d->dirName; +} + +void DirWatch::setDirName(const QString &dir) +{ + if (d->watcher) { + delete d->watcher; + delete d->watcher_relay; + d->watcher = nullptr; + d->watcher_relay = nullptr; + } + + d->dirName = dir; + + if (!d->dirName.isEmpty() && QFileInfo(d->dirName).isDir()) { + d->watcher = new QFileSystemWatcher(this); + d->watcher_relay = new QFileSystemWatcherRelay(d->watcher, this); + connect(d->watcher_relay, &QFileSystemWatcherRelay::directoryChanged, d, &Private::watcher_changed); + + d->watcher->addPath(d->dirName); + } +} + +//---------------------------------------------------------------------------- +// FileWatch +//---------------------------------------------------------------------------- + +class FileWatch::Private : public QObject +{ + Q_OBJECT +public: + FileWatch *q; + QFileSystemWatcher *watcher; + QFileSystemWatcherRelay *watcher_relay; + QString fileName; // file (optionally w/ path) as provided by user + QString filePath; // absolute path of file, calculated by us + bool fileExisted; + + Private(FileWatch *_q) + : QObject(_q) + , q(_q) + , watcher(nullptr) + , watcher_relay(nullptr) + { + } + + void start(const QString &_fileName) + { + fileName = _fileName; + + watcher = new QFileSystemWatcher(this); + watcher_relay = new QFileSystemWatcherRelay(watcher, this); + connect(watcher_relay, &QFileSystemWatcherRelay::directoryChanged, this, &Private::dir_changed); + connect(watcher_relay, &QFileSystemWatcherRelay::fileChanged, this, &Private::file_changed); + + QFileInfo fi(fileName); + fi.makeAbsolute(); + filePath = fi.filePath(); + const QDir dir = fi.dir(); + + // we watch both the directory and the file itself. the + // reason we watch the directory is so we can detect when + // the file is deleted/created + + // we don't bother checking for dir existence before adding, + // since there isn't an atomic way to do both at once. if + // it turns out that the dir doesn't exist, then the + // monitoring will just silently not work at all. + + watcher->addPath(dir.path()); + + // can't watch for non-existent directory + if (!watcher->directories().contains(dir.path())) { + stop(); + return; + } + + // save whether or not the file exists + fileExisted = fi.exists(); + + // add only if file existent + // if no it will be added on directoryChanged signal + if (fileExisted) + watcher->addPath(filePath); + + // TODO: address race conditions and think about error + // reporting instead of silently failing. probably this + // will require a Qt API update. + } + + void stop() + { + if (watcher) { + delete watcher; + delete watcher_relay; + watcher = nullptr; + watcher_relay = nullptr; + } + + fileName.clear(); + filePath.clear(); + } + +private Q_SLOTS: + void dir_changed(const QString &path) + { + Q_UNUSED(path); + QFileInfo fi(filePath); + const bool exists = fi.exists(); + if (exists && !fileExisted) { + // this means the file was created. put a + // watch on it. + fileExisted = true; + watcher->addPath(filePath); + emit q->changed(); + } + } + + void file_changed(const QString &path) + { + Q_UNUSED(path); + QFileInfo fi(filePath); + if (!fi.exists() && !fileExisted) { + // Got a file changed signal on a file that does not exist + // and is not actively watched. This happens when we + // previously watched a file but it was deleted and after + // the original deletion changed-signal we get another one + // (for example because of bad signal timing). In this scenario + // we must ignore the change as the change, whatever it may + // have been, is of no interest to us because we don't watch + // the file and furthermore the file does not even exist. + return; + } else if (!fi.exists()) { + fileExisted = false; + }; + emit q->changed(); + } +}; + +FileWatch::FileWatch(const QString &file, QObject *parent) + : QObject(parent) +{ + d = new Private(this); + d->start(file); +} + +FileWatch::~FileWatch() +{ + delete d; +} + +QString FileWatch::fileName() const +{ + return d->fileName; +} + +void FileWatch::setFileName(const QString &file) +{ + d->stop(); + d->start(file); +} + +} + +#include "dirwatch.moc" diff --git a/local/recipes/libs/qca/source/src/support/logger.cpp b/local/recipes/libs/qca/source/src/support/logger.cpp new file mode 100644 index 0000000000..056d0cccb1 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/logger.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2007 Brad Hards + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_support.h" + +#include + +namespace QCA { + +AbstractLogDevice::AbstractLogDevice(const QString &name, QObject *parent) + : QObject(parent) + , m_name(name) +{ +} + +AbstractLogDevice::~AbstractLogDevice() +{ +} + +QString AbstractLogDevice::name() const +{ + return m_name; +} + +void AbstractLogDevice::logTextMessage(const QString &message, Logger::Severity severity) +{ + Q_UNUSED(message); + Q_UNUSED(severity); +} + +void AbstractLogDevice::logBinaryMessage(const QByteArray &blob, Logger::Severity severity) +{ + Q_UNUSED(blob); + Q_UNUSED(severity); +} + +Logger::Logger() +{ + // d pointer? + m_logLevel = Logger::Notice; +} + +Logger::~Logger() +{ + // delete d; +} + +QStringList Logger::currentLogDevices() const +{ + return m_loggerNames; +} + +void Logger::registerLogDevice(AbstractLogDevice *logger) +{ + m_loggers.append(logger); + m_loggerNames.append(logger->name()); +} + +void Logger::unregisterLogDevice(const QString &loggerName) +{ + for (int i = 0; i < m_loggers.size(); ++i) { + if (m_loggers[i]->name() == loggerName) { + m_loggers.removeAt(i); + --i; // we backstep, to make sure we check the new entry in this position. + } + } + for (int i = 0; i < m_loggerNames.size(); ++i) { + if (m_loggerNames[i] == loggerName) { + m_loggerNames.removeAt(i); + --i; // we backstep, to make sure we check the new entry in this position. + } + } +} + +void Logger::setLevel(Severity level) +{ + m_logLevel = level; +} + +void Logger::logTextMessage(const QString &message, Severity severity) +{ + if (severity <= level()) { + for (AbstractLogDevice *logger : std::as_const(m_loggers)) { + logger->logTextMessage(message, severity); + } + } +} + +void Logger::logBinaryMessage(const QByteArray &blob, Severity severity) +{ + if (severity <= level()) { + for (AbstractLogDevice *logger : std::as_const(m_loggers)) { + logger->logBinaryMessage(blob, severity); + } + } +} + +} diff --git a/local/recipes/libs/qca/source/src/support/qpipe.cpp b/local/recipes/libs/qca/source/src/support/qpipe.cpp new file mode 100644 index 0000000000..122e96a895 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/qpipe.cpp @@ -0,0 +1,2035 @@ +/* + * Copyright (C) 2003-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +// Note: if we ever enable the threaded backend, we need to protect: +// QPipeDevice read and bytesAvailable +// QPipeEnd finalize + +// Note: we never use the return value for QPipeWriter::stop, but I don't +// think this matters much + +#include "qpipe.h" + +#include +#include + +// sorry, i've added this dependency for now, but it's easy enough to take +// with you if you want qpipe independent of qca +#include "qca_safeobj.h" + +#ifdef Q_OS_WIN +#include +#include +#include +#include +#include +#include +#else +#include +#endif + +#ifdef Q_OS_UNIX +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_FILIO_H +#include +#endif +#endif + +#define USE_POLL + +#define CONSOLE_CHAREXPAND 5 +#define PIPEWRITER_POLL 1000 +#define PIPEREADER_POLL 100 +#define PIPEWRITER_BLOCK 8192 +#define PIPEEND_BLOCK 8192 +#define PIPEEND_READBUF 16384 +#define PIPEEND_READBUF_SEC 1024 + +namespace QCA { + +#ifdef Q_OS_UNIX +// adapted from qt +Q_GLOBAL_STATIC(QMutex, ign_mutex) +static bool ign_sigpipe = false; + +static void ignore_sigpipe() +{ + // Set to ignore SIGPIPE once only. + QMutexLocker locker(ign_mutex()); + if (!ign_sigpipe) { + ign_sigpipe = true; + struct sigaction noaction; + memset(&noaction, 0, sizeof(noaction)); + noaction.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &noaction, nullptr); + } +} +#endif + +#ifdef Q_OS_WIN +static int pipe_dword_cap_to_int(DWORD dw) +{ + if (sizeof(int) <= sizeof(DWORD)) + return (int)((dw > INT_MAX) ? INT_MAX : dw); + else + return (int)dw; +} + +static bool pipe_dword_overflows_int(DWORD dw) +{ + if (sizeof(int) <= sizeof(DWORD)) + return (dw > INT_MAX) ? true : false; + else + return false; +} +#endif + +#ifdef Q_OS_UNIX +static int pipe_size_t_cap_to_int(size_t size) +{ + if (sizeof(int) <= sizeof(size_t)) + return (int)((size > INT_MAX) ? INT_MAX : size); + else // maybe silly.. can int ever be larger than size_t? + return (int)size; +} +#endif + +static bool pipe_set_blocking(Q_PIPE_ID pipe, bool b) +{ +#ifdef Q_OS_WIN + DWORD flags = 0; + if (!b) + flags |= PIPE_NOWAIT; + if (!SetNamedPipeHandleState(pipe, &flags, NULL, NULL)) + return false; + return true; +#endif +#ifdef Q_OS_UNIX + int flags = fcntl(pipe, F_GETFL); + if (!b) + flags |= O_NONBLOCK; + else + flags &= ~O_NONBLOCK; + if (fcntl(pipe, F_SETFL, flags) == -1) + return false; + return true; +#endif +} + +// on windows, the pipe is closed and the new pipe is returned in newPipe +static bool pipe_set_inheritable(Q_PIPE_ID pipe, bool b, Q_PIPE_ID *newPipe = nullptr) +{ +#ifdef Q_OS_WIN + // windows is required to accept a new pipe id + if (!newPipe) + return false; + HANDLE h; + if (!DuplicateHandle(GetCurrentProcess(), pipe, GetCurrentProcess(), &h, 0, b, DUPLICATE_SAME_ACCESS)) + return false; + *newPipe = h; + return true; +#endif +#ifdef Q_OS_UNIX + if (newPipe) + *newPipe = pipe; + int flags = fcntl(pipe, F_GETFD); + if (!b) + flags |= FD_CLOEXEC; + else + flags &= ~FD_CLOEXEC; + if (fcntl(pipe, F_SETFD, flags) == -1) + return false; + return true; +#endif +} + +// returns number of bytes available +static int pipe_read_avail(Q_PIPE_ID pipe) +{ + int bytesAvail = 0; +#ifdef Q_OS_WIN + DWORD i = 0; + if (PeekNamedPipe(pipe, 0, 0, 0, &i, 0)) + bytesAvail = pipe_dword_cap_to_int(i); +#endif +#ifdef Q_OS_UNIX + size_t nbytes = 0; + if (ioctl(pipe, FIONREAD, (char *)&nbytes) >= 0) + bytesAvail = pipe_size_t_cap_to_int(nbytes); +#endif + return bytesAvail; +} + +// returns number of bytes actually read, no more than 'max'. +// -1 on error. 0 means no data, NOT EOF. +// note: even though this function looks like it can return data and EOF +// at the same time, it never actually does. +static int pipe_read(Q_PIPE_ID pipe, char *data, int max, bool *eof) +{ + int bytesRead = 0; + if (eof) + *eof = false; + if (max < 1) + return 0; +#ifdef Q_OS_WIN + DWORD maxread = max; + DWORD r = 0; + if (!ReadFile(pipe, data, maxread, &r, 0)) { + const DWORD err = GetLastError(); + if (err == ERROR_HANDLE_EOF) { + if (eof) + *eof = true; + } else if (err == ERROR_NO_DATA) { + r = 0; + } else + return -1; + } + bytesRead = (int)r; // safe to cast, since 'max' is signed +#endif +#ifdef Q_OS_UNIX + int r = 0; + int ret = read(pipe, data, max); + if (ret == -1) { + if (errno != EAGAIN) + return -1; + } else if (ret == 0) { + if (eof) + *eof = true; + } else + r = ret; + + bytesRead = r; +#endif + return bytesRead; +} + +// returns number of bytes actually written. +// for blocking pipes, this should always be 'size'. +// -1 on error. +static int pipe_write(Q_PIPE_ID pipe, const char *data, int size) +{ +#ifdef Q_OS_WIN + DWORD written; + if (!WriteFile(pipe, data, size, &written, 0)) + return -1; + return (int)written; // safe to cast, since 'size' is signed +#endif +#ifdef Q_OS_UNIX + ignore_sigpipe(); + int r = 0; + int ret = write(pipe, data, size); + if (ret == -1) { + if (errno != EAGAIN) + return -1; + } else + r = ret; + return r; +#endif +} + +// Windows Console functions + +#ifdef Q_OS_WIN + +static bool pipe_is_a_console(Q_PIPE_ID pipe) +{ + DWORD mode; + if (GetConsoleMode(pipe, &mode)) + return true; + return false; +} + +// returns the number of keypress events in the console input queue, +// or -1 if there is an error (don't forget this!!) +static int pipe_read_avail_console(Q_PIPE_ID pipe) +{ + DWORD count, i; + INPUT_RECORD *rec; + int n, icount, total; + + // how many events are there? + if (!GetNumberOfConsoleInputEvents(pipe, &count)) + return -1; + + // peek them all + rec = (INPUT_RECORD *)malloc(count * sizeof(INPUT_RECORD)); + BOOL ret; + ret = PeekConsoleInputW(pipe, rec, count, &i); + if (!ret) { + free(rec); + return -1; + } + + icount = pipe_dword_cap_to_int(i); // process only the amount returned + + // see which ones are normal keypress events + total = 0; + for (n = 0; n < icount; ++n) { + if (rec[n].EventType == KEY_EVENT) { + KEY_EVENT_RECORD *ke = &rec[n].Event.KeyEvent; + if (ke->bKeyDown && ke->uChar.AsciiChar != 0) + total += ke->wRepeatCount; + } + } + + free(rec); + return total; +} + +// pass dec to keep a long-running decoder, else 0 +static int pipe_read_console(Q_PIPE_ID pipe, ushort *data, int max, bool *eof, QTextDecoder *dec = 0) +{ + int n, size, count; + bool own_decoder; + + if (eof) + *eof = false; + if (max < 1) + return 0; + + count = pipe_read_avail_console(pipe); + if (count == -1) + return -1; + if (count == 0) + return 0; + + if (dec) { + own_decoder = false; + } else { + dec = 0; + own_decoder = true; + } + + size = 0; + for (n = 0; n < count && size < max; ++n) { + bool use_uni = true; + quint16 uni = 0; + quint8 ansi = 0; + + BOOL ret; + DWORD i; + ret = ReadConsoleW(pipe, &uni, 1, &i, NULL); + if (!ret) { + // if the first read is an error, then report error + if (n == 0) { + delete dec; + return -1; + } + // if we have some data, don't count this as an error. + // we'll probably get it again next time around... + else + break; + } + + QString substr; + if (use_uni) + substr = QChar(uni); + else + substr = dec->toUnicode((const char *)&ansi, 1); + + for (int k = 0; k < substr.length() && size < max; ++k) { + QChar c = substr[k]; + if (c == QChar(0x1A)) // EOF? + { + if (eof) + *eof = true; + break; + } + data[size++] = substr[k].unicode(); + } + } + if (own_decoder) + delete dec; + + return size; +} + +static int pipe_write_console(Q_PIPE_ID pipe, const ushort *data, int size) +{ + DWORD i; + BOOL ret; + ret = WriteConsoleW(pipe, data, size, &i, NULL); + if (!ret) + return -1; + return (int)i; // safe to cast since 'size' is signed +} +#endif + +#ifdef Q_OS_WIN + +// Here is the multi-backend stuff for windows. QPipeWriter and QPipeReader +// define a common interface, and then subclasses (like QPipeWriterThread) +// are used by QPipeDevice. The base classes inherit from QThread, even +// if threads aren't used, so that I can define signals without dealing +// with multiple QObject inheritance in the thread subclasses (it is also +// possible that I'm missing something obvious and don't need to do this). + +// Note: +// QPipeWriterThread and QPipeReaderThread require the pipes to be in +// blocking mode. QPipeWriterPoll and QPipeReaderPoll require the pipes +// to be in non-blocking mode. + +//---------------------------------------------------------------------------- +// QPipeWriter +//---------------------------------------------------------------------------- +class QPipeWriter : public QThread +{ + Q_OBJECT +public: + QPipeWriter(QObject *parent = nullptr) + : QThread(parent) + { + } + + virtual ~QPipeWriter() + { + } + + // start + virtual void start() = 0; + + // stop, and return number of bytes written so far + virtual int stop() = 0; + + // data pointer needs to remain until canWrite is emitted + virtual int write(const char *data, int size) = 0; + +Q_SIGNALS: + // result values: + // = 0 : success + // = -1 : error + void canWrite(int result, int bytesWritten); + +protected: + virtual void run() + { + // implement a default to satisfy the polling subclass + } +}; + +//---------------------------------------------------------------------------- +// QPipeReader +//---------------------------------------------------------------------------- +class QPipeReader : public QThread +{ + Q_OBJECT +public: + QPipeReader(QObject *parent = nullptr) + : QThread(parent) + { + } + + virtual ~QPipeReader() + { + } + + // start + virtual void start() = 0; + + // to be called after every read + virtual void resume() = 0; + +Q_SIGNALS: + // result values: + // >= 0 : readAhead + // = -1 : atEnd + // = -2 : atError + // = -3 : data available, but no readAhead + void canRead(int result); + +protected: + virtual void run() + { + // implement a default to satisfy the polling subclass + } +}; + +//---------------------------------------------------------------------------- +// QPipeWriterThread +//---------------------------------------------------------------------------- +class QPipeWriterThread : public QPipeWriter +{ + Q_OBJECT +public: + Q_PIPE_ID pipe; + QMutex m; + QWaitCondition w; + bool do_quit; + const char *data; + int size; + + QPipeWriterThread(Q_PIPE_ID id, QObject *parent = nullptr) + : QPipeWriter(parent) + { + do_quit = false; + data = 0; + connect(this, &QPipeWriterThread::canWrite_p, this, &QPipeWriterThread::canWrite); + DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS); + } + + virtual ~QPipeWriterThread() + { + stop(); + CloseHandle(pipe); + } + + virtual void start() + { + pipe_set_blocking(pipe, true); + QThread::start(); + } + + virtual int stop() + { + if (isRunning()) { + m.lock(); + do_quit = true; + w.wakeOne(); + m.unlock(); + if (!wait(100)) + terminate(); + do_quit = false; + data = 0; + } + return size; + } + + virtual int write(const char *_data, int _size) + { + if (!isRunning()) + return -1; + + QMutexLocker locker(&m); + if (data) + return 0; + + data = _data; + size = _size; + w.wakeOne(); + return _size; + } + +protected: + virtual void run() + { + while (1) { + m.lock(); + + while (!data && !do_quit) + w.wait(&m); + + if (do_quit) { + m.unlock(); + break; + } + + const char *p = data; + int len = size; + + m.unlock(); + + int ret = internalWrite(p, len); + + m.lock(); + data = 0; + size = ret; + m.unlock(); + + emit canWrite_p(ret < len ? -1 : 0, ret); + } + } + +private: + // attempts to write len bytes. value returned is number of bytes written. + // any return value less than len means a write error was encountered + int internalWrite(const char *p, int len) + { + int total = 0; + while (total < len) { + m.lock(); + if (do_quit) { + m.unlock(); + return 0; + } + m.unlock(); + + int ret = pipe_write(pipe, p + total, qMin(PIPEWRITER_BLOCK, len - total)); + if (ret == -1) { + // from qt, don't know why + if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER + { + // give the os a rest + msleep(100); + continue; + } + + // on any other error, end thread + return total; + } + total += ret; + } + return total; + } + +Q_SIGNALS: + void canWrite_p(int result, int bytesWritten); +}; + +//---------------------------------------------------------------------------- +// QPipeWriterPoll +//---------------------------------------------------------------------------- +class QPipeWriterPoll : public QPipeWriter +{ + Q_OBJECT +public: + Q_PIPE_ID pipe; + const char *data; + int size; + SafeTimer timer; + int total; + + QPipeWriterPoll(Q_PIPE_ID id, QObject *parent = nullptr) + : QPipeWriter(parent) + , timer(this) + { + pipe = id; + data = 0; + connect(&timer, &SafeTimer::timeout, this, &QPipeWriterPoll::tryNextWrite); + } + + virtual ~QPipeWriterPoll() + { + } + + virtual void start() + { + pipe_set_blocking(pipe, false); + } + + // return number of bytes written + virtual int stop() + { + timer.stop(); + data = 0; + return total; + } + + // data pointer needs to remain until canWrite is emitted + virtual int write(const char *_data, int _size) + { + total = 0; + data = _data; + size = _size; + timer.start(0); // write at next event loop + return _size; + } + +private Q_SLOTS: + void tryNextWrite() + { + int written = pipe_write(pipe, data + total, size - total); + bool error = false; + if (written == -1) { + error = true; + written = 0; // no bytes written on error + + // from qt, they don't count it as fatal + if (GetLastError() == 0xE8) // NT_STATUS_INVALID_USER_BUFFER + error = false; + } + + total += written; + if (error || total == size) { + timer.stop(); + data = 0; + emit canWrite(error ? -1 : 0, total); + return; + } + + timer.setInterval(PIPEWRITER_POLL); + } +}; + +//---------------------------------------------------------------------------- +// QPipeReaderThread +//---------------------------------------------------------------------------- +class QPipeReaderThread : public QPipeReader +{ + Q_OBJECT +public: + Q_PIPE_ID pipe; + QMutex m; + QWaitCondition w; + bool do_quit, active; + + QPipeReaderThread(Q_PIPE_ID id, QObject *parent = nullptr) + : QPipeReader(parent) + { + do_quit = false; + active = true; + connect(this, &QPipeReaderThread::canRead_p, this, &QPipeReaderThread::canRead); + DuplicateHandle(GetCurrentProcess(), id, GetCurrentProcess(), &pipe, 0, false, DUPLICATE_SAME_ACCESS); + } + + virtual ~QPipeReaderThread() + { + if (isRunning()) { + m.lock(); + do_quit = true; + w.wakeOne(); + m.unlock(); + if (!wait(100)) + terminate(); + } + CloseHandle(pipe); + } + + virtual void start() + { + pipe_set_blocking(pipe, true); + QThread::start(); + } + + virtual void resume() + { + QMutexLocker locker(&m); + pipe_set_blocking(pipe, true); + active = true; + w.wakeOne(); + } + +protected: + virtual void run() + { + while (1) { + m.lock(); + + while (!active && !do_quit) + w.wait(&m); + + if (do_quit) { + m.unlock(); + break; + } + + m.unlock(); + + while (1) { + unsigned char c; + bool done; + int ret = pipe_read(pipe, (char *)&c, 1, &done); + if (done || ret != 0) // eof, error, or data? + { + int result; + + if (done) // we got EOF? + result = -1; + else if (ret == -1) // we got an error? + result = -2; + else if (ret >= 1) // we got some data?? queue it + result = c; + else // will never happen + result = -2; + + m.lock(); + active = false; + pipe_set_blocking(pipe, false); + m.unlock(); + + emit canRead_p(result); + break; + } + } + } + } + +Q_SIGNALS: + void canRead_p(int result); +}; + +//---------------------------------------------------------------------------- +// QPipeReaderPoll +//---------------------------------------------------------------------------- +class QPipeReaderPoll : public QPipeReader +{ + Q_OBJECT +public: + Q_PIPE_ID pipe; + SafeTimer timer; + bool consoleMode; + + QPipeReaderPoll(Q_PIPE_ID id, QObject *parent = nullptr) + : QPipeReader(parent) + , timer(this) + { + pipe = id; + connect(&timer, &SafeTimer::timeout, this, &QPipeReaderPoll::tryRead); + } + + virtual ~QPipeReaderPoll() + { + } + + virtual void start() + { + pipe_set_blocking(pipe, false); + consoleMode = pipe_is_a_console(pipe); + resume(); + } + + virtual void resume() + { + timer.start(0); + } + +private Q_SLOTS: + void tryRead() + { + if (consoleMode) + tryReadConsole(); + else + tryReadPipe(); + } + +private: + void tryReadPipe() + { + // is there data available for reading? if so, signal. + int bytes = pipe_read_avail(pipe); + if (bytes > 0) { + timer.stop(); + emit canRead(-3); // no readAhead + return; + } + + // no data available? probe for EOF/error + unsigned char c; + bool done; + int ret = pipe_read(pipe, (char *)&c, 1, &done); + if (done || ret != 0) // eof, error, or data? + { + int result; + + if (done) // we got EOF? + result = -1; + else if (ret == -1) // we got an error? + result = -2; + else if (ret >= 1) // we got some data?? queue it + result = c; + else // will never happen + result = -2; + + timer.stop(); + emit canRead(result); + return; + } + + timer.setInterval(PIPEREADER_POLL); + } + + void tryReadConsole() + { + // is there data available for reading? if so, signal. + int count = pipe_read_avail_console(pipe); + if (count > 0) { + timer.stop(); + emit canRead(-3); // no readAhead + return; + } + + timer.setInterval(PIPEREADER_POLL); + } +}; + +// end of windows pipe writer/reader implementations + +#endif + +//---------------------------------------------------------------------------- +// QPipeDevice +//---------------------------------------------------------------------------- +class QPipeDevice::Private : public QObject +{ + Q_OBJECT +public: + QPipeDevice *q; + Q_PIPE_ID pipe; + QPipeDevice::Type type; + bool enabled; + bool blockReadNotify; + bool canWrite; + int writeResult; + int lastTaken, lastWritten; + +#ifdef Q_OS_WIN + bool atEnd, atError, forceNotify; + int readAhead; + SafeTimer *readTimer; + QTextDecoder *dec; + bool consoleMode; + QPipeWriter *pipeWriter; + QPipeReader *pipeReader; +#endif +#ifdef Q_OS_UNIX + SafeSocketNotifier *sn_read, *sn_write; +#endif + + Private(QPipeDevice *_q) + : QObject(_q) + , q(_q) + , pipe(INVALID_Q_PIPE_ID) + { +#ifdef Q_OS_WIN + readTimer = 0; + pipeWriter = 0; + pipeReader = 0; + dec = 0; +#endif +#ifdef Q_OS_UNIX + sn_read = nullptr; + sn_write = nullptr; +#endif + } + + ~Private() override + { + reset(); + } + + void reset() + { +#ifdef Q_OS_WIN + atEnd = false; + atError = false; + forceNotify = false; + readAhead = -1; + delete readTimer; + readTimer = 0; + delete pipeWriter; + pipeWriter = 0; + delete pipeReader; + pipeReader = 0; + delete dec; + dec = 0; + consoleMode = false; +#endif +#ifdef Q_OS_UNIX + delete sn_read; + sn_read = nullptr; + delete sn_write; + sn_write = nullptr; +#endif + if (pipe != INVALID_Q_PIPE_ID) { +#ifdef Q_OS_WIN + CloseHandle(pipe); +#endif +#ifdef Q_OS_UNIX + ::close(pipe); +#endif + pipe = INVALID_Q_PIPE_ID; + } + + enabled = false; + blockReadNotify = false; + canWrite = true; + writeResult = -1; + } + + void setup(Q_PIPE_ID id, QPipeDevice::Type _type) + { + pipe = id; + type = _type; + } + + void enable() + { + if (enabled) + return; + + enabled = true; + + if (type == QPipeDevice::Read) { +#ifdef Q_OS_WIN + // for windows, the blocking mode is chosen by the QPipeReader + + // console might need a decoder + if (consoleMode) { + dec = 0; + } + + // pipe reader +#ifdef USE_POLL + pipeReader = new QPipeReaderPoll(pipe, this); +#else + // console always polls, no matter what + if (consoleMode) + pipeReader = new QPipeReaderPoll(pipe, this); + else + pipeReader = new QPipeReaderThread(pipe, this); +#endif + connect(pipeReader, &QPipeReader::canRead, this, &Private::pr_canRead); + pipeReader->start(); + + // polling timer + readTimer = new SafeTimer(this); + connect(readTimer, &SafeTimer::timeout, this, &Private::t_timeout); + + // updated: now that we have pipeReader, this no longer + // polls for data. it only does delayed singleshot + // notifications. + readTimer->setSingleShot(true); +#endif +#ifdef Q_OS_UNIX + pipe_set_blocking(pipe, false); + + // socket notifier + sn_read = new SafeSocketNotifier(pipe, QSocketNotifier::Read, this); + connect(sn_read, &SafeSocketNotifier::activated, this, &Private::sn_read_activated); +#endif + } else { + // for windows, the blocking mode is chosen by the QPipeWriter +#ifdef Q_OS_UNIX + pipe_set_blocking(pipe, false); + + // socket notifier + sn_write = new SafeSocketNotifier(pipe, QSocketNotifier::Write, this); + connect(sn_write, &SafeSocketNotifier::activated, this, &Private::sn_write_activated); + sn_write->setEnabled(false); +#endif + } + } + +public Q_SLOTS: + void t_timeout() + { +#ifdef Q_OS_WIN + if (blockReadNotify) + return; + + // were we forced to notify? this can happen if we want to + // spread out results across two reads. whatever caused + // the forceNotify already knows what to do, so all we do + // is signal. + if (forceNotify) { + forceNotify = false; + blockReadNotify = true; + emit q->notify(); + return; + } +#endif + } + + void pw_canWrite(int result, int bytesWritten) + { +#ifdef Q_OS_WIN + if (result == 0) { + writeResult = 0; + lastWritten = lastTaken; // success means all bytes + } else { + writeResult = -1; + lastWritten = bytesWritten; + } + + canWrite = true; + emit q->notify(); +#else + Q_UNUSED(result); + Q_UNUSED(bytesWritten); +#endif + } + + void pr_canRead(int result) + { +#ifdef Q_OS_WIN + blockReadNotify = true; + if (result == -1) + atEnd = true; + else if (result == -2) + atError = true; + else if (result != -3) + readAhead = result; + emit q->notify(); +#else + Q_UNUSED(result); +#endif + } + + void sn_read_activated() + { +#ifdef Q_OS_UNIX + if (blockReadNotify) + return; + + blockReadNotify = true; + emit q->notify(); +#endif + } + + void sn_write_activated() + { +#ifdef Q_OS_UNIX + writeResult = 0; + lastWritten = lastTaken; + + canWrite = true; + sn_write->setEnabled(false); + emit q->notify(); +#endif + } +}; + +QPipeDevice::QPipeDevice(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +QPipeDevice::~QPipeDevice() +{ + delete d; +} + +QPipeDevice::Type QPipeDevice::type() const +{ + return d->type; +} + +bool QPipeDevice::isValid() const +{ + return (d->pipe != INVALID_Q_PIPE_ID); +} + +Q_PIPE_ID QPipeDevice::id() const +{ + return d->pipe; +} + +int QPipeDevice::idAsInt() const +{ +#ifdef Q_OS_WIN + DWORD dw; + memcpy(&dw, &d->pipe, sizeof(DWORD)); + return (int)dw; // FIXME? assumes handle value fits in signed int +#endif +#ifdef Q_OS_UNIX + return d->pipe; +#endif +} + +void QPipeDevice::take(Q_PIPE_ID id, Type t) +{ + close(); + d->setup(id, t); +} + +void QPipeDevice::enable() +{ +#ifdef Q_OS_WIN + d->consoleMode = pipe_is_a_console(d->pipe); +#endif + d->enable(); +} + +void QPipeDevice::close() +{ + d->reset(); +} + +void QPipeDevice::release() +{ + d->pipe = INVALID_Q_PIPE_ID; + d->reset(); +} + +bool QPipeDevice::setInheritable(bool enabled) +{ +#ifdef Q_OS_WIN + Q_PIPE_ID newPipe; + if (!pipe_set_inheritable(d->pipe, enabled, &newPipe)) + return false; + d->pipe = newPipe; +#ifdef USE_POLL + if (d->pipeReader) + static_cast(d->pipeReader)->pipe = d->pipe; + if (d->pipeWriter) + static_cast(d->pipeWriter)->pipe = d->pipe; +#endif + return true; +#endif +#ifdef Q_OS_UNIX + return pipe_set_inheritable(d->pipe, enabled, nullptr); +#endif +} + +int QPipeDevice::bytesAvailable() const +{ + int n; +#ifdef Q_OS_WIN + if (d->consoleMode) + n = pipe_read_avail_console(d->pipe); + else + n = pipe_read_avail(d->pipe); + if (d->readAhead != -1) + ++n; +#else + n = pipe_read_avail(d->pipe); +#endif + return n; +} + +int QPipeDevice::read(char *data, int maxsize) +{ + if (d->type != QPipeDevice::Read) + return -1; + + // must read at least 1 byte + if (maxsize < 1) + return -1; + +#ifdef Q_OS_WIN + // for windows console: + // the number of bytes in utf8 can exceed the number of actual + // characters it represents. to be safe, we'll assume that + // utf8 could outnumber characters X:1. this does mean that + // the maxsize parameter needs to be at least X to do + // anything. (X = CONSOLE_CHAREXPAND) + if (d->consoleMode && maxsize < CONSOLE_CHAREXPAND) + return -1; + + // for resuming the pipeReader + bool wasBlocked = d->blockReadNotify; +#endif + + d->blockReadNotify = false; + +#ifdef Q_OS_WIN + // predetermined results + if (d->atEnd) { + close(); + return 0; + } + if (d->atError) { + close(); + return -1; + } + + int offset = 0; + int size = maxsize; + + // prepend readAhead if we have it + if (d->readAhead != -1) { + unsigned char c = (unsigned char)d->readAhead; + d->readAhead = -1; + memcpy(&data[0], &c, 1); + ++offset; + --size; + + // readAhead was enough data for the caller? + if (size == 0) { + if (wasBlocked) + d->pipeReader->resume(); + return offset; + } + } + + // read from the pipe now + bool done; + int ret; + if (d->consoleMode) { + // read a fraction of the number of characters as requested, + // to guarantee the result fits + int num = size / CONSOLE_CHAREXPAND; + +#ifdef QPIPE_SECURE + SecureArray destbuf(num * sizeof(ushort), 0); +#else + QByteArray destbuf(num * sizeof(ushort), 0); +#endif + ushort *dest = (ushort *)destbuf.data(); + + ret = pipe_read_console(d->pipe, dest, num, &done, d->dec); + if (ret != -1) { + // for security, encode one character at a time without + // performing a QString conversion of the whole thing + QTextCodec *codec = QTextCodec::codecForMib(106); + QTextCodec::ConverterState cstate(QTextCodec::IgnoreHeader); + int at = 0; + for (int n = 0; n < ret; ++n) { + QChar c(dest[n]); + QByteArray out = codec->fromUnicode(&c, 1, &cstate); + memcpy(data + offset + at, out.data(), out.size()); + at += out.size(); + } + ret = at; // change ret to actual bytes + } + } else + ret = pipe_read(d->pipe, data + offset, size, &done); + if (done || ret == -1) // eof or error + { + // did we already have some data? if so, defer the eof/error + if (offset) { + d->forceNotify = true; + if (done) + d->atEnd = true; + else + d->atError = true; + + // readTimer is a singleshot, so we have to start it + // for forceNotify to work + d->readTimer->start(); + } + // otherwise, bail + else { + close(); + if (done) + return 0; + else + return -1; + } + } else + offset += ret; + + // pipe still active? resume the pipeReader + if (wasBlocked && !d->atEnd && !d->atError) + d->pipeReader->resume(); + + // no data means error + if (offset == 0) + return -1; + + return offset; +#endif +#ifdef Q_OS_UNIX + bool done; + int r = pipe_read(d->pipe, data, maxsize, &done); + if (done) { + close(); + return 0; + } + if (r == -1) { + close(); + return -1; + } + + // no data means error + if (r == 0) + return -1; + + return r; +#endif +} + +int QPipeDevice::write(const char *data, int size) +{ + if (d->type != QPipeDevice::Write) + return -1; + + // allowed to write? + if (!d->canWrite) + return -1; + + // if size is zero, don't bother + if (size == 0) + return 0; + + int r; +#ifdef Q_OS_WIN + if (!d->pipeWriter) { +#ifdef USE_POLL + d->pipeWriter = new QPipeWriterPoll(d->pipe, d); +#else + // console always polls, no matter what + if (d->consoleMode) + d->pipeWriter = new QPipeReaderPoll(d->pipe, d); + else + d->pipeWriter = new QPipeWriterThread(d->pipe, d); +#endif + connect(d->pipeWriter, &QPipeWriter::canWrite, d, &Private::pw_canWrite); + d->pipeWriter->start(); + } + + if (d->consoleMode) { + // Note: we convert to QString here, but it should not be a + // security issue (see pipe_write_console comment above) + + // for console, just write direct. we won't use pipewriter + QString out = QString::fromUtf8(QByteArray(data, size)); + r = pipe_write_console(d->pipe, out.utf16(), out.length()); + if (r == -1) + return -1; + + // convert characters to bytes + r = out.mid(0, r).toUtf8().size(); + + // simulate. we invoke the signal of pipewriter rather than our + // own slot, so that the invoke can be cancelled. + d->canWrite = false; + QMetaObject::invokeMethod(d->pipeWriter, "canWrite", Qt::QueuedConnection, Q_ARG(int, 0), Q_ARG(int, r)); + } else { + d->canWrite = false; + r = d->pipeWriter->write(data, size); + } + + d->lastTaken = r; + if (r == -1) { + close(); + return -1; + } +#endif +#ifdef Q_OS_UNIX + r = pipe_write(d->pipe, data, size); + d->lastTaken = r; + if (r == -1) { + close(); + return -1; + } + + d->canWrite = false; + d->sn_write->setEnabled(true); +#endif + return r; +} + +int QPipeDevice::writeResult(int *written) const +{ + if (written) + *written = d->lastWritten; + return d->writeResult; +} + +//---------------------------------------------------------------------------- +// QPipeEnd +//---------------------------------------------------------------------------- +enum ResetMode +{ + ResetSession = 0, + ResetSessionAndData = 1, + ResetAll = 2 +}; + +class QPipeEnd::Private : public QObject +{ + Q_OBJECT +public: + QPipeEnd *q; + QPipeDevice pipe; + QPipeDevice::Type type; + QByteArray buf; + QByteArray curWrite; + +#ifdef Q_OS_WIN + bool consoleMode; +#endif + +#ifdef QPIPE_SECURE + bool secure; + SecureArray sec_buf; + SecureArray sec_curWrite; +#endif + SafeTimer readTrigger, writeTrigger, closeTrigger, writeErrorTrigger; + bool canRead, activeWrite; + int lastWrite; + bool closeLater; + bool closing; + + Private(QPipeEnd *_q) + : QObject(_q) + , q(_q) + , pipe(this) + , readTrigger(this) + , writeTrigger(this) + , closeTrigger(this) + , writeErrorTrigger(this) + { + readTrigger.setSingleShot(true); + writeTrigger.setSingleShot(true); + closeTrigger.setSingleShot(true); + writeErrorTrigger.setSingleShot(true); + connect(&pipe, &QPipeDevice::notify, this, &Private::pipe_notify); + connect(&readTrigger, &SafeTimer::timeout, this, &Private::doRead); + connect(&writeTrigger, &SafeTimer::timeout, this, &Private::doWrite); + connect(&closeTrigger, &SafeTimer::timeout, this, &Private::doClose); + connect(&writeErrorTrigger, &SafeTimer::timeout, this, &Private::doWriteError); + reset(ResetSessionAndData); + } + + void reset(ResetMode mode) + { + pipe.close(); + readTrigger.stop(); + writeTrigger.stop(); + closeTrigger.stop(); + writeErrorTrigger.stop(); + canRead = false; + activeWrite = false; + lastWrite = 0; + closeLater = false; + closing = false; + curWrite.clear(); +#ifdef QPIPE_SECURE + secure = false; + sec_curWrite.clear(); +#endif + + if (mode >= ResetSessionAndData) { + buf.clear(); +#ifdef QPIPE_SECURE + sec_buf.clear(); +#endif + } + } + + void setup(Q_PIPE_ID id, QPipeDevice::Type _type) + { + type = _type; +#ifdef Q_OS_WIN + consoleMode = pipe_is_a_console(id); +#endif + pipe.take(id, type); + } + + int pendingSize() const + { +#ifdef QPIPE_SECURE + if (secure) + return sec_buf.size(); + else +#endif + return buf.size(); + } + + int pendingFreeSize() const + { +#ifdef QPIPE_SECURE + if (secure) + return qMax(PIPEEND_READBUF_SEC - sec_buf.size(), 0); + else +#endif + return qMax(PIPEEND_READBUF - buf.size(), 0); + } + + void appendArray(QByteArray *a, const QByteArray &b) + { + (*a) += b; + } + +#ifdef QPIPE_SECURE + void appendArray(SecureArray *a, const SecureArray &b) + { + a->append(b); + } +#endif + + void takeArray(QByteArray *a, int len) + { + char *p = a->data(); + const int newsize = a->size() - len; + memmove(p, p + len, newsize); + a->resize(newsize); + } + +#ifdef QPIPE_SECURE + void takeArray(SecureArray *a, int len) + { + char *p = a->data(); + const int newsize = a->size() - len; + memmove(p, p + len, newsize); + a->resize(newsize); + } +#endif + + void setupNextRead() + { + if (pipe.isValid() && canRead) { + canRead = false; + readTrigger.start(0); + } + } + + void setupNextWrite() + { + if (!activeWrite) { + activeWrite = true; + writeTrigger.start(0); + } + } + + QByteArray read(QByteArray *buf, int bytes) + { + QByteArray a; + if (bytes == -1 || bytes > buf->size()) { + a = *buf; + } else { + a.resize(bytes); + memcpy(a.data(), buf->data(), a.size()); + } + + takeArray(buf, a.size()); + setupNextRead(); + return a; + } + + void write(QByteArray *buf, const QByteArray &a) + { + appendArray(buf, a); + setupNextWrite(); + } + +#ifdef QPIPE_SECURE + SecureArray readSecure(SecureArray *buf, int bytes) + { + SecureArray a; + if (bytes == -1 || bytes > buf->size()) { + a = *buf; + } else { + a.resize(bytes); + memcpy(a.data(), buf->data(), a.size()); + } + + takeArray(buf, a.size()); + setupNextRead(); + return a; + } + + void writeSecure(SecureArray *buf, const SecureArray &a) + { + appendArray(buf, a); + setupNextWrite(); + } +#endif + +public Q_SLOTS: + void pipe_notify() + { + if (pipe.type() == QPipeDevice::Read) { + doRead(); + } else { + int x; + int writeResult = pipe.writeResult(&x); + if (writeResult == -1) + lastWrite = x; // if error, we may have written less bytes + + // remove what we just wrote + bool moreData = false; +#ifdef QPIPE_SECURE + if (secure) { + takeArray(&sec_buf, lastWrite); + moreData = !sec_buf.isEmpty(); + } else +#endif + { + takeArray(&buf, lastWrite); + moreData = !buf.isEmpty(); + } + +#ifdef QPIPE_SECURE + sec_curWrite.clear(); +#endif + curWrite.clear(); + + x = lastWrite; + lastWrite = 0; + + if (writeResult == 0) { + // more to write? do it + if (moreData) { + writeTrigger.start(0); + } + // done with all writing + else { + activeWrite = false; + if (closeLater) { + closeLater = false; + closeTrigger.start(0); + } + } + } else + writeErrorTrigger.start(); + + if (x > 0) + emit q->bytesWritten(x); + } + } + + void doRead() + { + doReadActual(true); + } + + void doReadActual(bool sigs) + { + const int left = pendingFreeSize(); + if (left == 0) { + canRead = true; + return; + } + + int max; +#ifdef Q_OS_WIN + if (consoleMode) { + // need a minimum amount for console + if (left < CONSOLE_CHAREXPAND) { + canRead = true; + return; + } + + // don't use pipe.bytesAvailable() for console mode, + // as it is somewhat bogus. fortunately, there is + // no problem with overreading from the console. + max = qMin(left, 32); + } else +#endif + { + max = qMin(left, pipe.bytesAvailable()); + } + + int ret; +#ifdef QPIPE_SECURE + if (secure) { + SecureArray a(max); + ret = pipe.read(a.data(), a.size()); + if (ret >= 1) { + a.resize(ret); + sec_buf.append(a); + } + } else +#endif + { + QByteArray a(max, 0); + ret = pipe.read(a.data(), a.size()); + if (ret >= 1) { + a.resize(ret); + buf += a; + } + } + + if (ret < 1) { + reset(ResetSession); + if (sigs) { + if (ret == 0) + emit q->error(QPipeEnd::ErrorEOF); + else + emit q->error(QPipeEnd::ErrorBroken); + } + return; + } + + if (sigs) + emit q->readyRead(); + } + + void doWrite() + { + int ret; +#ifdef QPIPE_SECURE + if (secure) { + sec_curWrite.resize(qMin(PIPEEND_BLOCK, sec_buf.size())); + memcpy(sec_curWrite.data(), sec_buf.data(), sec_curWrite.size()); + + ret = pipe.write(sec_curWrite.data(), sec_curWrite.size()); + } else +#endif + { + curWrite.resize(qMin(PIPEEND_BLOCK, buf.size())); + memcpy(curWrite.data(), buf.data(), curWrite.size()); + + ret = pipe.write(curWrite.data(), curWrite.size()); + } + + if (ret == -1) { + reset(ResetSession); + emit q->error(QPipeEnd::ErrorBroken); + return; + } + + lastWrite = ret; + } + + void doClose() + { + reset(ResetSession); + emit q->closed(); + } + + void doWriteError() + { + reset(ResetSession); + emit q->error(QPipeEnd::ErrorBroken); + } +}; + +QPipeEnd::QPipeEnd(QObject *parent) + : QObject(parent) +{ + d = new Private(this); +} + +QPipeEnd::~QPipeEnd() +{ + delete d; +} + +void QPipeEnd::reset() +{ + d->reset(ResetAll); +} + +QPipeDevice::Type QPipeEnd::type() const +{ + return d->pipe.type(); +} + +bool QPipeEnd::isValid() const +{ + return d->pipe.isValid(); +} + +Q_PIPE_ID QPipeEnd::id() const +{ + return d->pipe.id(); +} + +int QPipeEnd::idAsInt() const +{ + return d->pipe.idAsInt(); +} + +void QPipeEnd::take(Q_PIPE_ID id, QPipeDevice::Type t) +{ + reset(); + d->setup(id, t); +} + +#ifdef QPIPE_SECURE +void QPipeEnd::setSecurityEnabled(bool secure) +{ + // no change + if (d->secure == secure) + return; + + if (secure) { + d->sec_buf = d->buf; + d->buf.clear(); + } else { + d->buf = d->sec_buf.toByteArray(); + d->sec_buf.clear(); + } + + d->secure = secure; +} +#endif + +void QPipeEnd::enable() +{ + d->pipe.enable(); +} + +void QPipeEnd::close() +{ + if (!isValid() || d->closing) + return; + + d->closing = true; + + if (d->activeWrite) + d->closeLater = true; + else + d->closeTrigger.start(0); +} + +void QPipeEnd::release() +{ + if (!isValid()) + return; + + d->pipe.release(); + d->reset(ResetSession); +} + +bool QPipeEnd::setInheritable(bool enabled) +{ + return d->pipe.setInheritable(enabled); +} + +void QPipeEnd::finalize() +{ + if (!isValid()) + return; + + if (d->pipe.bytesAvailable()) + d->doReadActual(false); + d->reset(ResetSession); +} + +void QPipeEnd::finalizeAndRelease() +{ + if (!isValid()) + return; + + if (d->pipe.bytesAvailable()) + d->doReadActual(false); + d->pipe.release(); + d->reset(ResetSession); +} + +int QPipeEnd::bytesAvailable() const +{ + return d->pendingSize(); +} + +int QPipeEnd::bytesToWrite() const +{ + return d->pendingSize(); +} + +QByteArray QPipeEnd::read(int bytes) +{ + return d->read(&d->buf, bytes); +} + +void QPipeEnd::write(const QByteArray &buf) +{ + if (!isValid() || d->closing) + return; + + if (buf.isEmpty()) + return; + +#ifdef QPIPE_SECURE + if (d->secure) // call writeSecure() instead + return; +#endif + + d->write(&d->buf, buf); +} + +#ifdef QPIPE_SECURE +SecureArray QPipeEnd::readSecure(int bytes) +{ + return d->readSecure(&d->sec_buf, bytes); +} + +void QPipeEnd::writeSecure(const SecureArray &buf) +{ + if (!isValid() || d->closing) + return; + + if (buf.isEmpty()) + return; + + if (!d->secure) // call write() instead + return; + + d->writeSecure(&d->sec_buf, buf); +} +#endif + +QByteArray QPipeEnd::takeBytesToWrite() +{ + // only call this on inactive sessions + if (isValid()) + return QByteArray(); + + QByteArray a = d->buf; + d->buf.clear(); + return a; +} + +#ifdef QPIPE_SECURE +SecureArray QPipeEnd::takeBytesToWriteSecure() +{ + // only call this on inactive sessions + if (isValid()) + return SecureArray(); + + SecureArray a = d->sec_buf; + d->sec_buf.clear(); + return a; +} +#endif + +//---------------------------------------------------------------------------- +// QPipe +//---------------------------------------------------------------------------- +QPipe::QPipe(QObject *parent) + : i(parent) + , o(parent) +{ +} + +QPipe::~QPipe() +{ +} + +void QPipe::reset() +{ + i.reset(); + o.reset(); +} + +#ifdef QPIPE_SECURE +bool QPipe::create(bool secure) +#else +bool QPipe::create() +#endif +{ + reset(); + +#ifdef Q_OS_WIN + SECURITY_ATTRIBUTES secAttr; + memset(&secAttr, 0, sizeof secAttr); + secAttr.nLength = sizeof secAttr; + secAttr.bInheritHandle = false; + + HANDLE r, w; + if (!CreatePipe(&r, &w, &secAttr, 0)) + return false; + i.take(r, QPipeDevice::Read); + o.take(w, QPipeDevice::Write); +#endif + +#ifdef Q_OS_UNIX + int p[2]; + if (pipe(p) == -1) + return false; + if (!pipe_set_inheritable(p[0], false, nullptr) || !pipe_set_inheritable(p[1], false, nullptr)) { + close(p[0]); + close(p[1]); + return false; + } + i.take(p[0], QPipeDevice::Read); + o.take(p[1], QPipeDevice::Write); +#endif + +#ifdef QPIPE_SECURE + i.setSecurityEnabled(secure); + o.setSecurityEnabled(secure); +#endif + + return true; +} + +} + +#include "qpipe.moc" diff --git a/local/recipes/libs/qca/source/src/support/synchronizer.cpp b/local/recipes/libs/qca/source/src/support/synchronizer.cpp new file mode 100644 index 0000000000..4c8d613c61 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/synchronizer.cpp @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_safetimer.h" +#include "qca_support.h" + +#include +#include +#include +#include +#include +#include +#include + +// #define TIMERFIXER_DEBUG + +#ifdef TIMERFIXER_DEBUG +#include +#endif + +namespace QCA { + +//---------------------------------------------------------------------------- +// TimerFixer +//---------------------------------------------------------------------------- +class TimerFixer : public QObject +{ + Q_OBJECT +public: + struct TimerInfo + { + int id; + int interval; + QElapsedTimer time; + bool fixInterval; + + TimerInfo() + : fixInterval(false) + { + } + }; + + TimerFixer *fixerParent; + QList fixerChildren; + + QObject *target; + QAbstractEventDispatcher *ed; + QList timers; + + static bool haveFixer(QObject *obj) + { + return obj->findChild() ? true : false; + } + + TimerFixer(QObject *_target, TimerFixer *_fp = nullptr) + : QObject(_target) + { + ed = nullptr; + + target = _target; + fixerParent = _fp; + if (fixerParent) + fixerParent->fixerChildren.append(this); + +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] pairing with %p (%s)\n", this, target, target->metaObject()->className()); +#endif + edlink(); + target->installEventFilter(this); + + const QObjectList list = target->children(); + for (int n = 0; n < list.count(); ++n) + hook(list[n]); + } + + ~TimerFixer() override + { + if (fixerParent) + fixerParent->fixerChildren.removeAll(this); + + QList list = fixerChildren; + for (int n = 0; n < list.count(); ++n) + delete list[n]; + list.clear(); + + updateTimerList(); // do this just to trip debug output + + target->removeEventFilter(this); + edunlink(); +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] unpaired with %p (%s)\n", this, target, target->metaObject()->className()); +#endif + } + + bool event(QEvent *e) override + { + switch (e->type()) { + case QEvent::ThreadChange: // this happens second + // printf("TimerFixer[%p] self changing threads\n", this); + edunlink(); + QMetaObject::invokeMethod(this, "fixTimers", Qt::QueuedConnection); + break; + default: + break; + } + + return QObject::event(e); + } + + bool eventFilter(QObject *, QEvent *e) override + { + switch (e->type()) { + case QEvent::ChildAdded: + hook(((QChildEvent *)e)->child()); + break; + case QEvent::ChildRemoved: + unhook(((QChildEvent *)e)->child()); + break; + case QEvent::Timer: + handleTimerEvent(((QTimerEvent *)e)->timerId()); + break; + case QEvent::ThreadChange: // this happens first +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] target changing threads\n", this); +#endif + break; + default: + break; + } + + return false; + } + +private Q_SLOTS: + void edlink() + { + ed = QAbstractEventDispatcher::instance(); + // printf("TimerFixer[%p] linking to dispatcher %p\n", this, ed); + connect(ed, &QAbstractEventDispatcher::aboutToBlock, this, &TimerFixer::ed_aboutToBlock); + } + + void edunlink() + { + // printf("TimerFixer[%p] unlinking from dispatcher %p\n", this, ed); + if (ed) { + disconnect(ed, &QAbstractEventDispatcher::aboutToBlock, this, &TimerFixer::ed_aboutToBlock); + ed = nullptr; + } + } + + void ed_aboutToBlock() + { + // printf("TimerFixer[%p] aboutToBlock\n", this); + updateTimerList(); + } + + void fixTimers() + { + updateTimerList(); + edlink(); + + for (int n = 0; n < timers.count(); ++n) { + TimerInfo &info = timers[n]; + + QThread *objectThread = target->thread(); + QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance(objectThread); + + const int timeLeft = qMax(info.interval - static_cast(info.time.elapsed()), 0); + info.fixInterval = true; + ed->unregisterTimer(info.id); + info.id = ed->registerTimer(timeLeft, Qt::CoarseTimer, target); + +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] adjusting [%d] to %d\n", this, info.id, timeLeft); +#endif + } + } + +private: + void hook(QObject *obj) + { + // don't watch a fixer or any object that already has one + // SafeTimer has own method to fix timers, skip it too + if (obj == this || qobject_cast(obj) || haveFixer(obj) || qobject_cast(obj)) + return; + + new TimerFixer(obj, this); + } + + void unhook(QObject *obj) + { + TimerFixer *t = nullptr; + for (int n = 0; n < fixerChildren.count(); ++n) { + if (fixerChildren[n]->target == obj) + t = fixerChildren[n]; + } + delete t; + } + + void handleTimerEvent(int id) + { + bool found = false; + int n; + for (n = 0; n < timers.count(); ++n) { + if (timers[n].id == id) { + found = true; + break; + } + } + if (!found) { + // printf("*** unrecognized timer [%d] activated ***\n", id); + return; + } + + TimerInfo &info = timers[n]; +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] timer [%d] activated!\n", this, info.id); +#endif + + if (info.fixInterval) { +#ifdef TIMERFIXER_DEBUG + printf("restoring correct interval (%d)\n", info.interval); +#endif + info.fixInterval = false; + ed->unregisterTimer(info.id); + info.id = ed->registerTimer(info.interval, Qt::CoarseTimer, target); + } + + info.time.start(); + } + + void updateTimerList() + { + QList edtimers; + if (ed) + edtimers = ed->registeredTimers(target); + + // removed? + for (int n = 0; n < timers.count(); ++n) { + bool found = false; + int id = timers[n].id; + for (int i = 0; i < edtimers.count(); ++i) { + if (edtimers[i].timerId == id) { + found = true; + break; + } + } + + if (!found) { + timers.removeAt(n); + --n; +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] timer [%d] removed\n", this, id); +#endif + } + } + + // added? + for (int n = 0; n < edtimers.count(); ++n) { + int id = edtimers[n].timerId; + bool found = false; + for (int i = 0; i < timers.count(); ++i) { + if (timers[i].id == id) { + found = true; + break; + } + } + + if (!found) { + TimerInfo info; + info.id = id; + info.interval = edtimers[n].interval; + info.time.start(); + timers += info; +#ifdef TIMERFIXER_DEBUG + printf("TimerFixer[%p] timer [%d] added (interval=%d)\n", this, info.id, info.interval); +#endif + } + } + } +}; + +//---------------------------------------------------------------------------- +// Synchronizer +//---------------------------------------------------------------------------- +class SynchronizerAgent : public QObject +{ + Q_OBJECT +public: + SynchronizerAgent(QObject *parent = nullptr) + : QObject(parent) + { + QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection); + } + +Q_SIGNALS: + void started(); +}; + +class Synchronizer::Private : public QThread +{ + Q_OBJECT +public: + Synchronizer *q; + + bool active; + bool do_quit; + bool cond_met; + + QObject *obj; + QEventLoop *loop; + SynchronizerAgent *agent; + TimerFixer *fixer; + QMutex m; + QWaitCondition w; + QThread *orig_thread; + + Private(QObject *_obj, Synchronizer *_q) + : QThread(_q) + , q(_q) + , active(false) + , do_quit(false) + , cond_met(false) + , obj(_obj) + , loop(nullptr) + , agent(nullptr) + , fixer(nullptr) + , m() + , w() + , orig_thread(nullptr) + { + // SafeTimer has own method to fix timers, skip it too + if (!qobject_cast(obj)) + fixer = new TimerFixer(obj); + } + + ~Private() override + { + stop(); + delete fixer; + } + + void start() + { + if (active) + return; + + m.lock(); + active = true; + do_quit = false; + QThread::start(); + w.wait(&m); + m.unlock(); + } + + void stop() + { + if (!active) + return; + + m.lock(); + do_quit = true; + w.wakeOne(); + m.unlock(); + wait(); + active = false; + } + + bool waitForCondition(int msecs) + { + unsigned long time = ULONG_MAX; + if (msecs != -1) + time = msecs; + + // move object to the worker thread + cond_met = false; + orig_thread = QThread::currentThread(); + q->setParent(nullptr); // don't follow the object + QObject *orig_parent = obj->parent(); + obj->setParent(nullptr); // unparent the target or the move will fail + obj->moveToThread(this); + + // tell the worker thread to start, wait for completion + m.lock(); + w.wakeOne(); + if (!w.wait(&m, time)) { + if (loop) { + // if we timed out, tell the worker to quit + QMetaObject::invokeMethod(loop, "quit"); + w.wait(&m); + } + } + + // at this point the worker is done. cleanup and return + m.unlock(); + + // restore parents + obj->setParent(orig_parent); + q->setParent(obj); + + return cond_met; + } + + void conditionMet() + { + if (!loop) + return; + loop->quit(); + cond_met = true; + } + +protected: + void run() override + { + m.lock(); + QEventLoop eventLoop; + + while (true) { + // thread now sleeps, waiting for work + w.wakeOne(); + w.wait(&m); + if (do_quit) { + m.unlock(); + break; + } + + loop = &eventLoop; + agent = new SynchronizerAgent; + connect(agent, &SynchronizerAgent::started, this, &Private::agent_started, Qt::DirectConnection); + + // run the event loop + eventLoop.exec(); + + delete agent; + agent = nullptr; + + // eventloop done, flush pending events + QCoreApplication::instance()->sendPostedEvents(); + QCoreApplication::instance()->sendPostedEvents(nullptr, QEvent::DeferredDelete); + + // and move the object back + obj->moveToThread(orig_thread); + + m.lock(); + loop = nullptr; + w.wakeOne(); + } + } + +private Q_SLOTS: + void agent_started() + { + m.unlock(); + } +}; + +Synchronizer::Synchronizer(QObject *parent) + : QObject(parent) +{ + d = new Private(parent, this); +} + +Synchronizer::~Synchronizer() +{ + delete d; +} + +bool Synchronizer::waitForCondition(int msecs) +{ + d->start(); + return d->waitForCondition(msecs); +} + +void Synchronizer::conditionMet() +{ + d->conditionMet(); +} + +} + +#include "synchronizer.moc" diff --git a/local/recipes/libs/qca/source/src/support/syncthread.cpp b/local/recipes/libs/qca/source/src/support/syncthread.cpp new file mode 100644 index 0000000000..bbe55b5484 --- /dev/null +++ b/local/recipes/libs/qca/source/src/support/syncthread.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2006 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "qca_support.h" + +#include +#include +#include +#include + +namespace QCA { + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +int methodReturnType(const QMetaObject *obj, const QByteArray &method, const QList &argTypes) +#else +QByteArray methodReturnType( + const QMetaObject *obj, + const QByteArray &method, + const QList argTypes) // clazy:exclude=function-args-by-ref NOLINT(performance-unnecessary-value-param) + // TODO make argTypes const & when we break ABI +#endif +{ + for (int n = 0; n < obj->methodCount(); ++n) { + QMetaMethod m = obj->method(n); + const QByteArray sig = m.methodSignature(); + int offset = sig.indexOf('('); + if (offset == -1) + continue; + const QByteArray name = sig.mid(0, offset); + if (name != method) + continue; + if (m.parameterTypes() != argTypes) + continue; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + return m.returnType(); +#else + return m.typeName(); +#endif + } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + return QMetaType::UnknownType; +#else + return QByteArray(); +#endif +} + +bool invokeMethodWithVariants(QObject *obj, + const QByteArray &method, + const QVariantList &args, + QVariant *ret, + Qt::ConnectionType type) +{ + // QMetaObject::invokeMethod() has a 10 argument maximum + if (args.count() > 10) + return false; + + QList argTypes; + for (int n = 0; n < args.count(); ++n) { + argTypes += args[n].typeName(); + } + + // get return type +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + const auto metatype = methodReturnType(obj->metaObject(), method, argTypes); + if (metatype == QMetaType::UnknownType) { + return false; + } +#else + int metatype = QMetaType::Void; + const QByteArray retTypeName = methodReturnType(obj->metaObject(), method, argTypes); + if (!retTypeName.isEmpty() && retTypeName != "void") { + metatype = QMetaType::type(retTypeName.data()); + if (metatype == QMetaType::UnknownType) // lookup failed + return false; + } +#endif + + QGenericArgument arg[10]; + for (int n = 0; n < args.count(); ++n) + arg[n] = QGenericArgument(args[n].typeName(), args[n].constData()); + + QGenericReturnArgument retarg; + QVariant retval; + + if (metatype != QMetaType::Void) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + retval = QVariant(QMetaType {metatype}, (const void *)nullptr); +#else + retval = QVariant(metatype, (const void *)nullptr); +#endif + retarg = QGenericReturnArgument(retval.typeName(), retval.data()); + } + + if (!QMetaObject::invokeMethod(obj, + method.data(), + type, + retarg, + arg[0], + arg[1], + arg[2], + arg[3], + arg[4], + arg[5], + arg[6], + arg[7], + arg[8], + arg[9])) + return false; + + if (retval.isValid() && ret) + *ret = retval; + return true; +} + +//---------------------------------------------------------------------------- +// SyncThread +//---------------------------------------------------------------------------- +class SyncThreadAgent; + +class SyncThread::Private : public QObject +{ + Q_OBJECT +public: + SyncThread *q; + QMutex m; + QWaitCondition w; + QEventLoop *loop; + SyncThreadAgent *agent; + bool last_success; + QVariant last_ret; + + Private(SyncThread *_q) + : QObject(_q) + , q(_q) + { + loop = nullptr; + agent = nullptr; + } + +public Q_SLOTS: + void agent_started(); + void agent_call_ret(bool success, const QVariant &ret); +}; + +class SyncThreadAgent : public QObject +{ + Q_OBJECT +public: + SyncThreadAgent(QObject *parent = nullptr) + : QObject(parent) + { + QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection); + } + +Q_SIGNALS: + void started(); + void call_ret(bool success, const QVariant &ret); + +public Q_SLOTS: + void call_do(QObject *obj, const QByteArray &method, const QVariantList &args) + { + QVariant ret; + bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection); + emit call_ret(ok, ret); + } +}; + +SyncThread::SyncThread(QObject *parent) + : QThread(parent) +{ + d = new Private(this); + qRegisterMetaType("QVariant"); + qRegisterMetaType("QVariantList"); +} + +SyncThread::~SyncThread() +{ + stop(); + delete d; +} + +void SyncThread::start() +{ + QMutexLocker locker(&d->m); + Q_ASSERT(!d->loop); + QThread::start(); + d->w.wait(&d->m); +} + +void SyncThread::stop() +{ + QMutexLocker locker(&d->m); + if (!d->loop) + return; + QMetaObject::invokeMethod(d->loop, "quit"); + d->w.wait(&d->m); + wait(); +} + +QVariant SyncThread::call(QObject *obj, const QByteArray &method, const QVariantList &args, bool *ok) +{ + QMutexLocker locker(&d->m); + bool ret; + Q_UNUSED(ret); // In really ret is used. I use this hack to suppress a compiler warning + // clang-format off + // Otherwise the QObject* gets turned into Object * that is not normalized and is slightly slower + ret = QMetaObject::invokeMethod(d->agent, "call_do", + Qt::QueuedConnection, Q_ARG(QObject*, obj), + Q_ARG(QByteArray, method), Q_ARG(QVariantList, args)); + // clang-format on + Q_ASSERT(ret); + d->w.wait(&d->m); + if (ok) + *ok = d->last_success; + QVariant v = d->last_ret; + d->last_ret = QVariant(); + return v; +} + +void SyncThread::run() +{ + d->m.lock(); + d->loop = new QEventLoop; + d->agent = new SyncThreadAgent; + connect(d->agent, &SyncThreadAgent::started, d, &Private::agent_started, Qt::DirectConnection); + connect(d->agent, &SyncThreadAgent::call_ret, d, &Private::agent_call_ret, Qt::DirectConnection); + d->loop->exec(); + d->m.lock(); + atEnd(); + delete d->agent; + delete d->loop; + d->agent = nullptr; + d->loop = nullptr; + d->w.wakeOne(); + d->m.unlock(); +} + +void SyncThread::Private::agent_started() +{ + q->atStart(); + w.wakeOne(); + m.unlock(); +} + +void SyncThread::Private::agent_call_ret(bool success, const QVariant &ret) +{ + QMutexLocker locker(&m); + last_success = success; + last_ret = ret; + w.wakeOne(); +} + +} + +#include "syncthread.moc" diff --git a/local/recipes/libs/qca/source/tools/CMakeLists.txt b/local/recipes/libs/qca/source/tools/CMakeLists.txt new file mode 100644 index 0000000000..a3bc38a7da --- /dev/null +++ b/local/recipes/libs/qca/source/tools/CMakeLists.txt @@ -0,0 +1,3 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") +add_subdirectory(mozcerts) +add_subdirectory(qcatool) diff --git a/local/recipes/libs/qca/source/tools/mozcerts/CMakeLists.txt b/local/recipes/libs/qca/source/tools/mozcerts/CMakeLists.txt new file mode 100644 index 0000000000..dd1963e624 --- /dev/null +++ b/local/recipes/libs/qca/source/tools/mozcerts/CMakeLists.txt @@ -0,0 +1,12 @@ +project(mozcerts) + +set(mozcerts_bin_SRCS main.cpp) + +add_executable(${MOZCERTS_NAME} ${mozcerts_bin_SRCS}) + +target_link_qca_libraries(${MOZCERTS_NAME}) + +if(NOT DEVELOPER_MODE) + install(TARGETS ${MOZCERTS_NAME} DESTINATION "${QCA_BINARY_INSTALL_DIR}") + install_pdb(${MOZCERTS_NAME} ${QCA_BINARY_INSTALL_DIR}) +endif() diff --git a/local/recipes/libs/qca/source/tools/mozcerts/main.cpp b/local/recipes/libs/qca/source/tools/mozcerts/main.cpp new file mode 100644 index 0000000000..e374215aae --- /dev/null +++ b/local/recipes/libs/qca/source/tools/mozcerts/main.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2005 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +/* mozilla certdata converter. adapted from the debian ruby script */ + +#include + +#include +#include +#include +#include + +QStringList splitWithQuotes(const QString &in, char c); + +int main(int argc, char **argv) +{ + QCA::Initializer qcaInit; + QCoreApplication app(argc, argv); + + if (argc < 3) { + printf("usage: mozcerts [certdata.txt] [outfile.pem]\n"); + return 0; + } + + QFile infile(QString::fromLocal8Bit(argv[1])); + if (!infile.open(QFile::ReadOnly)) { + fprintf(stderr, "Error opening input file\n"); + return 1; + } + + QFile outfile(QString::fromLocal8Bit(argv[2])); + if (!outfile.open(QFile::WriteOnly | QFile::Truncate)) { + fprintf(stderr, "Error opening output file\n"); + return 1; + } + + int count = 0; + QString name; + QTextStream ts(&infile); + while (!ts.atEnd()) { + QString line = ts.readLine(); + if (line.startsWith(QLatin1Char('#'))) + continue; + line = line.trimmed(); + if (line.isEmpty()) + continue; + + if (line.startsWith(QLatin1String("CKA_LABEL"))) { + const QStringList list = splitWithQuotes(line, ' '); + if (list.count() != 3) + continue; + + name = list[2]; + // make an output filename based on the name + // outname = name.replace(QRegExp("\\/"), "_") + // .replace(QRegExp("\\s+"), "_") + // .replace(QRegExp("[()]"), "=") + // .replace(QRegExp(","), "_") + ".pem"; + continue; + } else if (line == QLatin1String("CKA_VALUE MULTILINE_OCTAL")) { + QByteArray buf; + while (!ts.atEnd()) { + line = ts.readLine().trimmed(); + if (line == QLatin1String("END")) + break; + static const QRegularExpression rx(QStringLiteral("\\\\([0-3][0-7][0-7])")); + int pos = 0; + QRegularExpressionMatch match = rx.match(line, pos); + while (match.hasMatch()) { + QString str = match.captured(1); + uchar c = str.toInt(nullptr, 8); + buf.append(c); + pos += match.capturedLength(); + match = rx.match(line, pos); + } + } + + printf(">> [%s], %d bytes\n", qPrintable(name), int(buf.size())); + + QTextStream ts(&outfile); + ts << "-----BEGIN CERTIFICATE-----" << '\n'; + QCA::Base64 enc; + enc.setLineBreaksEnabled(true); + enc.setLineBreaksColumn(64); + ts << enc.arrayToString(buf) << '\n'; + ts << "-----END CERTIFICATE-----" << '\n'; + + ++count; + } + } + printf("Wrote %d certs to [%s]\n", count, argv[2]); + + return 0; +} + +int find_notchar(const QString &str, char c, int offset) +{ + for (int n = offset; n < str.length(); ++n) { + if (str[n] != QLatin1Char(c)) + return n; + } + return -1; +} + +QStringList splitWithQuotes(const QString &in, char c) +{ + QStringList result; + int at = 0; + if (in[at] == QLatin1Char(c)) + at = find_notchar(in, c, at); + while (at != -1) { + bool quote = false; + int end; + QString str; + if (in[at] == QLatin1Char('\"')) { + quote = true; + ++at; + end = in.indexOf(QLatin1Char('\"'), at); + if (end == -1) + break; + } else + end = in.indexOf(QLatin1Char(c), at); + + if (end != -1) + str = in.mid(at, end - at); + else + str = in.mid(at); + + if (!str.isEmpty()) + result += str; + + if (quote) + end = in.indexOf(QLatin1Char(c), end); + + if (end != -1) + at = find_notchar(in, c, end); + else + at = -1; + } + return result; +} diff --git a/local/recipes/libs/qca/source/tools/qcatool/CMakeLists.txt b/local/recipes/libs/qca/source/tools/qcatool/CMakeLists.txt new file mode 100644 index 0000000000..47cc79ce81 --- /dev/null +++ b/local/recipes/libs/qca/source/tools/qcatool/CMakeLists.txt @@ -0,0 +1,12 @@ +project(qcatool) + +set(qcatool_bin_SRCS main.cpp) + +add_executable(${QCA_TOOL_NAME} ${qcatool_bin_SRCS}) + +target_link_qca_libraries(${QCA_TOOL_NAME}) + +if(NOT DEVELOPER_MODE) + install(TARGETS ${QCA_TOOL_NAME} DESTINATION "${QCA_BINARY_INSTALL_DIR}") + install_pdb(${QCA_TOOL_NAME} ${QCA_BINARY_INSTALL_DIR}) +endif() diff --git a/local/recipes/libs/qca/source/tools/qcatool/main.cpp b/local/recipes/libs/qca/source/tools/qcatool/main.cpp new file mode 100644 index 0000000000..133d72d45d --- /dev/null +++ b/local/recipes/libs/qca/source/tools/qcatool/main.cpp @@ -0,0 +1,4263 @@ +/* + * Copyright (C) 2005-2007 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +const char *const APPNAME = "qcatool"; +const char *const EXENAME = "qcatool"; +const char *const VERSION = QCA_VERSION_STR; + +static QStringList wrapstring(const QString &str, int width) +{ + QStringList out; + QString simp = str.simplified(); + QString rest = simp; + while (true) { + int lastSpace = -1; + int n; + for (n = 0; n < rest.length(); ++n) { + if (rest[n].isSpace()) + lastSpace = n; + if (n == width) + break; + } + if (n == rest.length()) { + out += rest; + break; + } + + QString line; + if (lastSpace != -1) { + line = rest.mid(0, lastSpace); + rest = rest.mid(lastSpace + 1); + } else { + line = rest.mid(0, n); + rest = rest.mid(n); + } + out += line; + } + return out; +} + +class StreamLogger : public QCA::AbstractLogDevice +{ + Q_OBJECT +public: + StreamLogger(QTextStream &stream) + : QCA::AbstractLogDevice(QStringLiteral("Stream logger")) + , _stream(stream) + { + QCA::logger()->registerLogDevice(this); + } + + ~StreamLogger() override + { + QCA::logger()->unregisterLogDevice(name()); + } + + void logTextMessage(const QString &message, enum QCA::Logger::Severity severity) override + { + _stream << now() << " " << severityName(severity) << " " << message << Qt::endl; + } + + void logBinaryMessage(const QByteArray &blob, enum QCA::Logger::Severity severity) override + { + Q_UNUSED(blob); + _stream << now() << " " << severityName(severity) << " " + << "Binary blob not implemented yet" << Qt::endl; + } + +private: + inline const char *severityName(enum QCA::Logger::Severity severity) + { + if (severity <= QCA::Logger::Debug) { + return s_severityNames[severity]; + } else { + return s_severityNames[QCA::Logger::Debug + 1]; + } + } + + inline QString now() + { + static QString format = QStringLiteral("yyyy-MM-dd hh:mm:ss"); + return QDateTime::currentDateTime().toString(format); + } + +private: + static const char *s_severityNames[]; + QTextStream &_stream; +}; + +const char *StreamLogger::s_severityNames[] = {"Q", "M", "A", "C", "E", "W", "N", "I", "D", "U"}; + +static void output_plugin_diagnostic_text() +{ + QString str = QCA::pluginDiagnosticText(); + QCA::clearPluginDiagnosticText(); + if (str[str.length() - 1] == QLatin1Char('\n')) + str.truncate(str.length() - 1); + const QStringList lines = str.split(QLatin1Char('\n'), Qt::KeepEmptyParts); + for (int n = 0; n < lines.count(); ++n) + fprintf(stderr, "plugin: %s\n", qPrintable(lines[n])); +} + +static void output_keystore_diagnostic_text() +{ + QString str = QCA::KeyStoreManager::diagnosticText(); + QCA::KeyStoreManager::clearDiagnosticText(); + if (str[str.length() - 1] == QLatin1Char('\n')) + str.truncate(str.length() - 1); + const QStringList lines = str.split(QLatin1Char('\n'), Qt::KeepEmptyParts); + for (int n = 0; n < lines.count(); ++n) + fprintf(stderr, "keystore: %s\n", qPrintable(lines[n])); +} + +static void output_message_diagnostic_text(QCA::SecureMessage *msg) +{ + QString str = msg->diagnosticText(); + if (str[str.length() - 1] == QLatin1Char('\n')) + str.truncate(str.length() - 1); + const QStringList lines = str.split(QLatin1Char('\n'), Qt::KeepEmptyParts); + for (int n = 0; n < lines.count(); ++n) + fprintf(stderr, "message: %s\n", qPrintable(lines[n])); +} + +class AnimatedKeyGen : public QObject +{ + Q_OBJECT +public: + static QCA::PrivateKey makeKey(QCA::PKey::Type type, int bits, QCA::DLGroupSet set) + { + AnimatedKeyGen kg; + kg.type = type; + kg.bits = bits; + kg.set = set; + QEventLoop eventLoop; + kg.eventLoop = &eventLoop; + QTimer::singleShot(0, &kg, &AnimatedKeyGen::start); + eventLoop.exec(); + QCA::PrivateKey key = kg.key; + return key; + } + +private: + QCA::PKey::Type type; + int bits; + QCA::DLGroupSet set; + QEventLoop *eventLoop; + QCA::KeyGenerator gen; + QCA::DLGroup group; + QCA::PrivateKey key; + QTimer t; + int x; + + AnimatedKeyGen() + { + gen.setBlockingEnabled(false); + connect(&gen, &QCA::KeyGenerator::finished, this, &AnimatedKeyGen::gen_finished); + connect(&t, &QTimer::timeout, this, &AnimatedKeyGen::t_timeout); + } + +private Q_SLOTS: + void start() + { + printf("Generating Key ... "); + fflush(stdout); + x = 0; + t.start(125); + + if (type == QCA::PKey::RSA) + gen.createRSA(bits); + else + gen.createDLGroup(set); + } + + void gen_finished() + { + if (type == QCA::PKey::DSA || type == QCA::PKey::DH) { + if (group.isNull()) { + group = gen.dlGroup(); + + if (type == QCA::PKey::DSA) + gen.createDSA(group); + else + gen.createDH(group); + return; + } + } + + key = gen.key(); + + printf("\b"); + if (!key.isNull()) + printf("Done\n"); + else + printf("Error\n"); + + eventLoop->exit(); + } + + void t_timeout() + { + if (x == 0) + printf("\b/"); + else if (x == 1) + printf("\b-"); + else if (x == 2) + printf("\b\\"); + else if (x == 3) + printf("\b|"); + fflush(stdout); + + ++x; + x %= 4; + } +}; + +class KeyStoreMonitor : public QObject +{ + Q_OBJECT +public: + static void monitor() + { + KeyStoreMonitor monitor; + QEventLoop eventLoop; + monitor.eventLoop = &eventLoop; + QTimer::singleShot(0, &monitor, &KeyStoreMonitor::start); + eventLoop.exec(); + } + +private: + QEventLoop *eventLoop; + QCA::KeyStoreManager *ksm; + QList keyStores; + QCA::ConsolePrompt *prompt; + +private Q_SLOTS: + void start() + { + // user can quit the monitoring by pressing enter + printf("Monitoring keystores, press 'q' to quit.\n"); + prompt = new QCA::ConsolePrompt(this); + connect(prompt, &QCA::ConsolePrompt::finished, this, &KeyStoreMonitor::prompt_finished); + prompt->getChar(); + + // kick off the subsystem + QCA::KeyStoreManager::start(); + + // setup keystore manager for monitoring + ksm = new QCA::KeyStoreManager(this); + connect(ksm, &QCA::KeyStoreManager::keyStoreAvailable, this, &KeyStoreMonitor::ks_available); + foreach (const QString &keyStoreId, ksm->keyStores()) + ks_available(keyStoreId); + } + + void ks_available(const QString &keyStoreId) + { + QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, ksm); + connect(ks, &QCA::KeyStore::updated, this, &KeyStoreMonitor::ks_updated); + connect(ks, &QCA::KeyStore::unavailable, this, &KeyStoreMonitor::ks_unavailable); + keyStores += ks; + + printf(" available: %s\n", qPrintable(ks->name())); + } + + void ks_updated() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + + printf(" updated: %s\n", qPrintable(ks->name())); + } + + void ks_unavailable() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + + printf(" unavailable: %s\n", qPrintable(ks->name())); + keyStores.removeAll(ks); + delete ks; + } + + void prompt_finished() + { + QChar c = prompt->resultChar(); + if (c == QLatin1Char('q') || c == QLatin1Char('Q')) { + eventLoop->exit(); + return; + } + prompt->getChar(); + } +}; + +class PassphrasePrompt : public QObject +{ + Q_OBJECT +public: + class Item + { + public: + QString promptStr; + int id; + QCA::Event event; + }; + + QCA::EventHandler handler; + bool allowPrompt; + bool warned; + bool have_pass; + bool used_pass; + QCA::SecureArray pass; + QCA::ConsolePrompt *prompt; + int prompt_id; + QCA::Event prompt_event; + QList pending; + bool auto_accept; + + QCA::KeyStoreManager ksm; + QList keyStores; + + PassphrasePrompt() + : handler(this) + , ksm(this) + { + allowPrompt = true; + warned = false; + have_pass = false; + auto_accept = false; + + prompt = nullptr; + + connect(&handler, &QCA::EventHandler::eventReady, this, &PassphrasePrompt::ph_eventReady); + handler.start(); + + connect(&ksm, &QCA::KeyStoreManager::keyStoreAvailable, this, &PassphrasePrompt::ks_available); + foreach (const QString &keyStoreId, ksm.keyStores()) + ks_available(keyStoreId); + } + + ~PassphrasePrompt() override + { + qDeleteAll(keyStores); + + if (prompt) { + handler.reject(prompt_id); + delete prompt; + } + + while (!pending.isEmpty()) + handler.reject(pending.takeFirst().id); + } + + void setExplicitPassword(const QCA::SecureArray &_pass) + { + have_pass = true; + used_pass = false; + pass = _pass; + } + +private Q_SLOTS: + void ph_eventReady(int id, const QCA::Event &e) + { + if (have_pass) { + // only allow using an explicit passphrase once + if (used_pass) { + handler.reject(id); + return; + } + used_pass = true; + handler.submitPassword(id, pass); + return; + } + + if (!allowPrompt) { + if (!have_pass && !warned) { + warned = true; + fprintf(stderr, "Error: no passphrase specified (use '--pass=' for none).\n"); + } + + handler.reject(id); + return; + } + + if (e.type() == QCA::Event::Password) { + QString type = QStringLiteral("password"); + if (e.passwordStyle() == QCA::Event::StylePassphrase) + type = QStringLiteral("passphrase"); + else if (e.passwordStyle() == QCA::Event::StylePIN) + type = QStringLiteral("PIN"); + + QString str; + if (e.source() == QCA::Event::KeyStore) { + QString name; + QCA::KeyStoreEntry entry = e.keyStoreEntry(); + if (!entry.isNull()) { + name = entry.name(); + } else { + if (e.keyStoreInfo().type() == QCA::KeyStore::SmartCard) + name = QStringLiteral("the '") + e.keyStoreInfo().name() + QStringLiteral("' token"); + else + name = e.keyStoreInfo().name(); + } + str = QStringLiteral("Enter %1 for %2").arg(type, name); + } else if (!e.fileName().isEmpty()) + str = QStringLiteral("Enter %1 for %2").arg(type, e.fileName()); + else + str = QStringLiteral("Enter %1").arg(type); + + if (!prompt) { + prompt = new QCA::ConsolePrompt(this); + connect(prompt, &QCA::ConsolePrompt::finished, this, &PassphrasePrompt::prompt_finished); + prompt_id = id; + prompt_event = e; + prompt->getHidden(str); + } else { + Item i; + i.promptStr = str; + i.id = id; + i.event = e; + pending += i; + } + } else if (e.type() == QCA::Event::Token) { + // even though we're being prompted for a missing token, + // we should still check if the token is present, due to + // a possible race between insert and token request. + bool found = false; + + // token-only + if (e.keyStoreEntry().isNull()) { + foreach (QCA::KeyStore *ks, keyStores) { + if (ks->id() == e.keyStoreInfo().id()) { + found = true; + break; + } + } + } + // token-entry + else { + QCA::KeyStoreEntry kse = e.keyStoreEntry(); + + QCA::KeyStore *ks = nullptr; + foreach (QCA::KeyStore *i, keyStores) { + if (i->id() == e.keyStoreInfo().id()) { + ks = i; + break; + } + } + if (ks) { + QList list = ks->entryList(); + foreach (const QCA::KeyStoreEntry &e, list) { + if (e.id() == kse.id() && kse.isAvailable()) { + found = true; + break; + } + } + } + } + if (found) { + // auto-accept + handler.tokenOkay(id); + return; + } + + QCA::KeyStoreEntry entry = e.keyStoreEntry(); + QString name; + if (!entry.isNull()) { + name = QStringLiteral("Please make ") + entry.name() + QStringLiteral(" (of ") + entry.storeName() + + QStringLiteral(") available"); + } else { + name = QStringLiteral("Please insert the '") + e.keyStoreInfo().name() + QStringLiteral("' token"); + } + + QString str = QStringLiteral("%1 and press Enter (or 'q' to cancel) ...").arg(name); + + if (!prompt) { + fprintf(stderr, "%s\n", qPrintable(str)); + prompt = new QCA::ConsolePrompt(this); + connect(prompt, &QCA::ConsolePrompt::finished, this, &PassphrasePrompt::prompt_finished); + prompt_id = id; + prompt_event = e; + prompt->getChar(); + } else { + Item i; + i.promptStr = str; + i.id = id; + i.event = e; + pending += i; + } + } else + handler.reject(id); + } + + void prompt_finished() + { + if (prompt_event.type() == QCA::Event::Password) { + handler.submitPassword(prompt_id, prompt->result()); + } else { + if (auto_accept) { + auto_accept = false; + handler.tokenOkay(prompt_id); + } else { + QChar c = prompt->resultChar(); + if (c == QLatin1Char('\r') || c == QLatin1Char('\n')) + handler.tokenOkay(prompt_id); + else if (c == QLatin1Char('q') || c == QLatin1Char('Q')) + handler.reject(prompt_id); + else { + // retry + prompt->getChar(); + return; + } + } + } + + if (!pending.isEmpty()) { + Item i = pending.takeFirst(); + prompt_id = i.id; + prompt_event = i.event; + if (i.event.type() == QCA::Event::Password) { + prompt->getHidden(i.promptStr); + } else // Token + { + fprintf(stderr, "%s\n", qPrintable(i.promptStr)); + prompt->getChar(); + } + } else { + delete prompt; + prompt = nullptr; + } + } + + void ks_available(const QString &keyStoreId) + { + QCA::KeyStore *ks = new QCA::KeyStore(keyStoreId, &ksm); + connect(ks, &QCA::KeyStore::updated, this, &PassphrasePrompt::ks_updated); + connect(ks, &QCA::KeyStore::unavailable, this, &PassphrasePrompt::ks_unavailable); + keyStores += ks; + ks->startAsynchronousMode(); + + // are we currently in a token-only prompt? + if (prompt && prompt_event.type() == QCA::Event::Token && prompt_event.keyStoreEntry().isNull()) { + // was the token we're looking for just inserted? + if (prompt_event.keyStoreInfo().id() == keyStoreId) { + fprintf(stderr, "Token inserted! Continuing...\n"); + + // auto-accept + auto_accept = true; + prompt_finished(); + } + } + } + + void ks_unavailable() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + keyStores.removeAll(ks); + delete ks; + } + + void ks_updated() + { + QCA::KeyStore *ks = (QCA::KeyStore *)sender(); + + // are we currently in a token-entry prompt? + if (prompt && prompt_event.type() == QCA::Event::Token && !prompt_event.keyStoreEntry().isNull()) { + QCA::KeyStoreEntry kse = prompt_event.keyStoreEntry(); + + // was the token of the entry we're looking for updated? + if (prompt_event.keyStoreInfo().id() == ks->id()) { + // is the entry available? + bool avail = false; + QList list = ks->entryList(); + foreach (const QCA::KeyStoreEntry &e, list) { + if (e.id() == kse.id()) { + avail = kse.isAvailable(); + break; + } + } + if (avail) { + fprintf(stderr, "Entry available! Continuing...\n"); + + // auto-accept + auto_accept = true; + prompt_finished(); + } + } + } + } +}; + +class PassphrasePromptThread : public QCA::SyncThread +{ + Q_OBJECT +public: + PassphrasePrompt *pp; + + PassphrasePromptThread() + { + start(); + } + + ~PassphrasePromptThread() override + { + stop(); + } + +protected: + void atStart() override + { + pp = new PassphrasePrompt; + } + + void atEnd() override + { + delete pp; + } +}; + +static bool promptForNewPassphrase(QCA::SecureArray *result) +{ + QCA::ConsolePrompt prompt; + prompt.getHidden(QStringLiteral("Enter new passphrase")); + prompt.waitForFinished(); + QCA::SecureArray out = prompt.result(); + + prompt.getHidden(QStringLiteral("Confirm new passphrase")); + prompt.waitForFinished(); + + if (prompt.result() != out) { + fprintf(stderr, "Error: confirmation does not match original entry.\n"); + return false; + } + *result = out; + return true; +} + +static void ksm_start_and_wait() +{ + // activate the KeyStoreManager and block until ready + QCA::KeyStoreManager::start(); + { + QCA::KeyStoreManager ksm; + ksm.waitForBusyFinished(); + } +} + +static QString line_encode(const QString &in) +{ + QString out; + for (const QChar &c : in) { + if (c == QLatin1Char('\\')) + out += QStringLiteral("\\\\"); + else if (c == QLatin1Char('\n')) + out += QStringLiteral("\\n"); + else + out += c; + } + return out; +} + +static QString line_decode(const QString &in) +{ + QString out; + for (int n = 0; n < in.length(); ++n) { + if (in[n] == QLatin1Char('\\')) { + if (n + 1 < in.length()) { + if (in[n + 1] == QLatin1Char('\\')) + out += QLatin1Char('\\'); + else if (in[n + 1] == QLatin1Char('n')) + out += QLatin1Char('\n'); + ++n; + } + } else + out += in[n]; + } + return out; +} + +static QString make_ksentry_string(const QString &id) +{ + QString out; + out += QStringLiteral("QCATOOL_KEYSTOREENTRY_1\n"); + out += line_encode(id) + QLatin1Char('\n'); + return out; +} + +/*static bool write_ksentry_file(const QString &id, const QString &fileName) +{ + QFile f(fileName); + if(!f.open(QFile::WriteOnly | QFile::Truncate)) + return false; + f.write(make_ksentry_string(id).toUtf8()); + return true; +}*/ + +static QString read_ksentry_file(const QString &fileName) +{ + QString out; + + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) + return out; + QTextStream ts(&f); + int linenum = 0; + while (!ts.atEnd()) { + QString line = ts.readLine(); + if (linenum == 0) { + if (line != QLatin1String("QCATOOL_KEYSTOREENTRY_1")) + return out; + } else { + out = line_decode(line); + break; + } + ++linenum; + } + return out; +} + +static bool is_pem_file(const QString &fileName) +{ + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) + return false; + QTextStream ts(&f); + if (!ts.atEnd()) { + QString line = ts.readLine(); + if (line.startsWith(QLatin1String("-----BEGIN"))) + return true; + } + return false; +} + +static QByteArray read_der_file(const QString &fileName) +{ + QFile f(fileName); + if (!f.open(QFile::ReadOnly)) + return QByteArray(); + return f.readAll(); +} + +class InfoType +{ +public: + QCA::CertificateInfoType type; + QString varname; + QString shortname; + QString name; + QString desc; + + InfoType() + { + } + + InfoType(const QCA::CertificateInfoType &_type, + const QString &_varname, + const QString &_shortname, + const QString &_name, + const QString &_desc) + : type(_type) + , varname(_varname) + , shortname(_shortname) + , name(_name) + , desc(_desc) + { + } +}; + +static QList makeInfoTypeList(bool legacyEmail = false) +{ + QList out; + out += InfoType(QCA::CommonName, + QStringLiteral("CommonName"), + QStringLiteral("CN"), + QStringLiteral("Common Name (CN)"), + QStringLiteral("Full name, domain, anything")); + out += InfoType( + QCA::Email, QStringLiteral("Email"), QLatin1String(""), QStringLiteral("Email Address"), QLatin1String("")); + if (legacyEmail) + out += InfoType(QCA::EmailLegacy, + QStringLiteral("EmailLegacy"), + QLatin1String(""), + QStringLiteral("PKCS#9 Email Address"), + QLatin1String("")); + out += InfoType(QCA::Organization, + QStringLiteral("Organization"), + QStringLiteral("O"), + QStringLiteral("Organization (O)"), + QStringLiteral("Company, group, etc")); + out += InfoType(QCA::OrganizationalUnit, + QStringLiteral("OrganizationalUnit"), + QStringLiteral("OU"), + QStringLiteral("Organizational Unit (OU)"), + QStringLiteral("Division/branch of organization")); + out += InfoType(QCA::Locality, + QStringLiteral("Locality"), + QLatin1String(""), + QStringLiteral("Locality (L)"), + QStringLiteral("City, shire, part of a state")); + out += InfoType(QCA::State, + QStringLiteral("State"), + QLatin1String(""), + QStringLiteral("State (ST)"), + QStringLiteral("State within the country")); + out += InfoType(QCA::Country, + QStringLiteral("Country"), + QStringLiteral("C"), + QStringLiteral("Country Code (C)"), + QStringLiteral("2-letter code")); + out += InfoType(QCA::IncorporationLocality, + QStringLiteral("IncorporationLocality"), + QLatin1String(""), + QStringLiteral("Incorporation Locality"), + QStringLiteral("For EV certificates")); + out += InfoType(QCA::IncorporationState, + QStringLiteral("IncorporationState"), + QLatin1String(""), + QStringLiteral("Incorporation State"), + QStringLiteral("For EV certificates")); + out += InfoType(QCA::IncorporationCountry, + QStringLiteral("IncorporationCountry"), + QLatin1String(""), + QStringLiteral("Incorporation Country"), + QStringLiteral("For EV certificates")); + out += InfoType(QCA::URI, QStringLiteral("URI"), QLatin1String(""), QStringLiteral("URI"), QLatin1String("")); + out += InfoType(QCA::DNS, + QStringLiteral("DNS"), + QLatin1String(""), + QStringLiteral("Domain Name"), + QStringLiteral("Domain (dnsName)")); + out += InfoType(QCA::IPAddress, + QStringLiteral("IPAddress"), + QLatin1String(""), + QStringLiteral("IP Adddress"), + QLatin1String("")); + out += InfoType(QCA::XMPP, + QStringLiteral("XMPP"), + QLatin1String(""), + QStringLiteral("XMPP Address (JID)"), + QStringLiteral("From RFC 3920 (id-on-xmppAddr)")); + return out; +} + +class MyConstraintType +{ +public: + QCA::ConstraintType type; + QString varname; + QString name; + QString desc; + + MyConstraintType() + { + } + + MyConstraintType(const QCA::ConstraintType &_type, + const QString &_varname, + const QString &_name, + const QString &_desc) + : type(_type) + , varname(_varname) + , name(_name) + , desc(_desc) + { + } +}; + +static QList makeConstraintTypeList() +{ + QList out; + out += MyConstraintType(QCA::DigitalSignature, + QStringLiteral("DigitalSignature"), + QStringLiteral("Digital Signature"), + QStringLiteral("Can be used for signing")); + out += MyConstraintType(QCA::NonRepudiation, + QStringLiteral("NonRepudiation"), + QStringLiteral("Non-Repudiation"), + QStringLiteral("Usage is legally binding")); + out += MyConstraintType(QCA::KeyEncipherment, + QStringLiteral("KeyEncipherment"), + QStringLiteral("Key Encipherment"), + QStringLiteral("Can encrypt other keys")); + out += MyConstraintType(QCA::DataEncipherment, + QStringLiteral("DataEncipherment"), + QStringLiteral("Data Encipherment"), + QStringLiteral("Can encrypt arbitrary data")); + out += MyConstraintType(QCA::KeyAgreement, + QStringLiteral("KeyAgreement"), + QStringLiteral("Key Agreement"), + QStringLiteral("Can perform key agreement (DH)")); + out += MyConstraintType(QCA::KeyCertificateSign, + QStringLiteral("KeyCertificateSign"), + QStringLiteral("Certificate Sign"), + QStringLiteral("Can sign other certificates")); + out += MyConstraintType( + QCA::CRLSign, QStringLiteral("CRLSign"), QStringLiteral("CRL Sign"), QStringLiteral("Can sign CRLs")); + out += MyConstraintType(QCA::EncipherOnly, + QStringLiteral("EncipherOnly"), + QStringLiteral("Encipher Only"), + QStringLiteral("Can be used for encrypting")); + out += MyConstraintType(QCA::DecipherOnly, + QStringLiteral("DecipherOnly"), + QStringLiteral("Decipher Only"), + QStringLiteral("Can be used for decrypting")); + out += MyConstraintType(QCA::ServerAuth, + QStringLiteral("ServerAuth"), + QStringLiteral("Server Authentication"), + QStringLiteral("TLS Server")); + out += MyConstraintType(QCA::ClientAuth, + QStringLiteral("ClientAuth"), + QStringLiteral("Client Authentication"), + QStringLiteral("TLS Client")); + out += MyConstraintType( + QCA::CodeSigning, QStringLiteral("CodeSigning"), QStringLiteral("Code Signing"), QLatin1String("")); + out += MyConstraintType(QCA::EmailProtection, + QStringLiteral("EmailProtection"), + QStringLiteral("Email Protection"), + QStringLiteral("S/MIME")); + out += MyConstraintType( + QCA::IPSecEndSystem, QStringLiteral("IPSecEndSystem"), QStringLiteral("IPSec End-System"), QLatin1String("")); + out += MyConstraintType( + QCA::IPSecTunnel, QStringLiteral("IPSecTunnel"), QStringLiteral("IPSec Tunnel"), QLatin1String("")); + out += + MyConstraintType(QCA::IPSecUser, QStringLiteral("IPSecUser"), QStringLiteral("IPSec User"), QLatin1String("")); + out += MyConstraintType( + QCA::TimeStamping, QStringLiteral("TimeStamping"), QStringLiteral("Time Stamping"), QLatin1String("")); + out += MyConstraintType( + QCA::OCSPSigning, QStringLiteral("OCSPSigning"), QStringLiteral("OCSP Signing"), QLatin1String("")); + return out; +} + +const char *crlEntryReasonToString(QCA::CRLEntry::Reason r) +{ + switch (r) { + case QCA::CRLEntry::Unspecified: + return "Unspecified"; + case QCA::CRLEntry::KeyCompromise: + return "KeyCompromise"; + case QCA::CRLEntry::CACompromise: + return "CACompromise"; + case QCA::CRLEntry::AffiliationChanged: + return "AffiliationChanged"; + case QCA::CRLEntry::Superseded: + return "Superseded"; + case QCA::CRLEntry::CessationOfOperation: + return "CessationOfOperation"; + case QCA::CRLEntry::CertificateHold: + return "CertificateHold"; + case QCA::CRLEntry::RemoveFromCRL: + return "RemoveFromCRL"; + case QCA::CRLEntry::PrivilegeWithdrawn: + return "PrivilegeWithdrawn"; + case QCA::CRLEntry::AACompromise: + return "AACompromise"; + default: + return "Unknown"; + } +} + +static bool validOid(const QString &in) +{ + for (const QChar &c : in) { + if (!c.isDigit() && c != QLatin1Char('.')) + return false; + } + return true; +} + +class ValidityLength +{ +public: + int years, months, days; +}; + +static int vl_getnext(const QString &in, int offset = 0) +{ + if (offset >= in.length()) + return in.length(); + + int n = offset; + bool lookForNonDigit; + + if (in[n].isDigit()) + lookForNonDigit = true; + else + lookForNonDigit = false; + + for (++n; n < in.length(); ++n) { + if (in[n].isDigit() != lookForNonDigit) + break; + } + return n; +} + +static QStringList vl_getparts(const QString &in) +{ + QStringList out; + int offset = 0; + while (true) { + int n = vl_getnext(in, offset); + if (n == offset) + break; + out += in.mid(offset, n - offset); + offset = n; + } + return out; +} + +static bool parseValidityLength(const QString &in, ValidityLength *vl) +{ + vl->years = -1; + vl->months = -1; + vl->days = -1; + + QStringList parts = vl_getparts(in); + while (true) { + // first part should be a number + if (parts.count() < 1) + break; + QString str = parts.takeFirst(); + bool ok; + int x = str.toInt(&ok); + if (!ok) + return false; + + // next part should be 1 letter plus any amount of space + if (parts.count() < 1) + return false; + str = parts.takeFirst(); + if (!str[0].isLetter()) + return false; + str = str.trimmed(); // remove space + + if (str == QLatin1String("y")) { + if (vl->years != -1) + return false; + vl->years = x; + } + if (str == QLatin1String("m")) { + if (vl->months != -1) + return false; + vl->months = x; + } + if (str == QLatin1String("d")) { + if (vl->days != -1) + return false; + vl->days = x; + } + } + + if (vl->years == -1) + vl->years = 0; + if (vl->months == -1) + vl->months = 0; + if (vl->days == -1) + vl->days = 0; + + return true; +} + +static QString prompt_for(const QString &prompt) +{ + printf("%s: ", prompt.toLatin1().data()); + fflush(stdout); + QByteArray result(256, 0); + if (fgets((char *)result.data(), result.size(), stdin)) + return QString::fromLocal8Bit(result).trimmed(); + else + return QString(); +} + +static QCA::CertificateOptions promptForCertAttributes(bool advanced, bool req) +{ + QCA::CertificateOptions opts; + + if (advanced) { + if (!req) { + while (true) { + QString str = prompt_for( + QStringLiteral("Create an end user ('user') certificate or a CA ('ca') certificate? [user]")); + if (str.isEmpty()) + str = QStringLiteral("user"); + if (str != QLatin1String("user") && str != QLatin1String("ca")) { + printf("'%s' is not a valid entry.\n", qPrintable(str)); + continue; + } + + if (str == QLatin1String("ca")) + opts.setAsCA(); + break; + } + printf("\n"); + + while (true) { + QString str = prompt_for(QStringLiteral("Serial Number")); + QCA::BigInteger num; + if (str.isEmpty() || !num.fromString(str)) { + printf("'%s' is not a valid entry.\n", qPrintable(str)); + continue; + } + + opts.setSerialNumber(num); + break; + } + printf("\n"); + } + + { + QCA::CertificateInfoOrdered info; + printf( + "Choose the information attributes to add to the certificate. They will be\n" + "added in the order they are entered.\n\n"); + printf("Available information attributes:\n"); + QList list = makeInfoTypeList(); + for (int n = 0; n < list.count(); ++n) { + const InfoType &i = list[n]; + char c = 'a' + n; + printf(" %c) %-32s %s\n", c, qPrintable(i.name), qPrintable(i.desc)); + } + printf("\n"); + while (true) { + int index; + while (true) { + QString str = prompt_for(QStringLiteral("Select an attribute to add, or enter to move on")); + if (str.isEmpty()) { + index = -1; + break; + } + if (str.length() == 1) { + index = str[0].toLatin1() - 'a'; + if (index >= 0 && index < list.count()) + break; + } + printf("'%s' is not a valid entry.\n", qPrintable(str)); + } + if (index == -1) + break; + + QString val = prompt_for(list[index].name); + info += QCA::CertificateInfoPair(list[index].type, val); + printf("Added attribute.\n\n"); + } + opts.setInfoOrdered(info); + } + + { + QCA::Constraints constraints; + printf("\n"); + printf("Choose the constraint attributes to add to the certificate.\n\n"); + printf("Available attributes:\n"); + QList list = makeConstraintTypeList(); + for (int n = 0; n < list.count(); ++n) { + const MyConstraintType &i = list[n]; + char c = 'a' + n; + printf(" %c) %-32s %s\n", c, qPrintable(i.name), qPrintable(i.desc)); + } + printf("\n"); + printf("If no constraints are added, then the certificate may be used for any purpose.\n\n"); + while (true) { + int index; + while (true) { + QString str = prompt_for(QStringLiteral("Select an attribute to add, or enter to move on")); + if (str.isEmpty()) { + index = -1; + break; + } + if (str.length() == 1) { + index = str[0].toLatin1() - 'a'; + if (index >= 0 && index < list.count()) + break; + } + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } + if (index == -1) + break; + + if (constraints.contains(list[index].type)) { + printf("You have already added '%s'.\n\n", qPrintable(list[index].name)); + continue; + } + + constraints += list[index].type; + printf("Added attribute.\n\n"); + } + opts.setConstraints(constraints); + } + + { + QStringList policies; + printf("\n"); + printf( + "Are there any policy OID attributes that you wish to add? Use the dotted\n" + "string format.\n\n"); + while (true) { + QString str = prompt_for(QStringLiteral("Enter a policy OID to add, or enter to move on")); + if (str.isEmpty()) + break; + if (!validOid(str)) { + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + continue; + } + if (policies.contains(str)) { + printf("You have already added '%s'.\n\n", qPrintable(str)); + continue; + } + + policies += str; + printf("Added attribute.\n\n"); + } + opts.setPolicies(policies); + } + + printf("\n"); + } else { + QCA::CertificateInfo info; + info.insert(QCA::CommonName, prompt_for(QStringLiteral("Common Name"))); + info.insert(QCA::Country, prompt_for(QStringLiteral("Country Code (2 letters)"))); + info.insert(QCA::Organization, prompt_for(QStringLiteral("Organization"))); + info.insert(QCA::Email, prompt_for(QStringLiteral("Email"))); + opts.setInfo(info); + + printf("\n"); + } + + if (!req) { + while (true) { + QString str = prompt_for(QStringLiteral("How long should the certificate be valid? (e.g. '1y2m3d')")); + ValidityLength vl; + if (!parseValidityLength(str, &vl)) { + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + continue; + } + + if (vl.years == 0 && vl.months == 0 && vl.days == 0) { + printf("The certificate must be valid for at least one day.\n\n"); + continue; + } + + QDateTime start = QDateTime::currentDateTimeUtc(); + QDateTime end = start; + if (vl.years > 0) + end = end.addYears(vl.years); + if (vl.months > 0) + end = end.addMonths(vl.months); + if (vl.days > 0) + end = end.addDays(vl.days); + opts.setValidityPeriod(start, end); + + QStringList parts; + if (vl.years > 0) + parts += QStringLiteral("%1 year(s)").arg(vl.years); + if (vl.months > 0) + parts += QStringLiteral("%1 month(s)").arg(vl.months); + if (vl.days > 0) + parts += QStringLiteral("%1 day(s)").arg(vl.days); + QString out; + if (parts.count() == 1) + out = parts[0]; + else if (parts.count() == 2) + out = parts[0] + QStringLiteral(" and ") + parts[1]; + else if (parts.count() == 3) + out = parts[0] + QStringLiteral(", ") + parts[1] + QStringLiteral(", and ") + parts[2]; + printf("Certificate will be valid for %s.\n", qPrintable(out)); + break; + } + printf("\n"); + } + + return opts; +} + +// qsettings seems to give us a string type for both bool and int (and +// possibly others, but those are the only two we care about here). +// in order to figure out what is actually a bool or an int, we need +// to examine the string. so for the functions below, we convert +// the variant to a string, and then inspect it to see if it looks +// like a bool or an int. + +static bool string_is_bool(const QString &in) +{ + QString lc = in.toLower(); + if (lc == QLatin1String("true") || lc == QLatin1String("false")) + return true; + return false; +} + +static bool string_is_int(const QString &in) +{ + bool ok; + in.toInt(&ok); + return ok; +} + +static bool variant_is_bool(const QVariant &in) +{ + if (in.canConvert() && string_is_bool(in.toString())) + return true; + return false; +} + +static bool variant_is_int(const QVariant &in) +{ + if (in.canConvert() && string_is_int(in.toString())) + return true; + return false; +} + +static QString prompt_for_string(const QString &prompt, const QString &def = QString()) +{ + printf("%s", prompt.toLatin1().data()); + fflush(stdout); + QByteArray result(256, 0); + if (!fgets((char *)result.data(), result.size(), stdin)) + return QString(); + if (result[result.length() - 1] == '\n') + result.truncate(result.length() - 1); + // empty input -> use default + if (result.isEmpty()) + return def; + // trimmed input could result in an empty value, but in that case + // it is treated as if the user wishes to submit an empty value. + return QString::fromLocal8Bit(result).trimmed(); +} + +static int prompt_for_int(const QString &prompt, int def = 0) +{ + while (true) { + QString str = prompt_for_string(prompt); + if (str.isEmpty()) + return def; + bool ok; + int x = str.toInt(&ok); + if (ok) + return x; + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } +} + +static bool partial_compare_nocase(const QString &in, const QString &target, int min = 1) +{ + if (in.length() >= min && in.length() <= target.length() && target.mid(0, in.length()).toLower() == in.toLower()) + return true; + return false; +} + +static bool prompt_for_bool(const QString &prompt, bool def = false) +{ + while (true) { + QString str = prompt_for_string(prompt); + if (str.isEmpty()) + return def; + if (partial_compare_nocase(str, QStringLiteral("true"))) + return true; + else if (partial_compare_nocase(str, QStringLiteral("false"))) + return false; + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } +} + +static bool prompt_for_yesno(const QString &prompt, bool def = false) +{ + while (true) { + QString str = prompt_for_string(prompt); + if (str.isEmpty()) + return def; + if (partial_compare_nocase(str, QStringLiteral("yes"))) + return true; + else if (partial_compare_nocase(str, QStringLiteral("no"))) + return false; + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } +} + +static QString prompt_for_slotevent_method(const QString &prompt, const QString &def = QString()) +{ + while (true) { + QString str = prompt_for_string(prompt); + if (str.isEmpty()) + return def; + if (partial_compare_nocase(str, QStringLiteral("auto"))) + return QStringLiteral("auto"); + else if (partial_compare_nocase(str, QStringLiteral("trigger"))) + return QStringLiteral("trigger"); + else if (partial_compare_nocase(str, QStringLiteral("poll"))) + return QStringLiteral("poll"); + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } +} + +static QVariantMap provider_config_edit_generic(const QVariantMap &in) +{ + QVariantMap config = in; + QMutableMapIterator it(config); + while (it.hasNext()) { + it.next(); + QString var = it.key(); + if (var == QLatin1String("formtype")) + continue; + QVariant val = it.value(); + + // fields must be bool, int, or string + QVariant newval; + QString prompt = QStringLiteral("%1: [%2] ").arg(var, val.toString()); + if (variant_is_bool(val)) + newval = prompt_for_bool(QStringLiteral("bool ") + prompt, val.toBool()); + else if (variant_is_int(val)) + newval = prompt_for_int(QStringLiteral("int ") + prompt, val.toInt()); + else if (val.canConvert()) + newval = prompt_for_string(QStringLiteral("string ") + prompt, val.toString()); + else + continue; // skip bogus fields + + it.setValue(newval); + } + + return config; +} + +class Pkcs11ProviderConfig +{ +public: + bool allow_protected_authentication; + bool cert_private; + bool enabled; + QString library; + QString name; + int private_mask; + QString slotevent_method; + int slotevent_timeout; + + Pkcs11ProviderConfig() + : allow_protected_authentication(true) + , cert_private(false) + , enabled(false) + , private_mask(0) + , slotevent_method(QStringLiteral("auto")) + , slotevent_timeout(0) + { + } + + QVariantMap toVariantMap() const + { + QVariantMap out; + out[QStringLiteral("allow_protected_authentication")] = allow_protected_authentication; + out[QStringLiteral("cert_private")] = cert_private; + out[QStringLiteral("enabled")] = enabled; + out[QStringLiteral("library")] = library; + out[QStringLiteral("name")] = name; + out[QStringLiteral("private_mask")] = private_mask; + out[QStringLiteral("slotevent_method")] = slotevent_method; + out[QStringLiteral("slotevent_timeout")] = slotevent_timeout; + return out; + } + + bool fromVariantMap(const QVariantMap &in) + { + allow_protected_authentication = in[QStringLiteral("allow_protected_authentication")].toBool(); + cert_private = in[QStringLiteral("cert_private")].toBool(); + enabled = in[QStringLiteral("enabled")].toBool(); + library = in[QStringLiteral("library")].toString(); + name = in[QStringLiteral("name")].toString(); + private_mask = in[QStringLiteral("private_mask")].toInt(); + slotevent_method = in[QStringLiteral("slotevent_method")].toString(); + slotevent_timeout = in[QStringLiteral("slotevent_timeout")].toInt(); + return true; + } +}; + +class Pkcs11Config +{ +public: + bool allow_load_rootca; + bool allow_protected_authentication; + int log_level; + int pin_cache; + QList providers; + + QVariantMap orig_config; + + Pkcs11Config() + : allow_load_rootca(false) + , allow_protected_authentication(true) + , log_level(0) + , pin_cache(-1) + { + } + + QVariantMap toVariantMap() const + { + QVariantMap out = orig_config; + + // form type + out[QStringLiteral("formtype")] = QLatin1String("http://affinix.com/qca/forms/qca-pkcs11#1.0"); + + // base settings + out[QStringLiteral("allow_load_rootca")] = allow_load_rootca; + out[QStringLiteral("allow_protected_authentication")] = allow_protected_authentication; + out[QStringLiteral("log_level")] = log_level; + out[QStringLiteral("pin_cache")] = pin_cache; + + // provider settings (always write at least 10 providers) + for (int n = 0; n < 10 || n < providers.count(); ++n) { + QString prefix = QString::asprintf("provider_%02d_", n); + + Pkcs11ProviderConfig provider; + if (n < providers.count()) + provider = providers[n]; + + QVariantMap subconfig = provider.toVariantMap(); + QMapIterator it(subconfig); + while (it.hasNext()) { + it.next(); + out.insert(prefix + it.key(), it.value()); + } + } + + return out; + } + + bool fromVariantMap(const QVariantMap &in) + { + if (in[QStringLiteral("formtype")] != QLatin1String("http://affinix.com/qca/forms/qca-pkcs11#1.0")) + return false; + + allow_load_rootca = in[QStringLiteral("allow_load_rootca")].toBool(); + allow_protected_authentication = in[QStringLiteral("allow_protected_authentication")].toBool(); + log_level = in[QStringLiteral("log_level")].toInt(); + pin_cache = in[QStringLiteral("pin_cache")].toInt(); + + for (int n = 0;; ++n) { + QString prefix = QString::asprintf("provider_%02d_", n); + + // collect all key/values with this prefix into a + // a separate container, leaving out the prefix + // from the keys. + QVariantMap subconfig; + QMapIterator it(in); + while (it.hasNext()) { + it.next(); + if (it.key().startsWith(prefix)) + subconfig.insert(it.key().mid(prefix.length()), it.value()); + } + + // if there are no config items with this prefix, we're done + if (subconfig.isEmpty()) + break; + + Pkcs11ProviderConfig provider; + if (!provider.fromVariantMap(subconfig)) + return false; + + // skip unnamed entries + if (provider.name.isEmpty()) + continue; + + // skip duplicate entries + bool have_name_already = false; + foreach (const Pkcs11ProviderConfig &i, providers) { + if (i.name == provider.name) { + have_name_already = true; + break; + } + } + if (have_name_already) + continue; + + providers += provider; + } + + orig_config = in; + return true; + } +}; + +static QVariantMap provider_config_edit_pkcs11(const QVariantMap &in) +{ + Pkcs11Config config; + if (!config.fromVariantMap(in)) { + fprintf(stderr, "Error: unable to parse PKCS#11 provider configuration.\n"); + return QVariantMap(); + } + + while (true) { + printf("\n"); + printf("Global settings:\n"); + printf(" Allow loading of root CAs: %s\n", config.allow_load_rootca ? "Yes" : "No"); + printf(" Allow protected authentication: %s\n", config.allow_protected_authentication ? "Yes" : "No"); + QString str; + if (config.pin_cache == -1) + str = QStringLiteral("No limit"); + else + str = QStringLiteral("%1 seconds").arg(config.pin_cache); + printf(" Maximum PIN cache time: %s\n", qPrintable(str)); + printf(" Log level: %d\n", config.log_level); + printf("\n"); + printf("PKCS#11 modules:\n"); + if (!config.providers.isEmpty()) { + foreach (const Pkcs11ProviderConfig &provider, config.providers) + printf(" %s\n", qPrintable(provider.name)); + } else + printf(" (None)\n"); + printf("\n"); + printf("Actions:\n"); + printf(" a) Edit global settings\n"); + printf(" b) Add PKCS#11 module\n"); + printf(" c) Edit PKCS#11 module\n"); + printf(" d) Remove PKCS#11 module\n"); + printf("\n"); + + int index; + while (true) { + QString str = prompt_for(QStringLiteral("Select an action, or enter to quit")); + if (str.isEmpty()) { + index = -1; + break; + } + if (str.length() == 1) { + index = str[0].toLatin1() - 'a'; + if (index >= 0 && index < 4) + break; + } + printf("'%s' is not a valid entry.\n\n", qPrintable(str)); + } + if (index == -1) + break; + + if (index == 0) { + printf("\n"); + + QString prompt; + prompt = QStringLiteral("Allow loading of root CAs: [%1] ") + .arg(config.allow_load_rootca ? QStringLiteral("Yes") : QStringLiteral("No")); + config.allow_load_rootca = prompt_for_yesno(prompt, config.allow_load_rootca); + prompt = QStringLiteral("Allow protected authentication: [%1] ") + .arg(config.allow_protected_authentication ? QStringLiteral("Yes") : QStringLiteral("No")); + config.allow_protected_authentication = prompt_for_yesno(prompt, config.allow_protected_authentication); + prompt = QStringLiteral("Maximum PIN cache time in seconds (-1 for no limit): [%1] ").arg(config.pin_cache); + config.pin_cache = prompt_for_int(prompt, config.pin_cache); + prompt = QStringLiteral("Log level: [%1] ").arg(config.log_level); + config.log_level = prompt_for_int(prompt, config.log_level); + } else // 1, 2, 3 + { + int at = -1; + + // for edit/remove, need to select provider + if (index == 2 || index == 3) { + printf("\nWhich PKCS#11 module?\n"); + for (int n = 0; n < config.providers.count(); ++n) { + const Pkcs11ProviderConfig &provider = config.providers[n]; + char c = 'a' + n; + printf(" %c) %s\n", c, qPrintable(provider.name)); + } + printf("\n"); + + int index; + while (true) { + QString str = prompt_for(QStringLiteral("Select a module, or enter to go back")); + if (str.isEmpty()) { + index = -1; + break; + } + if (str.length() == 1) { + index = str[0].toLatin1() - 'a'; + if (index >= 0 && index < config.providers.count()) + break; + } + printf("'%s' is not a valid entry.\n", qPrintable(str)); + } + + // exit? + if (index == -1) + continue; + + at = index; + } + + // edit the entry + if (index == 1 || index == 2) { + Pkcs11ProviderConfig provider; + if (index == 2) // edit + provider = config.providers[at]; + provider.enabled = true; + printf("\n"); + + QString prompt; + + // prompt for unique name + while (true) { + if (index == 1) + prompt = QStringLiteral("Unique friendly name: "); + else + prompt = QStringLiteral("Unique friendly name: [%1] ").arg(provider.name); + provider.name = prompt_for_string(prompt, provider.name); + + if (provider.name.isEmpty()) { + printf("The friendly name cannot be blank.\n\n"); + continue; + } + + bool have_name_already = false; + for (int n = 0; n < config.providers.count(); ++n) { + const Pkcs11ProviderConfig &i = config.providers[n]; + + // skip checking against the entry we are editing + if (at != -1 && n == at) + continue; + + if (i.name == provider.name) { + have_name_already = true; + break; + } + } + if (have_name_already) { + printf("This name is already used by another module.\n\n"); + continue; + } + + break; + } + + // prompt for library file + QString last; + while (true) { + if (index == 1) + prompt = QStringLiteral("Library filename: "); + else + prompt = QStringLiteral("Library filename: [%1] ").arg(provider.library); + provider.library = prompt_for_string(prompt, provider.library); + + if (provider.library.isEmpty()) { + printf("The library filename cannot be blank.\n\n"); + continue; + } + + if (last != provider.library && !QFile::exists(provider.library)) { + last = provider.library; + printf("'%s' does not exist.\nPress enter again if you really want this.\n\n", + qPrintable(provider.library)); + continue; + } + + break; + } + + prompt = + QStringLiteral("Allow protected authentication: [%1] ") + .arg(provider.allow_protected_authentication ? QStringLiteral("Yes") : QStringLiteral("No")); + provider.allow_protected_authentication = + prompt_for_yesno(prompt, provider.allow_protected_authentication); + prompt = QStringLiteral("Provider stores certificates as private objects: [%1] ") + .arg(provider.cert_private ? QStringLiteral("Yes") : QStringLiteral("No")); + provider.cert_private = prompt_for_yesno(prompt, provider.cert_private); + printf("\n"); + printf("Provider private key mask:\n"); + printf(" 0 Determine automatically.\n"); + printf(" 1 Use sign.\n"); + printf(" 2 Use sign recover.\n"); + printf(" 4 Use decrypt.\n"); + printf(" 8 Use unwrap.\n"); + prompt = QStringLiteral("Mask value: [%1] ").arg(provider.private_mask); + provider.private_mask = prompt_for_int(prompt, provider.private_mask); + printf("\n"); + printf("Slot event method:\n"); + printf(" auto Determine automatically.\n"); + printf(" trigger Use trigger.\n"); + printf(" poll Use poll.\n"); + prompt = QStringLiteral("Method value: [%1] ").arg(provider.slotevent_method); + provider.slotevent_method = prompt_for_slotevent_method(prompt, provider.slotevent_method); + if (provider.slotevent_method == QLatin1String("poll")) { + prompt = + QStringLiteral("Poll timeout (0 for no preference): [%1] ").arg(provider.slotevent_timeout); + provider.slotevent_timeout = prompt_for_int(prompt, provider.slotevent_timeout); + } else + provider.slotevent_timeout = 0; + + if (index == 1) + config.providers += provider; + else // 2 + config.providers[at] = provider; + } + // remove the entry + else // 3 + { + config.providers.removeAt(at); + } + } + } + + return config.toVariantMap(); +} + +static QVariantMap provider_config_edit(const QVariantMap &in) +{ + // see if we have a configurator for a known form type + if (in[QStringLiteral("formtype")] == QLatin1String("http://affinix.com/qca/forms/qca-pkcs11#1.0")) + return provider_config_edit_pkcs11(in); + + // otherwise, use the generic configurator + return provider_config_edit_generic(in); +} + +static QString get_fingerprint(const QCA::Certificate &cert, const QString &hashType) +{ + QString hex = QCA::Hash(hashType).hashToString(cert.toDER()); + QString out; + for (int n = 0; n < hex.size(); ++n) { + if (n != 0 && n % 2 == 0) + out += QLatin1Char(':'); + out += hex[n]; + } + return out; +} + +static QString kstype_to_string(QCA::KeyStore::Type _type) +{ + QString type; + switch (_type) { + case QCA::KeyStore::System: + type = QStringLiteral("Sys "); + break; + case QCA::KeyStore::User: + type = QStringLiteral("User"); + break; + case QCA::KeyStore::Application: + type = QStringLiteral("App "); + break; + case QCA::KeyStore::SmartCard: + type = QStringLiteral("Card"); + break; + case QCA::KeyStore::PGPKeyring: + type = QStringLiteral("PGP "); + break; + default: + type = QStringLiteral("XXXX"); + break; + } + return type; +} + +static QString ksentrytype_to_string(QCA::KeyStoreEntry::Type _type) +{ + QString type; + switch (_type) { + case QCA::KeyStoreEntry::TypeKeyBundle: + type = QStringLiteral("Key "); + break; + case QCA::KeyStoreEntry::TypeCertificate: + type = QStringLiteral("Cert"); + break; + case QCA::KeyStoreEntry::TypeCRL: + type = QStringLiteral("CRL "); + break; + case QCA::KeyStoreEntry::TypePGPSecretKey: + type = QStringLiteral("PSec"); + break; + case QCA::KeyStoreEntry::TypePGPPublicKey: + type = QStringLiteral("PPub"); + break; + default: + type = QStringLiteral("XXXX"); + break; + } + return type; +} + +static void try_print_info(const char *name, const QStringList &values) +{ + if (!values.isEmpty()) { + QString value = values.join(QStringLiteral(", ")); + printf(" %s: %s\n", name, value.toUtf8().data()); + } +} + +static void print_info(const char *title, const QCA::CertificateInfo &info) +{ + QList list = makeInfoTypeList(); + printf("%s\n", title); + foreach (const InfoType &t, list) + try_print_info(qPrintable(t.name), info.values(t.type)); +} + +static void print_info_ordered(const char *title, const QCA::CertificateInfoOrdered &info) +{ + QList list = makeInfoTypeList(true); + printf("%s\n", title); + foreach (const QCA::CertificateInfoPair &pair, info) { + QCA::CertificateInfoType type = pair.type(); + QString name; + int at = -1; + for (int n = 0; n < list.count(); ++n) { + if (list[n].type == type) { + at = n; + break; + } + } + + // known type? + if (at != -1) { + name = list[at].name; + } else { + if (pair.type().section() == QCA::CertificateInfoType::DN) + name = QStringLiteral("DN:") + pair.type().id(); + else + name = QStringLiteral("AN:") + pair.type().id(); + } + + printf(" %s: %s\n", qPrintable(name), pair.value().toUtf8().data()); + } +} + +static QString constraint_to_string(const QCA::ConstraintType &t) +{ + QList list = makeConstraintTypeList(); + for (int n = 0; n < list.count(); ++n) { + if (list[n].type == t) + return list[n].name; + } + return t.id(); +} + +static QString sigalgo_to_string(QCA::SignatureAlgorithm algo) +{ + QString str; + switch (algo) { + case QCA::EMSA1_SHA1: + str = QStringLiteral("EMSA1(SHA1)"); + break; + case QCA::EMSA3_SHA1: + str = QStringLiteral("EMSA3(SHA1)"); + break; + case QCA::EMSA3_MD5: + str = QStringLiteral("EMSA3(MD5)"); + break; + case QCA::EMSA3_MD2: + str = QStringLiteral("EMSA3(MD2)"); + break; + case QCA::EMSA3_RIPEMD160: + str = QStringLiteral("EMSA3(RIPEMD160)"); + break; + case QCA::EMSA3_Raw: + str = QStringLiteral("EMSA3(raw)"); + break; + default: + str = QStringLiteral("Unknown"); + break; + } + return str; +} + +static void print_cert(const QCA::Certificate &cert, bool ordered = false) +{ + printf("Serial Number: %s\n", qPrintable(cert.serialNumber().toString())); + + if (ordered) { + print_info_ordered("Subject", cert.subjectInfoOrdered()); + print_info_ordered("Issuer", cert.issuerInfoOrdered()); + } else { + print_info("Subject", cert.subjectInfo()); + print_info("Issuer", cert.issuerInfo()); + } + + printf("Validity\n"); + printf(" Not before: %s\n", qPrintable(cert.notValidBefore().toString())); + printf(" Not after: %s\n", qPrintable(cert.notValidAfter().toString())); + + printf("Constraints\n"); + QCA::Constraints constraints = cert.constraints(); + int n; + if (!constraints.isEmpty()) { + for (n = 0; n < constraints.count(); ++n) + printf(" %s\n", qPrintable(constraint_to_string(constraints[n]))); + } else + printf(" No constraints\n"); + + printf("Policies\n"); + QStringList policies = cert.policies(); + if (!policies.isEmpty()) { + for (n = 0; n < policies.count(); ++n) + printf(" %s\n", qPrintable(policies[n])); + } else + printf(" No policies\n"); + + QByteArray id; + printf("Issuer Key ID: "); + id = cert.issuerKeyId(); + if (!id.isEmpty()) + printf("%s\n", qPrintable(QCA::arrayToHex(id))); + else + printf("None\n"); + + printf("Subject Key ID: "); + id = cert.subjectKeyId(); + if (!id.isEmpty()) + printf("%s\n", qPrintable(QCA::arrayToHex(id))); + else + printf("None\n"); + + printf("CA: %s\n", cert.isCA() ? "Yes" : "No"); + printf("Signature Algorithm: %s\n", qPrintable(sigalgo_to_string(cert.signatureAlgorithm()))); + + QCA::PublicKey key = cert.subjectPublicKey(); + printf("Public Key:\n%s", key.toPEM().toLatin1().data()); + + printf("SHA1 Fingerprint: %s\n", qPrintable(get_fingerprint(cert, QStringLiteral("sha1")))); + printf("MD5 Fingerprint: %s\n", qPrintable(get_fingerprint(cert, QStringLiteral("md5")))); +} + +static void print_certreq(const QCA::CertificateRequest &cert, bool ordered = false) +{ + if (ordered) + print_info_ordered("Subject", cert.subjectInfoOrdered()); + else + print_info("Subject", cert.subjectInfo()); + + printf("Constraints\n"); + QCA::Constraints constraints = cert.constraints(); + int n; + if (!constraints.isEmpty()) { + for (n = 0; n < constraints.count(); ++n) + printf(" %s\n", qPrintable(constraint_to_string(constraints[n]))); + } else + printf(" No constraints\n"); + + printf("Policies\n"); + QStringList policies = cert.policies(); + if (!policies.isEmpty()) { + for (n = 0; n < policies.count(); ++n) + printf(" %s\n", qPrintable(policies[n])); + } else + printf(" No policies\n"); + + printf("CA: %s\n", cert.isCA() ? "Yes" : "No"); + printf("Signature Algorithm: %s\n", qPrintable(sigalgo_to_string(cert.signatureAlgorithm()))); + + QCA::PublicKey key = cert.subjectPublicKey(); + printf("Public Key:\n%s", key.toPEM().toLatin1().data()); +} + +static void print_crl(const QCA::CRL &crl, bool ordered = false) +{ + if (ordered) + print_info_ordered("Issuer", crl.issuerInfoOrdered()); + else + print_info("Issuer", crl.issuerInfo()); + + int num = crl.number(); + if (num != -1) + printf("Number: %d\n", num); + + printf("Validity\n"); + printf(" This update: %s\n", qPrintable(crl.thisUpdate().toString())); + printf(" Next update: %s\n", qPrintable(crl.nextUpdate().toString())); + + QByteArray id; + printf("Issuer Key ID: "); + id = crl.issuerKeyId(); + if (!id.isEmpty()) + printf("%s\n", qPrintable(QCA::arrayToHex(id))); + else + printf("None\n"); + + printf("Signature Algorithm: %s\n", qPrintable(sigalgo_to_string(crl.signatureAlgorithm()))); + + QList revokedList = crl.revoked(); + foreach (const QCA::CRLEntry &entry, revokedList) { + printf(" %s: %s, %s\n", + qPrintable(entry.serialNumber().toString()), + crlEntryReasonToString(entry.reason()), + qPrintable(entry.time().toString())); + } +} + +static QString format_pgp_fingerprint(const QString &in) +{ + QString out; + bool first = true; + for (int n = 0; n + 3 < in.length(); n += 4) { + if (!first) + out += QLatin1Char(' '); + else + first = false; + out += in.mid(n, 4).toUpper(); + } + return out; +} + +static void print_pgp(const QCA::PGPKey &key) +{ + printf("Key ID: %s\n", qPrintable(key.keyId())); + printf("User IDs:\n"); + foreach (const QString &s, key.userIds()) + printf(" %s\n", qPrintable(s)); + printf("Validity\n"); + printf(" Not before: %s\n", qPrintable(key.creationDate().toString())); + if (!key.expirationDate().isNull()) + printf(" Not after: %s\n", qPrintable(key.expirationDate().toString())); + else + printf(" Not after: (no expiration)\n"); + printf("In Keyring: %s\n", key.inKeyring() ? "Yes" : "No"); + printf("Secret Key: %s\n", key.isSecret() ? "Yes" : "No"); + printf("Trusted: %s\n", key.isTrusted() ? "Yes" : "No"); + printf("Fingerprint: %s\n", qPrintable(format_pgp_fingerprint(key.fingerprint()))); +} + +static QString validityToString(QCA::Validity v) +{ + QString s; + switch (v) { + case QCA::ValidityGood: + s = QStringLiteral("Validated"); + break; + case QCA::ErrorRejected: + s = QStringLiteral("Root CA is marked to reject the specified purpose"); + break; + case QCA::ErrorUntrusted: + s = QStringLiteral("Certificate not trusted for the required purpose"); + break; + case QCA::ErrorSignatureFailed: + s = QStringLiteral("Invalid signature"); + break; + case QCA::ErrorInvalidCA: + s = QStringLiteral("Invalid CA certificate"); + break; + case QCA::ErrorInvalidPurpose: + s = QStringLiteral("Invalid certificate purpose"); + break; + case QCA::ErrorSelfSigned: + s = QStringLiteral("Certificate is self-signed"); + break; + case QCA::ErrorRevoked: + s = QStringLiteral("Certificate has been revoked"); + break; + case QCA::ErrorPathLengthExceeded: + s = QStringLiteral("Maximum certificate chain length exceeded"); + break; + case QCA::ErrorExpired: + s = QStringLiteral("Certificate has expired"); + break; + case QCA::ErrorExpiredCA: + s = QStringLiteral("CA has expired"); + break; + case QCA::ErrorValidityUnknown: + default: + s = QStringLiteral("General certificate validation error"); + break; + } + return s; +} + +static QString smIdentityResultToString(QCA::SecureMessageSignature::IdentityResult r) +{ + QString str; + switch (r) { + case QCA::SecureMessageSignature::Valid: + str = QStringLiteral("Valid"); + break; + case QCA::SecureMessageSignature::InvalidSignature: + str = QStringLiteral("InvalidSignature"); + break; + case QCA::SecureMessageSignature::InvalidKey: + str = QStringLiteral("InvalidKey"); + break; + case QCA::SecureMessageSignature::NoKey: + str = QStringLiteral("NoKey"); + break; + default: + str = QStringLiteral("Unknown"); + } + return str; +} + +static QString smErrorToString(QCA::SecureMessage::Error e) +{ + QMap map; + map[QCA::SecureMessage::ErrorPassphrase] = QStringLiteral("ErrorPassphrase"); + map[QCA::SecureMessage::ErrorFormat] = QStringLiteral("ErrorFormat"); + map[QCA::SecureMessage::ErrorSignerExpired] = QStringLiteral("ErrorSignerExpired"); + map[QCA::SecureMessage::ErrorSignerInvalid] = QStringLiteral("ErrorSignerInvalid"); + map[QCA::SecureMessage::ErrorEncryptExpired] = QStringLiteral("ErrorEncryptExpired"); + map[QCA::SecureMessage::ErrorEncryptUntrusted] = QStringLiteral("ErrorEncryptUntrusted"); + map[QCA::SecureMessage::ErrorEncryptInvalid] = QStringLiteral("ErrorEncryptInvalid"); + map[QCA::SecureMessage::ErrorNeedCard] = QStringLiteral("ErrorNeedCard"); + map[QCA::SecureMessage::ErrorCertKeyMismatch] = QStringLiteral("ErrorCertKeyMismatch"); + map[QCA::SecureMessage::ErrorUnknown] = QStringLiteral("ErrorUnknown"); + return map[e]; +} + +static void smDisplaySignatures(const QList &signers) +{ + foreach (const QCA::SecureMessageSignature &signer, signers) { + QCA::SecureMessageSignature::IdentityResult r = signer.identityResult(); + fprintf(stderr, "IdentityResult: %s\n", qPrintable(smIdentityResultToString(r))); + + QCA::SecureMessageKey key = signer.key(); + if (!key.isNull()) { + if (key.type() == QCA::SecureMessageKey::PGP) { + QCA::PGPKey pub = key.pgpPublicKey(); + fprintf(stderr, "From: %s (%s)\n", qPrintable(pub.primaryUserId()), qPrintable(pub.keyId())); + } else { + QCA::Certificate cert = key.x509CertificateChain().primary(); + QString emailStr; + QCA::CertificateInfo info = cert.subjectInfo(); + if (info.contains(QCA::Email)) + emailStr = QStringLiteral(" (%1)").arg(info.value(QCA::Email)); + fprintf(stderr, "From: %s%s\n", qPrintable(cert.commonName()), qPrintable(emailStr)); + } + } + } +} + +static const char *mime_signpart = + "Content-Type: text/plain; charset=UTF-8\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "\r\n" + "%1"; + +static const char *mime_signed = + "Content-Type: multipart/signed;\r\n" + " micalg=%1;\r\n" + " boundary=QCATOOL-0001;\r\n" + " protocol=\"application/pkcs7-signature\"\r\n" + "\r\n" + "\r\n" + "--QCATOOL-0001\r\n" + "%2\r\n" + "--QCATOOL-0001\r\n" + "Content-Transfer-Encoding: base64\r\n" + "Content-Type: application/pkcs7-signature;\r\n" + " name=smime.p7s\r\n" + "Content-Disposition: attachment;\r\n" + " filename=smime.p7s\r\n" + "\r\n" + "%3\r\n" + "\r\n" + "--QCATOOL-0001--\r\n"; + +static const char *mime_enveloped = + "Mime-Version: 1.0\r\n" + "Content-Transfer-Encoding: base64\r\n" + "Content-Type: application/pkcs7-mime;\r\n" + " name=smime.p7m;\r\n" + " smime-type=enveloped-data\r\n" + "Content-Disposition: attachment;\r\n" + " filename=smime.p7m\r\n" + "\r\n" + "%1\r\n"; + +static QString add_cr(const QString &in) +{ + QString out = in; + int at = 0; + while (true) { + at = out.indexOf(QLatin1Char('\n'), at); + if (at == -1) + break; + if (at - 1 >= 0 && out[at - 1] != QLatin1Char('\r')) { + out.insert(at, QLatin1Char('\r')); + ++at; + } + ++at; + } + return out; +} + +static QString rem_cr(const QString &in) +{ + QString out = in; + out.replace(QLatin1String("\r\n"), QLatin1String("\n")); + return out; +} + +static int indexOf_newline(const QString &in, int offset = 0) +{ + for (int n = offset; n < in.length(); ++n) { + if (n + 1 < in.length() && in[n] == QLatin1Char('\r') && in[n + 1] == QLatin1Char('\n')) + return n; + if (in[n] == QLatin1Char('\n')) + return n; + } + return -1; +} + +static int indexOf_doublenewline(const QString &in, int offset = 0) +{ + int at = -1; + while (true) { + int n = indexOf_newline(in, offset); + if (n == -1) + return -1; + + if (at != -1) { + if (n == offset) + break; + } + + at = n; + if (in[n] == QLatin1Char('\n')) + offset = n + 1; + else + offset = n + 2; + } + return at; +} + +// this is so gross +static int newline_len(const QString &in, int offset = 0) +{ + if (in[offset] == QLatin1Char('\r')) + return 2; + else + return 1; +} + +// all of this mime stuff is a total hack +static QString open_mime_envelope(const QString &in) +{ + int n = indexOf_doublenewline(in); + if (n == -1) + return QString(); + return in.mid(n + (newline_len(in, n) * 2)); // good lord +} + +static bool open_mime_data_sig(const QString &in, QString *data, QString *sig) +{ + int n = in.indexOf(QLatin1String("boundary=")); + if (n == -1) + return false; + n += 9; + int i = indexOf_newline(in, n); + if (i == -1) + return false; + QString boundary; + QString bregion = in.mid(n, i - n); + n = bregion.indexOf(QLatin1Char(';')); + if (n != -1) + boundary = bregion.mid(0, n); + else + boundary = bregion; + + if (boundary[0] == QLatin1Char('\"')) + boundary.remove(0, 1); + if (boundary[boundary.length() - 1] == QLatin1Char('\"')) + boundary.remove(boundary.length() - 1, 1); + // printf("boundary: [%s]\n", qPrintable(boundary)); + QString boundary_end = QStringLiteral("--") + boundary; + boundary = QStringLiteral("--") + boundary; + + QString work = open_mime_envelope(in); + // printf("work: [%s]\n", qPrintable(work)); + + n = work.indexOf(boundary); + if (n == -1) + return false; + n += boundary.length(); + i = indexOf_newline(work, n); + if (i == -1) + return false; + n += newline_len(work, i); + int data_start = n; + + n = work.indexOf(boundary, data_start); + if (n == -1) + return false; + int data_end = n; + + n = data_end + boundary.length(); + i = indexOf_newline(work, n); + if (i == -1) + return false; + n += newline_len(work, i); + int next = n; + + QString tmp_data = work.mid(data_start, data_end - data_start); + n = work.indexOf(boundary_end, next); + if (n == -1) + return false; + QString tmp_sig = work.mid(next, n - next); + + // nuke some newlines + if (tmp_data.right(2) == QLatin1String("\r\n")) + tmp_data.truncate(tmp_data.length() - 2); + else if (tmp_data.right(1) == QLatin1String("\n")) + tmp_data.truncate(tmp_data.length() - 1); + if (tmp_sig.right(2) == QLatin1String("\r\n")) + tmp_sig.truncate(tmp_sig.length() - 2); + else if (tmp_sig.right(1) == QLatin1String("\n")) + tmp_sig.truncate(tmp_sig.length() - 1); + + tmp_sig = open_mime_envelope(tmp_sig); + + *data = tmp_data; + *sig = tmp_sig; + return true; +} + +static QString idHash(const QString &id) +{ + // hash the id and take the rightmost 4 hex characters + return QCA::Hash(QStringLiteral("md5")).hashToString(id.toUtf8()).right(4); +} + +// first = ids, second = names +static QPair getKeyStoreStrings(const QStringList &list, QCA::KeyStoreManager *ksm) +{ + QPair out; + for (int n = 0; n < list.count(); ++n) { + QCA::KeyStore ks(list[n], ksm); + out.first.append(idHash(ks.id())); + out.second.append(ks.name()); + } + return out; +} + +static QPair getKeyStoreEntryStrings(const QList &list) +{ + QPair out; + for (int n = 0; n < list.count(); ++n) { + out.first.append(idHash(list[n].id())); + out.second.append(list[n].name()); + } + return out; +} + +static QList getPartialMatches(const QStringList &list, const QString &str) +{ + QList out; + for (int n = 0; n < list.count(); ++n) { + if (list[n].contains(str, Qt::CaseInsensitive)) + out += n; + } + return out; +} + +static int findByString(const QPair &in, const QString &str) +{ + // exact id match + int n = in.first.indexOf(str); + if (n != -1) + return n; + + // partial id match + QList ret = getPartialMatches(in.first, str); + if (!ret.isEmpty()) + return ret.first(); + + // partial name match + ret = getPartialMatches(in.second, str); + if (!ret.isEmpty()) + return ret.first(); + + return -1; +} + +static QString getKeyStore(const QString &name) +{ + QCA::KeyStoreManager ksm; + QStringList storeList = ksm.keyStores(); + int n = findByString(getKeyStoreStrings(storeList, &ksm), name); + if (n != -1) + return storeList[n]; + return QString(); +} + +static QCA::KeyStoreEntry getKeyStoreEntry(QCA::KeyStore *store, const QString &name) +{ + QList list = store->entryList(); + int n = findByString(getKeyStoreEntryStrings(list), name); + if (n != -1) + return list[n]; + return QCA::KeyStoreEntry(); +} + +// here are a bunch of get_Foo functions for the various types + +// E - generic entry +// K - private key +// C - cert +// X - keybundle +// P - pgp public key +// S - pgp secret key + +// in all cases but K, the store:obj notation can be used. if there +// is no colon present, then we treat the input as a filename. we +// try the file as an exported passive entry id, and if the type +// is C or X, we'll fall back to regular files if necessary. + +static QCA::KeyStoreEntry get_E(const QString &name, bool nopassiveerror = false) +{ + QCA::KeyStoreEntry entry; + + QCA::KeyStoreManager::start(); + + int n = name.indexOf(QLatin1Char(':')); + if (n != -1) { + ksm_start_and_wait(); + + // store:obj lookup + QString storeName = name.mid(0, n); + QString objectName = name.mid(n + 1); + + QCA::KeyStoreManager ksm; + QCA::KeyStore store(getKeyStore(storeName), &ksm); + if (!store.isValid()) { + fprintf(stderr, "Error: no such store [%s].\n", qPrintable(storeName)); + return entry; + } + + entry = getKeyStoreEntry(&store, objectName); + if (entry.isNull()) { + fprintf(stderr, "Error: no such object [%s].\n", qPrintable(objectName)); + return entry; + } + } else { + // exported id + QString serialized = read_ksentry_file(name); + entry = QCA::KeyStoreEntry(serialized); + if (entry.isNull()) { + if (!nopassiveerror) + fprintf(stderr, "Error: invalid/unknown entry [%s].\n", qPrintable(name)); + return entry; + } + } + + return entry; +} + +static QCA::PrivateKey get_K(const QString &name) +{ + QCA::PrivateKey key; + + int n = name.indexOf(QLatin1Char(':')); + if (n != -1) { + fprintf(stderr, "Error: cannot use store:obj notation for raw private keys.\n"); + return key; + } + + if (is_pem_file(name)) + key = QCA::PrivateKey::fromPEMFile(name); + else + key = QCA::PrivateKey::fromDER(read_der_file(name)); + if (key.isNull()) { + fprintf(stderr, "Error: unable to read/process private key file.\n"); + return key; + } + + return key; +} + +static QCA::Certificate get_C(const QString &name) +{ + QCA::KeyStoreEntry entry = get_E(name, true); + if (!entry.isNull()) { + if (entry.type() != QCA::KeyStoreEntry::TypeCertificate) { + fprintf(stderr, "Error: entry is not a certificate.\n"); + return QCA::Certificate(); + } + return entry.certificate(); + } + + if (!QCA::isSupported("cert")) { + fprintf(stderr, "Error: need 'cert' feature.\n"); + return QCA::Certificate(); + } + + // try file + QCA::Certificate cert; + if (is_pem_file(name)) + cert = QCA::Certificate::fromPEMFile(name); + else + cert = QCA::Certificate::fromDER(read_der_file(name)); + if (cert.isNull()) { + fprintf(stderr, "Error: unable to read/process certificate file.\n"); + return cert; + } + + return cert; +} + +static QCA::KeyBundle get_X(const QString &name) +{ + QCA::KeyStoreEntry entry = get_E(name, true); + if (!entry.isNull()) { + if (entry.type() != QCA::KeyStoreEntry::TypeKeyBundle) { + fprintf(stderr, "Error: entry is not a keybundle.\n"); + return QCA::KeyBundle(); + } + return entry.keyBundle(); + } + + if (!QCA::isSupported("pkcs12")) { + fprintf(stderr, "Error: need 'pkcs12' feature.\n"); + return QCA::KeyBundle(); + } + + // try file + QCA::KeyBundle key = QCA::KeyBundle::fromFile(name); + if (key.isNull()) { + fprintf(stderr, "Error: unable to read/process keybundle file.\n"); + return key; + } + + return key; +} + +static QCA::PGPKey get_P(const QString &name) +{ + QCA::KeyStoreEntry entry = get_E(name, true); + if (!entry.isNull()) { + if (entry.type() != QCA::KeyStoreEntry::TypePGPPublicKey && + entry.type() != QCA::KeyStoreEntry::TypePGPSecretKey) { + fprintf(stderr, "Error: entry is not a pgp public key.\n"); + return QCA::PGPKey(); + } + return entry.pgpPublicKey(); + } + + // try file + QCA::PGPKey key = QCA::PGPKey::fromFile(name); + if (key.isNull()) { + fprintf(stderr, "Error: unable to read/process pgp key file.\n"); + return key; + } + + return key; +} + +static QPair get_S(const QString &name, bool noerror = false) +{ + QPair key; + QCA::KeyStoreEntry entry = get_E(name, true); + if (!entry.isNull()) { + if (entry.type() != QCA::KeyStoreEntry::TypePGPSecretKey) { + if (!noerror) + fprintf(stderr, "Error: entry is not a pgp secret key.\n"); + return key; + } + + key.first = entry.pgpSecretKey(); + key.second = entry.pgpPublicKey(); + return key; + } + return key; +} + +static void usage() +{ + printf("%s: simple qca utility\n", APPNAME); + printf("usage: %s (options) [command]\n", EXENAME); + printf(" options: --pass=x, --newpass=x, --nonroots=x, --roots=x, --nosys,\n"); + printf(" --noprompt, --ordered, --debug, --log-file=x, --log-level=n,\n"); + printf(" --nobundle\n"); + printf("\n"); + printf(" help|--help|-h This help text\n"); + printf(" version|--version|-v Print version information\n"); + printf(" plugins List available plugins\n"); + printf(" config [command]\n"); + printf(" save [provider] Save default provider config\n"); + printf(" edit [provider] Edit provider config\n"); + printf(" key [command]\n"); + printf(" make rsa|dsa [bits] Create a key pair\n"); + printf(" changepass [K] Add/change/remove passphrase of a key\n"); + printf(" cert [command]\n"); + printf(" makereq [K] Create certificate request (CSR)\n"); + printf(" makeself [K] Create self-signed certificate\n"); + printf(" makereqadv [K] Advanced version of 'makereq'\n"); + printf(" makeselfadv [K] Advanced version of 'makeself'\n"); + printf(" validate [C] Validate certificate\n"); + printf(" keybundle [command]\n"); + printf(" make [K] [C] Create a keybundle\n"); + printf(" extract [X] Extract certificate(s) and key\n"); + printf(" changepass [X] Change passphrase of a keybundle\n"); + printf(" keystore [command]\n"); + printf(" list-stores List all available keystores\n"); + printf(" list [storeName] List content of a keystore\n"); + printf(" monitor Monitor for keystore availability\n"); + printf(" export [E] Export a keystore entry's content\n"); + printf(" exportref [E] Export a keystore entry reference\n"); + printf(" addkb [storeName] [cert.p12] Add a keybundle into a keystore\n"); + printf(" addpgp [storeName] [key.asc] Add a PGP key into a keystore\n"); + printf(" remove [E] Remove an object from a keystore\n"); + printf(" show [command]\n"); + printf(" cert [C] Examine a certificate\n"); + printf(" req [req.pem] Examine a certificate request (CSR)\n"); + printf(" crl [crl.pem] Examine a certificate revocation list\n"); + printf(" kb [X] Examine a keybundle\n"); + printf(" pgp [P|S] Examine a PGP key\n"); + printf(" message [command]\n"); + printf(" sign pgp|pgpdetach|smime [X|S] Sign a message\n"); + printf(" encrypt pgp|smime [C|P] Encrypt a message\n"); + printf(" signencrypt [S] [P] PGP sign & encrypt a message\n"); + printf(" verify pgp|smime Verify a message\n"); + printf(" decrypt pgp|smime ((X) ...) Decrypt a message (S/MIME needs X)\n"); + printf(" exportcerts Export certs from S/MIME message\n"); + printf("\n"); + printf("Object types: K = private key, C = certificate, X = key bundle,\n"); + printf(" P = PGP public key, S = PGP secret key, E = generic entry\n"); + printf("\n"); + printf("An object must be either a filename or a keystore reference (\"store:obj\").\n"); + printf("\n"); + printf("Log level is from 0 (quiet) to 8 (debug)\n"); + printf("\n"); +} + +int main(int argc, char **argv) +{ + QCA::Initializer qcaInit; + QCoreApplication app(argc, argv); + QFile logFile; + QTextStream logStream(stderr); + StreamLogger streamLogger(logStream); + + QStringList args; + for (int n = 1; n < argc; ++n) + args.append(QString::fromLocal8Bit(argv[n])); + + if (args.count() < 1) { + usage(); + return 1; + } + + bool have_pass = false; + bool have_newpass = false; + QCA::SecureArray pass, newpass; + bool allowprompt = true; + bool ordered = false; + bool debug = false; + bool nosys = false; + bool nobundle = false; + QString rootsFile, nonRootsFile; + + for (int n = 0; n < args.count(); ++n) { + QString s = args[n]; + if (!s.startsWith(QLatin1String("--"))) + continue; + QString var; + QString val; + int x = s.indexOf(QLatin1Char('=')); + if (x != -1) { + var = s.mid(2, x - 2); + val = s.mid(x + 1); + } else { + var = s.mid(2); + } + + bool known = true; + + if (var == QLatin1String("pass")) { + have_pass = true; + pass = val.toUtf8(); + } else if (var == QLatin1String("newpass")) { + have_newpass = true; + newpass = val.toUtf8(); + } else if (var == QLatin1String("log-file")) { + logFile.setFileName(val); + logFile.open(QIODevice::Append | QIODevice::Text | QIODevice::Unbuffered); + logStream.setDevice(&logFile); + } else if (var == QLatin1String("log-level")) { + QCA::logger()->setLevel((QCA::Logger::Severity)val.toInt()); + } else if (var == QLatin1String("noprompt")) + allowprompt = false; + else if (var == QLatin1String("ordered")) + ordered = true; + else if (var == QLatin1String("debug")) + debug = true; + else if (var == QLatin1String("roots")) + rootsFile = val; + else if (var == QLatin1String("nonroots")) + nonRootsFile = val; + else if (var == QLatin1String("nosys")) + nosys = true; + else if (var == QLatin1String("nobundle")) + nobundle = true; + else + known = false; + + if (known) { + args.removeAt(n); + --n; // adjust position + } + } + + // help + if (args.isEmpty() || args[0] == QLatin1String("help") || args[0] == QLatin1String("--help") || + args[0] == QLatin1String("-h")) { + usage(); + return 0; + } + + // version + if (args[0] == QLatin1String("version") || args[0] == QLatin1String("--version") || + args[0] == QLatin1String("-v")) { + int ver = qcaVersion(); + int maj = (ver >> 16) & 0xff; + int min = (ver >> 8) & 0xff; + int bug = ver & 0xff; + printf("%s version %s by Justin Karneges\n", APPNAME, VERSION); + printf("Using QCA version %d.%d.%d\n", maj, min, bug); + return 0; + } + + // show plugins + if (args[0] == QLatin1String("plugins")) { + QStringList paths = QCA::pluginPaths(); + if (!paths.isEmpty()) { + for (int n = 0; n < paths.count(); ++n) { + printf(" %s\n", qPrintable(QDir::toNativeSeparators(paths[n]))); + } + } else + printf(" (none)\n"); + + QCA::ProviderList list = QCA::providers(); + + if (debug) + output_plugin_diagnostic_text(); + + printf("Available Providers:\n"); + if (!list.isEmpty()) { + for (int n = 0; n < list.count(); ++n) { + printf(" %s\n", qPrintable(list[n]->name())); + QString credit = list[n]->credit(); + if (!credit.isEmpty()) { + QStringList lines = wrapstring(credit, 74); + foreach (const QString &s, lines) + printf(" %s\n", qPrintable(s)); + } + if (debug) { + QStringList capabilities = list[n]->features(); + foreach (const QString &capability, capabilities) { + printf(" *%s", qPrintable(capability)); + if (!QCA::isSupported(qPrintable(capability), list[n]->name())) { + printf("(NOT supported) - bug"); + } + printf("\n"); + } + } + } + } else + printf(" (none)\n"); + + QCA::unloadAllPlugins(); + + if (debug) + output_plugin_diagnostic_text(); + + return 0; + } + + // config stuff + if (args[0] == QLatin1String("config")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("save")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QString name = args[2]; + QCA::Provider *p = QCA::findProvider(name); + if (!p) { + fprintf(stderr, "Error: no such provider '%s'.\n", qPrintable(name)); + return 1; + } + + QVariantMap map1 = p->defaultConfig(); + if (map1.isEmpty()) { + fprintf(stderr, "Error: provider does not support configuration.\n"); + return 1; + } + + // set and save + QCA::setProviderConfig(name, map1); + QCA::saveProviderConfig(name); + printf("Done.\n"); + return 0; + } else if (args[1] == QLatin1String("edit")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QString name = args[2]; + if (!QCA::findProvider(name)) { + fprintf(stderr, "Error: no such provider '%s'.\n", qPrintable(name)); + return 1; + } + + QVariantMap map1 = QCA::getProviderConfig(name); + if (map1.isEmpty()) { + fprintf(stderr, "Error: provider does not support configuration.\n"); + return 1; + } + + printf("Editing configuration for %s ...\n", qPrintable(name)); + printf("Note: to clear a string entry, type whitespace and press enter.\n"); + + map1 = provider_config_edit(map1); + if (map1.isEmpty()) + return 1; + + // set and save + QCA::setProviderConfig(name, map1); + QCA::saveProviderConfig(name); + printf("Done.\n"); + return 0; + } else { + usage(); + return 1; + } + } + + // enable console passphrase prompt + PassphrasePromptThread passphrasePrompt; + if (!allowprompt) + passphrasePrompt.pp->allowPrompt = false; + if (have_pass) + passphrasePrompt.pp->setExplicitPassword(pass); + + if (args[0] == QLatin1String("key")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("make")) { + if (args.count() < 4) { + usage(); + return 1; + } + + bool genrsa; + int bits; + + if (args[2] == QLatin1String("rsa")) { + if (!QCA::isSupported("rsa")) { + fprintf(stderr, "Error: need 'rsa' feature.\n"); + return 1; + } + + genrsa = true; + bits = args[3].toInt(); + if (bits < 512) { + fprintf(stderr, "Error: RSA bits must be at least 512.\n"); + return 1; + } + } else if (args[2] == QLatin1String("dsa")) { + if (!QCA::isSupported("dsa")) { + fprintf(stderr, "Error: need 'dsa' feature.\n"); + return 1; + } + + if (!QCA::isSupported("dlgroup")) { + fprintf(stderr, "Error: need 'dlgroup' feature.\n"); + return 1; + } + + genrsa = false; + bits = args[3].toInt(); + if (bits != 512 && bits != 768 && bits != 1024) { + fprintf(stderr, "Error: DSA bits must be 512, 768, or 1024.\n"); + return 1; + } + } else { + usage(); + return 1; + } + + if (!allowprompt && !have_newpass) { + fprintf(stderr, "Error: no passphrase specified (use '--newpass=' for none).\n"); + return 1; + } + + QCA::PrivateKey priv; + QString pubFileName, privFileName; + + if (genrsa) { + // note: third arg is bogus, doesn't apply to RSA + priv = AnimatedKeyGen::makeKey(QCA::PKey::RSA, bits, QCA::DSA_512); + pubFileName = QStringLiteral("rsapub.pem"); + privFileName = QStringLiteral("rsapriv.pem"); + } else // dsa + { + QCA::DLGroupSet set; + if (bits == 512) + set = QCA::DSA_512; + else if (bits == 768) + set = QCA::DSA_768; + else // 1024 + set = QCA::DSA_1024; + + // note: second arg is bogus, doesn't apply to DSA + priv = AnimatedKeyGen::makeKey(QCA::PKey::DSA, 0, set); + pubFileName = QStringLiteral("dsapub.pem"); + privFileName = QStringLiteral("dsapriv.pem"); + } + + if (priv.isNull()) { + fprintf(stderr, "Error: unable to generate key.\n"); + return 1; + } + + QCA::PublicKey pub = priv.toPublicKey(); + + // prompt for new passphrase if necessary + if (!have_newpass) { + while (!promptForNewPassphrase(&newpass)) { } + have_newpass = true; + } + + if (pub.toPEMFile(pubFileName)) + printf("Public key saved to %s\n", qPrintable(pubFileName)); + else { + fprintf(stderr, "Error: can't encode/write %s\n", qPrintable(pubFileName)); + return 1; + } + + bool ok; + if (!newpass.isEmpty()) + ok = priv.toPEMFile(privFileName, newpass); + else + ok = priv.toPEMFile(privFileName); + if (ok) + printf("Private key saved to %s\n", qPrintable(privFileName)); + else { + fprintf(stderr, "Error: can't encode/write %s\n", qPrintable(privFileName)); + return 1; + } + } else if (args[1] == QLatin1String("changepass")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::PrivateKey priv = get_K(args[2]); + if (priv.isNull()) + return 1; + + if (!allowprompt && !have_newpass) { + fprintf(stderr, "Error: no passphrase specified (use '--newpass=' for none).\n"); + return 1; + } + + // prompt for new passphrase if necessary + if (!have_newpass) { + while (!promptForNewPassphrase(&newpass)) { } + have_newpass = true; + } + + QString out; + if (!newpass.isEmpty()) + out = priv.toPEM(newpass); + else + out = priv.toPEM(); + if (!out.isEmpty()) + printf("%s", qPrintable(out)); + else { + fprintf(stderr, "Error: can't encode key.\n"); + return 1; + } + } else { + usage(); + return 1; + } + } else if (args[0] == QLatin1String("cert")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("makereq") || args[1] == QLatin1String("makereqadv")) { + if (args.count() < 3) { + usage(); + return 1; + } + + if (!QCA::isSupported("csr")) { + fprintf(stderr, "Error: need 'csr' feature.\n"); + return 1; + } + + QCA::PrivateKey priv = get_K(args[2]); + if (priv.isNull()) + return 1; + + printf("\n"); + + bool advanced = (args[1] == QLatin1String("makereqadv")) ? true : false; + + QCA::CertificateOptions opts = promptForCertAttributes(advanced, true); + QCA::CertificateRequest req(opts, priv); + + QString reqname = QStringLiteral("certreq.pem"); + if (req.toPEMFile(reqname)) + printf("Certificate request saved to %s\n", qPrintable(reqname)); + else { + fprintf(stderr, "Error: can't encode/write %s\n", qPrintable(reqname)); + return 1; + } + } else if (args[1] == QLatin1String("makeself") || args[1] == QLatin1String("makeselfadv")) { + if (args.count() < 3) { + usage(); + return 1; + } + + if (!QCA::isSupported("cert")) { + fprintf(stderr, "Error: need 'cert' feature.\n"); + return 1; + } + + QCA::PrivateKey priv = get_K(args[2]); + if (priv.isNull()) + return 1; + + printf("\n"); + + bool advanced = (args[1] == QLatin1String("makeselfadv")) ? true : false; + + QCA::CertificateOptions opts = promptForCertAttributes(advanced, false); + QCA::Certificate cert(opts, priv); + + QString certname = QStringLiteral("cert.pem"); + if (cert.toPEMFile(certname)) + printf("Certificate saved to %s\n", qPrintable(certname)); + else { + fprintf(stderr, "Error: can't encode/write %s\n", qPrintable(certname)); + return 1; + } + } else if (args[1] == QLatin1String("validate")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::Certificate target = get_C(args[2]); + if (target.isNull()) + return 1; + + // get roots + QCA::CertificateCollection roots; + if (!nosys) + roots += QCA::systemStore(); + if (!rootsFile.isEmpty()) + roots += QCA::CertificateCollection::fromFlatTextFile(rootsFile); + + // get nonroots + QCA::CertificateCollection nonroots; + if (!nonRootsFile.isEmpty()) + nonroots = QCA::CertificateCollection::fromFlatTextFile(nonRootsFile); + + QCA::Validity v = target.validate(roots, nonroots); + if (v == QCA::ValidityGood) + printf("Certificate is valid\n"); + else { + printf("Certificate is NOT valid: %s\n", qPrintable(validityToString(v))); + return 1; + } + } else { + usage(); + return 1; + } + } else if (args[0] == QLatin1String("keybundle")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("make")) { + if (args.count() < 4) { + usage(); + return 1; + } + + if (!QCA::isSupported("pkcs12")) { + fprintf(stderr, "Error: need 'pkcs12' feature.\n"); + return 1; + } + + QCA::PrivateKey priv = get_K(args[2]); + if (priv.isNull()) + return 1; + + QCA::Certificate cert = get_C(args[3]); + if (cert.isNull()) + return 1; + + // get roots + QCA::CertificateCollection roots; + if (!nosys) + roots += QCA::systemStore(); + if (!rootsFile.isEmpty()) + roots += QCA::CertificateCollection::fromFlatTextFile(rootsFile); + + // get nonroots + QCA::CertificateCollection nonroots; + if (!nonRootsFile.isEmpty()) + nonroots = QCA::CertificateCollection::fromFlatTextFile(nonRootsFile); + + QList issuer_pool = roots.certificates() + nonroots.certificates(); + + QCA::CertificateChain chain; + chain += cert; + chain = chain.complete(issuer_pool); + + QCA::KeyBundle key; + key.setName(chain.primary().commonName()); + key.setCertificateChainAndKey(chain, priv); + + if (!allowprompt && !have_newpass) { + fprintf(stderr, "Error: no passphrase specified (use '--newpass=' for none).\n"); + return 1; + } + + // prompt for new passphrase if necessary + if (!have_newpass) { + while (!promptForNewPassphrase(&newpass)) { } + have_newpass = true; + } + + if (newpass.isEmpty()) { + fprintf(stderr, "Error: keybundles cannot have empty passphrases.\n"); + return 1; + } + + QString newFileName = QStringLiteral("cert.p12"); + + if (key.toFile(newFileName, newpass)) + printf("Keybundle saved to %s\n", qPrintable(newFileName)); + else { + fprintf(stderr, "Error: can't encode keybundle.\n"); + return 1; + } + } else if (args[1] == QLatin1String("extract")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyBundle key = get_X(args[2]); + if (key.isNull()) + return 1; + + QCA::PrivateKey priv = key.privateKey(); + bool export_priv = priv.canExport(); + + if (export_priv) { + fprintf(stderr, "You will need to create a passphrase for the extracted private key.\n"); + + if (!allowprompt && !have_newpass) { + fprintf(stderr, "Error: no passphrase specified (use '--newpass=' for none).\n"); + return 1; + } + + // prompt for new passphrase if necessary + if (!have_newpass) { + while (!promptForNewPassphrase(&newpass)) { } + have_newpass = true; + } + } + + printf("Certs: (first is primary)\n"); + QCA::CertificateChain chain = key.certificateChain(); + for (int n = 0; n < chain.count(); ++n) + printf("%s", qPrintable(chain[n].toPEM())); + printf("Private Key:\n"); + if (export_priv) { + QString out; + if (!newpass.isEmpty()) + out = priv.toPEM(newpass); + else + out = priv.toPEM(); + printf("%s", qPrintable(out)); + } else { + printf("(Key is not exportable)\n"); + } + } else if (args[1] == QLatin1String("changepass")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyBundle key = get_X(args[2]); + if (key.isNull()) + return 1; + + if (!key.privateKey().canExport()) { + fprintf(stderr, "Error: private key not exportable.\n"); + return 1; + } + + if (!allowprompt && !have_newpass) { + fprintf(stderr, "Error: no passphrase specified (use '--newpass=' for none).\n"); + return 1; + } + + // prompt for new passphrase if necessary + if (!have_newpass) { + while (!promptForNewPassphrase(&newpass)) { } + have_newpass = true; + } + + if (newpass.isEmpty()) { + fprintf(stderr, "Error: keybundles cannot have empty passphrases.\n"); + return 1; + } + + QFileInfo fi(args[2]); + QString newFileName = fi.baseName() + QStringLiteral("_new.p12"); + + if (key.toFile(newFileName, newpass)) + printf("Keybundle saved to %s\n", qPrintable(newFileName)); + else { + fprintf(stderr, "Error: can't encode keybundle.\n"); + return 1; + } + } else { + usage(); + return 1; + } + } else if (args[0] == QLatin1String("keystore")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("list-stores")) { + ksm_start_and_wait(); + + QCA::KeyStoreManager ksm; + QStringList storeList = ksm.keyStores(); + + for (int n = 0; n < storeList.count(); ++n) { + QCA::KeyStore ks(storeList[n], &ksm); + QString type = kstype_to_string(ks.type()); + printf("%s %s [%s]\n", qPrintable(type), qPrintable(idHash(ks.id())), qPrintable(ks.name())); + } + + if (debug) + output_keystore_diagnostic_text(); + } else if (args[1] == QLatin1String("list")) { + if (args.count() < 3) { + usage(); + return 1; + } + + ksm_start_and_wait(); + + QCA::KeyStoreManager ksm; + QCA::KeyStore store(getKeyStore(args[2]), &ksm); + if (!store.isValid()) { + if (debug) + output_keystore_diagnostic_text(); + + fprintf(stderr, "Error: no such store\n"); + return 1; + } + + QList list = store.entryList(); + for (int n = 0; n < list.count(); ++n) { + QCA::KeyStoreEntry i = list[n]; + QString type = ksentrytype_to_string(i.type()); + printf("%s %s [%s]\n", qPrintable(type), qPrintable(idHash(i.id())), qPrintable(i.name())); + } + + if (debug) + output_keystore_diagnostic_text(); + } else if (args[1] == QLatin1String("monitor")) { + KeyStoreMonitor::monitor(); + + if (debug) + output_keystore_diagnostic_text(); + } else if (args[1] == QLatin1String("export")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyStoreEntry entry = get_E(args[2]); + if (entry.isNull()) + return 1; + + if (entry.type() == QCA::KeyStoreEntry::TypeCertificate) + printf("%s", qPrintable(entry.certificate().toPEM())); + else if (entry.type() == QCA::KeyStoreEntry::TypeCRL) + printf("%s", qPrintable(entry.crl().toPEM())); + else if (entry.type() == QCA::KeyStoreEntry::TypePGPPublicKey || + entry.type() == QCA::KeyStoreEntry::TypePGPSecretKey) + printf("%s", qPrintable(entry.pgpPublicKey().toString())); + else if (entry.type() == QCA::KeyStoreEntry::TypeKeyBundle) { + fprintf(stderr, "Error: use 'keybundle extract' command instead.\n"); + return 1; + } else { + fprintf(stderr, "Error: cannot export type '%d'.\n", entry.type()); + return 1; + } + } else if (args[1] == QLatin1String("exportref")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyStoreEntry entry = get_E(args[2]); + if (entry.isNull()) + return 1; + printf("%s", make_ksentry_string(entry.toString()).toUtf8().data()); + } else if (args[1] == QLatin1String("addkb")) { + if (args.count() < 4) { + usage(); + return 1; + } + + ksm_start_and_wait(); + + QCA::KeyStoreManager ksm; + QCA::KeyStore store(getKeyStore(args[2]), &ksm); + if (!store.isValid()) { + fprintf(stderr, "Error: no such store\n"); + return 1; + } + + QCA::KeyBundle key = get_X(args[3]); + if (key.isNull()) + return 1; + + if (!store.writeEntry(key).isEmpty()) + printf("Entry written.\n"); + else { + fprintf(stderr, "Error: unable to write entry.\n"); + return 1; + } + } else if (args[1] == QLatin1String("addpgp")) { + if (args.count() < 4) { + usage(); + return 1; + } + + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + ksm_start_and_wait(); + + QCA::KeyStoreManager ksm; + QCA::KeyStore store(getKeyStore(args[2]), &ksm); + if (!store.isValid()) { + fprintf(stderr, "Error: no such store\n"); + return 1; + } + + QCA::PGPKey pub = QCA::PGPKey::fromFile(args[3]); + if (pub.isNull()) + return 1; + + if (!store.writeEntry(pub).isEmpty()) + printf("Entry written.\n"); + else { + fprintf(stderr, "Error: unable to write entry.\n"); + return 1; + } + } else if (args[1] == QLatin1String("remove")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyStoreEntry entry = get_E(args[2]); + if (entry.isNull()) + return 1; + + QCA::KeyStoreManager ksm; + QCA::KeyStore store(entry.storeId(), &ksm); + if (!store.isValid()) { + fprintf(stderr, "Error: no such store\n"); + return 1; + } + + if (store.removeEntry(entry.id())) + printf("Entry removed.\n"); + else { + fprintf(stderr, "Error: unable to remove entry.\n"); + return 1; + } + } else { + usage(); + return 1; + } + } else if (args[0] == QLatin1String("show")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("cert")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::Certificate cert = get_C(args[2]); + if (cert.isNull()) + return 1; + + print_cert(cert, ordered); + } else if (args[1] == QLatin1String("req")) { + if (args.count() < 3) { + usage(); + return 1; + } + + if (!QCA::isSupported("csr")) { + fprintf(stderr, "Error: need 'csr' feature.\n"); + return 1; + } + + QCA::CertificateRequest req(args[2]); + if (req.isNull()) { + fprintf(stderr, "Error: can't read/process certificate request file.\n"); + return 1; + } + + print_certreq(req, ordered); + } else if (args[1] == QLatin1String("crl")) { + if (args.count() < 3) { + usage(); + return 1; + } + + if (!QCA::isSupported("crl")) { + fprintf(stderr, "Error: need 'crl' feature.\n"); + return 1; + } + + QCA::CRL crl; + if (is_pem_file(args[2])) + crl = QCA::CRL::fromPEMFile(args[2]); + else + crl = QCA::CRL::fromDER(read_der_file(args[2])); + if (crl.isNull()) { + fprintf(stderr, "Error: unable to read/process CRL file.\n"); + return 1; + } + + print_crl(crl, ordered); + } else if (args[1] == QLatin1String("kb")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::KeyBundle key = get_X(args[2]); + if (key.isNull()) + return 1; + + printf("Keybundle contains %d certificates. Displaying primary:\n", int(key.certificateChain().count())); + print_cert(key.certificateChain().primary(), ordered); + } else if (args[1] == QLatin1String("pgp")) { + if (args.count() < 3) { + usage(); + return 1; + } + + // try for secret key, then try public key + QCA::PGPKey key = get_S(args[2], true).first; + if (key.isNull()) { + key = get_P(args[2]); + if (key.isNull()) + return 1; + } + + print_pgp(key); + } else { + usage(); + return 1; + } + } else if (args[0] == QLatin1String("message")) { + if (args.count() < 2) { + usage(); + return 1; + } + + if (args[1] == QLatin1String("sign")) { + if (args.count() < 4) { + usage(); + return 1; + } + + QCA::SecureMessageSystem *sms; + QCA::SecureMessageKey skey; + QCA::SecureMessage::SignMode mode; + bool pgp = false; + + if (args[2] == QLatin1String("pgp")) { + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + QPair key = get_S(args[3]); + if (key.first.isNull()) + return 1; + + sms = new QCA::OpenPGP; + skey.setPGPSecretKey(key.first); + mode = QCA::SecureMessage::Clearsign; + pgp = true; + } else if (args[2] == QLatin1String("pgpdetach")) { + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + QPair key = get_S(args[3]); + if (key.first.isNull()) + return 1; + + sms = new QCA::OpenPGP; + skey.setPGPSecretKey(key.first); + mode = QCA::SecureMessage::Detached; + pgp = true; + } else if (args[2] == QLatin1String("smime")) { + if (!QCA::isSupported("cms")) { + fprintf(stderr, "Error: need 'cms' feature.\n"); + return 1; + } + + QCA::KeyBundle key = get_X(args[3]); + if (key.isNull()) + return 1; + + // get nonroots + QCA::CertificateCollection nonroots; + if (!nonRootsFile.isEmpty()) + nonroots = QCA::CertificateCollection::fromFlatTextFile(nonRootsFile); + + QList issuer_pool = nonroots.certificates(); + + QCA::CertificateChain chain = key.certificateChain(); + chain = chain.complete(issuer_pool); + + sms = new QCA::CMS; + skey.setX509CertificateChain(chain); + skey.setX509PrivateKey(key.privateKey()); + mode = QCA::SecureMessage::Detached; + } else { + usage(); + return 1; + } + + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + // smime envelope + if (!pgp) { + QString text = add_cr(QString::fromUtf8(plain)); + plain = QString::fromLatin1(mime_signpart).arg(text).toUtf8(); + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + msg->setSigner(skey); + // pgp should always be ascii + if (pgp) + msg->setFormat(QCA::SecureMessage::Ascii); + msg->setBundleSignerEnabled(!nobundle); + msg->startSign(mode); + msg->update(plain); + msg->end(); + msg->waitForFinished(-1); + + if (debug) { + output_keystore_diagnostic_text(); + output_message_diagnostic_text(msg); + } + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + + fprintf(stderr, "Error: unable to sign: %s\n", qPrintable(errstr)); + return 1; + } + + QString hashName = msg->hashName(); + + QByteArray output; + if (mode == QCA::SecureMessage::Detached) + output = msg->signature(); + else + output = msg->read(); + + delete msg; + delete sms; + + // smime envelope + if (!pgp) { + QCA::Base64 enc; + enc.setLineBreaksEnabled(true); + enc.setLineBreaksColumn(76); + QString sigtext = add_cr(enc.arrayToString(output)); + QString str = QString::fromLatin1(mime_signed).arg(hashName, QString::fromUtf8(plain), sigtext); + output = str.toUtf8(); + } + + printf("%s", output.data()); + } else if (args[1] == QLatin1String("encrypt")) { + if (args.count() < 4) { + usage(); + return 1; + } + + QCA::SecureMessageSystem *sms; + QCA::SecureMessageKey skey; + bool pgp = false; + + if (args[2] == QLatin1String("pgp")) { + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + QCA::PGPKey key = get_P(args[3]); + if (key.isNull()) + return 1; + + sms = new QCA::OpenPGP; + skey.setPGPPublicKey(key); + pgp = true; + } else if (args[2] == QLatin1String("smime")) { + if (!QCA::isSupported("cms")) { + fprintf(stderr, "Error: need 'cms' feature.\n"); + return 1; + } + + QCA::Certificate cert = get_C(args[3]); + if (cert.isNull()) + return 1; + + sms = new QCA::CMS; + skey.setX509CertificateChain(cert); + } else { + usage(); + return 1; + } + + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + msg->setRecipient(skey); + // pgp should always be ascii + if (pgp) + msg->setFormat(QCA::SecureMessage::Ascii); + msg->startEncrypt(); + msg->update(plain); + msg->end(); + msg->waitForFinished(-1); + + if (debug) { + output_keystore_diagnostic_text(); + output_message_diagnostic_text(msg); + } + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + fprintf(stderr, "Error: unable to encrypt: %s\n", qPrintable(errstr)); + return 1; + } + + QByteArray output = msg->read(); + delete msg; + delete sms; + + // smime envelope + if (!pgp) { + QCA::Base64 enc; + enc.setLineBreaksEnabled(true); + enc.setLineBreaksColumn(76); + QString enctext = add_cr(enc.arrayToString(output)); + QString str = QString::fromLatin1(mime_enveloped).arg(enctext); + output = str.toUtf8(); + } + + printf("%s", output.data()); + } else if (args[1] == QLatin1String("signencrypt")) { + if (args.count() < 4) { + usage(); + return 1; + } + + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + QCA::SecureMessageSystem *sms; + QCA::SecureMessageKey skey; + QCA::SecureMessageKey rkey; + + { + QPair sec = get_S(args[2]); + if (sec.first.isNull()) + return 1; + + QCA::PGPKey pub = get_P(args[3]); + if (pub.isNull()) + return 1; + + sms = new QCA::OpenPGP; + skey.setPGPSecretKey(sec.first); + rkey.setPGPPublicKey(pub); + } + + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + if (!msg->canSignAndEncrypt()) { + delete msg; + delete sms; + fprintf(stderr, "Error: cannot perform integrated sign and encrypt.\n"); + return 1; + } + + msg->setSigner(skey); + msg->setRecipient(rkey); + msg->setFormat(QCA::SecureMessage::Ascii); + msg->startSignAndEncrypt(); + msg->update(plain); + msg->end(); + msg->waitForFinished(-1); + + if (debug) { + output_keystore_diagnostic_text(); + output_message_diagnostic_text(msg); + } + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + fprintf(stderr, "Error: unable to sign and encrypt: %s\n", qPrintable(errstr)); + return 1; + } + + QByteArray output = msg->read(); + delete msg; + delete sms; + + printf("%s", output.data()); + } else if (args[1] == QLatin1String("verify")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::SecureMessageSystem *sms; + bool pgp = false; + + if (args[2] == QLatin1String("pgp")) { + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + sms = new QCA::OpenPGP; + pgp = true; + } else if (args[2] == QLatin1String("smime")) { + if (!QCA::isSupported("cms")) { + fprintf(stderr, "Error: need 'cms' feature.\n"); + return 1; + } + + // get roots + QCA::CertificateCollection roots; + if (!nosys) + roots += QCA::systemStore(); + if (!rootsFile.isEmpty()) + roots += QCA::CertificateCollection::fromFlatTextFile(rootsFile); + + // get intermediates and possible signers, in case + // the message does not have them. + QCA::CertificateCollection nonroots; + if (!nonRootsFile.isEmpty()) + nonroots += QCA::CertificateCollection::fromFlatTextFile(nonRootsFile); + + sms = new QCA::CMS; + ((QCA::CMS *)sms)->setTrustedCertificates(roots); + ((QCA::CMS *)sms)->setUntrustedCertificates(nonroots); + } else { + usage(); + return 1; + } + + QByteArray data, sig; + QString smime_text; + { + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + if (pgp) { + // pgp can be either a detached signature followed + // by data, or an integrated message. + + // detached signature? + if (plain.startsWith("-----BEGIN PGP SIGNATURE-----")) { + QByteArray footer = "-----END PGP SIGNATURE-----\n"; + int n = plain.indexOf(footer); + if (n == -1) { + delete sms; + fprintf(stderr, "Error: pgp signature header, but no footer.\n"); + return 1; + } + + n += footer.length(); + sig = plain.mid(0, n); + data = plain.mid(n); + } else { + data = plain; + } + } else { + // smime envelope + QString in = QString::fromUtf8(plain); + in = add_cr(in); // change the line endings?! + QString str, sigtext; + if (!open_mime_data_sig(in, &str, &sigtext)) { + fprintf(stderr, "Error: can't parse message file.\n"); + return 1; + } + + data = str.toUtf8(); + smime_text = str; + + QCA::Base64 dec; + dec.setLineBreaksEnabled(true); + sig = dec.stringToArray(rem_cr(sigtext)).toByteArray(); + } + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + if (pgp) + msg->setFormat(QCA::SecureMessage::Ascii); + msg->startVerify(sig); + msg->update(data); + msg->end(); + msg->waitForFinished(-1); + + if (debug) { + output_keystore_diagnostic_text(); + output_message_diagnostic_text(msg); + } + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + fprintf(stderr, "Error: verify failed: %s\n", qPrintable(errstr)); + return 1; + } + + QByteArray output; + if (pgp && sig.isEmpty()) + output = msg->read(); + + QList signers = msg->signers(); + delete msg; + delete sms; + + // for pgp clearsign, pgp signed (non-detached), and smime, + // the signed content was inside of the message. we need + // to print that content now + if (pgp) { + printf("%s", output.data()); + } else { + QString str = open_mime_envelope(smime_text); + printf("%s", str.toUtf8().data()); + } + + smDisplaySignatures(signers); + + bool allgood = true; + foreach (const QCA::SecureMessageSignature &signer, signers) { + if (signer.identityResult() != QCA::SecureMessageSignature::Valid) { + allgood = false; + break; + } + } + + if (!allgood) + return 1; + } else if (args[1] == QLatin1String("decrypt")) { + if (args.count() < 3) { + usage(); + return 1; + } + + QCA::SecureMessageSystem *sms; + bool pgp = false; + + if (args[2] == QLatin1String("pgp")) { + if (!QCA::isSupported("openpgp")) { + fprintf(stderr, "Error: need 'openpgp' feature.\n"); + return 1; + } + + ksm_start_and_wait(); + + sms = new QCA::OpenPGP; + pgp = true; + } else if (args[2] == QLatin1String("smime")) { + if (args.count() < 4) { + usage(); + return 1; + } + + if (!QCA::isSupported("cms")) { + fprintf(stderr, "Error: need 'cms' feature.\n"); + return 1; + } + + // user can provide many possible decrypt keys + QList keys; + for (int n = 3; n < args.count(); ++n) { + QCA::KeyBundle key = get_X(args[n]); + if (key.isNull()) + return 1; + keys += key; + } + + sms = new QCA::CMS; + + QList skeys; + foreach (const QCA::KeyBundle &key, keys) { + QCA::SecureMessageKey skey; + skey.setX509CertificateChain(key.certificateChain()); + skey.setX509PrivateKey(key.privateKey()); + skeys += skey; + } + + ((QCA::CMS *)sms)->setPrivateKeys(skeys); + } else { + usage(); + return 1; + } + + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + // smime envelope + if (!pgp) { + QString in = QString::fromUtf8(plain); + QString str = open_mime_envelope(in); + if (str.isEmpty()) { + delete sms; + fprintf(stderr, "Error: can't parse message file.\n"); + return 1; + } + + QCA::Base64 dec; + dec.setLineBreaksEnabled(true); + plain = dec.stringToArray(rem_cr(str)).toByteArray(); + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + if (pgp) + msg->setFormat(QCA::SecureMessage::Ascii); + msg->startDecrypt(); + msg->update(plain); + msg->end(); + msg->waitForFinished(-1); + + if (debug) { + output_keystore_diagnostic_text(); + output_message_diagnostic_text(msg); + } + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + fprintf(stderr, "Error: decrypt failed: %s\n", qPrintable(errstr)); + return 1; + } + + QByteArray output = msg->read(); + + QList signers; + bool wasSigned = false; + if (msg->wasSigned()) { + signers = msg->signers(); + wasSigned = true; + } + delete msg; + delete sms; + + printf("%s", output.data()); + + if (wasSigned) { + fprintf(stderr, "Message was also signed:\n"); + + smDisplaySignatures(signers); + + bool allgood = true; + foreach (const QCA::SecureMessageSignature &signer, signers) { + if (signer.identityResult() != QCA::SecureMessageSignature::Valid) { + allgood = false; + break; + } + } + + if (!allgood) + return 1; + } + } else if (args[1] == QLatin1String("exportcerts")) { + if (!QCA::isSupported("cms")) { + fprintf(stderr, "Error: need 'cms' feature.\n"); + return 1; + } + + QCA::SecureMessageSystem *sms = new QCA::CMS; + + QByteArray data, sig; + QString smime_text; + { + // read input data from stdin all at once + QByteArray plain; + while (!feof(stdin)) { + QByteArray block(1024, 0); + int n = fread(block.data(), 1, 1024, stdin); + if (n < 0) + break; + block.resize(n); + plain += block; + } + + // smime envelope + QString in = QString::fromUtf8(plain); + QString str, sigtext; + if (!open_mime_data_sig(in, &str, &sigtext)) { + delete sms; + fprintf(stderr, "Error: can't parse message file.\n"); + return 1; + } + + data = str.toUtf8(); + smime_text = str; + + QCA::Base64 dec; + dec.setLineBreaksEnabled(true); + sig = dec.stringToArray(rem_cr(sigtext)).toByteArray(); + } + + QCA::SecureMessage *msg = new QCA::SecureMessage(sms); + msg->startVerify(sig); + msg->update(data); + msg->end(); + msg->waitForFinished(-1); + + if (debug) + output_message_diagnostic_text(msg); + + if (!msg->success()) { + QString errstr = smErrorToString(msg->errorCode()); + delete msg; + delete sms; + fprintf(stderr, "Error: export failed: %s\n", qPrintable(errstr)); + return 1; + } + + QList signers = msg->signers(); + delete msg; + delete sms; + + // print out all certs of all signers + foreach (const QCA::SecureMessageSignature &signer, signers) { + QCA::SecureMessageKey key = signer.key(); + if (!key.isNull()) { + foreach (const QCA::Certificate &c, key.x509CertificateChain()) + printf("%s", qPrintable(c.toPEM())); + } + } + } else { + usage(); + return 1; + } + } else { + usage(); + return 1; + } + + return 0; +} + +#include "main.moc" diff --git a/local/recipes/libs/qca/source/unittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/CMakeLists.txt new file mode 100644 index 0000000000..d76825a1de --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/CMakeLists.txt @@ -0,0 +1,41 @@ +ENABLE_TESTING() +find_package(Qt${QT_MAJOR_VERSION} REQUIRED Test) +if(NOT BUILD_WITH_QT6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}") +endif() +# QTEST_MAIN is using QApplication when QT_GUI_LIB is defined +remove_definitions(-DQT_GUI_LIB) + +add_subdirectory(base64unittest) +add_subdirectory(bigintunittest) +add_subdirectory(certunittest) +add_subdirectory(cipherunittest) +add_subdirectory(clientplugin) +add_subdirectory(dsaunittest) +add_subdirectory(filewatchunittest) +add_subdirectory(hashunittest) +add_subdirectory(hexunittest) +add_subdirectory(kdfunittest) +add_subdirectory(keybundle) +add_subdirectory(keygenunittest) +add_subdirectory(keylengthunittest) +add_subdirectory(keystore) +add_subdirectory(logger) +add_subdirectory(macunittest) +add_subdirectory(metatype) +add_subdirectory(pgpunittest) +add_subdirectory(pipeunittest) +add_subdirectory(pkits) +add_subdirectory(rsaunittest) +add_subdirectory(securearrayunittest) +add_subdirectory(staticunittest) +add_subdirectory(symmetrickeyunittest) +add_subdirectory(tls) +add_subdirectory(velox) + +#Tests that require OpenSSL +#Remove once we stop supporting openssl < 1.1.1i +find_package(OpenSSL 1.1.1) +if(OPENSSL_FOUND) + add_subdirectory(cms) +endif() diff --git a/local/recipes/libs/qca/source/unittest/README b/local/recipes/libs/qca/source/unittest/README new file mode 100644 index 0000000000..716284cc8a --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/README @@ -0,0 +1,24 @@ +This directory holds simple unit tests for QCA. + +You can run the whole test suite by doing "make test" in this +directory. You can also run a single set of tests by doing "make test" +in the applicable subdirectory. See "TestPlan" for more detail. + +The unittests were originally designed to be run through cmake, +however they should work just fine without it. Please report any +problems. + +The "testcerts" directory is not a unit test. It is the tools used +to generate certificates used in unit tests, and is a copy of the +CA.pl script and associated configuration file provided with openssl. + +These tests are implemented using the QTestLib test framework provided +with Qt 4.1 and later. If you are having trouble with a test, you can +get more information by running the test applicable directly (e.g. if +you can't make the Base64 test work, you run the ./base64unittest +executable) with the -v1 or -v2 options. You can also specify a single +test to be run. + +Thanks to Trolltech for providing Qt and agreeing to release QTestLib, +especially to Harald Fernengel for all the development work, a great +tutorial at Akademy 2005 and substantial assistance with QTestLib. diff --git a/local/recipes/libs/qca/source/unittest/TestPlan b/local/recipes/libs/qca/source/unittest/TestPlan new file mode 100644 index 0000000000..5bacdd9ddd --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/TestPlan @@ -0,0 +1,85 @@ +QCA Test Plan + +There are two types of tests that you should consider running on your +QCA build - manual functionality tests, and automated "self checking" +tests. + +You should start with a couple of quick manual tests, then do the +automated tests, and then conduct more sophisticated manual tests. + + + +Initial Manual Testing + +The fist step is to use the "qcatool" command line tool to verify +basic operation. + + +Test 1 - Verify startup + +Execute the "qcatool" application with no arguments + +Expected result: Information on usage of the application is +displayed. + + + +Test 2 - Verify application version + +Execute the "qcatool" application with the "--version" option + +Expected result: Information on the version of QCA and the version of +qcatool is displayed. + + + +Test 3 - Verify plugin can be loaded + +Execute the "qcatool" application with the "plugins" option + +Expected result: The plugin paths are displayed (which correspond with +the appropriate plugin directory for Qt, and the current +directory). + +The list of providers is displayed, or "(none)" is displayed if no +providers are installed. Note: "(none)" should not be displayed if any +providers are installed. + + + +Test 4 - Run "self checking" tests + +Note: this test does not exercise any providers unless the providers +are installed. + +Note: automated unit testing with qmake is experimental. + +Run "make test" in the build directory. + +Expected result: All (23) tests pass. + + + +Additional "self checking" tests + +Depending on test requirements, consider running additional unit tests +that are not in the "make test" set. For example, to run the unit +tests for TLS Server Name Indication, run the "veloxunittest" test +application from the "unittest/velox" directory. + +Note that tests outside the "make test" set are potentially fragile, +and should not be expected to pass in all circumstances. Nor should +the tests be expected to fail if there is a problem. You should ensure +that you understand what the test is supposed to be checking before +running the test and attempting to interpret the results. + + + +Additional manual tests + +Depending on test requirements, consider using "qcatool" to check for +additional functionality. + +Depending on test requirements, consider using code in the "examples" +directory to verify functionality. + diff --git a/local/recipes/libs/qca/source/unittest/base64unittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/base64unittest/CMakeLists.txt new file mode 100644 index 0000000000..d14cf37e8c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/base64unittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(base64unittest_bin_SRCS base64unittest.cpp) + +add_executable(base64unittest ${base64unittest_bin_SRCS} ) + +target_link_qca_test_libraries(base64unittest) + +add_qca_test(base64unittest "Base64") diff --git a/local/recipes/libs/qca/source/unittest/base64unittest/base64unittest.cpp b/local/recipes/libs/qca/source/unittest/base64unittest/base64unittest.cpp new file mode 100644 index 0000000000..408edc5370 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/base64unittest/base64unittest.cpp @@ -0,0 +1,130 @@ +/** + * base64unittest.cpp + * + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class Base64UnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void test1_data(); + void test1(); + void test2_data(); + void test2(); + +private: + QCA::Initializer *m_init; +}; + +void Base64UnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void Base64UnitTest::cleanupTestCase() +{ + delete m_init; +} + +void Base64UnitTest::test1_data() +{ + QTest::addColumn("raw"); + QTest::addColumn("encoded"); + + // these are from the Botan test suite. Note that these are hex encoded! + QTest::newRow("31") << QStringLiteral("31") << QStringLiteral("4d513d3d"); + QTest::newRow("235c91") << QStringLiteral("235c91") << QStringLiteral("49317952"); + QTest::newRow("414") << QStringLiteral("4142634452313236") << QStringLiteral("51554a6a524649784d6a593d"); + QTest::newRow("241") << QStringLiteral("241bb300a3989a620659") + << QStringLiteral("4a42757a414b4f596d6d494757513d3d"); + QTest::newRow("313") << QStringLiteral("31323537374343666671333435337836") + << QStringLiteral("4d5449314e7a644451325a6d63544d304e544e344e673d3d"); + QTest::newRow("60e") << QStringLiteral("60e8e5ebb1a5eac95a01ec7f8796b2dce471") + << QStringLiteral("594f6a6c3637476c36736c614165782f68356179334f5278"); + QTest::newRow("3134") << QStringLiteral("31346d354f33313333372c31274d754e7354307050346231333a29") + << QStringLiteral("4d5452744e55387a4d544d7a4e7977784a303131546e4e554d4842514e4749784d7a6f70"); +} + +void Base64UnitTest::test2_data() +{ + QTest::addColumn("raw"); + QTest::addColumn("encoded"); + + // these are from Python 2.3's tests for base64 + QTest::newRow("www.python.org") << QStringLiteral("www.python.org") << QStringLiteral("d3d3LnB5dGhvbi5vcmc="); + QTest::newRow("a") << QStringLiteral("a") << QStringLiteral("YQ=="); + QTest::newRow("ab") << QStringLiteral("ab") << QStringLiteral("YWI="); + QTest::newRow("abc") << QStringLiteral("abc") << QStringLiteral("YWJj"); + QTest::newRow("empty") << QString(QLatin1String("")) << QString(QLatin1String("")); + QTest::newRow("a-Z") << QStringLiteral( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#0^&*();:<>,. []{}") + << QStringLiteral( + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3ODkhQC" + "MwXiYqKCk7Ojw+LC4gW117fQ=="); + + // these are generated by Python 2.3. I removed the trailing newline + QTest::newRow("31") << QStringLiteral("31") << QStringLiteral("MzE="); + QTest::newRow("QCA_2.0") << QStringLiteral("QCA_2.0") << QStringLiteral("UUNBXzIuMA=="); + QTest::newRow("j-0") << QStringLiteral("jh/*-*/*-/4983589230") << QStringLiteral("amgvKi0qLyotLzQ5ODM1ODkyMzA="); +} + +void Base64UnitTest::test1() +{ + QCA::Base64 base64Object; + + QFETCH(QString, raw); + QFETCH(QString, encoded); + + QCOMPARE(QCA::arrayToHex(base64Object.encode(QCA::hexToArray(raw)).toByteArray()), encoded); + QCOMPARE(QCA::arrayToHex(base64Object.decode(QCA::hexToArray(encoded)).toByteArray()), raw); +} + +void Base64UnitTest::test2() +{ + QCA::Base64 base64Object; + + QFETCH(QString, raw); + QFETCH(QString, encoded); + + QCOMPARE(base64Object.encodeString(raw), encoded); + QCOMPARE(base64Object.decodeString(encoded), raw); + + QCOMPARE(QCA::arrayToBase64(raw.toUtf8()), encoded); + QCOMPARE(QLatin1String(QCA::base64ToArray(encoded)), raw); +} + +QTEST_MAIN(Base64UnitTest) + +#include "base64unittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/bigintunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/bigintunittest/CMakeLists.txt new file mode 100644 index 0000000000..1ecc93de8d --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/bigintunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(bigintunittest_bin_SRCS bigintunittest.cpp) + +add_executable(bigintunittest ${bigintunittest_bin_SRCS} ) + +target_link_qca_test_libraries(bigintunittest) + +add_qca_test(bigintunittest "BigInteger") diff --git a/local/recipes/libs/qca/source/unittest/bigintunittest/bigintunittest.cpp b/local/recipes/libs/qca/source/unittest/bigintunittest/bigintunittest.cpp new file mode 100644 index 0000000000..041af21a8b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/bigintunittest/bigintunittest.cpp @@ -0,0 +1,1138 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class BigIntUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void allTests(); + +private: + QCA::Initializer *m_init; +}; + +void BigIntUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void BigIntUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void BigIntUnitTest::allTests() +{ + QCA::BigInteger result; + + // Some string conversion tests + QCOMPARE(QCA::BigInteger("255").toString(), QCA::BigInteger(255).toString()); + QCOMPARE(QCA::BigInteger("-255").toString(), QCA::BigInteger(-255).toString()); + QCOMPARE(QCA::BigInteger("255").toString(), QStringLiteral("255")); + QCOMPARE(QCA::BigInteger("-255").toString(), QStringLiteral("-255")); + QCOMPARE(QCA::BigInteger("255"), QCA::BigInteger(QCA::BigInteger(255).toArray())); + QCOMPARE(QCA::BigInteger("-255"), QCA::BigInteger(QCA::BigInteger(-255).toArray())); + + // Some operator tests + QCOMPARE(QCA::BigInteger("255") == QCA::BigInteger(255), true); + QCOMPARE(QCA::BigInteger("-255") == QCA::BigInteger(-255), true); + QCOMPARE(QCA::BigInteger("256") != QCA::BigInteger(255), true); + QCOMPARE(QCA::BigInteger("-256") != QCA::BigInteger(-255), true); + + // Some comparison tests + QCA::BigInteger a("4000000000000"); + QCA::BigInteger b("-4000000000000"); + QCA::BigInteger c("2000000000000"); + QCOMPARE(a < b, false); + QCOMPARE(a <= b, false); + QCOMPARE(a.compare(b), 1); + QCOMPARE(a > b, true); + QCOMPARE(a >= b, true); + QCOMPARE(a > c, true); + QCOMPARE(c.compare(b), 1); + QCOMPARE(c.compare(a), -1); + + // Check if the stream operator is any good + QString testString; + QTextStream ts(&testString, QIODevice::WriteOnly); + ts << a << b << c << Qt::endl; + QCOMPARE(testString, QStringLiteral("4000000000000-40000000000002000000000000\n")); + + // Botan's addition tests + QCOMPARE(QCA::BigInteger(255) += QCA::BigInteger(1), QCA::BigInteger(256)); + result = QCA::BigInteger(255) += QCA::BigInteger(1); + QCOMPARE(result.toString(), QCA::BigInteger(256).toString()); + + result = QCA::BigInteger("65535") += QCA::BigInteger("1"); + QCOMPARE(result.toString(), QStringLiteral("65536")); + QCOMPARE(result, QCA::BigInteger("65536")); + + result = QCA::BigInteger("4294967295") += QCA::BigInteger(1); + QCOMPARE(result.toString(), QStringLiteral("4294967296")); + QCOMPARE(result, QCA::BigInteger("4294967296")); + + result = QCA::BigInteger("18446744073709551615") += QCA::BigInteger(1); + QCOMPARE(result.toString(), QStringLiteral("18446744073709551616")); + QCOMPARE(result, QCA::BigInteger("18446744073709551616")); + + result = QCA::BigInteger("124536363637272472") += QCA::BigInteger("124536363637272472"); + QCOMPARE(result.toString(), QStringLiteral("249072727274544944")); + QCOMPARE(result, QCA::BigInteger("249072727274544944")); + + result = QCA::BigInteger("9223372036854775807") += QCA::BigInteger("281474976710655"); + QCOMPARE(result.toString(), QStringLiteral("9223653511831486462")); + QCOMPARE(result, QCA::BigInteger("9223653511831486462")); + + result = QCA::BigInteger("9223372036854775807") += QCA::BigInteger("137438953471"); + QCOMPARE(result.toString(), QStringLiteral("9223372174293729278")); + QCOMPARE(result, QCA::BigInteger("9223372174293729278")); + + // Botan's carry tests + result = QCA::BigInteger("340282366920938463463374607431768211455") += + QCA::BigInteger("340282366920938463463374607431768211455"); + QCOMPARE(result.toString(), QStringLiteral("680564733841876926926749214863536422910")); + QCOMPARE(result, QCA::BigInteger("680564733841876926926749214863536422910")); + + result = QCA::BigInteger("340282366920938463463374607431768211455") += + QCA::BigInteger("340282366920938463463374607431768211450"); + QCOMPARE(result.toString(), QStringLiteral("680564733841876926926749214863536422905")); + QCOMPARE(result, QCA::BigInteger("680564733841876926926749214863536422905")); + + result = QCA::BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935") += + QCA::BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935"); + QCOMPARE(result.toString(), + QStringLiteral("231584178474632390847141970017375815706539969331281128078915168015826259279870")); + QCOMPARE(result, QCA::BigInteger("231584178474632390847141970017375815706539969331281128078915168015826259279870")); + + result = QCA::BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935") += + QCA::BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639919"); + QCOMPARE(result.toString(), + QStringLiteral("231584178474632390847141970017375815706539969331281128078915168015826259279854")); + QCOMPARE(result, QCA::BigInteger("231584178474632390847141970017375815706539969331281128078915168015826259279854")); + + result = QCA::BigInteger( + "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858" + "186486050853753882811946569946433649006084095") += QCA::BigInteger("18446744073709551616"); + QCOMPARE(result.toString(), + QStringLiteral("134078079299425970995740249982058461274793658205923933777235614437217640300735469768018742" + "98166903427690031858186486050853753882811946588393177722715635711")); + QCOMPARE(result, + QCA::BigInteger("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874" + "298166903427690031858186486050853753882811946588393177722715635711")); + + result = QCA::BigInteger( + "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858" + "186486050853753882811946569946433649006084095") += QCA::BigInteger("1"); + QCOMPARE(result.toString(), + QStringLiteral("134078079299425970995740249982058461274793658205923933777235614437217640300735469768018742" + "98166903427690031858186486050853753882811946569946433649006084096")); + QCOMPARE(result, + QCA::BigInteger("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874" + "298166903427690031858186486050853753882811946569946433649006084096")); + + result = QCA::BigInteger( + "-3979427001391940661083482696042714676976618976483847341650296529192053560111268857919862747528477749805933030" + "6128763345008528325994574657552726381901") += QCA::BigInteger("-342238655038"); + QCOMPARE(result.toString(), + QStringLiteral("-39794270013919406610834826960427146769766189764838473416502965291920535601112688579198627" + "475284777498059330306128763345008528325994574657894965036939")); + QCOMPARE(result, + QCA::BigInteger("-3979427001391940661083482696042714676976618976483847341650296529192053560111268857919862" + "7475284777498059330306128763345008528325994574657894965036939")); + + result = QCA::BigInteger( + "25110291853498940831251897922987678157346336093292373576945426289097725034326735312448621015537884914") += + QCA::BigInteger("-36551081154398645734533965739979697527373251608055056627686956281114038842935173436543461"); + QCOMPARE( + result.toString(), + QStringLiteral( + "25110291853462389750097499277253144191606356395765000325337371232470038078045621273605685842101341453")); + QCOMPARE( + result, + QCA::BigInteger( + "25110291853462389750097499277253144191606356395765000325337371232470038078045621273605685842101341453")); + + result = QCA::BigInteger("27802650352") += QCA::BigInteger("660736146705288303126411072388564329913778942"); + QCOMPARE(result.toString(), QStringLiteral("660736146705288303126411072388564357716429294")); + QCOMPARE(result, QCA::BigInteger("660736146705288303126411072388564357716429294")); + + result = QCA::BigInteger( + "-1348245899955041864800954463709881466231496038216683608715424566397833766910915722793041224478985289") += + QCA::BigInteger( + "1151714952286618235856515264359526625702022859705853911311473221800833298790436145729926116122727676438617" + "3666571334749062651694592291882972"); + QCOMPARE(result.toString(), + QStringLiteral("115171495228661823585651526435952662570188803511585840712499312635446231064381299612610444" + "77618561339819775832804423833339858653367812897683")); + QCOMPARE(result, + QCA::BigInteger("11517149522866182358565152643595266257018880351158584071249931263544623106438129961261044" + "477618561339819775832804423833339858653367812897683")); + + result = QCA::BigInteger( + "-17540530441681616962868251635133601915039026254996886583618243914226325157426408929602625346567256761818") += + QCA::BigInteger("865200427983527245206901810160356641402419461642082623179544681519016990"); + QCOMPARE(result.toString(), + QStringLiteral("-17540530441681616962868251635132736714611042727751679681808083557584922737964766846979445" + "801885737744828")); + QCOMPARE(result, + QCA::BigInteger("-1754053044168161696286825163513273671461104272775167968180808355758492273796476684697944" + "5801885737744828")); + + result = QCA::BigInteger("128844776074298261556398714096948603458177018275051329218555498374") += QCA::BigInteger( + "44381631382915087636205223513461060322054892810769796122995361187369527639191715091334647906024675972047519364" + "8"); + QCOMPARE(result.toString(), + QStringLiteral("443816313829150876362052235134610603220548928236542737304251873430093990488865754371523497" + "335298088939030692022")); + QCOMPARE(result, + QCA::BigInteger("44381631382915087636205223513461060322054892823654273730425187343009399048886575437152349" + "7335298088939030692022")); + + result = QCA::BigInteger("1709484189262457846620911889502097055085989595277300243221975568275935717696463") += + QCA::BigInteger("-1646592344139809206374540620411514484579951199941360"); + QCOMPARE(result.toString(), + QStringLiteral("1709484189262457846620911887855504710946180388902759622810461083695984517755103")); + QCOMPARE(result, + QCA::BigInteger("1709484189262457846620911887855504710946180388902759622810461083695984517755103")); + + result = QCA::BigInteger( + "32017586542963717616570934157618710254018062780641801520492877117023353895132395250905592913967322327352806288" + "3083030595199153877335714942842") += + QCA::BigInteger( + "-2828241696960736089879965882386687935938570856545481227619497640844399275054327390050478930503975773972"); + QCOMPARE(result.toString(), + QStringLiteral("320175865429637176165709341576187102537352386109457279115048805287846851015385381652510447" + "912053725632683663608028703205148674946831739168870")); + QCOMPARE(result, + QCA::BigInteger("32017586542963717616570934157618710253735238610945727911504880528784685101538538165251044" + "7912053725632683663608028703205148674946831739168870")); + + result = QCA::BigInteger( + "-4035398360542181725908295312107496142105415014744259439963377204111754181625695349185753326709217") += + QCA::BigInteger("85450213703789913646546187382091037800"); + QCOMPARE(result.toString(), + QStringLiteral( + "-4035398360542181725908295312107496142105415014744259439963291753898050391712048802998371235671417")); + QCOMPARE(result, + QCA::BigInteger( + "-4035398360542181725908295312107496142105415014744259439963291753898050391712048802998371235671417")); + + result = QCA::BigInteger( + "-1292166446073479876801522363382357887431657639184151284775525387363973852756087726243671676713861533673009088" + "319851") += + QCA::BigInteger( + "8045388958745181755374994252823750582362455317985903504033438417669555720706432671419456956248951093302427" + "49935754739434394691714971"); + QCOMPARE(result.toString(), + QStringLiteral("804538895874518174245332979208895181434723168416232462971686202582804287295117879777971842" + "868807383086571073221893205761385603395120")); + QCOMPARE(result, + QCA::BigInteger("80453889587451817424533297920889518143472316841623246297168620258280428729511787977797184" + "2868807383086571073221893205761385603395120")); + + result = QCA::BigInteger( + "-4519865887009263094594517568520056973794810149560079685292342518849465226829012150220864325970243240622408355" + "64200177389") += QCA::BigInteger("15762983479"); + QCOMPARE(result.toString(), + QStringLiteral("-45198658870092630945945175685200569737948101495600796852923425188494652268290121502208643" + "2597024324062240835548437193910")); + QCOMPARE(result, + QCA::BigInteger("-4519865887009263094594517568520056973794810149560079685292342518849465226829012150220864" + "32597024324062240835548437193910")); + + result = QCA::BigInteger( + "-3907475412115728816974567022055278374116794025624287474334038831885743634200801846649105209920908153587891040" + "882946582394429615396962188674594744360388466") += + QCA::BigInteger("193893611236537854694879677478106237157079207398283117392998175454362643521031390"); + QCOMPARE(result.toString(), + QStringLiteral("-39074754121157288169745670220552783741167940256242874743340388318857436340069082354125673" + "55226028476109784803725867374996146498003964013220232100839357076")); + QCOMPARE(result, + QCA::BigInteger("-3907475412115728816974567022055278374116794025624287474334038831885743634006908235412567" + "355226028476109784803725867374996146498003964013220232100839357076")); + + result = QCA::BigInteger("-72603710637966201224690926289") += + QCA::BigInteger("-13618442642298533261581255034923612640512507150728017106768861506299813289801666559564532"); + QCOMPARE( + result.toString(), + QStringLiteral("-13618442642298533261581255034923612640512507150728017106768934110010451256002891250490821")); + QCOMPARE( + result, + QCA::BigInteger("-13618442642298533261581255034923612640512507150728017106768934110010451256002891250490821")); + + result = QCA::BigInteger( + "56077960835713056831402948406790747107889446769357509759472207603483968107693997028111823994257399379783658853" + "302692762256851623103019589392739") += + QCA::BigInteger("-427057313888431079237360487703561848638868677065083968842"); + QCOMPARE(result.toString(), + QStringLiteral("560779608357130568314029484067907471078894467693575097594722076034839681076939970281113969" + "36943510948704421492814989200408212754425954505423897")); + QCOMPARE(result, + QCA::BigInteger("56077960835713056831402948406790747107889446769357509759472207603483968107693997028111396" + "936943510948704421492814989200408212754425954505423897")); + + result = QCA::BigInteger("-2209800838508504443494783762534800337712101405156784708782197580824527899758308") += + QCA::BigInteger( + "4284407650303949586450021392583759850781770841835415277411207859644308960659857039623581632798746339397171" + "0495985285591895096794994387176281079"); + QCOMPARE(result.toString(), + QStringLiteral("428440765030394958645002139258375985078177084183541527741120785942332887680900659527410325" + "65452663056259609090828500883112899214169859276522771")); + QCOMPARE(result, + QCA::BigInteger("42844076503039495864500213925837598507817708418354152774112078594233288768090065952741032" + "565452663056259609090828500883112899214169859276522771")); + + result = QCA::BigInteger( + "33887767308809826842417841176152232321272231788338404526859019370507113927387984766381329515371768224976188337" + "692") += QCA::BigInteger("349484339542971517481628970179002500341"); + QCOMPARE(result.toString(), + QStringLiteral("338877673088098268424178411761522323212722317883384045268590193705071139277374691059243010" + "32853397195155190838033")); + QCOMPARE(result, + QCA::BigInteger("33887767308809826842417841176152232321272231788338404526859019370507113927737469105924301" + "032853397195155190838033")); + + result = QCA::BigInteger( + "85748089639858660722587321621536298082690707526412426951630101551228144063151688592419555048867068162") += + QCA::BigInteger("-383634567691961960211191292397062452265352651123492760493087381707279"); + QCOMPARE( + result.toString(), + QStringLiteral( + "85748089639858660722587321621535914448123015564452215760337704488775878710500565099659061961485360883")); + QCOMPARE( + result, + QCA::BigInteger( + "85748089639858660722587321621535914448123015564452215760337704488775878710500565099659061961485360883")); + + result = QCA::BigInteger("23889807888563742283608049816129153552608399262924421832404872043475") += + QCA::BigInteger("995"); + QCOMPARE(result.toString(), QStringLiteral("23889807888563742283608049816129153552608399262924421832404872044470")); + QCOMPARE(result, QCA::BigInteger("23889807888563742283608049816129153552608399262924421832404872044470")); + + result = QCA::BigInteger( + "-6547869258334748646692309625826942226114726807018592624664656062396549960483067839575496977812718292577743295" + "38985") += QCA::BigInteger("-276137507159648540503039013089014674747"); + QCOMPARE(result.toString(), + QStringLiteral("-65478692583347486466923096258269422261147268070185926246646560623965499604858292146470934" + "6321774868270863344213732")); + QCOMPARE(result, + QCA::BigInteger("-6547869258334748646692309625826942226114726807018592624664656062396549960485829214647093" + "46321774868270863344213732")); + + result = QCA::BigInteger("50463316268089933") += QCA::BigInteger( + "-1405915834634318069210003494981352875890054233189278509478942429953101385694731575213124136524392343244191305" + "27702899917161307657443381774866237429"); + QCOMPARE(result.toString(), + QStringLiteral("-14059158346343180692100034949813528758900542331892785094789424299531013856947315752131241" + "3652439234324419130527702899917161307657392918458598147496")); + QCOMPARE(result, + QCA::BigInteger("-1405915834634318069210003494981352875890054233189278509478942429953101385694731575213124" + "13652439234324419130527702899917161307657392918458598147496")); + + result = QCA::BigInteger( + "1339015021665554488163337105187026760232395594198925052890859936\ +418304234254229440059229155546157793544192") += + QCA::BigInteger( + "6294037420283433712414743361937677483761554699961644450461297486224793278823004487175687771163597590566132" + "592591599249970281125781761944353272"); + QCOMPARE(result.toString(), + QStringLiteral("629403742028343371241474336193767748510056972162719893862463459141182003905540008137461282" + "4054457526984436826845828690029510281327919737897464")); + QCOMPARE(result, + QCA::BigInteger("62940374202834337124147433619376774851005697216271989386246345914118200390554000813746128" + "24054457526984436826845828690029510281327919737897464")); + + result = QCA::BigInteger("-241446683") += QCA::BigInteger( + "-282671163032866994488211995758272717472259277760825940523445628\ +442206062910449311538519756165635175664610569214430918184214"); + QCOMPARE(result.toString(), + QStringLiteral("-28267116303286699448821199575827271747225927776082594052344562844220606291044931153851975" + "6165635175664610569214431159630897")); + QCOMPARE(result, + QCA::BigInteger("-2826711630328669944882119957582727174722592777608259405234456284422060629104493115385197" + "56165635175664610569214431159630897")); + + result = QCA::BigInteger( + "23586055033034526379960814219020565159517446117183831284424451195057397075503263789123424483550462390668969955" + "63581") += + QCA::BigInteger("-3830437229145325165273364525551261440648845791949681661260946956860463720730123941973615"); + QCOMPARE(result.toString(), + QStringLiteral("235860550330345263799608141807161928680641944644501860289118367885689391560064471765139549" + "1494582518336773053589966")); + QCOMPARE(result, + QCA::BigInteger("23586055033034526379960814180716192868064194464450186028911836788568939156006447176513954" + "91494582518336773053589966")); + + result = QCA::BigInteger("1860794367587960058388097846258490") += + QCA::BigInteger("-237344494507203983863096991896035366478949095337787603280"); + QCOMPARE(result.toString(), QStringLiteral("-237344494507203983863095131101667778518890707239941344790")); + QCOMPARE(result, QCA::BigInteger("-237344494507203983863095131101667778518890707239941344790")); + + result = QCA::BigInteger("-286399096802321907543674770412181810379003627366516307780436082546") += + QCA::BigInteger("6433131620680089024037442172197761714707480582555136398379812339597187475099646442833150194"); + QCOMPARE( + result.toString(), + QStringLiteral("6433131620680089024037441885798664912385573038880365986198001960593560108583338662397067648")); + QCOMPARE( + result, + QCA::BigInteger("6433131620680089024037441885798664912385573038880365986198001960593560108583338662397067648")); + + result = QCA::BigInteger( + "18118033907710236955953781758362789478332280418185972957475244257214680056902377349016498752054120312533829578" + "5763244283224569259250011493") += + QCA::BigInteger( + "-119912766577350317025030707802803587547945939765717835695952624506754949712992302334818793328075301820498" + "3010837846725666878521137637491"); + QCOMPARE(result.toString(), + QStringLiteral("179981211411328866389287510505599858907843344784202551217792916327079251071893850466816799" + "587260450107133312774925397557557690738112374002")); + QCOMPARE(result, + QCA::BigInteger("17998121141132886638928751050559985890784334478420255121779291632707925107189385046681679" + "9587260450107133312774925397557557690738112374002")); + + result = QCA::BigInteger( + "-6414020139555553381140864289162018465205127581107592617628203214491558550345077676836677565241902214951203461" + "1311149858695307750874152") += QCA::BigInteger("174441039"); + QCOMPARE(result.toString(), + QStringLiteral("-64140201395555533811408642891620184652051275811075926176282032144915585503450776768366775" + "652419022149512034611311149858695307576433113")); + QCOMPARE(result, + QCA::BigInteger("-6414020139555553381140864289162018465205127581107592617628203214491558550345077676836677" + "5652419022149512034611311149858695307576433113")); + + result = QCA::BigInteger( + "12727579443088358572080378780185073375305574454222304955616346165037244198775127175123602392596401935136013522" + "02821462208896049331599624285621") += + QCA::BigInteger( + "7326562354017884140300121264633612334070903165496641915889499701\ +38457507491850467631029977010"); + QCOMPARE(result.toString(), + QStringLiteral("127275794430883585720803787801850733753055744542296315179703640491775443200397607874576732" + "9576189857705190302172959919716387899799230654262631")); + QCOMPARE(result, + QCA::BigInteger("12727579443088358572080378780185073375305574454229631517970364049177544320039760787457673" + "29576189857705190302172959919716387899799230654262631")); + + result = QCA::BigInteger("-296171972628230") += QCA::BigInteger( + "-8295766099121843219000823699362222865173820102569731517716391727126741710202086962877467940292139"); + QCOMPARE(result.toString(), + QStringLiteral( + "-8295766099121843219000823699362222865173820102569731517716391727126741710202086963173639912920369")); + QCOMPARE(result, + QCA::BigInteger( + "-8295766099121843219000823699362222865173820102569731517716391727126741710202086963173639912920369")); + + result = QCA::BigInteger("746985914068199510024843682108839444828414222769191520615967632362127522466922882591") += + QCA::BigInteger("-20487191102299831461877807785745372724903547246374023"); + QCOMPARE(result.toString(), + QStringLiteral("746985914068199510024843682108818957637311922937729642808181886989402618919676508568")); + QCOMPARE(result, + QCA::BigInteger("746985914068199510024843682108818957637311922937729642808181886989402618919676508568")); + + result = QCA::BigInteger("-4") += + QCA::BigInteger("-2344390090753264806043234960981151613122271366762590006930318876906455201397017135"); + QCOMPARE(result.toString(), + QStringLiteral("-2344390090753264806043234960981151613122271366762590006930318876906455201397017139")); + QCOMPARE(result, + QCA::BigInteger("-2344390090753264806043234960981151613122271366762590006930318876906455201397017139")); + + result = QCA::BigInteger("-44876180273995737337769331875058141129678736711749946388832275767882143882764") += + QCA::BigInteger("20982187786"); + QCOMPARE(result.toString(), + QStringLiteral("-44876180273995737337769331875058141129678736711749946388832275767861161694978")); + QCOMPARE(result, QCA::BigInteger("-44876180273995737337769331875058141129678736711749946388832275767861161694978")); + + result = QCA::BigInteger( + "-601944008264824351134005823298148744369561537910415436895793990789678217920719566630222862549689727198849" + "4") += + QCA::BigInteger( + "532566302499155416003316607801593784583652720754079760364736422291735917382015688217276924340984564880"); + QCOMPARE(result.toString(), + QStringLiteral("-60189075163457443559240549163736858499110317263834002891975751714744904432898136506140113" + "48572556287423614")); + QCOMPARE(result, + QCA::BigInteger("-6018907516345744355924054916373685849911031726383400289197575171474490443289813650614011" + "348572556287423614")); + + result = QCA::BigInteger( + "-7375547156361602684772634935716753083385095966292105905292822923781472871944886871927821129478599825311797681" + "2683153264088230182865250970217610487") += + QCA::BigInteger("-30100016097092378349958946184353117306134810372681"); + QCOMPARE(result.toString(), + QStringLiteral("-73755471563616026847726349357167530833850959662921059052928229237814728719448868719278211" + "294786028353134073905061503223034414535982557105027983168")); + QCOMPARE(result, + QCA::BigInteger("-7375547156361602684772634935716753083385095966292105905292822923781472871944886871927821" + "1294786028353134073905061503223034414535982557105027983168")); + + result = QCA::BigInteger( + "-2211177066689704345686852756638946306674958952044447080285364283965878599873864667094550865713828159912") += + QCA::BigInteger( + "-536556043937245689200756579876160678199726920153847573681478030051738396345585808165230823703346036004092" + "1820049494698892905680307378540208"); + QCOMPARE(result.toString(), + QStringLiteral("-53655604393724568920075657987616067842084462682281800825016330571563302701308170336967553" + "17318824644006800419923359365987456546021206700120")); + QCOMPARE(result, + QCA::BigInteger("-5365560439372456892007565798761606784208446268228180082501633057156330270130817033696755" + "317318824644006800419923359365987456546021206700120")); + + result = QCA::BigInteger( + "60741225123371088419685216490350768416336915742544171041442859708190687151580370231498672521465704184848502349" + "79838064249373816163440") += QCA::BigInteger("301843614094506325875637699"); + QCOMPARE(result.toString(), + QStringLiteral("607412251233710884196852164903507684163369157425441710414428597081906871515803702314986725" + "2146570418484850536823452158755699691801139")); + QCOMPARE(result, + QCA::BigInteger("60741225123371088419685216490350768416336915742544171041442859708190687151580370231498672" + "52146570418484850536823452158755699691801139")); + + result = QCA::BigInteger( + "-5182147769311581499087713405643489820105439851080650534792191527346598920424997741288096547136515478330872068" + "93256740737426200715673766732196603988") += + QCA::BigInteger( + "-2983517255774769372611552588738613700467454531142255734565888403876035392822615770224917521828071895197" + "9"); + QCOMPARE(result.toString(), + QStringLiteral("-51821477693115814990877134056434898201054401494323761122691287885018577942863677880335496" + "6136208893491971245653610668963583902964848985012915555967")); + QCOMPARE(result, + QCA::BigInteger("-5182147769311581499087713405643489820105440149432376112269128788501857794286367788033549" + "66136208893491971245653610668963583902964848985012915555967")); + + result = QCA::BigInteger("15937412249227240968245047444122") += QCA::BigInteger( + "186214680376169426108822450700978827886569053440254258585576645530381613666540347032550716844628275956253"); + QCOMPARE(result.toString(), + QStringLiteral("186214680376169426108822450700978827886569053440254258585576645530381613682477759281777957" + "812873323400375")); + QCOMPARE(result, + QCA::BigInteger("18621468037616942610882245070097882788656905344025425858557664553038161368247775928177795" + "7812873323400375")); + + result = QCA::BigInteger( + "-1252801011625868585504750425292810762392310545870176170791196952700385571348584614055110796749581358409708177" + "7160") += + QCA::BigInteger( + "-539986280927242338236008809854961759996986302156061552378097160849129372827386927545686899193598721998757" + "419572890"); + QCOMPARE(result.toString(), + QStringLiteral("-55251429104350102409105631410788986762090940761476331408600913037613322854087277368623800" + "7161094535582854501350050")); + QCOMPARE(result, + QCA::BigInteger("-5525142910435010240910563141078898676209094076147633140860091303761332285408727736862380" + "07161094535582854501350050")); + + result = QCA::BigInteger("-2454746908") += QCA::BigInteger( + "-3822957127889394780055242156360370187075592078655552376050604679934415014573879513870030211860839641756441626" + "913419699098985245833920954444218"); + QCOMPARE(result.toString(), + QStringLiteral("-38229571278893947800552421563603701870755920786555523760506046799344150145738795138700302" + "11860839641756441626913419699098985245833923409191126")); + QCOMPARE(result, + QCA::BigInteger("-3822957127889394780055242156360370187075592078655552376050604679934415014573879513870030" + "211860839641756441626913419699098985245833923409191126")); + + result = QCA::BigInteger("-54288706131860071583318409080596095357980447323635") += QCA::BigInteger( + "-4253394105560156310989737429933273230514384568190270696062942611579402976432972405594521244327792021815897638" + "74"); + QCOMPARE(result.toString(), + QStringLiteral("-42533941055601563109897374299332732305143845681902706960629431544664642950336882387786120" + "5028874560162037087509")); + QCOMPARE(result, + QCA::BigInteger("-4253394105560156310989737429933273230514384568190270696062943154466464295033688238778612" + "05028874560162037087509")); + + result = QCA::BigInteger( + "1418766894051319870818496026367686195459604395660119754151922014257535705077512233275240217434104") += + QCA::BigInteger("-111987390206074845527"); + QCOMPARE(result.toString(), + QStringLiteral( + "1418766894051319870818496026367686195459604395660119754151922014257535705077400245885034142588577")); + QCOMPARE(result, + QCA::BigInteger( + "1418766894051319870818496026367686195459604395660119754151922014257535705077400245885034142588577")); + + result = QCA::BigInteger( + "-6904101318604104774561038575945435154096774792428336186348093024529626004763532868225501682312348541164651530" + "78845744722987447719420052500874721214723") += + QCA::BigInteger( + "-258469037743394674731135699243278836145549479106673938483740960989738710973653960062315588091814633168127" + "2708396146283818299"); + QCOMPARE(result.toString(), + QStringLiteral("-69041013186041047745610386017923389284362422655419061106759766390845739154309267165995977" + "8128621963853004753702001625641133779400692760897021005033022")); + QCOMPARE(result, + QCA::BigInteger("-6904101318604104774561038601792338928436242265541906110675976639084573915430926716599597" + "78128621963853004753702001625641133779400692760897021005033022")); + + result = QCA::BigInteger("-2326153002179462643778624079324592172489363679671158") += + QCA::BigInteger("-109819757548464054181938329012610459679"); + QCOMPARE(result.toString(), QStringLiteral("-2326153002179572463536172543378774110818376290130837")); + QCOMPARE(result, QCA::BigInteger("-2326153002179572463536172543378774110818376290130837")); + + result = QCA::BigInteger( + "-4428752250566525488353857709194941742993785578807911414016959206453045495320705299466107784149485981354180907" + "411034982168391") += + QCA::BigInteger( + "-39247778259374215325521768005388007526581235832446540589720560855741992694947322437679214611686905696"); + QCOMPARE(result.toString(), + QStringLiteral("-44287522505665254883538969569732011172091111005759168020244857876888779418612950200269635" + "26142180928676618586625646669074087")); + QCOMPARE(result, + QCA::BigInteger("-4428752250566525488353896956973201117209111100575916802024485787688877941861295020026963" + "526142180928676618586625646669074087")); + + result = QCA::BigInteger("3047") += QCA::BigInteger( + "-7356458785031315352377693216371961073343377689039020461804017379719600010085607082927794304834315616579528230" + "7508135277641315214"); + QCOMPARE(result.toString(), + QStringLiteral("-73564587850313153523776932163719610733433776890390204618040173797196000100856070829277943" + "048343156165795282307508135277641312167")); + QCOMPARE(result, + QCA::BigInteger("-7356458785031315352377693216371961073343377689039020461804017379719600010085607082927794" + "3048343156165795282307508135277641312167")); + + result = QCA::BigInteger( + "71397189765381049110362731262243394989390499523719445987286843598407339615555456955143712741779487184644001767" + "776382991377987516772847242986") += + QCA::BigInteger("-5821969555717973232123574849275726788359152255219972775831"); + QCOMPARE(result.toString(), + QStringLiteral("713971897653810491103627312622433949893904995237194459872868435984073396155554569493217431" + "86061513952520426918500656203018835261552874467155")); + QCOMPARE(result, + QCA::BigInteger("71397189765381049110362731262243394989390499523719445987286843598407339615555456949321743" + "186061513952520426918500656203018835261552874467155")); + + result = QCA::BigInteger( + "-1814097526566131387779640926359093790218263603909606471867269911652274001767668314665411600499352055079190702" + "33410228328274") += + QCA::BigInteger( + "-523301382154855044703947051892202646490840761177533623732372519689918420769842424772676407501350528096714" + "904915297347684247802773107355881667545916901"); + QCOMPARE(result.toString(), + QStringLiteral("-52330138215485504470394705207361239914745389995549771636828189871174478116080307195940339" + "8666577928273481736381838507734183008281026426115077774245175")); + QCOMPARE(result, + QCA::BigInteger("-5233013821548550447039470520736123991474538999554977163682818987117447811608030719594033" + "98666577928273481736381838507734183008281026426115077774245175")); + + result = QCA::BigInteger("6858961373707073067") += QCA::BigInteger( + "-3340515089338930614338442797642711071819749062833649913099030776499716064369180713270728698264719460945945941" + "15614990907"); + QCOMPARE(result.toString(), + QStringLiteral("-33405150893389306143384427976427110718197490628336499130990307764997160643691807132707286" + "9826471946087735632741907917840")); + QCOMPARE(result, + QCA::BigInteger("-3340515089338930614338442797642711071819749062833649913099030776499716064369180713270728" + "69826471946087735632741907917840")); + + result = QCA::BigInteger( + "-23635098930374569407171906960429616870908424281519944658490940109956689534874971218650241680916564611") += + QCA::BigInteger( + "-189589178757795228335995891331428279524485393011427187469792714438466702359827437934396866267364281985416" + "47202983677887505430060922528525205"); + QCOMPARE(result.toString(), + QStringLiteral("-18958917875779522833599589133142827952472174400073093316386443350807099852853652217721206" + "571394919138651603892518552858724080302603445089816")); + QCOMPARE(result, + QCA::BigInteger("-1895891787577952283359958913314282795247217440007309331638644335080709985285365221772120" + "6571394919138651603892518552858724080302603445089816")); + + // Botan's subtraction tests + result = QCA::BigInteger("0") -= QCA::BigInteger("0"); + QCOMPARE(result.toString(), QStringLiteral("0")); + QCOMPARE(result, QCA::BigInteger("0")); + + result = QCA::BigInteger("0") -= QCA::BigInteger("1"); + QCOMPARE(result.toString(), QStringLiteral("-1")); + QCOMPARE(result, QCA::BigInteger("-1")); + + result = QCA::BigInteger("0") -= QCA::BigInteger("4294967296"); + QCOMPARE(result.toString(), QStringLiteral("-4294967296")); + QCOMPARE(result, QCA::BigInteger("-4294967296")); + + // Next test is labelled # 2^512 - 1 + result = QCA::BigInteger( + "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858" + "186486050853753882811946569946433649006084095") -= QCA::BigInteger("1"); + QCOMPARE(result.toString(), + QStringLiteral("134078079299425970995740249982058461274793658205923933777235614437217640300735469768018742" + "98166903427690031858186486050853753882811946569946433649006084094")); + QCOMPARE(result, + QCA::BigInteger("13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874" + "298166903427690031858186486050853753882811946569946433649006084094")); + + result = QCA::BigInteger("89094716573076464980713547115099137014719483620102078148320806773871083148864") -= + QCA::BigInteger("49505213825110728957828173754776257356620450607893971553289366249708672306581"); + QCOMPARE(result.toString(), + QStringLiteral("39589502747965736022885373360322879658099033012208106595031440524162410842283")); + QCOMPARE(result, QCA::BigInteger("39589502747965736022885373360322879658099033012208106595031440524162410842283")); + + result = QCA::BigInteger("65894747009896006767807716946835412110318548717263922395390971078905789585431") -= + QCA::BigInteger("3884269741925508225990715416862047284194603799902650748631039608684367281358"); + QCOMPARE(result.toString(), + QStringLiteral("62010477267970498541817001529973364826123944917361271646759931470221422304073")); + QCOMPARE(result, QCA::BigInteger("62010477267970498541817001529973364826123944917361271646759931470221422304073")); + + result = QCA::BigInteger( + "59501963964519775669021213017070542183647171968931013600114917777619522537369647091659626133477106071641786829" + "87783755894811024288429224592316636383") -= + QCA::BigInteger( + "8750653273562160761286422180115618621879821429145276197424652349306577311499807887070429373153777028581165" + "316131683348567"); + QCOMPARE(result.toString(), + QStringLiteral("595019639645197756690212129295640094480255643560667917989587315588213082459168851174131026" + "4041133295664370795917354382741033995707263908460633287816")); + QCOMPARE(result, + QCA::BigInteger("59501963964519775669021212929564009448025564356066791798958731558821308245916885117413102" + "64041133295664370795917354382741033995707263908460633287816")); + + result = QCA::BigInteger("9815262808265519920770782360080149146267723690") -= QCA::BigInteger( + "14067005768891609281364919358115291341352189918255780397560060748765650205261663193732434161580120817"); + QCOMPARE( + result.toString(), + QStringLiteral( + "-14067005768891609281364919358115291341352189918255780387744797940500130284490880833652285015312397127")); + QCOMPARE( + result, + QCA::BigInteger( + "-14067005768891609281364919358115291341352189918255780387744797940500130284490880833652285015312397127")); + + result = QCA::BigInteger( + "-3901491029419486215684797223469406667043760137344853438401542216058534125031549938788864908670209347775308945" + "93416337175399865065870417717658815158195790") -= + QCA::BigInteger("1456031684988128870809574635750149625240648487837308"); + QCOMPARE(result.toString(), + QStringLiteral("-39014910294194862156847972234694066670437601373448534384015422160585341250315499387888649" + "0867020934778986926278404466046209439701620567342899463646033098")); + QCOMPARE(result, + QCA::BigInteger("-3901491029419486215684797223469406667043760137344853438401542216058534125031549938788864" + "90867020934778986926278404466046209439701620567342899463646033098")); + + result = QCA::BigInteger("7473774301764883450943") -= + QCA::BigInteger("-26256369859367890755157372820052387483402723790185562908491933812453"); + QCOMPARE(result.toString(), QStringLiteral("26256369859367890755157372820052387483402723797659337210256817263396")); + QCOMPARE(result, QCA::BigInteger("26256369859367890755157372820052387483402723797659337210256817263396")); + + result = QCA::BigInteger( + "36246343251214922024139186757009148849295485593397952003237349660142296147421019916619944353877490544706223768" + "684758263065399016597969") -= + QCA::BigInteger( + "2574427901445527995149185461475228850098549655325125750771680756403104624569522792792597223218143154924988" + "199562355517064962665954307425375180"); + QCOMPARE(result.toString(), + QStringLiteral("-25744278651991847439342634373360420930894008060296401573737287531657549644272266453715773" + "06598198801047497654856131748380204402888908408777211")); + QCOMPARE(result, + QCA::BigInteger("-2574427865199184743934263437336042093089400806029640157373728753165754964427226645371577" + "306598198801047497654856131748380204402888908408777211")); + + result = QCA::BigInteger("30129746266682790628283889040897642317014108334116727") -= + QCA::BigInteger("-1580480523895398762563721715474380903630073871362143915864398724834897608423"); + QCOMPARE(result.toString(), + QStringLiteral("1580480523895398762563751845220647586420702155251184813506715738943231725150")); + QCOMPARE(result, QCA::BigInteger("1580480523895398762563751845220647586420702155251184813506715738943231725150")); + + result = QCA::BigInteger("-4614735863800137951667138933166372061") -= + QCA::BigInteger("87175694379075561307234146162193190462135078700346746992273"); + QCOMPARE(result.toString(), QStringLiteral("-87175694379075561307238760898056990600086745839279913364334")); + QCOMPARE(result, QCA::BigInteger("-87175694379075561307238760898056990600086745839279913364334")); + + result = QCA::BigInteger("-3753904") -= QCA::BigInteger("-11269137783745339515071988205310702154422777729974"); + QCOMPARE(result.toString(), QStringLiteral("11269137783745339515071988205310702154422773976070")); + QCOMPARE(result, QCA::BigInteger("11269137783745339515071988205310702154422773976070")); + + result = QCA::BigInteger( + "59252394849537944008202127973817008840291885845547005014065278717183005886493293990079450595543785692690297587" + "0288") -= QCA::BigInteger("-205854658295495452479104108497931263758143158076949293929661651111"); + QCOMPARE(result.toString(), + QStringLiteral("592523948495379440082021279738170088402918858455675904798948282624309162973430871164552649" + "113514806220832637521399")); + QCOMPARE(result, + QCA::BigInteger("59252394849537944008202127973817008840291885845567590479894828262430916297343087116455264" + "9113514806220832637521399")); + + result = QCA::BigInteger("-33993701617495591491176844355") -= QCA::BigInteger( + "3438065097398894672826284379125235190693300918673662774192379185002391232383325160416036963599856704698280"); + QCOMPARE(result.toString(), + QStringLiteral("-34380650973988946728262843791252351906933009186736627741923791850023912323833591541176544" + "59191347881542635")); + QCOMPARE(result, + QCA::BigInteger("-3438065097398894672826284379125235190693300918673662774192379185002391232383359154117654" + "459191347881542635")); + + result = QCA::BigInteger("26876428790838270949718735111909136008255051776703") -= QCA::BigInteger( + "-1781128112966810373286192008831149275546995635268767241859967609117529616872536681035700534316457543887601645" + "022"); + QCOMPARE(result.toString(), + QStringLiteral("178112811296681037328619200883114927554699563526876724185996763599395840771080763075443564" + "6225593552142653421725")); + QCOMPARE(result, + QCA::BigInteger("17811281129668103732861920088311492755469956352687672418599676359939584077108076307544356" + "46225593552142653421725")); + + result = QCA::BigInteger( + "2059771092932179758019770618974659367350250375647433386639519387\ +69317693429941871882153770641334267205446421916220398066553188") -= + QCA::BigInteger("3342500267594994347156312297990633112620923791590960237694328174171473763026"); + QCOMPARE(result.toString(), + QStringLiteral("205977109293217975801977061897465936735025037564739996163684343774970537117643881249041149" + "717542676245208727588046226592790162")); + QCOMPARE(result, + QCA::BigInteger("20597710929321797580197706189746593673502503756473999616368434377497053711764388124904114" + "9717542676245208727588046226592790162")); + + result = QCA::BigInteger("5545520403000578843599072515870982842927227412121917598877293331575380404618111609") -= + QCA::BigInteger("5991287327241003718821424770352575362437680738923552868139860461945460339860477495902"); + QCOMPARE(result.toString(), + QStringLiteral("-5985741806838003139977825697836704379594753511511430950540983168613884959455859384293")); + QCOMPARE(result, + QCA::BigInteger("-5985741806838003139977825697836704379594753511511430950540983168613884959455859384293")); + + result = QCA::BigInteger("248039029608125071340") -= QCA::BigInteger("3664608673"); + QCOMPARE(result.toString(), QStringLiteral("248039029604460462667")); + QCOMPARE(result, QCA::BigInteger("248039029604460462667")); + + result = QCA::BigInteger("15425705711415937103627") -= QCA::BigInteger( + "-1435504065517745703440045276868982910754081405474123003767554211132837427846963435621523810229738262235546179" + "779885824"); + QCOMPARE(result.toString(), + QStringLiteral("143550406551774570344004527686898291075408140547412300376755421113283742784696343562152381" + "0229753687941257595716989451")); + QCOMPARE(result, + QCA::BigInteger("14355040655177457034400452768689829107540814054741230037675542111328374278469634356215238" + "10229753687941257595716989451")); + + result = QCA::BigInteger("50882847205108645607281568922683652688671738236030732914347600821086") -= + QCA::BigInteger("12176160963158"); + QCOMPARE(result.toString(), QStringLiteral("50882847205108645607281568922683652688671738236030732902171439857928")); + QCOMPARE(result, QCA::BigInteger("50882847205108645607281568922683652688671738236030732902171439857928")); + + result = QCA::BigInteger( + "-3542651856598581894767004787703302288554217246197356622850977105341631254320181588119095376220762923216041205" + "8300173038824256783171761132") -= + QCA::BigInteger("-4864862607366468843184694353123830534588538011093812418208808135799"); + QCOMPARE(result.toString(), + QStringLiteral("-35426518565985818947670047877033022885542172461973566228509771053416307678339208514722110" + "577513276108329877469762161945011838574363625333")); + QCOMPARE(result, + QCA::BigInteger("-3542651856598581894767004787703302288554217246197356622850977105341630767833920851472211" + "0577513276108329877469762161945011838574363625333")); + + result = QCA::BigInteger( + "-1428596214712268310382144828171384812520179141608121870013556402879770424002218157546599921571184") -= + QCA::BigInteger("-4054101"); + QCOMPARE(result.toString(), + QStringLiteral( + "-1428596214712268310382144828171384812520179141608121870013556402879770424002218157546599917517083")); + QCOMPARE(result, + QCA::BigInteger( + "-1428596214712268310382144828171384812520179141608121870013556402879770424002218157546599917517083")); + + result = QCA::BigInteger("-200931") -= QCA::BigInteger( + "-4455880246013049575948283291316071779115178672557051947544960765970517168228311149083493083504573514296684748" + "3009157514950177565952218520297258834187372"); + QCOMPARE(result.toString(), + QStringLiteral("445588024601304957594828329131607177911517867255705194754496076597051716822831114908349308" + "35045735142966847483009157514950177565952218520297258833986441")); + QCOMPARE(result, + QCA::BigInteger("44558802460130495759482832913160717791151786725570519475449607659705171682283111490834930" + "835045735142966847483009157514950177565952218520297258833986441")); + + result = QCA::BigInteger("105704314890799915321259") -= QCA::BigInteger( + "82792354594507641557491243849916981441456306687749410083165776119049069747385436947778487411878749535140554980" + "3329615347120938123226038208"); + QCOMPARE(result.toString(), + QStringLiteral("-82792354594507641557491243849916981441456306687749410083165776119049069747385436947778487" + "4118787495351405549803329509642806047323310716949")); + QCOMPARE(result, + QCA::BigInteger("-8279235459450764155749124384991698144145630668774941008316577611904906974738543694777848" + "74118787495351405549803329509642806047323310716949")); + + result = QCA::BigInteger("1448979433940064018828919290452280235308901982649341") -= + QCA::BigInteger("303926827425887072291878308433008512899006711759770318009"); + QCOMPARE(result.toString(), QStringLiteral("-303925378446453132227859479513718060618771402857787668668")); + QCOMPARE(result, QCA::BigInteger("-303925378446453132227859479513718060618771402857787668668")); + + result = QCA::BigInteger("-243237595290235750457450892290434789864") -= QCA::BigInteger( + "19817702076334276402981273067417321098467533300947463865383702005126562800253466403934608765512316565811954342" + "319565128573969"); + QCOMPARE(result.toString(), + QStringLiteral("-19817702076334276402981273067417321098467533300947463865383702005126562800253466403934852" + "003107606801562411793211855563363833")); + QCOMPARE(result, + QCA::BigInteger("-1981770207633427640298127306741732109846753330094746386538370200512656280025346640393485" + "2003107606801562411793211855563363833")); + + result = QCA::BigInteger("294037338365659932242802023634") -= + QCA::BigInteger("4401245995535867764294876849802142926077599828776505639975554254356763769548465"); + QCOMPARE(result.toString(), + QStringLiteral("-4401245995535867764294876849802142926077599828776211602637188594424520967524831")); + QCOMPARE(result, + QCA::BigInteger("-4401245995535867764294876849802142926077599828776211602637188594424520967524831")); + + result = QCA::BigInteger("7303853946195223307036710881687367004566538357189824031021831088365362") -= + QCA::BigInteger("119286025999378935715794641163321741"); + QCOMPARE(result.toString(), + QStringLiteral("7303853946195223307036710881687366885280512357810888315227189925043621")); + QCOMPARE(result, QCA::BigInteger("7303853946195223307036710881687366885280512357810888315227189925043621")); + + result = + QCA::BigInteger("571167355343287235687602610714110416067426289363505412908804940696550592413192300554016875") -= + QCA::BigInteger("15872188842802631759540597"); + QCOMPARE( + result.toString(), + QStringLiteral("571167355343287235687602610714110416067426289363505412908804940680678403570389668794476278")); + QCOMPARE( + result, + QCA::BigInteger("571167355343287235687602610714110416067426289363505412908804940680678403570389668794476278")); + + result = QCA::BigInteger("1002240129784524388754179399598974973256811336031329881209395070412702275169416754240") -= + QCA::BigInteger( + "5942948247886059134314539354042003351647830595287234900671578947794647475365720680007051520796770907993342" + "0746952"); + QCOMPARE(result.toString(), + QStringLiteral("-59429482478860591343145393539417793386693781564118169607116814504689663417625876918861120" + "137555006804764003992712")); + QCOMPARE(result, + QCA::BigInteger("-5942948247886059134314539353941779338669378156411816960711681450468966341762587691886112" + "0137555006804764003992712")); + + result = QCA::BigInteger( + "1370431648825444838359719050380239722263203134555431526491525074601463042144798545817957389") -= + QCA::BigInteger("3473869878"); + QCOMPARE( + result.toString(), + QStringLiteral("1370431648825444838359719050380239722263203134555431526491525074601463042144798542344087511")); + QCOMPARE( + result, + QCA::BigInteger("1370431648825444838359719050380239722263203134555431526491525074601463042144798542344087511")); + + result = QCA::BigInteger("8548280229254726209") -= + QCA::BigInteger("33066125035269904981849320434016892734943145935582141989968280846973981913056248918"); + QCOMPARE(result.toString(), + QStringLiteral("-33066125035269904981849320434016892734943145935582141989968280838425701683801522709")); + QCOMPARE(result, + QCA::BigInteger("-33066125035269904981849320434016892734943145935582141989968280838425701683801522709")); + + result = QCA::BigInteger( + "-1902355883268750648950815079596633217599012996302992895858417011175963029327693964733408210016910253836443785" + "9846398095065171936899503") -= + QCA::BigInteger( + "2489927112752354534228346876280965340763863196622012469575197689419310377944305084304077119122752284308807" + "9031762445684377195650493065096847292797"); + QCOMPARE(result.toString(), + QStringLiteral("-24899271127542568901116156269299161558434598298396114825715006823151687949554810473334048" + "130874856925188248134300810122237042048588130268784192300")); + QCOMPARE(result, + QCA::BigInteger("-2489927112754256890111615626929916155843459829839611482571500682315168794955481047333404" + "8130874856925188248134300810122237042048588130268784192300")); + + result = QCA::BigInteger( + "-1800353575522706389288305623797196690530870204356722928042061228497437075035917720399302198953687023") -= + QCA::BigInteger( + "-118756682615304660537085387309407764121711064830726245327571774713841280164583325446427884047654699244961" + "27460164"); + QCOMPARE(result.toString(), + QStringLiteral("118756682615286657001330160245514881065473092863820936625528207484560859552298351075677524" + "87045070622297173773141")); + QCOMPARE(result, + QCA::BigInteger("11875668261528665700133016024551488106547309286382093662552820748456085955229835107567752" + "487045070622297173773141")); + + result = QCA::BigInteger("-29861551039945217879") -= QCA::BigInteger( + "11134730259168556423534561466475429305816690823484096396972829608778892265003199963808382325823762328728689476" + "24793789212829885934"); + QCOMPARE(result.toString(), + QStringLiteral("-11134730259168556423534561466475429305816690823484096396972829608778892265003199963808382" + "32582376232872868947654655340252775103813")); + QCOMPARE(result, + QCA::BigInteger("-1113473025916855642353456146647542930581669082348409639697282960877889226500319996380838" + "232582376232872868947654655340252775103813")); + + result = QCA::BigInteger( + "56553296365676115383821827756495791765870729764975792067630330165532810366551228779710851013983764350649164198" + "7188791892506290") -= QCA::BigInteger("-2188105671531473889939411772533707"); + QCOMPARE(result.toString(), + QStringLiteral("565532963656761153838218277564957917658707297649757920676303301655328103665512287797108510" + "142025749178023115877128203665039997")); + QCOMPARE(result, + QCA::BigInteger("56553296365676115383821827756495791765870729764975792067630330165532810366551228779710851" + "0142025749178023115877128203665039997")); + + result = QCA::BigInteger("-349535960680522202843083381184496349093812380954435872337802226") -= + QCA::BigInteger("-1829600726218222026679938"); + QCOMPARE(result.toString(), QStringLiteral("-349535960680522202843083381184496349091982780228217650311122288")); + QCOMPARE(result, QCA::BigInteger("-349535960680522202843083381184496349091982780228217650311122288")); + + result = QCA::BigInteger("-1") -= QCA::BigInteger("-6726974989587128275"); + QCOMPARE(result.toString(), QStringLiteral("6726974989587128274")); + QCOMPARE(result, QCA::BigInteger("6726974989587128274")); + + result = QCA::BigInteger("-107142709838121196902389095205618516687047338619382145236348309762148611647954748824") -= + QCA::BigInteger("42484103615491"); + QCOMPARE(result.toString(), + QStringLiteral("-107142709838121196902389095205618516687047338619382145236348309762148654132058364315")); + QCOMPARE(result, + QCA::BigInteger("-107142709838121196902389095205618516687047338619382145236348309762148654132058364315")); + + result = + QCA::BigInteger("-90546630430085769764839607528116121381848878494574360812027599640018921358040178215575723") -= + QCA::BigInteger( + "-118922408531468986902800063237122125617455464103913195171141030774109638861272017660698580914239435114280" + "434761425243"); + QCOMPARE(result.toString(), + QStringLiteral("118922408531468986902800063146575495187369694339073587643024909392260760366697656848670981" + "274220513756240256545849520")); + QCOMPARE(result, + QCA::BigInteger("11892240853146898690280006314657549518736969433907358764302490939226076036669765684867098" + "1274220513756240256545849520")); + + result = QCA::BigInteger( + "-5545044667082427128801726416727657360001588430113578182850657573063241939882570324573086267287272360432363387" + "213743735507218270373633222520429") -= QCA::BigInteger("-151423255459028627628896755237194376177115"); + QCOMPARE(result.toString(), + QStringLiteral("-55450446670824271288017264167276573600015884301135781828506575730632419398825703245730862" + "67287272360280940131754715107878321515136438846343314")); + QCOMPARE(result, + QCA::BigInteger("-5545044667082427128801726416727657360001588430113578182850657573063241939882570324573086" + "267287272360280940131754715107878321515136438846343314")); + + result = QCA::BigInteger("-5247636471953421659649611318164848102069") -= + QCA::BigInteger("-4024324110573096565232590473170599175885004"); + QCOMPARE(result.toString(), QStringLiteral("4019076474101143143572940861852434327782935")); + QCOMPARE(result, QCA::BigInteger("4019076474101143143572940861852434327782935")); + + result = QCA::BigInteger("39412892606015043322484854253879371723186457838590224795040178472832") -= + QCA::BigInteger("-5038321321957452145034687815432890684825466579123474921848465393400312"); + QCOMPARE(result.toString(), + QStringLiteral("5077734214563467188357172669686770056548653036962065146643505571873144")); + QCOMPARE(result, QCA::BigInteger("5077734214563467188357172669686770056548653036962065146643505571873144")); + + result = QCA::BigInteger( + "-5597941458800922703568362450520876675318746972779964027720427420784331758329273633391278382952827027264258300" + "4969175230274821") -= + QCA::BigInteger( + "-109633110576212669339535976775635762395927171313557427036242111476016398579345366908401334025571265714128" + "108308032073779442181369365924213118258269679"); + QCOMPARE(result.toString(), + QStringLiteral("109633110576212669339535920796221174386700135629932921827475358288546670779705089704127126" + "182253682421391774395248244251171908726782919243943027994858")); + QCOMPARE(result, + QCA::BigInteger("10963311057621266933953592079622117438670013562993292182747535828854667077970508970412712" + "6182253682421391774395248244251171908726782919243943027994858")); + + result = + QCA::BigInteger("-38752353898173389347479216285772999906325286421302866854350737050533204094183249691110") -= + QCA::BigInteger( + "2428819407377764342156426895396654728835493564788997075896393065230009911546390816091652653701035085361"); + QCOMPARE(result.toString(), + QStringLiteral("-24288194073777643809087807935700440763147098505619969822216794865328767658971278666248567" + "47884284776471")); + QCOMPARE(result, + QCA::BigInteger("-2428819407377764380908780793570044076314709850561996982221679486532876765897127866624856" + "747884284776471")); + + result = QCA::BigInteger("-2784579005241382005249492720344") -= + QCA::BigInteger("-164204542616919252351131740123094674"); + QCOMPARE(result.toString(), QStringLiteral("164201758037914010969126490630374330")); + QCOMPARE(result, QCA::BigInteger("164201758037914010969126490630374330")); + + result = QCA::BigInteger("200948857420871544747808060972375039052401280822505804851732868100") -= + QCA::BigInteger("-795957177479360455258269298038670876462147576765875895105714"); + QCOMPARE(result.toString(), QStringLiteral("200949653378049024108263319241673077723277742970082570727627973814")); + QCOMPARE(result, QCA::BigInteger("200949653378049024108263319241673077723277742970082570727627973814")); + + result = QCA::BigInteger("217570540819") -= QCA::BigInteger( + "121955083597720420983384282166693307394185530431368476834980748302158718406063500763434561937200696970170700"); + QCOMPARE(result.toString(), + QStringLiteral("-12195508359772042098338428216669330739418553043136847683498074830215871840606350076343456" + "1937200479399629881")); + QCOMPARE(result, + QCA::BigInteger(QStringLiteral("-1219550835977204209833842821666933073941855304313684768349807483021587184" + "06063500763434561937200479399629881"))); + + result = QCA::BigInteger(QStringLiteral("2335319252198456765380587281374076367944")) -= + QCA::BigInteger(QStringLiteral("-4500271")); + QCOMPARE(result, QCA::BigInteger(QStringLiteral("2335319252198456765380587281374080868215"))); + + result = QCA::BigInteger( + QStringLiteral("-393694614027544181700073367147249369966344727230221941008713805434207925307052598")) -= + QCA::BigInteger(QStringLiteral("-153972676737062409261153899615588515236137907791841623991260363840680295565313" + "157972489168132345521780658007459602823125797806770")); + QCOMPARE(result.toString(), + QStringLiteral("153972676737062409261153899615588515236137907791447929377232819658980222198165908602522823" + "405115299839649293654168615200490754172")); + QCOMPARE(result, + QCA::BigInteger(QStringLiteral("15397267673706240926115389961558851523613790779144792937723281965898022219" + "8165908602522823405115299839649293654168615200490754172"))); + + result = QCA::BigInteger(QStringLiteral("114832549702862263167")) -= + QCA::BigInteger(QStringLiteral("1292186490722995955874527641883028787538667360089228102228659716577356947303995" + "3984775959232814911435097412913078625")); + QCOMPARE(result.toString(), + QStringLiteral("-12921864907229959558745276418830287875386673600892281022286597165773569473039953984775959" + "232814796602547710050815458")); + QCOMPARE(result, + QCA::BigInteger(QStringLiteral("-1292186490722995955874527641883028787538667360089228102228659716577356947" + "3039953984775959232814796602547710050815458"))); + + result = + QCA::BigInteger(QStringLiteral("6489502346837936889305337487724547956628371915228387374094443896266362105931065" + "153072983425911767580294076594078932835008494777866083")) -= + QCA::BigInteger(QStringLiteral("1099205476533612407829257935144627350486541654788267826664706620630745291371323" + "154513322608446957760026881954001581")); + QCOMPARE(result.toString(), + QStringLiteral("648950234683793688820613201119093554879911398008376002360790224147809427926635853244223813" + "4540444425780753985631975074981612823864502")); + QCOMPARE(result, + QCA::BigInteger(QStringLiteral("64895023468379368882061320111909355487991139800837600236079022414780942792" + "66358532442238134540444425780753985631975074981612823864502"))); + + result = + QCA::BigInteger(QStringLiteral("1699911441239587542538013131736629773378508702733583789516405216010771529944743" + "40806917796870911557233689087716056557")) -= + QCA::BigInteger(QStringLiteral("-15409167")); + QCOMPARE(result.toString(), + QStringLiteral("169991144123958754253801313173662977337850870273358378951640521601077152994474340806917796" + "870911557233689087731465724")); + QCOMPARE(result, + QCA::BigInteger(QStringLiteral("16999114412395875425380131317366297733785087027335837895164052160107715299" + "4474340806917796870911557233689087731465724"))); +} + +QTEST_MAIN(BigIntUnitTest) + +#include "bigintunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/certunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/certunittest/CMakeLists.txt new file mode 100644 index 0000000000..2ee40600e6 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/CMakeLists.txt @@ -0,0 +1,18 @@ +ENABLE_TESTING() + +set(certunittest_bin_SRCS certunittest.cpp) + +add_executable(certunittest ${certunittest_bin_SRCS} ) + +target_link_qca_test_libraries(certunittest) + + +FOREACH( testFileName RootCAcert.pem 76.pem altname.pem csr1.pem + GoodCACRL.pem ov-root-ca-cert.crt User.pem QcaTestClientCert.pem xmppcert.pem + Server.pem QcaTestServerCert.pem xmppcert.pem newreq.pem + QualitySSLIntermediateCA.crt QcaTestRootCert.pem Test_CRL.crl + RAIZ2007_CERTIFICATE_AND_CRL_SIGNING_SHA256.crt ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/certs/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/certs/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +add_qca_test(certunittest "Certificate") diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/76.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/76.pem new file mode 100644 index 0000000000..6b4989067c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/76.pem @@ -0,0 +1,94 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 118 (0x76) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SE, O=Stockholms universitet, CN=Stockholm University CA + Validity + Not Before: Mar 22 09:15:28 2006 GMT + Not After : Mar 22 09:15:28 2007 GMT + Subject: C=SE, O=Stockholms universitet, CN=sip1.su.se + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ad:4c:d7:4c:3d:fa:64:ae:c2:c1:92:47:fd:f6: + 94:35:37:1d:6a:a3:3b:27:28:99:b1:fa:ce:ef:4d: + dd:ed:c4:ff:6c:9d:f0:2b:14:fc:b6:b3:8e:87:f3: + ae:5b:08:06:15:7d:be:af:bc:a4:ba:7d:da:21:45: + d4:b8:3d:77:62:57:bf:c8:7a:87:ff:88:3d:bd:65: + fb:51:e1:42:06:54:88:d2:d0:31:9e:5a:ad:d1:0a: + a5:3e:04:9d:18:b1:dc:a0:ee:0f:3f:28:e8:9f:d8: + e3:d0:0f:f3:a4:91:99:1e:24:54:0a:8a:28:eb:76: + 2a:13:d3:18:7e:be:47:05:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Subject Key Identifier: + 3A:5C:5C:D1:CC:2C:9E:DF:73:F7:3B:D8:1B:59:B1:EA:B8:30:35:C5 + X509v3 Authority Key Identifier: + keyid:9E:2E:30:BA:37:D9:51:44:C9:9D:BF:18:21:F1:BD:7E:EE:B5:86:48 + DirName:/C=SE/O=Umea University/OU=SwUPKI-PCA/CN=SwUPKI Policy CA + serial:10 + + X509v3 CRL Distribution Points: + URI:http://ca.su.se/2005-1/crl-v2.crl + + X509v3 Certificate Policies: + Policy: 1.2.752.43.2.1.1.1 + CPS: http://ca.su.se/CPS + User Notice: + Explicit Text: Limited Liability, see http://www.swupki.su.se/CP + + X509v3 Issuer Alternative Name: + email:ca@su.se, URI:http://ca.su.se + X509v3 Subject Alternative Name: + DNS:incomingproxy.sip.su.se, DNS:incomingproxy1.sip.su.se, DNS:outgoingproxy.sip.su.se, DNS:outgoingproxy1.sip.su.se, DNS:out.sip.su.se, DNS:appserver.sip.su.se, DNS:appserver1.sip.su.se, DNS:sip1.su.se + Signature Algorithm: sha1WithRSAEncryption + 11:15:88:3b:ca:d7:29:87:41:3b:5a:6b:cc:e3:80:0d:ff:ca: + ab:bb:bb:51:5f:a6:92:15:6a:e3:2f:25:6b:ff:55:a4:e2:9a: + c2:2b:8c:b9:26:97:cd:c3:97:61:f5:9f:1f:fe:0c:85:b2:bd: + 62:16:c6:fa:7d:2d:e7:25:34:dd:dd:f5:65:59:17:dc:34:21: + 88:c7:98:3c:2a:e4:9b:de:ee:9f:ed:5c:e7:90:63:9e:89:13: + 11:11:24:1c:d4:6f:01:7a:1d:33:6d:d6:52:ec:16:0e:da:0f: + 44:2a:56:c6:49:3e:4f:c1:09:dc:e2:0f:4a:ee:9a:8f:c8:a4: + 8d:56:4c:db:eb:43:6e:8e:0f:fe:a9:88:de:ec:c0:9c:37:e6: + 51:9d:40:68:e9:4d:8d:67:4e:bf:40:45:05:9b:eb:94:22:16: + 7c:20:63:35:80:b7:a1:0b:b4:37:1b:8f:9d:e1:cd:fc:08:32: + 71:42:74:8f:3a:05:a2:5e:e4:af:86:14:26:28:3b:1b:ac:ac: + d1:69:e0:51:87:97:84:25:b4:e4:03:c0:e9:d0:49:9b:d1:4a: + e4:45:58:62:c5:e8:3d:ee:cb:71:51:c0:13:02:37:46:96:32: + 7d:30:b9:ee:1d:79:c8:ee:28:46:75:47:e0:e6:af:f5:d3:9b: + e9:b1:0a:4e +-----BEGIN CERTIFICATE----- +MIIE6zCCA9OgAwIBAgIBdjANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJTRTEf +MB0GA1UEChMWU3RvY2tob2xtcyB1bml2ZXJzaXRldDEgMB4GA1UEAxMXU3RvY2to +b2xtIFVuaXZlcnNpdHkgQ0EwHhcNMDYwMzIyMDkxNTI4WhcNMDcwMzIyMDkxNTI4 +WjBDMQswCQYDVQQGEwJTRTEfMB0GA1UEChMWU3RvY2tob2xtcyB1bml2ZXJzaXRl +dDETMBEGA1UEAxMKc2lwMS5zdS5zZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEArUzXTD36ZK7CwZJH/faUNTcdaqM7JyiZsfrO703d7cT/bJ3wKxT8trOOh/Ou +WwgGFX2+r7ykun3aIUXUuD13Yle/yHqH/4g9vWX7UeFCBlSI0tAxnlqt0QqlPgSd +GLHcoO4PPyjon9jj0A/zpJGZHiRUCooo63YqE9MYfr5HBfkCAwEAAaOCAl8wggJb +MAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYD +VR0OBBYEFDpcXNHMLJ7fc/c72BtZseq4MDXFMH8GA1UdIwR4MHaAFJ4uMLo32VFE +yZ2/GCHxvX7utYZIoVukWTBXMQswCQYDVQQGEwJTRTEYMBYGA1UEChMPVW1lYSBV +bml2ZXJzaXR5MRMwEQYDVQQLEwpTd1VQS0ktUENBMRkwFwYDVQQDExBTd1VQS0kg +UG9saWN5IENBggEQMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jYS5zdS5zZS8y +MDA1LTEvY3JsLXYyLmNybDB5BgNVHSAEcjBwMG4GCCqFcCsCAQEBMGIwHwYIKwYB +BQUHAgEWE2h0dHA6Ly9jYS5zdS5zZS9DUFMwPwYIKwYBBQUHAgIwMxoxTGltaXRl +ZCBMaWFiaWxpdHksIHNlZSBodHRwOi8vd3d3LnN3dXBraS5zdS5zZS9DUDAkBgNV +HRIEHTAbgQhjYUBzdS5zZYYPaHR0cDovL2NhLnN1LnNlMIG3BgNVHREEga8wgayC +F2luY29taW5ncHJveHkuc2lwLnN1LnNlghhpbmNvbWluZ3Byb3h5MS5zaXAuc3Uu +c2WCF291dGdvaW5ncHJveHkuc2lwLnN1LnNlghhvdXRnb2luZ3Byb3h5MS5zaXAu +c3Uuc2WCDW91dC5zaXAuc3Uuc2WCE2FwcHNlcnZlci5zaXAuc3Uuc2WCFGFwcHNl +cnZlcjEuc2lwLnN1LnNlggpzaXAxLnN1LnNlMA0GCSqGSIb3DQEBBQUAA4IBAQAR +FYg7ytcph0E7WmvM44AN/8qru7tRX6aSFWrjLyVr/1Wk4prCK4y5JpfNw5dh9Z8f +/gyFsr1iFsb6fS3nJTTd3fVlWRfcNCGIx5g8KuSb3u6f7VznkGOeiRMRESQc1G8B +eh0zbdZS7BYO2g9EKlbGST5PwQnc4g9K7pqPyKSNVkzb60Nujg/+qYje7MCcN+ZR +nUBo6U2NZ06/QEUFm+uUIhZ8IGM1gLehC7Q3G4+d4c38CDJxQnSPOgWiXuSvhhQm +KDsbrKzRaeBRh5eEJbTkA8Dp0Emb0UrkRVhixeg97stxUcATAjdGljJ9MLnuHXnI +7ihGdUfg5q/105vpsQpO +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/GoodCACRL.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/GoodCACRL.pem new file mode 100644 index 0000000000..4280080df8 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/GoodCACRL.pem @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBejCB5AIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJVUzEaMBgGA1UE +ChMRVGVzdCBDZXJ0aWZpY2F0ZXMxEDAOBgNVBAMTB0dvb2QgQ0EXDTAxMDQxOTE0 +NTcyMFoXDTExMDQxOTE0NTcyMFowRDAgAgEOFw0wMTA0MTkxNDU3MjBaMAwwCgYD +VR0VBAMKAQEwIAIBDxcNMDEwNDE5MTQ1NzIwWjAMMAoGA1UdFQQDCgEBoC8wLTAf +BgNVHSMEGDAWgBS3LqaCy8LIvKh7J0TXNTPfmhWUxzAKBgNVHRQEAwIBATANBgkq +hkiG9w0BAQUFAAOBgQCTwuwLcQctndeis/DtCE1uBpBmcgapwjBz8Rhyv6dRE5XE +MT8deUHt7avQlhEeMkdMxPfiCGVvc1XBWQlW8mB5JxgulEDdfrGSv7hX5UzFOJd1 +KqEXoiUN7A63lUCNLN+5+hD/vp5K8jdPJcsbyG3v5Am5AzYbwdn5TwBegIWSzQ== +-----END X509 CRL----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.crt new file mode 100644 index 0000000000..550ad21a72 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.pem new file mode 100644 index 0000000000..d4c13a1f9d --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEaTCCA1GgAwIBAgIBATANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4MzEzN1oXDTA2MDgxNjA4MzEzN1owfjELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMSYwJAYDVQQDEx1JbnNl +Y3VyZSBUZXN0IE9DU1BTZXJ2ZXIgQ2VydDElMCMGCSqGSIb3DQEJARYWaW5zZWN1 +cmVAdGVzdC5pbnNlY3VyZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAot4r +YDfD5d8Gj5HEQMOZaner0dDI2YsmO3tkG+Mq7CoWLtYy0SpP+lsFy7ad9hgnAuSA +a+LS160GaBEX6I6Y0iwebaw2zmO5PvPx8Acm2BSsz4LZqZz8XP3Hilt6r6F/qWVk +xU5R0lS3RsKUltkxItj5dUT9hNgAo9s1bR3k4LECAwEAAaOCAYMwggF/MAsGA1Ud +DwQEAwIDqDAeBgNVHSUEFzAVBggrBgEFBQcDAQYJKwYBBQUHMAEFMB0GA1UdDgQW +BBTyS+4wJTKxJTInzevz2OcVO+KjXzCBmQYDVR0jBIGRMIGOgBS/U0OCeNCew4Dl +G2fKBQDfuUiDpaFzpHEwbzELMAkGA1UEBhMCZGUxIDAeBgNVBAoTF0luc2VjdXJl +VGVzdENlcnRpZmljYXRlMRcwFQYDVQQDEw5Gb3IgVGVzdHMgT25seTElMCMGCSqG +SIb3DQEJARYWaW5zZWN1cmVAdGVzdC5pbnNlY3VyZYIBADAhBgNVHREEGjAYgRZp +bnNlY3VyZUB0ZXN0Lmluc2VjdXJlMCEGA1UdEgQaMBiBFmluc2VjdXJlQHRlc3Qu +aW5zZWN1cmUwEQYJYIZIAYb4QgEBBAQDAgZAMDwGCWCGSAGG+EIBDQQvFi1UaGlz +IGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgZm9yIHRlc3Rpbmcgb25seSEwDQYJKoZI +hvcNAQEEBQADggEBAKZVSYg5vuu3NEIb78GgWJdzhujUVAKjA8AYlACKne3JYkIa +i8uhLwiLTLToYh5X4X91BtdMKbW92rIpz2KZ5A414+fmF0NSyx3nIt2EfHoULBLw +VeJwewznU82PKgtSKB0urm3xf2OT478EN2eZrEVgoROvKFQbbh5zP88SOqamyg96 +wWpVw1lMq1rDqSc7uISV+xB+ETNbvmBjJ94W81QeCiTfu+2niaxqO2UA4rUR4b0p +wPZWUbAFd9aW73715sKIUT0RjmocBhnGbdCMPjBFFHKvgUpv+ERNwqm2MKB/jH0K +ueNsbU3JM/R66CyyO/3POk7roApbxwtVxLCmVIc= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.txt new file mode 100644 index 0000000000..3a3e5c047c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/OCSPServer.txt @@ -0,0 +1,63 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecur +e@test.insecure + Validity + Not Before: Aug 17 08:31:37 2001 GMT + Not After : Aug 16 08:31:37 2006 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure Test OCSPServer Ce +rt/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a2:de:2b:60:37:c3:e5:df:06:8f:91:c4:40:c3: + 99:6a:77:ab:d1:d0:c8:d9:8b:26:3b:7b:64:1b:e3: + 2a:ec:2a:16:2e:d6:32:d1:2a:4f:fa:5b:05:cb:b6: + 9d:f6:18:27:02:e4:80:6b:e2:d2:d7:ad:06:68:11: + 17:e8:8e:98:d2:2c:1e:6d:ac:36:ce:63:b9:3e:f3: + f1:f0:07:26:d8:14:ac:cf:82:d9:a9:9c:fc:5c:fd: + c7:8a:5b:7a:af:a1:7f:a9:65:64:c5:4e:51:d2:54: + b7:46:c2:94:96:d9:31:22:d8:f9:75:44:fd:84:d8: + 00:a3:db:35:6d:1d:e4:e0:b1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication, OCSP No Check + X509v3 Subject Key Identifier: + F2:4B:EE:30:25:32:B1:25:32:27:CD:EB:F3:D8:E7:15:3B:E2:A3:5F + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=inse +cure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Server + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + a6:55:49:88:39:be:eb:b7:34:42:1b:ef:c1:a0:58:97:73:86: + e8:d4:54:02:a3:03:c0:18:94:00:8a:9d:ed:c9:62:42:1a:8b: + cb:a1:2f:08:8b:4c:b4:e8:62:1e:57:e1:7f:75:06:d7:4c:29: + b5:bd:da:b2:29:cf:62:99:e4:0e:35:e3:e7:e6:17:43:52:cb: + 1d:e7:22:dd:84:7c:7a:14:2c:12:f0:55:e2:70:7b:0c:e7:53: + cd:8f:2a:0b:52:28:1d:2e:ae:6d:f1:7f:63:93:e3:bf:04:37: + 67:99:ac:45:60:a1:13:af:28:54:1b:6e:1e:73:3f:cf:12:3a: + a6:a6:ca:0f:7a:c1:6a:55:c3:59:4c:ab:5a:c3:a9:27:3b:b8: + 84:95:fb:10:7e:11:33:5b:be:60:63:27:de:16:f3:54:1e:0a: + 24:df:bb:ed:a7:89:ac:6a:3b:65:00:e2:b5:11:e1:bd:29:c0: + f6:56:51:b0:05:77:d6:96:ef:7e:f5:e6:c2:88:51:3d:11:8e: + 6a:1c:06:19:c6:6d:d0:8c:3e:30:45:14:72:af:81:4a:6f:f8: + 44:4d:c2:a9:b6:30:a0:7f:8c:7d:0a:b9:e3:6c:6d:4d:c9:33: + f4:7a:e8:2c:b2:3b:fd:cf:3a:4e:eb:a0:0a:5b:c7:0b:55:c4: + b0:a6:54:87 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestClientCert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestClientCert.pem new file mode 100644 index 0000000000..ba72b8900c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestClientCert.pem @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 13149359243510447488 (0xb67be8904d707d80) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 31 15:14:28 2013 GMT + Not After : Jul 26 15:14:28 2033 GMT + Subject: C=US, ST=Kalifornia, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Client Certificate/emailAddress=client@test.example.com, L=QcaLand + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:c8:de:85:e7:c6:22:b7:9c:d3:75:15:dc:78:90: + 4f:c9:ea:dc:19:d1:fb:93:b7:56:4c:d1:19:cc:06: + a4:9c:b6:b7:a3:a5:e3:27:70:48:a1:3d:ca:c1:2e: + c8:58:88:ac:31:4f:59:f9:47:83:8a:83:c1:15:f2: + b9:cb:58:3f:15:3c:1d:5d:83:df:b0:3f:06:66:e4: + 35:96:c3:47:4b:ce:c5:8a:da:03:30:be:a7:0b:28: + 56:88:7a:b5:25:3b:5e:37:ec:57:02:69:9e:d5:ba: + c8:be:b6:71:5c:1e:c5:2c:d9:57:c7:fd:f2:ce:9a: + f8:08:68:bc:a2:6f:d6:b0:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + E-mail Protection, TLS Web Client Authentication + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 1E:60:4E:03:12:7D:28:7B:A4:04:27:A9:61:B4:28:A2:D0:9B:50:D1 + X509v3 Authority Key Identifier: + keyid:F6:1C:45:1D:E1:B0:45:81:38:C6:05:68:C1:A7:CB:0F:7A:DE:03:63 + + X509v3 Subject Alternative Name: + email:client@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Signature Algorithm: sha1WithRSAEncryption + 55:1e:ad:df:e4:b4:d6:43:2e:75:cd:b8:3b:07:06:62:c4:15: + 1f:f9:ac:61:a2:e7:35:66:a2:70:43:cb:2d:25:2d:10:16:6d: + 44:84:84:80:82:71:80:a3:ba:ca:9c:4d:f0:69:9b:11:0d:93: + 7b:69:e8:b9:e5:1f:b8:f1:63:32:0f:2b:0e:97:99:06:23:b3: + 8f:cb:5e:5c:5b:63:cf:e8:74:34:42:f5:50:32:4b:b0:6e:bb: + 70:fb:70:00:d3:04:2c:a9:28:c7:0b:9d:53:03:86:43:a4:8c: + 8e:27:a1:d8:eb:a6:f9:71:dc:3b:68:c9:c2:49:be:1a:56:41: + 19:85 +-----BEGIN CERTIFICATE----- +MIIEJDCCA42gAwIBAgIJALZ76JBNcH2AMA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECAwcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UECgwYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLDB5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMMGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMTMwNzMxMTUxNDI4WhcNMzMwNzI2MTUxNDI4WjCBzjELMAkG +A1UEBhMCVVMxEzARBgNVBAgMCkthbGlmb3JuaWExITAfBgNVBAoMGFFjYSBEZXZl +bG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECwweQ2VydGlmaWNhdGUgR2VuZXJhdGlv +biBTZWN0aW9uMSQwIgYDVQQDDBtRY2EgVGVzdCBDbGllbnQgQ2VydGlmaWNhdGUx +JjAkBgkqhkiG9w0BCQEWF2NsaWVudEB0ZXN0LmV4YW1wbGUuY29tMRAwDgYDVQQH +DAdRY2FMYW5kMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI3oXnxiK3nNN1 +Fdx4kE/J6twZ0fuTt1ZM0RnMBqSctrejpeMncEihPcrBLshYiKwxT1n5R4OKg8EV +8rnLWD8VPB1dg9+wPwZm5DWWw0dLzsWK2gMwvqcLKFaIerUlO1437FcCaZ7Vusi+ +tnFcHsUs2VfH/fLOmvgIaLyib9awEQIDAQABo4IBBjCCAQIwCQYDVR0TBAIwADAR +BglghkgBhvhCAQEEBAMCBaAwCwYDVR0PBAQDAgTwMB0GA1UdJQQWMBQGCCsGAQUF +BwMEBggrBgEFBQcDAjAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg +Q2VydGlmaWNhdGUwHQYDVR0OBBYEFB5gTgMSfSh7pAQnqWG0KKLQm1DRMB8GA1Ud +IwQYMBaAFPYcRR3hsEWBOMYFaMGnyw963gNjMCIGA1UdEQQbMBmBF2NsaWVudEB0 +ZXN0LmV4YW1wbGUuY29tMCQGA1UdEgQdMBuBGXRlc3Rvbmx5QHRlc3QuZXhhbXBs +ZS5jb20wDQYJKoZIhvcNAQEFBQADgYEAVR6t3+S01kMudc24OwcGYsQVH/msYaLn +NWaicEPLLSUtEBZtRISEgIJxgKO6ypxN8GmbEQ2Te2noueUfuPFjMg8rDpeZBiOz +j8teXFtjz+h0NEL1UDJLsG67cPtwANMELKkoxwudUwOGQ6SMjieh2Oum+XHcO2jJ +wkm+GlZBGYU= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestRootCert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestRootCert.pem new file mode 100644 index 0000000000..d9ca1cd682 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestRootCert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID3TCCA0agAwIBAgIJALZ76JBNcH1/MA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECAwcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UECgwYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLDB5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMMGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMTMwNzMxMTM0MDIwWhcNMzMwNzI2MTM0MDIwWjCBzjELMAkG +A1UEBhMCQVUxJTAjBgNVBAgMHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnkx +ITAfBgNVBAoMGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECwweQ2Vy +dGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDDBlRY2EgVGVzdCBS +b290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0LmV4 +YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVfdLTilBbqSM+ +APq0Mki4feTOcgpp7GmuuyA6xGT5gPlFuqGv0dKxcNBZQBFX5/j4padEq5Yk7nnH +QfoIFJi2eqW7WRNmzWIB8w/eju43QvA9quHfg75K3c65lO/GUzVFQPjw9CQ6Abi2 +MAaFpufqmYCKpbkTXJgOxK/fa6t82wIDAQABo4HAMIG9MA8GA1UdEwEB/wQFMAMB +Af8wCwYDVR0PBAQDAgHmMB0GA1UdDgQWBBT2HEUd4bBFgTjGBWjBp8sPet4DYzAf +BgNVHSMEGDAWgBT2HEUd4bBFgTjGBWjBp8sPet4DYzARBglghkgBhvhCAQEEBAMC +AQYwJAYDVR0RBB0wG4EZdGVzdG9ubHlAdGVzdC5leGFtcGxlLmNvbTAkBgNVHRIE +HTAbgRl0ZXN0b25seUB0ZXN0LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4GB +AKmYXyuCv2VfRjeQzy2RxbfAM9oF8bP1mkkM9SfkxZp7UHKlp3tH2HRGZ4SdR67b +DLH7Rb6zxAq//K8wrE5NTQqMRu6uIwkO1yM2+iawPE8soCDyISQeAQX7lQnRSJ94 +prpJmD4R+i9/RY7TlpvhI6TeYZcgt7QC5cDZIgd0rdtY +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestServerCert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestServerCert.pem new file mode 100644 index 0000000000..045d1277e2 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/QcaTestServerCert.pem @@ -0,0 +1,75 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 13149359243510447489 (0xb67be8904d707d81) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 31 15:23:25 2013 GMT + Not After : Jul 26 15:23:25 2033 GMT + Subject: C=IL, ST=Qca Province, O=Qca Development and Test, OU=Server Management Section, CN=Qca Server Test certificate/emailAddress=server@test.example.com, L=TLS City + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:aa:8a:7c:bd:45:52:83:ef:2b:51:51:a5:f1:ee: + ed:21:1c:2d:a5:5d:4b:af:fa:15:ed:b6:95:ba:59: + d5:d6:53:ab:b1:ee:98:41:fa:e2:30:cd:b6:e0:1e: + 60:35:e9:fc:63:16:18:5e:d9:9f:32:45:74:6a:b3: + a2:69:df:ea:88:4a:62:54:3b:8f:e8:76:de:9e:94: + 32:12:7e:67:08:a8:98:a1:3e:64:ab:6b:80:5b:be: + 51:69:6d:dd:77:80:f1:3c:9d:c9:06:ff:5d:5a:7f: + fd:06:14:db:32:29:cf:46:77:ef:3c:ae:43:d8:0e: + 90:93:df:85:74:bc:e3:bf:fd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 81:98:70:C8:B8:1E:AB:53:E7:2D:04:46:B6:57:90:AA:0D:3E:AB:1A + X509v3 Authority Key Identifier: + keyid:F6:1C:45:1D:E1:B0:45:81:38:C6:05:68:C1:A7:CB:0F:7A:DE:03:63 + + X509v3 Subject Alternative Name: + email:server@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Signature Algorithm: sha1WithRSAEncryption + 41:74:7c:68:71:03:0a:64:94:f2:80:9d:0c:31:3a:68:c4:12: + 7f:b1:6f:de:76:a5:b3:0d:07:f4:06:65:34:69:64:73:9d:66: + 7d:f5:49:87:df:77:46:77:41:96:73:48:a0:bd:9c:bd:74:ea: + 74:68:34:5f:80:03:3e:4c:d1:0b:5b:be:29:d4:43:75:8c:4b: + a2:bf:18:d0:41:60:2c:3c:76:a1:2d:75:76:22:b4:a5:8d:17: + 7a:43:e6:c0:95:23:7f:cd:ad:78:66:81:66:59:a8:06:c2:c1: + 22:19:da:98:8f:bc:f7:e6:cc:87:87:b4:a7:41:96:de:09:b1: + d9:bc +-----BEGIN CERTIFICATE----- +MIIEAzCCA2ygAwIBAgIJALZ76JBNcH2BMA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECAwcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UECgwYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLDB5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMMGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMTMwNzMxMTUyMzI1WhcNMzMwNzI2MTUyMzI1WjCBzDELMAkG +A1UEBhMCSUwxFTATBgNVBAgMDFFjYSBQcm92aW5jZTEhMB8GA1UECgwYUWNhIERl +dmVsb3BtZW50IGFuZCBUZXN0MSIwIAYDVQQLDBlTZXJ2ZXIgTWFuYWdlbWVudCBT +ZWN0aW9uMSQwIgYDVQQDDBtRY2EgU2VydmVyIFRlc3QgY2VydGlmaWNhdGUxJjAk +BgkqhkiG9w0BCQEWF3NlcnZlckB0ZXN0LmV4YW1wbGUuY29tMREwDwYDVQQHDAhU +TFMgQ2l0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqop8vUVSg+8rUVGl +8e7tIRwtpV1Lr/oV7baVulnV1lOrse6YQfriMM224B5gNen8YxYYXtmfMkV0arOi +ad/qiEpiVDuP6HbenpQyEn5nCKiYoT5kq2uAW75RaW3dd4DxPJ3JBv9dWn/9BhTb +MinPRnfvPK5D2A6Qk9+FdLzjv/0CAwEAAaOB6DCB5TAJBgNVHRMEAjAAMAsGA1Ud +DwQEAwIF4DATBgNVHSUEDDAKBggrBgEFBQcDATAsBglghkgBhvhCAQ0EHxYdT3Bl +blNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFIGYcMi4HqtT5y0E +RrZXkKoNPqsaMB8GA1UdIwQYMBaAFPYcRR3hsEWBOMYFaMGnyw963gNjMCIGA1Ud +EQQbMBmBF3NlcnZlckB0ZXN0LmV4YW1wbGUuY29tMCQGA1UdEgQdMBuBGXRlc3Rv +bmx5QHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADgYEAQXR8aHEDCmSU +8oCdDDE6aMQSf7Fv3nalsw0H9AZlNGlkc51mffVJh993RndBlnNIoL2cvXTqdGg0 +X4ADPkzRC1u+KdRDdYxLor8Y0EFgLDx2oS11diK0pY0XekPmwJUjf82teGaBZlmo +BsLBIhnamI+89+bMh4e0p0GW3gmx2bw= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/QualitySSLIntermediateCA.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/QualitySSLIntermediateCA.crt new file mode 100644 index 0000000000..961dfaa74e --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/QualitySSLIntermediateCA.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFKjCCBJOgAwIBAgIEAgACmjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJV +UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU +cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds +b2JhbCBSb290MB4XDTAyMDgyNzE5MDIwMFoXDTEyMDgyNzIzNTkwMFowgdwxCzAJ +BgNVBAYTAkdCMRcwFQYDVQQKEw5Db21vZG8gTGltaXRlZDEdMBsGA1UECxMUQ29t +b2RvIFRydXN0IE5ldHdvcmsxRjBEBgNVBAsTPVRlcm1zIGFuZCBDb25kaXRpb25z +IG9mIHVzZTogaHR0cDovL3d3dy5jb21vZG8ubmV0L3JlcG9zaXRvcnkxHzAdBgNV +BAsTFihjKTIwMDIgQ29tb2RvIExpbWl0ZWQxLDAqBgNVBAMTI0NvbW9kbyBDbGFz +cyAzIFNlY3VyaXR5IFNlcnZpY2VzIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA8gy2z4eE6gpxFFIt6FdcSVI6z8PwQm1i8v6m6T48eGQDDiB+a2tp +h4lUOAX02scFQAUYd378a4sOHKKCzKyFmznpy0tIGEhrKOTC0VuuA6l+mC9ME3Hf +sCkMTqqmNyY4udBEUoKQPnBI1nqbCQe8lOT0VSzytyq+HJEcaouDTTVsEOFz2iHZ +YtjxGbDx5yCNtZdHI0tqgTUbr0jgNqiQTE1M7PWIzsax0C//eZAB2FFk5y+xCI1d +z636soCWq6yLtUy0dMJHE+3oIzH0KrlhG73OpFs3Mb3lnJz7sg/XxTu/zFqrD8iG +QIkippAg07NsvhLz4yAsu8GuQ1raFnboHwIDAQABo4IB2TCCAdUwRQYDVR0fBD4w +PDA6oDigNoY0aHR0cDovL3d3dy5wdWJsaWMtdHJ1c3QuY29tL2NnaS1iaW4vQ1JM +LzIwMTgvY2RwLmNybDAdBgNVHQ4EFgQUNuDofG2dRZHumeVCdk1ws1AwrF4wgZIG +A1UdIASBijCBhzBJBgoqhkiG+GMBAgEFMDswOQYIKwYBBQUHAgEWLWh0dHA6Ly93 +d3cucHVibGljLXRydXN0LmNvbS9DUFMvT21uaVJvb3QuaHRtbDA6BgwrBgEEAbIx +AQIBAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9zZWN1cmUuY29tb2RvLm5ldC9D +UDCBiQYDVR0jBIGBMH+heaR3MHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg +Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywg +SW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3SCAgGlMCsG +A1UdEAQkMCKADzIwMDIwODI3MTkwMjI0WoEPMjAwOTA4MjcyMzU5MDBaMA4GA1Ud +DwEB/wQEAwIB5jAPBgNVHRMECDAGAQH/AgEAMA0GCSqGSIb3DQEBBQUAA4GBADoe +JG/a2zZs/jpzOd3NahxpoQAfb9Su1R/UiCmlIcJX9lV7MOfSZNYOxKpwPHZ04iqu +x0ZnMpLJS/Gn1+BWvPZyEJ1/sHXWnVe1cYWqxDqnS7jsD+bS+P+1zdRFJazqBqeK +tc0yIuQhkhvvzjSuMEQa7pt/8JQRhoqHGQEoOs+z +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/RAIZ2007_CERTIFICATE_AND_CRL_SIGNING_SHA256.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/RAIZ2007_CERTIFICATE_AND_CRL_SIGNING_SHA256.crt new file mode 100644 index 0000000000..71f9f88dd2 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/RAIZ2007_CERTIFICATE_AND_CRL_SIGNING_SHA256.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA.txt new file mode 100644 index 0000000000..60866bdcf0 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA.txt @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Validity + Not Before: Aug 17 08:30:39 2001 GMT + Not After : Aug 15 08:30:39 2011 GMT + Subject: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b2:45:99:89:0c:30:32:fa:c5:25:cb:4d:00:79: + 2f:85:a4:e3:e6:d3:08:6f:00:8a:88:42:95:9d:50: + 3d:56:af:40:bb:67:39:62:76:ac:e2:61:13:5a:7e: + bf:e6:29:dc:95:e2:2c:b5:a1:ea:f2:b4:6d:8d:ba: + b7:66:9c:04:06:71:54:ac:be:0a:b6:9e:ab:32:cf: + 2d:c4:14:64:a3:25:0e:2a:53:d5:d7:b0:86:a5:b3: + fd:bc:4f:9a:ed:23:f8:c2:0f:af:69:c2:13:3f:a9: + 93:29:60:aa:a8:5e:fc:d3:f2:d8:6e:af:72:54:c7: + 80:91:45:f3:29:00:7a:c0:66:5a:7f:ae:aa:2e:91: + f1:17:5b:dd:34:b6:13:6d:2f:6a:28:f6:2a:7e:05: + f7:f8:70:5d:cf:c0:f8:fe:e5:9c:1e:44:b6:e6:21: + 80:91:2f:f9:5c:94:05:71:3e:06:de:50:b5:b4:c8: + 3e:48:0f:a6:b8:b8:21:c8:72:8b:44:3b:14:c1:95: + 52:7b:9e:af:69:e7:94:76:01:32:37:73:37:3a:e3: + ba:78:f4:f4:95:af:65:a1:77:47:fe:74:4b:db:3b: + 39:1d:ed:af:61:be:66:27:7f:14:61:d0:4f:62:e0: + 4a:bf:f4:75:13:43:14:86:5c:8b:d1:20:f2:d2:1c: + fe:03 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 16:94:25:0c:4f:64:60:e7:03:2a:28:3b:68:ec:70:5a:19:f2: + e4:97:c2:14:08:38:4a:0b:ec:a4:57:9c:83:41:2c:09:14:e2: + 3b:db:14:c2:44:74:c4:ca:ef:f1:4c:30:4f:a7:37:d9:0a:a5: + 08:34:27:39:b1:a6:3e:81:e8:e4:76:70:22:7a:c6:39:46:63: + cb:0f:26:dd:f6:d0:c3:15:67:5a:d7:82:bd:b0:11:7a:00:f9: + c6:d2:d2:b8:a2:1a:cf:7b:05:d8:ad:5a:87:67:1a:cc:d6:54: + a4:12:bc:f5:29:36:ca:0f:d8:c1:2a:97:d1:f1:4e:6f:7b:74: + 93:8d:a3:fb:00:85:4d:91:50:80:c2:df:e5:2a:c9:7e:59:ab: + a2:ea:62:06:3e:79:49:e0:74:9a:99:01:6c:1c:10:ef:79:1d: + e7:2c:04:35:7a:52:0f:30:17:07:a3:7d:de:d7:27:2b:a3:da: + 36:47:02:70:54:13:f3:e0:fa:50:81:27:91:06:cd:9e:ef:3d: + 34:83:68:71:3b:09:b5:4c:f1:12:9d:ec:44:8f:7e:31:2b:08: + 10:7f:81:57:18:c4:2e:b5:c7:2b:5a:ab:63:5e:7a:00:9f:21: + ae:d3:f7:5c:93:21:fd:fe:37:94:07:48:e2:98:21:59:1b:21: + ae:19:75:f2 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA2cert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA2cert.pem new file mode 100644 index 0000000000..03a26d060b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCA2cert.pem @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIFATCCA+mgAwIBAgIBADANBgkqhkiG9w0BAQQFADB/MQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMTHkZvciBU +ZXN0cyBPbmx5IG5leHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1 +cmVAdGVzdC5pbnNlY3VyZTAeFw0wMjA2MjcxMjE2MzJaFw0xMjA2MjQxMjE2MzJa +MH8xCzAJBgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRlc3RDZXJ0aWZpY2F0 +ZTEnMCUGA1UEAxMeRm9yIFRlc3RzIE9ubHkgbmV4dCBnZW5lcmF0aW9uMSUwIwYJ +KoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEApU/ZjFU69b1kOa7R14gUA+fK4W2fiG5Rl7l1Y9Oa +ykDRQXOXzb2Jtqru0R8wdYHpKDDfJMnf0NkNbsMT9/EPztuEXhxgRM/V1+GxlZqR +w3B7vDg41wjBuq8/9xOfd8WqdeXID5/JSo/z0Q2v0ifBgCP60DbCFtPneIdElGSY +tCpNd2qG06CNJz5gvaHDIpQbjgQ2KiGSJStH+cYlwf24JdZgslXqo6JVg3/7SMHq +mY2A/MIFZRvUEwataZxtmOkba2AhwFesKq1V4DeIvH7VD29Ub0dB4O9r7LHTjxzG +j4nRrkNi6L4R4HN8q4CtxbJNaoMvFAuMKTIdiBDjEB5G7QIDAQABo4IBhjCCAYIw +DwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAeYwHQYDVR0OBBYEFI8IT5xTwVzI +5gzXEy7LUjwjlgIUMIGrBgNVHSMEgaMwgaCAFI8IT5xTwVzI5gzXEy7LUjwjlgIU +oYGEpIGBMH8xCzAJBgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRlc3RDZXJ0 +aWZpY2F0ZTEnMCUGA1UEAxMeRm9yIFRlc3RzIE9ubHkgbmV4dCBnZW5lcmF0aW9u +MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlggEAMCEGA1Ud +EQQaMBiBFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwIQYDVR0SBBowGIEWaW5zZWN1 +cmVAdGVzdC5pbnNlY3VyZTARBglghkgBhvhCAQEEBAMCAAcwPAYJYIZIAYb4QgEN +BC8WLVRoaXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBmb3IgdGVzdGluZyBvbmx5 +ITANBgkqhkiG9w0BAQQFAAOCAQEAKG4CjdQ60pskcVVS9batPkOr3HR+20jgxtaW +Cul+QmepJCZTj2XjmspLlw00ZVcjxTuxsBVKQoSPA0V7xrNU6GVYQtfnYWoQ1Lw+ +c2+J6XZ5iV58uyz4IJVgdq+kyXjopMiJV/cHqDX5fPeLT35L3UNZy8TdhHW+tj7X +sZelbK6kig9mzOBV2g0Pa86DwctHxL/eRDqX0+Mkvy9YAsBVhHDhVRWBpVMmQFMd +NbEiGRB0FEKTM+ztlb0QyBrhrjHI9a+P2Q5iap7HuiUrD7BRQ8YWEOUWI8jEdRaI +kC/K0U+WTB6e32XidjR7GCqFULLCE45of5JWJ/eV9gL5znhbEg== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.crt new file mode 100644 index 0000000000..71bc1f4360 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.pem new file mode 100644 index 0000000000..22ab6c013d --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/RootCAcert.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEzzCCA7egAwIBAgIBADANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4MzAzOVoXDTExMDgxNTA4MzAzOVowbzELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMRcwFQYDVQQDEw5Gb3Ig +VGVzdHMgT25seTElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVzdC5pbnNlY3Vy +ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJFmYkMMDL6xSXLTQB5 +L4Wk4+bTCG8AiohClZ1QPVavQLtnOWJ2rOJhE1p+v+Yp3JXiLLWh6vK0bY26t2ac +BAZxVKy+CraeqzLPLcQUZKMlDipT1dewhqWz/bxPmu0j+MIPr2nCEz+pkylgqqhe +/NPy2G6vclTHgJFF8ykAesBmWn+uqi6R8Rdb3TS2E20vaij2Kn4F9/hwXc/A+P7l +nB5EtuYhgJEv+VyUBXE+Bt5QtbTIPkgPpri4Ichyi0Q7FMGVUnuer2nnlHYBMjdz +Nzrjunj09JWvZaF3R/50S9s7OR3tr2G+Zid/FGHQT2LgSr/0dRNDFIZci9Eg8tIc +/gMCAwEAAaOCAXQwggFwMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G +A1UdDgQWBBS/U0OCeNCew4DlG2fKBQDfuUiDpTCBmQYDVR0jBIGRMIGOgBS/U0OC +eNCew4DlG2fKBQDfuUiDpaFzpHEwbzELMAkGA1UEBhMCZGUxIDAeBgNVBAoTF0lu +c2VjdXJlVGVzdENlcnRpZmljYXRlMRcwFQYDVQQDEw5Gb3IgVGVzdHMgT25seTEl +MCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVzdC5pbnNlY3VyZYIBADAhBgNVHREE +GjAYgRZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlMCEGA1UdEgQaMBiBFmluc2VjdXJl +QHRlc3QuaW5zZWN1cmUwEQYJYIZIAYb4QgEBBAQDAgAHMDwGCWCGSAGG+EIBDQQv +Fi1UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1ZWQgZm9yIHRlc3Rpbmcgb25seSEw +DQYJKoZIhvcNAQEEBQADggEBABaUJQxPZGDnAyooO2jscFoZ8uSXwhQIOEoL7KRX +nINBLAkU4jvbFMJEdMTK7/FMME+nN9kKpQg0Jzmxpj6B6OR2cCJ6xjlGY8sPJt32 +0MMVZ1rXgr2wEXoA+cbS0riiGs97BditWodnGszWVKQSvPUpNsoP2MEql9HxTm97 +dJONo/sAhU2RUIDC3+UqyX5Zq6LqYgY+eUngdJqZAWwcEO95HecsBDV6Ug8wFwej +fd7XJyuj2jZHAnBUE/Pg+lCBJ5EGzZ7vPTSDaHE7CbVM8RKd7ESPfjErCBB/gVcY +xC61xytaq2NeegCfIa7T91yTIf3+N5QHSOKYIVkbIa4ZdfI= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.crt new file mode 100644 index 0000000000..5e1220ad6d Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.p12 b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.p12 new file mode 100644 index 0000000000..52f2d558d8 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.pem new file mode 100644 index 0000000000..b2acc08e3e --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEVTCCAz2gAwIBAgIBBDANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4NDYyNFoXDTA2MDgxNjA4NDYyNFowdTELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMR0wGwYDVQQDExRJbnNl +Y3VyZSBTZXJ2ZXIgQ2VydDElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVzdC5p +bnNlY3VyZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1b8Mn6p8N+N6rxIk +ieA2g4xTUuK/U4Pu6JyGfl+8Jcb56oYhrAb/85S4Pje05wV++CezIot0uqXZqoAP +it2hcoQ07nSD34Lq7qYTa8LrtxJWrJIHRBSQCWuii1iM2tjoki93Sx80mlIYj0cR +Ku5AbQatySDWtbozUarWpB0VOwUCAwEAAaOCAXgwggF0MAsGA1UdDwQEAwIDqDAT +BgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUAjTiyQb24LRCU74EwMungjpt +tQkwgZkGA1UdIwSBkTCBjoAUv1NDgnjQnsOA5RtnygUA37lIg6Whc6RxMG8xCzAJ +BgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRlc3RDZXJ0aWZpY2F0ZTEXMBUG +A1UEAxMORm9yIFRlc3RzIE9ubHkxJTAjBgkqhkiG9w0BCQEWFmluc2VjdXJlQHRl +c3QuaW5zZWN1cmWCAQAwIQYDVR0RBBowGIEWaW5zZWN1cmVAdGVzdC5pbnNlY3Vy +ZTAhBgNVHRIEGjAYgRZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlMBEGCWCGSAGG+EIB +AQQEAwIGQDA8BglghkgBhvhCAQ0ELxYtVGhpcyBjZXJ0aWZpY2F0ZSB3YXMgaXNz +dWVkIGZvciB0ZXN0aW5nIG9ubHkhMA0GCSqGSIb3DQEBBAUAA4IBAQBD54lkQ7f/ +tNV53P7xVm3juHHZvez2fBsBf/pvQRkvqPgSgm5TBfX/TyZe/UcfQ9LPZhZHbs7u +udmiuf/zKvbswwGyC5kMZN5l3ZvWag4NQZEraAWcbZTmMkAlurw7i4DfhDbfys70 +OpGKBlWmcw+7oT7woSGX3clS02E/EFbA+g7nF8vx3vLTCbdTj5ZD+xLCV462AHfL +Zyfgdwnihdlo5+V1qUJU6oEszDopNsYyLdAVPYnSaqyG7EtBLTrQMUHDf8vTqB16 +XBpr3+U5RBki8G12LwfZ5rSM5l9A50DST9Qp3+On1J6vkAH4dlUPaaHBPxhSEz9k +9H+4GzzMaogS +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.txt new file mode 100644 index 0000000000..ac820ce638 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Server.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4 (0x4) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Validity + Not Before: Aug 17 08:46:24 2001 GMT + Not After : Aug 16 08:46:24 2006 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure Server Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:d5:bf:0c:9f:aa:7c:37:e3:7a:af:12:24:89:e0: + 36:83:8c:53:52:e2:bf:53:83:ee:e8:9c:86:7e:5f: + bc:25:c6:f9:ea:86:21:ac:06:ff:f3:94:b8:3e:37: + b4:e7:05:7e:f8:27:b3:22:8b:74:ba:a5:d9:aa:80: + 0f:8a:dd:a1:72:84:34:ee:74:83:df:82:ea:ee:a6: + 13:6b:c2:eb:b7:12:56:ac:92:07:44:14:90:09:6b: + a2:8b:58:8c:da:d8:e8:92:2f:77:4b:1f:34:9a:52: + 18:8f:47:11:2a:ee:40:6d:06:ad:c9:20:d6:b5:ba: + 33:51:aa:d6:a4:1d:15:3b:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Key Identifier: + 02:34:E2:C9:06:F6:E0:B4:42:53:BE:04:C0:CB:A7:82:3A:6D:B5:09 + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Server + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 43:e7:89:64:43:b7:ff:b4:d5:79:dc:fe:f1:56:6d:e3:b8:71: + d9:bd:ec:f6:7c:1b:01:7f:fa:6f:41:19:2f:a8:f8:12:82:6e: + 53:05:f5:ff:4f:26:5e:fd:47:1f:43:d2:cf:66:16:47:6e:ce: + ee:b9:d9:a2:b9:ff:f3:2a:f6:ec:c3:01:b2:0b:99:0c:64:de: + 65:dd:9b:d6:6a:0e:0d:41:91:2b:68:05:9c:6d:94:e6:32:40: + 25:ba:bc:3b:8b:80:df:84:36:df:ca:ce:f4:3a:91:8a:06:55: + a6:73:0f:bb:a1:3e:f0:a1:21:97:dd:c9:52:d3:61:3f:10:56: + c0:fa:0e:e7:17:cb:f1:de:f2:d3:09:b7:53:8f:96:43:fb:12: + c2:57:8e:b6:00:77:cb:67:27:e0:77:09:e2:85:d9:68:e7:e5: + 75:a9:42:54:ea:81:2c:cc:3a:29:36:c6:32:2d:d0:15:3d:89: + d2:6a:ac:86:ec:4b:41:2d:3a:d0:31:41:c3:7f:cb:d3:a8:1d: + 7a:5c:1a:6b:df:e5:39:44:19:22:f0:6d:76:2f:07:d9:e6:b4: + 8c:e6:5f:40:e7:40:d2:4f:d4:29:df:e3:a7:d4:9e:af:90:01: + f8:76:55:0f:69:a1:c1:3f:18:52:13:3f:64:f4:7f:b8:1b:3c: + cc:6a:88:12 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverkey.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverkey.pem new file mode 100644 index 0000000000..c901d087b6 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDVvwyfqnw343qvEiSJ4DaDjFNS4r9Tg+7onIZ+X7wlxvnqhiGs +Bv/zlLg+N7TnBX74J7Mii3S6pdmqgA+K3aFyhDTudIPfguruphNrwuu3ElaskgdE +FJAJa6KLWIza2OiSL3dLHzSaUhiPRxEq7kBtBq3JINa1ujNRqtakHRU7BQIDAQAB +AoGAB9CASaYV/IUYiyYCp/fGhnCu6yzXCdqc9WwjjqM5Ybgwkt5shLmMyf757Wxj +9L5CshfheLXYgqplltIvv0fzCweeQCLFKrFVSdxI8N01VAdVGmAZvqUSBfChkkag +lhMJ3bEqmsr2G1WsPJQXUuA+audFm4MC0ki6shNh+s39twECQQD5vovoKWL4Ib08 +PSKBq2N/i1XZlhlu1b1QXmNjlk2ar3B/+sdv0Hbw3sKDeZpoKsybfoPyea45faX5 +eaiZ3yF1AkEA2xmrhWBQQUdbIOIhR21/GHFoHUpovnG/pIHQwBb1IuCWCTRKrSh8 +ub0xKb7+aAedPxwrC38UzK2tm4+bWvtxUQJALRLKxVfS2N2d/aU6+RQpnPdUwzRn +2q0QwdSHM44I64YGU9K689832Dkb+gaUa4Bt9RJcVgLIAvA+aEwgtcSjkQJAdgiM +OJw8YA5672ojF4HLmHVv62esqfxJi+xLc1Bq21E2Qtsi58oJ914O4Dh+gbioY9le +7yCVKfbeshFZVlhjIQJBALvRAEi256ZCKfA91IqurT/kvJa6M2KC8Y6vj9OMY+cP +UZZSFM/pZRBoL+eh0HGILDlDCrObyA7bU2a4imvTsw8= +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.crt new file mode 100644 index 0000000000..25fe989d01 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.p12 b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.p12 new file mode 100644 index 0000000000..ef7b83bcb0 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.pem new file mode 100644 index 0000000000..663d084735 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrev.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEXTCCA0WgAwIBAgIBBTANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4NDcwMloXDTA2MDgxNjA4NDcwMlowfTELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMSUwIwYDVQQDExxJbnNl +Y3VyZSBTZXJ2ZXIgQ2VydCByZXZva2VkMSUwIwYJKoZIhvcNAQkBFhZpbnNlY3Vy +ZUB0ZXN0Lmluc2VjdXJlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJOp6M +tXs2lajdgmS9j+rVCGI5SehsOVOovm7MeWD+777+MYk7t0lBrfDYFRUYMxJomlfI ++Lx/vJdFNdXEyoyC+7UUnv+pmOv5QhbCEkL21Fz0Nqy834cAy39M/uPkJTbo2U3X +k92alVLSsw5La9Dbnj3wN4Xa8c2bnUrg+LNWJwIDAQABo4IBeDCCAXQwCwYDVR0P +BAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBTxWO4/rkl8BTNv +Ewno1nb7qS/6jTCBmQYDVR0jBIGRMIGOgBS/U0OCeNCew4DlG2fKBQDfuUiDpaFz +pHEwbzELMAkGA1UEBhMCZGUxIDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmlj +YXRlMRcwFQYDVQQDEw5Gb3IgVGVzdHMgT25seTElMCMGCSqGSIb3DQEJARYWaW5z +ZWN1cmVAdGVzdC5pbnNlY3VyZYIBADAhBgNVHREEGjAYgRZpbnNlY3VyZUB0ZXN0 +Lmluc2VjdXJlMCEGA1UdEgQaMBiBFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwEQYJ +YIZIAYb4QgEBBAQDAgZAMDwGCWCGSAGG+EIBDQQvFi1UaGlzIGNlcnRpZmljYXRl +IHdhcyBpc3N1ZWQgZm9yIHRlc3Rpbmcgb25seSEwDQYJKoZIhvcNAQEEBQADggEB +AGqiwh7B17OigTMvi1wzmRxhaB8lWUcwruVzjjjBL9g6flRey1n9IZjE1jnfAtwe +j3ciMD9fCTSlw5XdOBQ3WItwHnk4oZ5pc4zObZfWrmATshTZKNnvQEVUOvcEEngu +m5uyq3H5lGAHEpGVr6xf5e45L3KYYj7K/CrkSz9h9cmBhLCqnQfVzq1cXTSYon+0 +opRNqoQnm+UeOIi5TOSKzUiuXDkmxSZy9PntGSW/21cTz7ariuCuDdRT1OY94wI8 +yO1oxhOoGT9jdVLFD1zjFZCwybI+vkXFXn67dlWB0pPwnp8BAm03NMTrGZl55nfr +s3NMp2KqAx837lP1yHEfU5s= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrevkey.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrevkey.pem new file mode 100644 index 0000000000..402ea8f6a2 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Serverrevkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDJOp6MtXs2lajdgmS9j+rVCGI5SehsOVOovm7MeWD+777+MYk7 +t0lBrfDYFRUYMxJomlfI+Lx/vJdFNdXEyoyC+7UUnv+pmOv5QhbCEkL21Fz0Nqy8 +34cAy39M/uPkJTbo2U3Xk92alVLSsw5La9Dbnj3wN4Xa8c2bnUrg+LNWJwIDAQAB +AoGAXg3wHYSV2qWJED/qJlAmSvxoLK7G3A7Pc4fO8fOpyn70nos4wZihvPk4IUd5 +XJ5CdHHvphfcwze63LaU/C5QDfNO5uHCOjLWc/jxCPxQ7DRJkAQXUfZc56rBOsei +JQ+jgjqzMEfVtgOXuz7hOqvyN+IZ21qmWitoP7bbjJ9ME0ECQQD+2yt/7xxwirPc +XJAO8gcpWu0pF3u7pLYWD6modFKFa1Z8TGHiu4EePNBut39i3ym2U7YWJkoh4M/C +F+Rh1H9LAkEAyiHU7LYPJ5J9GGW8xA1ns6a669M/jhBwwP68M6De9tb9JprOuMWV +8bkE0bTrnZiKfYduk42GGaY8Hl1HYT6PFQJAFXZBiImLXJLhqKoG26tYHQxyMmau +3dN2Hg99mxkIpgGvC9Km36AotHIsn1ZGnP3sFlWgXOcmkQnMlSzL580sVwJAOlN+ +3HtAbjvQCx04Vh5EIUvoPipr+XN3Bcm7xu4RyIqK6/vZ0Ol69hBceqLJJmWg+M3+ +s2cwHfChAmYKNd5WbQJBAMfbNRhKGXK/M6bbKD92FMhpjEMaY4++WmqQ+yCGjLGD +OiSYAsHiDtcgtHhTvPp8ULzcsbbgbMiECTwh7h6Gw4c= +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Severrev.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Severrev.txt new file mode 100644 index 0000000000..f4aef0de5b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Severrev.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Validity + Not Before: Aug 17 08:47:02 2001 GMT + Not After : Aug 16 08:47:02 2006 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure Server Cert revoked/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c9:3a:9e:8c:b5:7b:36:95:a8:dd:82:64:bd:8f: + ea:d5:08:62:39:49:e8:6c:39:53:a8:be:6e:cc:79: + 60:fe:ef:be:fe:31:89:3b:b7:49:41:ad:f0:d8:15: + 15:18:33:12:68:9a:57:c8:f8:bc:7f:bc:97:45:35: + d5:c4:ca:8c:82:fb:b5:14:9e:ff:a9:98:eb:f9:42: + 16:c2:12:42:f6:d4:5c:f4:36:ac:bc:df:87:00:cb: + 7f:4c:fe:e3:e4:25:36:e8:d9:4d:d7:93:dd:9a:95: + 52:d2:b3:0e:4b:6b:d0:db:9e:3d:f0:37:85:da:f1: + cd:9b:9d:4a:e0:f8:b3:56:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Key Identifier: + F1:58:EE:3F:AE:49:7C:05:33:6F:13:09:E8:D6:76:FB:A9:2F:FA:8D + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Server + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 6a:a2:c2:1e:c1:d7:b3:a2:81:33:2f:8b:5c:33:99:1c:61:68: + 1f:25:59:47:30:ae:e5:73:8e:38:c1:2f:d8:3a:7e:54:5e:cb: + 59:fd:21:98:c4:d6:39:df:02:dc:1e:8f:77:22:30:3f:5f:09: + 34:a5:c3:95:dd:38:14:37:58:8b:70:1e:79:38:a1:9e:69:73: + 8c:ce:6d:97:d6:ae:60:13:b2:14:d9:28:d9:ef:40:45:54:3a: + f7:04:12:78:2e:9b:9b:b2:ab:71:f9:94:60:07:12:91:95:af: + ac:5f:e5:ee:39:2f:72:98:62:3e:ca:fc:2a:e4:4b:3f:61:f5: + c9:81:84:b0:aa:9d:07:d5:ce:ad:5c:5d:34:98:a2:7f:b4:a2: + 94:4d:aa:84:27:9b:e5:1e:38:88:b9:4c:e4:8a:cd:48:ae:5c: + 39:26:c5:26:72:f4:f9:ed:19:25:bf:db:57:13:cf:b6:ab:8a: + e0:ae:0d:d4:53:d4:e6:3d:e3:02:3c:c8:ed:68:c6:13:a8:19: + 3f:63:75:52:c5:0f:5c:e3:15:90:b0:c9:b2:3e:be:45:c5:5e: + 7e:bb:76:55:81:d2:93:f0:9e:9f:01:02:6d:37:34:c4:eb:19: + 99:79:e6:77:eb:b3:73:4c:a7:62:aa:03:1f:37:ee:53:f5:c8: + 71:1f:53:9b diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Test_CRL.crl b/local/recipes/libs/qca/source/unittest/certunittest/certs/Test_CRL.crl new file mode 100644 index 0000000000..6a4ed3f1a1 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Test_CRL.crl @@ -0,0 +1,13 @@ +-----BEGIN X509 CRL----- +MIIB3zCByDANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEgMB4GA1UEChMX +SW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBUZXN0cyBPbmx5 +MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlFw0wMTA4MTcx +MTEyMDNaFw0wNjA4MTYxMTEyMDNaMCgwEgIBAxcNMDEwODE3MTExMDM5WjASAgEF +Fw0wMTA4MTcxMTExNTlaMA0GCSqGSIb3DQEBBAUAA4IBAQB47lMVCKlPoBAgLway +76eNRq1749jt/7g/Ouh06isNM66/CgzVL2xKSC3s2FX4xKg320niWI6Dvm4H3M6I +7RvuoCvZBVpu1MA8z2No89g2UPWlSxUAvuvo2GOGRgo+8nc/84g8biLUxTSF8Vs4 +T1Hngo1qrfePM4ou1uu7LhRnR8tuIVoQT6W3RSlEsQRBRM3y+VkOPAf0GBGyl6WG +WiymXHqsqis80WbX50tr859Cltqbu2yaFAX++IEBBDB7JoVi1blumgarqfXYkoUW +n9d3F8qySNjsfhOV613fXpmfXFZ33uTFsLSoihP8f6+Cusx2rfuGap7jOPv7j7sj +l2Y1 +-----END X509 CRL----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/User.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.crt new file mode 100644 index 0000000000..326afaa4f9 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/User.p12 b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.p12 new file mode 100644 index 0000000000..bb53a3d1a6 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/User.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.pem new file mode 100644 index 0000000000..3e724697a7 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEYjCCA0qgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4MzIzOFoXDTA2MDgxNjA4MzIzOFoweDELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMSAwHgYDVQQDExdJbnNl +Y3VyZSBVc2VyIFRlc3QgQ2VydDElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVz +dC5pbnNlY3VyZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArCM8+V7VH46Y ++bMtgOaqFc8vCSBpSeL5hnHN3uwEH8/OqwKaO9hMP15lFpzEJOIPMVtOSLCg4dJy ++eS3azL3/B+4qDVqbCgKSXDMKhBDKKw0TvfhN4tgfmvy0rpgMHYApfyRdewnvKgV +YkI+sDwupmZJo87kuvPM2JzbV/DNAyMCAwEAAaOCAYIwggF+MAsGA1UdDwQEAwIE +8DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFIiefvcp +cZ17KA82Gq5tANOd4arbMIGZBgNVHSMEgZEwgY6AFL9TQ4J40J7DgOUbZ8oFAN+5 +SIOloXOkcTBvMQswCQYDVQQGEwJkZTEgMB4GA1UEChMXSW5zZWN1cmVUZXN0Q2Vy +dGlmaWNhdGUxFzAVBgNVBAMTDkZvciBUZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkB +FhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlggEAMCEGA1UdEQQaMBiBFmluc2VjdXJl +QHRlc3QuaW5zZWN1cmUwIQYDVR0SBBowGIEWaW5zZWN1cmVAdGVzdC5pbnNlY3Vy +ZTARBglghkgBhvhCAQEEBAMCBaAwPAYJYIZIAYb4QgENBC8WLVRoaXMgY2VydGlm +aWNhdGUgd2FzIGlzc3VlZCBmb3IgdGVzdGluZyBvbmx5ITANBgkqhkiG9w0BAQQF +AAOCAQEAeRBEcR/xp4pLH3VbQmTbZEGjVEBDxNAapsdIDrKB1ecA3JMhZDjweKc4 +MG5M+FQ5hcCT8kSi+6bL15BJRyyMB4727NRSC1i/2VkZmUGhhk3AR9UjsvrCC00D +gPuHdQPrIxl9+CK26ypATizb5VapzmoBc2B/dWeVh+KJbEkgTudfFj98Dqn8kiUn +bqbC3OMPa1uiez8oer8h6OAyOinmx0atjTqS5SOLI+2+p1lpMHMhodn4jgmd8Pms +KQ0jMyA0ZQ1tozQXOw9VpRYegsm8LMq0emdfybxpwGbrCIIk7BXjBIDrhYbnb3GK +blykzt4bqOeDtJuTgyBOS3Ldxqgfzg== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/User.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.txt new file mode 100644 index 0000000000..3a3069c6ae --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/User.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Validity + Not Before: Aug 17 08:32:38 2001 GMT + Not After : Aug 16 08:32:38 2006 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure User Test Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:ac:23:3c:f9:5e:d5:1f:8e:98:f9:b3:2d:80:e6: + aa:15:cf:2f:09:20:69:49:e2:f9:86:71:cd:de:ec: + 04:1f:cf:ce:ab:02:9a:3b:d8:4c:3f:5e:65:16:9c: + c4:24:e2:0f:31:5b:4e:48:b0:a0:e1:d2:72:f9:e4: + b7:6b:32:f7:fc:1f:b8:a8:35:6a:6c:28:0a:49:70: + cc:2a:10:43:28:ac:34:4e:f7:e1:37:8b:60:7e:6b: + f2:d2:ba:60:30:76:00:a5:fc:91:75:ec:27:bc:a8: + 15:62:42:3e:b0:3c:2e:a6:66:49:a3:ce:e4:ba:f3: + cc:d8:9c:db:57:f0:cd:03:23 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 88:9E:7E:F7:29:71:9D:7B:28:0F:36:1A:AE:6D:00:D3:9D:E1:AA:DB + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 79:10:44:71:1f:f1:a7:8a:4b:1f:75:5b:42:64:db:64:41:a3: + 54:40:43:c4:d0:1a:a6:c7:48:0e:b2:81:d5:e7:00:dc:93:21: + 64:38:f0:78:a7:38:30:6e:4c:f8:54:39:85:c0:93:f2:44:a2: + fb:a6:cb:d7:90:49:47:2c:8c:07:8e:f6:ec:d4:52:0b:58:bf: + d9:59:19:99:41:a1:86:4d:c0:47:d5:23:b2:fa:c2:0b:4d:03: + 80:fb:87:75:03:eb:23:19:7d:f8:22:b6:eb:2a:40:4e:2c:db: + e5:56:a9:ce:6a:01:73:60:7f:75:67:95:87:e2:89:6c:49:20: + 4e:e7:5f:16:3f:7c:0e:a9:fc:92:25:27:6e:a6:c2:dc:e3:0f: + 6b:5b:a2:7b:3f:28:7a:bf:21:e8:e0:32:3a:29:e6:c7:46:ad: + 8d:3a:92:e5:23:8b:23:ed:be:a7:59:69:30:73:21:a1:d9:f8: + 8e:09:9d:f0:f9:ac:29:0d:23:33:20:34:65:0d:6d:a3:34:17: + 3b:0f:55:a5:16:1e:82:c9:bc:2c:ca:b4:7a:67:5f:c9:bc:69: + c0:66:eb:08:82:24:ec:15:e3:04:80:eb:85:86:e7:6f:71:8a: + 6e:5c:a4:ce:de:1b:a8:e7:83:b4:9b:93:83:20:4e:4b:72:dd: + c6:a8:1f:ce diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userkey.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userkey.pem new file mode 100644 index 0000000000..81731a284c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCsIzz5XtUfjpj5sy2A5qoVzy8JIGlJ4vmGcc3e7AQfz86rApo7 +2Ew/XmUWnMQk4g8xW05IsKDh0nL55LdrMvf8H7ioNWpsKApJcMwqEEMorDRO9+E3 +i2B+a/LSumAwdgCl/JF17Ce8qBViQj6wPC6mZkmjzuS688zYnNtX8M0DIwIDAQAB +AoGAUmPrY1BIofoWri1csj21Wwr3cF7bBkplNDx0VSaSMse8G437VHmKxSnhKJmQ +KDcrHmydY51m469e6MzYHa8fkfwFiqRhBE7rSw9n0K1sqzU6fJYXgpxdV+GOQcKw +v+Lu+o6ej4BGQ7woJZXOiC3GDiWu3rC91UNC9eC74yCGuAECQQDhd36m/M9Bjw+C +pNi55oFGdOCaiL+OT9I3Gt2+7MIo4d2YGvhl8Nr3PC6bEq1DzoWiaE+qxE3JFZdp +J2+F0fCjAkEAw3LsfrqVZH5HW57csAapmhA+oiCTP3cDDObQ3pKNi3sfYKq8u+aK +93XAbw3+sPaWlQbVnQF+2fNxOZB9TqFLgQJALVw+Fdhs1hKzGySRGa1/Oq6O9Wgn +qbjzYPS9wgid812lmFFswg2X7/+inL5AL5EgH5F+3atKvvbiFFzDuheHowJAHwiS +cJTjv68lWXDiDbkhGOtXZprRhpQ5EcVciNqwSuNj2g+CJDu4+Q3jXj7Un/indEY/ +iMyB/c1fvwooO2H1AQJAEmlUKcfUMdMKbsnqcBfUcge3POdb06pXDpZ/+X0g2OBE +1fTIQgPgP6y+Ucp/WCW6l2pEJtt26KI5kEp31WSbHA== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.crt new file mode 100644 index 0000000000..b861e16e79 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.p12 b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.p12 new file mode 100644 index 0000000000..77b69e5c2f Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.pem new file mode 100644 index 0000000000..c81fe5d86b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEZTCCA02gAwIBAgIBAzANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBU +ZXN0cyBPbmx5MSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MB4XDTAxMDgxNzA4MzYzOFoXDTA2MDgxNjA4MzYzOFowezELMAkGA1UEBhMCZGUx +IDAeBgNVBAoTF0luc2VjdXJlVGVzdENlcnRpZmljYXRlMSMwIQYDVQQDExpJbnNl +Y3VyZSByZXZva2VkIHVzZXIgY2VydDElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVA +dGVzdC5pbnNlY3VyZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAs/qGIhsu +mDnsw4E2G6tTUvQ3sCjxInaw4P06LB8Yhnu6zP4D0PltKN2CIDUVefJjXTFcMBRt +54UZ+d398XhHK1qAI4F+m4ynkjoc0KRRgw8M50qNyy42MBY7z3dfF+aMQ7RNddwT +v2pV30zqjYR9D213MKn6phcU1dFCMYYJUXcCAwEAAaOCAYIwggF+MAsGA1UdDwQE +AwIE8DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFBw0 +A/ujVFIdP4lqGXN2TpQbGyiiMIGZBgNVHSMEgZEwgY6AFL9TQ4J40J7DgOUbZ8oF +AN+5SIOloXOkcTBvMQswCQYDVQQGEwJkZTEgMB4GA1UEChMXSW5zZWN1cmVUZXN0 +Q2VydGlmaWNhdGUxFzAVBgNVBAMTDkZvciBUZXN0cyBPbmx5MSUwIwYJKoZIhvcN +AQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlggEAMCEGA1UdEQQaMBiBFmluc2Vj +dXJlQHRlc3QuaW5zZWN1cmUwIQYDVR0SBBowGIEWaW5zZWN1cmVAdGVzdC5pbnNl +Y3VyZTARBglghkgBhvhCAQEEBAMCBaAwPAYJYIZIAYb4QgENBC8WLVRoaXMgY2Vy +dGlmaWNhdGUgd2FzIGlzc3VlZCBmb3IgdGVzdGluZyBvbmx5ITANBgkqhkiG9w0B +AQQFAAOCAQEAEMLedo94+L7jVQT3KytdhDOaQDrVVd+rMEsHmvqobBNfyJ7ZrXQf +3DerytOzckyrbw49E5mmr2iLVg1Pjsn1eimoe0bzv2uDsstLiEGGktji2b4u60QB +wwYJZGqUbKjSX0Rao38RkKKd2YjQquvPMD+IE/gdG3Cg1c3XrR9qv0drulesMzYS +yOvSbDhaOkc5QFGEM6oYo9WgbVEKFMufCXAdxQlJkm2VOEgs0azN9aa71X8ul3tN +d9Vcp3URcPwNcrrnCgMsP1kLHFaIVilXTA4iEkHmqhxGtAcT2C7o2fPiLSCur06k +X5iC9aE0S42ZW/MH03L98Qu1YWhdQHFdLA== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.txt new file mode 100644 index 0000000000..61a8e74791 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrev.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only/Email=insecure@test.insecure + Validity + Not Before: Aug 17 08:36:38 2001 GMT + Not After : Aug 16 08:36:38 2006 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure revoked user cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b3:fa:86:22:1b:2e:98:39:ec:c3:81:36:1b:ab: + 53:52:f4:37:b0:28:f1:22:76:b0:e0:fd:3a:2c:1f: + 18:86:7b:ba:cc:fe:03:d0:f9:6d:28:dd:82:20:35: + 15:79:f2:63:5d:31:5c:30:14:6d:e7:85:19:f9:dd: + fd:f1:78:47:2b:5a:80:23:81:7e:9b:8c:a7:92:3a: + 1c:d0:a4:51:83:0f:0c:e7:4a:8d:cb:2e:36:30:16: + 3b:cf:77:5f:17:e6:8c:43:b4:4d:75:dc:13:bf:6a: + 55:df:4c:ea:8d:84:7d:0f:6d:77:30:a9:fa:a6:17: + 14:d5:d1:42:31:86:09:51:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 1C:34:03:FB:A3:54:52:1D:3F:89:6A:19:73:76:4E:94:1B:1B:28:A2 + X509v3 Authority Key Identifier: + keyid:BF:53:43:82:78:D0:9E:C3:80:E5:1B:67:CA:05:00:DF:B9:48:83:A5 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 10:c2:de:76:8f:78:f8:be:e3:55:04:f7:2b:2b:5d:84:33:9a: + 40:3a:d5:55:df:ab:30:4b:07:9a:fa:a8:6c:13:5f:c8:9e:d9: + ad:74:1f:dc:37:ab:ca:d3:b3:72:4c:ab:6f:0e:3d:13:99:a6: + af:68:8b:56:0d:4f:8e:c9:f5:7a:29:a8:7b:46:f3:bf:6b:83: + b2:cb:4b:88:41:86:92:d8:e2:d9:be:2e:eb:44:01:c3:06:09: + 64:6a:94:6c:a8:d2:5f:44:5a:a3:7f:11:90:a2:9d:d9:88:d0: + aa:eb:cf:30:3f:88:13:f8:1d:1b:70:a0:d5:cd:d7:ad:1f:6a: + bf:47:6b:ba:57:ac:33:36:12:c8:eb:d2:6c:38:5a:3a:47:39: + 40:51:84:33:aa:18:a3:d5:a0:6d:51:0a:14:cb:9f:09:70:1d: + c5:09:49:92:6d:95:38:48:2c:d1:ac:cd:f5:a6:bb:d5:7f:2e: + 97:7b:4d:77:d5:5c:a7:75:11:70:fc:0d:72:ba:e7:0a:03:2c: + 3f:59:0b:1c:56:88:56:29:57:4c:0e:22:12:41:e6:aa:1c:46: + b4:07:13:d8:2e:e8:d9:f3:e2:2d:20:ae:af:4e:a4:5f:98:82: + f5:a1:34:4b:8d:99:5b:f3:07:d3:72:fd:f1:0b:b5:61:68:5d: + 40:71:5d:2c diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrevkey.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrevkey.pem new file mode 100644 index 0000000000..ddd31f1e12 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/Userrevkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQCz+oYiGy6YOezDgTYbq1NS9DewKPEidrDg/TosHxiGe7rM/gPQ ++W0o3YIgNRV58mNdMVwwFG3nhRn53f3xeEcrWoAjgX6bjKeSOhzQpFGDDwznSo3L +LjYwFjvPd18X5oxDtE113BO/alXfTOqNhH0PbXcwqfqmFxTV0UIxhglRdwIDAQAB +AoGBAKum71EODbV/4XFhBeMD1teSNp6bncfZ3b7npRi5m6F/1lx2k9s2WMcV5Gql +VlNVOzGBx0PP6DZcuraV5AHuTijP49eremn2YMAOQHbVD1W9D0xiIIoXnjl3+94/ +6sQFSA3ZIJTDfSRCqDkZEqpIh3h753zbLPlOJu1QnLiMb6uJAkEA46Uh6jHWHdgY +Q52L5qcVtE9xTt0qt1WUAj91sY1MUDI90FW8Cy/HjGqPgRVPgl3GF/hG6lyWK0oZ +uIAj8dt+uwJBAMpldlQidgwbHhv2VFGUi3jv9GDCWQ9M9dieGqz5oD0PxJeq6oJX +CYQVLb1PiZwI1HAWzVR7yJYSmX+UaQOZ0nUCQQC3hGtX4n9LpebBs6OR+UbNCnI8 +8p06GRptyXz2+wL3b9lXN5aVqhoDf/BaTrS/UxucPUHmM2e4VE9x5pOTqbB7AkBb +o27dDzFVr92FGZX5zgEMQ9DpEnXSeK0DZCp90RRdMUt4xFkjpJbZZ+Fqyp1quZC+ +I4TaUKV0VX2Mhzy49aeVAkEAyEJCFOKDZhfrCsa+spUS1f2IAjno7KTOM/c6QaT5 +5QmQxVxBA/eq/78sXAsti4ECub6lVL2nffA8g7kDdkNJSA== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/altname.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/altname.pem new file mode 100644 index 0000000000..ca5e74f9ba --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/altname.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICzDCCAjWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEa +MBgGA1UEChMRVGVzdCBDZXJ0aWZpY2F0ZXMxIzAhBgNVBAMTGm5hbWVDb25zdHJh +aW50cyBSRkM4MjIgQ0ExMB4XDTAxMDQxOTE0NTcyMFoXDTExMDQxOTE0NTcyMFow +ZjELMAkGA1UEBhMCVVMxGjAYBgNVBAoTEVRlc3QgQ2VydGlmaWNhdGVzMTswOQYD +VQQDEzJWYWxpZCBSRkM4MjIgbmFtZUNvbnN0cmFpbnRzIEVFIENlcnRpZmljYXRl +IFRlc3QyMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmgblTsP6gle2uacP +DDJPff0VnqgTN1VtCh/uqZINqMtzbfcADz7KNpqETX64spwhD8/3m9yEVpJStgPq +o/mbcf/G2L3+zkx2t7mQLTy115q304S7KBauhK/aen56yKrHOuUv+qmOSYpqZKwi +ZbobiLq/CMbUfYx6zaM8Bd59VBsCAwEAAaOBoTCBnjAfBgNVHSMEGDAWgBTjf4V6 +jqI7nu64Eh15E6rEvS5ZrTAdBgNVHQ4EFgQUtCANQs2V6ofUY9VPDtbRD+W3O/sw +DgYDVR0PAQH/BAQDAgTwMBcGA1UdIAQQMA4wDAYKYIZIAWUDAgEwATAzBgNVHREE +LDAqgShUZXN0MjFFRUBtYWlsc2VydmVyLnRlc3RjZXJ0aWZpY2F0ZXMuZ292MA0G +CSqGSIb3DQEBBQUAA4GBAB1qFEM9zKmqItkLPuorp06yLsoL0xL3X+c4ym7JP034 +2kYhJ7SoZFmFbIRB6z472KWbJc17oM9LK6GOt08QBEIHhQk1pZrueBJDrCv8WmR3 +7FHwbkNcRn8DFYiV3//yjYP+bgN142Lj3O9SpuUy/a32bsupo0ykWADqwwY1ntmi +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/crl.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/crl.txt new file mode 100644 index 0000000000..2abe8bcbcf --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/crl.txt @@ -0,0 +1,27 @@ +Certificate Revocation List (CRL): + Version 1 (0x0) + Signature Algorithm: md5WithRSAEncryption + Issuer: /C=de/O=InsecureTestCertificate/CN=For Tests Only/Email=insecure@test.insecure + Last Update: Aug 17 11:12:03 2001 GMT + Next Update: Aug 16 11:12:03 2006 GMT +Revoked Certificates: + Serial Number: 03 + Revocation Date: Aug 17 11:10:39 2001 GMT + Serial Number: 05 + Revocation Date: Aug 17 11:11:59 2001 GMT + Signature Algorithm: md5WithRSAEncryption + 78:ee:53:15:08:a9:4f:a0:10:20:2f:06:b2:ef:a7:8d:46:ad: + 7b:e3:d8:ed:ff:b8:3f:3a:e8:74:ea:2b:0d:33:ae:bf:0a:0c: + d5:2f:6c:4a:48:2d:ec:d8:55:f8:c4:a8:37:db:49:e2:58:8e: + 83:be:6e:07:dc:ce:88:ed:1b:ee:a0:2b:d9:05:5a:6e:d4:c0: + 3c:cf:63:68:f3:d8:36:50:f5:a5:4b:15:00:be:eb:e8:d8:63: + 86:46:0a:3e:f2:77:3f:f3:88:3c:6e:22:d4:c5:34:85:f1:5b: + 38:4f:51:e7:82:8d:6a:ad:f7:8f:33:8a:2e:d6:eb:bb:2e:14: + 67:47:cb:6e:21:5a:10:4f:a5:b7:45:29:44:b1:04:41:44:cd: + f2:f9:59:0e:3c:07:f4:18:11:b2:97:a5:86:5a:2c:a6:5c:7a: + ac:aa:2b:3c:d1:66:d7:e7:4b:6b:f3:9f:42:96:da:9b:bb:6c: + 9a:14:05:fe:f8:81:01:04:30:7b:26:85:62:d5:b9:6e:9a:06: + ab:a9:f5:d8:92:85:16:9f:d7:77:17:ca:b2:48:d8:ec:7e:13: + 95:eb:5d:df:5e:99:9f:5c:56:77:de:e4:c5:b0:b4:a8:8a:13: + fc:7f:af:82:ba:cc:76:ad:fb:86:6a:9e:e3:38:fb:fb:8f:bb: + 23:97:66:35 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/csr1.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/csr1.pem new file mode 100644 index 0000000000..c4f07d940e --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/csr1.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIB3TCCAUYCAQAwgZwxCzAJBgNVBAYTAkFVMREwDwYDVQQIEw hWaWN0b3JpYTEQ +MA4GA1UEBxMHTWl0Y2hhbTEWMBQGA1UEChMNR0UgSW50ZXJsb2 dpeDEUMBIGA1UE +CxMLRW5naW5lZXJpbmcxETAPBgNVBAMTCGNvbGRmaXJlMScwJQ YJKoZIhvcNAQkB +FhhzdGV2ZW4ubWVycmlmaWVsZEBnZS5jb20wgZ8wDQYJKoZIhv cNAQEBBQADgY0A +MIGJAoGBAJVRAW+GFTHOWdvtZvh+QZV8S0s5Oun9xk9OIosS0W P45v2eHHf6fnVx +MSTDH2jVC//Z7le1awLx9JSFJyBcueDFrunFmsygkxd+FiWmuh tB53gRv5Fgo5Hu +cSNiDssWZR01khBYP+aK3erCdmOJBeqmRlbAdWEDUzs8niLSbe cHAgMBAAGgADAN +BgkqhkiG9w0BAQQFAAOBgQCMU/PbXvsmHIVjsh0Jus7Em8ZG00 0gpzEwGEBpEDwr +oONKkv5AsP0OkRxFpAVIth2N9DGMTegfMAv4YLB7rmrQHF8V7L +CHSN+PEWpaW78 +noO+2loTpT7RKmIhpq3jqL4SAWYj00UjzDWVEnNPQWOEqlGLR9 bAi3TA/RIwW6nj ++g== +-----END CERTIFICATE REQUEST----- + diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/newreq.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/newreq.pem new file mode 100644 index 0000000000..56251fe9b3 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/newreq.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICFDCCAX0CAQAwgZwxCzAJBgNVBAYTAkFJMRwwGgYDVQQIExNIdXR0IFJpdmVy +IFByb3ZpbmNlMRgwFgYDVQQHEw9MZXNzZXIgSW50ZXJuZXQxFzAVBgNVBAoTDk15 +IENvbXBhbnkgTHRkMSAwHgYDVQQLExdCYWNrd2F0ZXIgQnJhbmNoIE9mZmljZTEa +MBgGA1UEAxMRRmlyc3ROYW1lIFN1cm5hbWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0A +MIGJAoGBANhGJhCQfy/ttrBtSEaX/fS8cW5X3lkv0f3fMjT/22Smgum6Z6owE/Zf +htkvMjKNlUWdJlyUwoItn2qcAlFygb2zeP8Gf861TRtHXQPdivw7MoY42dcZ4Ab/ +kB14962MwjpDY2ubww3a5AaweLd61Wd7zw0kbLMtuk3HKMtJPt7RAgMBAAGgNzAY +BgkqhkiG9w0BCQcxCxMJQ2hhbGxlbmdlMBsGCSqGSIb3DQEJAjEOEwxPcHRpb25h +bCBDb3kwDQYJKoZIhvcNAQEEBQADgYEAUjnPD8u9GoetcYTiNfp+RH7fdoQcCBye +L61IK207t1eOJTKBZ6dgzGTLL4Os2cdmV3nL6oqQjOtG9if/960+c+NoY5ulNpk3 +V3ORJrNacXPFEb5aQNapW221EddaePCEXX2Wcvqc+SCr420fbKi28u6xJjLUdB8b +iTnCT3F6TFk= +-----END CERTIFICATE REQUEST----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/ov-root-ca-cert.crt b/local/recipes/libs/qca/source/unittest/certunittest/certs/ov-root-ca-cert.crt new file mode 100644 index 0000000000..71bc1f4360 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/certunittest/certs/ov-root-ca-cert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.pem new file mode 100644 index 0000000000..ef9389ebd6 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.pem @@ -0,0 +1,86 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only next generation/Email=insecure@test.insecure + Validity + Not Before: Jul 1 10:21:49 2002 GMT + Not After : Jun 30 10:21:49 2007 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure Server Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:bd:45:c9:dc:e9:70:4d:90:95:ff:07:09:24:8e: + 08:8c:d2:64:ce:16:02:00:3d:8a:15:fe:e2:9a:eb: + 81:3c:67:55:7e:5c:e1:75:ea:09:b4:76:84:c3:04: + 3e:fc:8e:49:77:ad:97:db:44:5b:3e:44:32:b3:70: + c0:fe:4e:0f:82:bb:97:4b:11:34:0d:06:64:c6:8f: + 60:85:3c:b9:a2:7c:fa:ce:28:ab:3c:3b:2d:72:d8: + e9:e4:c1:44:f3:83:00:5c:9c:51:78:6c:08:6d:a7: + 97:19:ce:9a:81:4b:7d:fc:13:f7:30:94:20:19:b2: + 60:16:77:68:a9:c4:3b:42:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Key Identifier: + F5:F1:29:8A:CD:31:98:96:2B:00:5B:78:55:F6:CC:69:55:EE:F3:18 + X509v3 Authority Key Identifier: + keyid:8F:08:4F:9C:53:C1:5C:C8:E6:0C:D7:13:2E:CB:52:3C:23:96:02:14 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Server + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 87:48:82:2d:5d:dc:e0:0a:a1:b9:11:3a:bf:37:40:cc:c3:42: + b1:9a:a7:62:3d:8d:0f:7e:bc:da:a9:cc:8f:2c:4b:66:c8:42: + 69:fc:a9:66:8b:f0:51:84:40:23:01:30:98:10:d8:76:01:b0: + c0:bd:ae:68:42:a7:33:c9:48:e5:30:be:4b:4e:8b:e7:f2:56: + 3f:11:2b:2b:10:1d:1e:51:98:39:62:c0:e1:cf:dc:ef:1b:c2: + 2c:1c:cf:94:87:d7:a0:32:c6:50:b2:f4:00:49:61:a5:80:11: + 9e:59:99:3e:d5:59:69:83:47:05:ae:08:bb:2c:0b:53:90:53: + a0:86:0d:9a:6c:d4:ce:c9:d2:fd:fb:b0:a8:24:64:70:0f:9f: + 2b:64:3b:11:40:fa:b7:30:ea:82:e1:4b:32:14:bd:d4:72:e0: + 3f:3e:27:26:b6:d1:80:8a:ad:d4:eb:b3:cf:fc:ab:0b:b6:2d: + 25:5b:0f:be:d5:f1:73:5a:2f:70:c3:fd:9f:3a:db:bc:ab:a7: + 5f:3c:aa:54:b3:c8:9d:a6:12:62:dc:7b:4b:8f:62:d7:fd:f7: + f4:f8:3e:be:ef:26:2b:b9:4b:40:a5:36:c2:e7:0b:7e:41:ba: + 00:88:41:de:0d:ef:fb:0c:e9:df:a0:92:b2:29:1d:ab:d3:45: + c8:16:37:52 +-----BEGIN CERTIFICATE----- +MIIEdzCCA1+gAwIBAgIBBjANBgkqhkiG9w0BAQQFADB/MQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMTHkZvciBU +ZXN0cyBPbmx5IG5leHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1 +cmVAdGVzdC5pbnNlY3VyZTAeFw0wMjA3MDExMDIxNDlaFw0wNzA2MzAxMDIxNDla +MHUxCzAJBgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRlc3RDZXJ0aWZpY2F0 +ZTEdMBsGA1UEAxMUSW5zZWN1cmUgU2VydmVyIENlcnQxJTAjBgkqhkiG9w0BCQEW +Fmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ +AoGBAL1FydzpcE2Qlf8HCSSOCIzSZM4WAgA9ihX+4prrgTxnVX5c4XXqCbR2hMME +PvyOSXetl9tEWz5EMrNwwP5OD4K7l0sRNA0GZMaPYIU8uaJ8+s4oqzw7LXLY6eTB +RPODAFycUXhsCG2nlxnOmoFLffwT9zCUIBmyYBZ3aKnEO0IhAgMBAAGjggGKMIIB +hjALBgNVHQ8EBAMCA6gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFPXx +KYrNMZiWKwBbeFX2zGlV7vMYMIGrBgNVHSMEgaMwgaCAFI8IT5xTwVzI5gzXEy7L +UjwjlgIUoYGEpIGBMH8xCzAJBgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRl +c3RDZXJ0aWZpY2F0ZTEnMCUGA1UEAxMeRm9yIFRlc3RzIE9ubHkgbmV4dCBnZW5l +cmF0aW9uMSUwIwYJKoZIhvcNAQkBFhZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJlggEA +MCEGA1UdEQQaMBiBFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwIQYDVR0SBBowGIEW +aW5zZWN1cmVAdGVzdC5pbnNlY3VyZTARBglghkgBhvhCAQEEBAMCBkAwPAYJYIZI +AYb4QgENBC8WLVRoaXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBmb3IgdGVzdGlu +ZyBvbmx5ITANBgkqhkiG9w0BAQQFAAOCAQEAh0iCLV3c4AqhuRE6vzdAzMNCsZqn +Yj2ND3682qnMjyxLZshCafypZovwUYRAIwEwmBDYdgGwwL2uaEKnM8lI5TC+S06L +5/JWPxErKxAdHlGYOWLA4c/c7xvCLBzPlIfXoDLGULL0AElhpYARnlmZPtVZaYNH +Ba4IuywLU5BToIYNmmzUzsnS/fuwqCRkcA+fK2Q7EUD6tzDqguFLMhS91HLgPz4n +JrbRgIqt1Ouzz/yrC7YtJVsPvtXxc1ovcMP9nzrbvKunXzyqVLPInaYSYtx7S49i +1/339Pg+vu8mK7lLQKU2wucLfkG6AIhB3g3v+wzp36CSsikdq9NFyBY3Ug== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.txt new file mode 100644 index 0000000000..241d0478ff --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/servergood2cert.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6 (0x6) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only next generation/Email=insecure@test.insecure + Validity + Not Before: Jul 1 10:21:49 2002 GMT + Not After : Jun 30 10:21:49 2007 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure Server Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:bd:45:c9:dc:e9:70:4d:90:95:ff:07:09:24:8e: + 08:8c:d2:64:ce:16:02:00:3d:8a:15:fe:e2:9a:eb: + 81:3c:67:55:7e:5c:e1:75:ea:09:b4:76:84:c3:04: + 3e:fc:8e:49:77:ad:97:db:44:5b:3e:44:32:b3:70: + c0:fe:4e:0f:82:bb:97:4b:11:34:0d:06:64:c6:8f: + 60:85:3c:b9:a2:7c:fa:ce:28:ab:3c:3b:2d:72:d8: + e9:e4:c1:44:f3:83:00:5c:9c:51:78:6c:08:6d:a7: + 97:19:ce:9a:81:4b:7d:fc:13:f7:30:94:20:19:b2: + 60:16:77:68:a9:c4:3b:42:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Key Encipherment, Key Agreement + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Key Identifier: + F5:F1:29:8A:CD:31:98:96:2B:00:5B:78:55:F6:CC:69:55:EE:F3:18 + X509v3 Authority Key Identifier: + keyid:8F:08:4F:9C:53:C1:5C:C8:E6:0C:D7:13:2E:CB:52:3C:23:96:02:14 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Server + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 87:48:82:2d:5d:dc:e0:0a:a1:b9:11:3a:bf:37:40:cc:c3:42: + b1:9a:a7:62:3d:8d:0f:7e:bc:da:a9:cc:8f:2c:4b:66:c8:42: + 69:fc:a9:66:8b:f0:51:84:40:23:01:30:98:10:d8:76:01:b0: + c0:bd:ae:68:42:a7:33:c9:48:e5:30:be:4b:4e:8b:e7:f2:56: + 3f:11:2b:2b:10:1d:1e:51:98:39:62:c0:e1:cf:dc:ef:1b:c2: + 2c:1c:cf:94:87:d7:a0:32:c6:50:b2:f4:00:49:61:a5:80:11: + 9e:59:99:3e:d5:59:69:83:47:05:ae:08:bb:2c:0b:53:90:53: + a0:86:0d:9a:6c:d4:ce:c9:d2:fd:fb:b0:a8:24:64:70:0f:9f: + 2b:64:3b:11:40:fa:b7:30:ea:82:e1:4b:32:14:bd:d4:72:e0: + 3f:3e:27:26:b6:d1:80:8a:ad:d4:eb:b3:cf:fc:ab:0b:b6:2d: + 25:5b:0f:be:d5:f1:73:5a:2f:70:c3:fd:9f:3a:db:bc:ab:a7: + 5f:3c:aa:54:b3:c8:9d:a6:12:62:dc:7b:4b:8f:62:d7:fd:f7: + f4:f8:3e:be:ef:26:2b:b9:4b:40:a5:36:c2:e7:0b:7e:41:ba: + 00:88:41:de:0d:ef:fb:0c:e9:df:a0:92:b2:29:1d:ab:d3:45: + c8:16:37:52 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.pem new file mode 100644 index 0000000000..7ca98f4c79 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.pem @@ -0,0 +1,87 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4 (0x4) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only next generation/Email=insecure@test.insecure + Validity + Not Before: Jul 1 09:58:50 2002 GMT + Not After : Jun 30 09:58:50 2007 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure User Test Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:f1:79:30:51:bb:49:33:97:ef:e8:03:91:df:f6: + 9d:3b:7e:c7:13:90:7f:60:16:fe:67:8d:b3:58:20: + 6e:09:21:89:f3:25:f3:0d:df:69:b0:33:71:72:70: + 67:af:52:4f:14:3a:6e:f6:6d:fd:b9:c3:8e:71:63: + 31:f7:f4:3a:6e:0b:54:88:ef:d0:57:87:9a:d6:e9: + d5:7d:78:a6:03:a4:54:77:04:f4:27:a3:04:ad:b1: + 12:4d:13:12:b5:e3:32:2e:03:be:b8:d7:8d:5a:c0: + 39:89:33:20:19:3c:32:43:69:5c:31:f2:5c:39:a9: + 54:15:26:ce:3b:bd:f1:92:d9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 7B:5C:26:F0:14:E4:7D:3C:5C:9D:5C:B4:86:A5:E7:6C:BE:8E:77:FB + X509v3 Authority Key Identifier: + keyid:8F:08:4F:9C:53:C1:5C:C8:E6:0C:D7:13:2E:CB:52:3C:23:96:02:14 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 46:1e:57:24:97:95:da:b9:c3:7e:66:ac:19:ba:08:6d:5e:2e: + 19:e7:bc:c7:78:c9:0d:e6:4a:76:18:b5:ef:d9:2c:6d:a8:3c: + 10:6e:d4:ce:7a:91:70:2a:19:13:2f:8a:60:82:14:57:8c:b0: + bd:ae:0d:0b:44:0d:ba:c7:e7:96:02:61:81:c7:07:c6:cc:73: + c6:a0:15:1c:a2:b4:5c:a5:28:21:6a:d6:c2:cd:84:52:05:36: + 8f:06:97:29:c0:fe:c6:05:32:03:10:cc:fd:1c:56:ce:80:40: + 1e:c2:19:96:8c:cf:27:5d:b5:88:e9:a0:9e:b7:ad:d0:73:c0: + d4:0f:37:09:63:64:57:3d:92:fc:2f:b8:c6:fa:3b:dd:91:f3: + 66:d0:5e:50:d3:1d:10:a5:56:03:c4:7a:dc:b4:5f:0d:a7:34: + c5:47:67:ee:c2:8e:1a:87:30:1f:60:bb:30:25:ce:cc:56:1b: + 22:1f:b2:ca:1e:17:65:92:15:16:ce:f9:09:21:e0:9f:45:dd: + 76:67:ba:f6:7e:98:e0:cf:fe:3c:b0:75:af:34:61:c9:9c:cf: + 42:99:01:cf:05:22:8f:c9:38:87:3f:85:11:8c:68:41:a9:97: + 95:62:56:7f:57:8e:ed:ef:cb:f9:29:7f:d9:9a:ee:3f:d5:c1: + 80:9e:85:05 +-----BEGIN CERTIFICATE----- +MIIEhDCCA2ygAwIBAgIBBDANBgkqhkiG9w0BAQQFADB/MQswCQYDVQQGEwJkZTEg +MB4GA1UEChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMTHkZvciBU +ZXN0cyBPbmx5IG5leHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1 +cmVAdGVzdC5pbnNlY3VyZTAeFw0wMjA3MDEwOTU4NTBaFw0wNzA2MzAwOTU4NTBa +MHgxCzAJBgNVBAYTAmRlMSAwHgYDVQQKExdJbnNlY3VyZVRlc3RDZXJ0aWZpY2F0 +ZTEgMB4GA1UEAxMXSW5zZWN1cmUgVXNlciBUZXN0IENlcnQxJTAjBgkqhkiG9w0B +CQEWFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwgZ8wDQYJKoZIhvcNAQEBBQADgY0A +MIGJAoGBAPF5MFG7STOX7+gDkd/2nTt+xxOQf2AW/meNs1ggbgkhifMl8w3fabAz +cXJwZ69STxQ6bvZt/bnDjnFjMff0Om4LVIjv0FeHmtbp1X14pgOkVHcE9CejBK2x +Ek0TErXjMi4DvrjXjVrAOYkzIBk8MkNpXDHyXDmpVBUmzju98ZLZAgMBAAGjggGU +MIIBkDALBgNVHQ8EBAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwME +MB0GA1UdDgQWBBR7XCbwFOR9PFydXLSGpedsvo53+zCBqwYDVR0jBIGjMIGggBSP +CE+cU8FcyOYM1xMuy1I8I5YCFKGBhKSBgTB/MQswCQYDVQQGEwJkZTEgMB4GA1UE +ChMXSW5zZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMTHkZvciBUZXN0cyBP +bmx5IG5leHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVz +dC5pbnNlY3VyZYIBADAhBgNVHREEGjAYgRZpbnNlY3VyZUB0ZXN0Lmluc2VjdXJl +MCEGA1UdEgQaMBiBFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwEQYJYIZIAYb4QgEB +BAQDAgWgMDwGCWCGSAGG+EIBDQQvFi1UaGlzIGNlcnRpZmljYXRlIHdhcyBpc3N1 +ZWQgZm9yIHRlc3Rpbmcgb25seSEwDQYJKoZIhvcNAQEEBQADggEBAEYeVySXldq5 +w35mrBm6CG1eLhnnvMd4yQ3mSnYYte/ZLG2oPBBu1M56kXAqGRMvimCCFFeMsL2u +DQtEDbrH55YCYYHHB8bMc8agFRyitFylKCFq1sLNhFIFNo8GlynA/sYFMgMQzP0c +Vs6AQB7CGZaMzyddtYjpoJ63rdBzwNQPNwljZFc9kvwvuMb6O92R82bQXlDTHRCl +VgPEety0Xw2nNMVHZ+7CjhqHMB9guzAlzsxWGyIfssoeF2WSFRbO+Qkh4J9F3XZn +uvZ+mODP/jywda80Ycmcz0KZAc8FIo/JOIc/hRGMaEGpl5ViVn9Xju3vy/kpf9ma +7j/VwYCehQU= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.txt b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.txt new file mode 100644 index 0000000000..8467ad31cd --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodcert.txt @@ -0,0 +1,60 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4 (0x4) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=de, O=InsecureTestCertificate, CN=For Tests Only next generation/Email=insecure@test.insecure + Validity + Not Before: Jul 1 09:58:50 2002 GMT + Not After : Jun 30 09:58:50 2007 GMT + Subject: C=de, O=InsecureTestCertificate, CN=Insecure User Test Cert/Email=insecure@test.insecure + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:f1:79:30:51:bb:49:33:97:ef:e8:03:91:df:f6: + 9d:3b:7e:c7:13:90:7f:60:16:fe:67:8d:b3:58:20: + 6e:09:21:89:f3:25:f3:0d:df:69:b0:33:71:72:70: + 67:af:52:4f:14:3a:6e:f6:6d:fd:b9:c3:8e:71:63: + 31:f7:f4:3a:6e:0b:54:88:ef:d0:57:87:9a:d6:e9: + d5:7d:78:a6:03:a4:54:77:04:f4:27:a3:04:ad:b1: + 12:4d:13:12:b5:e3:32:2e:03:be:b8:d7:8d:5a:c0: + 39:89:33:20:19:3c:32:43:69:5c:31:f2:5c:39:a9: + 54:15:26:ce:3b:bd:f1:92:d9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 7B:5C:26:F0:14:E4:7D:3C:5C:9D:5C:B4:86:A5:E7:6C:BE:8E:77:FB + X509v3 Authority Key Identifier: + keyid:8F:08:4F:9C:53:C1:5C:C8:E6:0C:D7:13:2E:CB:52:3C:23:96:02:14 + DirName:/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/Email=insecure@test.insecure + serial:00 + + X509v3 Subject Alternative Name: + email:insecure@test.insecure + X509v3 Issuer Alternative Name: + email:insecure@test.insecure + Netscape Cert Type: + SSL Client, S/MIME + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: md5WithRSAEncryption + 46:1e:57:24:97:95:da:b9:c3:7e:66:ac:19:ba:08:6d:5e:2e: + 19:e7:bc:c7:78:c9:0d:e6:4a:76:18:b5:ef:d9:2c:6d:a8:3c: + 10:6e:d4:ce:7a:91:70:2a:19:13:2f:8a:60:82:14:57:8c:b0: + bd:ae:0d:0b:44:0d:ba:c7:e7:96:02:61:81:c7:07:c6:cc:73: + c6:a0:15:1c:a2:b4:5c:a5:28:21:6a:d6:c2:cd:84:52:05:36: + 8f:06:97:29:c0:fe:c6:05:32:03:10:cc:fd:1c:56:ce:80:40: + 1e:c2:19:96:8c:cf:27:5d:b5:88:e9:a0:9e:b7:ad:d0:73:c0: + d4:0f:37:09:63:64:57:3d:92:fc:2f:b8:c6:fa:3b:dd:91:f3: + 66:d0:5e:50:d3:1d:10:a5:56:03:c4:7a:dc:b4:5f:0d:a7:34: + c5:47:67:ee:c2:8e:1a:87:30:1f:60:bb:30:25:ce:cc:56:1b: + 22:1f:b2:ca:1e:17:65:92:15:16:ce:f9:09:21:e0:9f:45:dd: + 76:67:ba:f6:7e:98:e0:cf:fe:3c:b0:75:af:34:61:c9:9c:cf: + 42:99:01:cf:05:22:8f:c9:38:87:3f:85:11:8c:68:41:a9:97: + 95:62:56:7f:57:8e:ed:ef:cb:f9:29:7f:d9:9a:ee:3f:d5:c1: + 80:9e:85:05 diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodkey.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodkey.pem new file mode 100644 index 0000000000..4a9caf553a --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/user2goodkey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDxeTBRu0kzl+/oA5Hf9p07fscTkH9gFv5njbNYIG4JIYnzJfMN +32mwM3FycGevUk8UOm72bf25w45xYzH39DpuC1SI79BXh5rW6dV9eKYDpFR3BPQn +owStsRJNExK14zIuA764141awDmJMyAZPDJDaVwx8lw5qVQVJs47vfGS2QIDAQAB +AoGBAO1KnDMVCoBK5JRpPaaK4EQg91zAeItizSnR09XcOIV8keWA+3I8g82FIAzH +bPyas9869OPxfo5YH9hJFEeHlwm4IUAI98YKzVv/IhRjYccmdGnvERbYl3k4bQX5 +HQhcwy6eHYcbe+MbKaJTHrp2f8zuJzaAkFA/+2ZOBqGzmCeJAkEA+/smgF+wrcmL +5U5xuELgI7/yOKGi2srFscPkQmm1jhshn/iNcV85npW9gVTCH80XL7lY9U/Nnv82 +MSxoI8F/SwJBAPVTIpZlaAbz0y82C2t0wQADccaUDSimuDGnL6ti4kITRkr4JY9N +SpQweV5ctXcg1A0Za5KYC7dZo8wjFG0ci+sCQQDyUKfKxbqStQG6BsCnMHB5EInv +WcjRXDPW6glksGEugfrI6m2ie69eSKNPbuGrUT+d3kCkzxRudQB5MzoGQHqXAkBX +I+uiPm0AIzW9jFXsGnG/vnl4jvhJm0bMJFWzbBFwZQZP9OrqhwrZroo98XJn2VpZ +ONFUJfvracTb6w4DX+N3AkEAocDaR/dAYRh0j+3nEsGeDkcbzGsm0oyRGrsVp14p +CzP1Ih6RWU84Wsegr7nkxVoCrylQGV4D6xjIaI+iIPOC/Q== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certs/xmppcert.pem b/local/recipes/libs/qca/source/unittest/certunittest/certs/xmppcert.pem new file mode 100644 index 0000000000..1d9f163b83 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certs/xmppcert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDajCCAtOgAwIBAgIJAIW3d7cp/vLxMA0GCSqGSIb3DQEBBQUAMIGFMRgwFgYD +VQQDEw9kZW1vLmphYmJlci5jb20xFTATBgNVBAoTDEphYmJlciwgSW5jLjEPMA0G +A1UEBxMGRGVudmVyMREwDwYDVQQIEwhDb2xvcmFkbzELMAkGA1UEBhMCVVMxITAf +BgkqhkiG9w0BCQEWEnN1cHBvcnRAamFiYmVyLmNvbTAeFw0wNTA5MDMxMzE2NTJa +Fw0wNjA5MDMxMzE2NTJaMIGFMRgwFgYDVQQDEw9kZW1vLmphYmJlci5jb20xFTAT +BgNVBAoTDEphYmJlciwgSW5jLjEPMA0GA1UEBxMGRGVudmVyMREwDwYDVQQIEwhD +b2xvcmFkbzELMAkGA1UEBhMCVVMxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRAamFi +YmVyLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuvgypbAX0LORubko +Kr/wx9G/0WMEInV9mcTlB8+mFnBGFaob365wkbN4d3Jlurt38rJaxGv16dvnshdX +IOMkKdYPUg2NEoe3SxGCjlybhY+I5f6mWzQ3cNuXimojc1Oke8MraPjR5bioJvor +tKxAqXT0/Es8NBU05WkesqYpfn0CAwEAAaOB3zCB3DAJBgNVHRMEAjAAMB0GA1Ud +DgQWBBTh42t32wwivWOKMKc0L1BZT3umqDCBkAYDVR0RBIGIMIGFgg9kZW1vLmph +YmJlci5jb22gHQYIKwYBBQUHCAWgEQwPZGVtby5qYWJiZXIuY29toCgGCCsGAQUF +BwgFoBwMGmNvbmZlcmVuY2UuZGVtby5qYWJiZXIuY29toCkGCCsGAQUFBwgFoB0M +G2luZm8tYnJva2VyLmRlbW8uamFiYmVyLmNvbTAdBgNVHSUEFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAF454Thn47QnofqvfAKSwly+s +NAn4GXcCmCAQL3D0U4/Q3M1GZsFaD3zDEQm4ozPV/FoGAnxscCbHevMJ7JGGTnL/ +BhX9AVrDb5hNeebb5pBF2tpZT3PUv5euIrCgz5/Bx3Rdsx4TS3r4bFJT1K/PHFeB +q8It3dBtKJypvaKqjDk= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/certunittest/certunittest.cpp b/local/recipes/libs/qca/source/unittest/certunittest/certunittest.cpp new file mode 100644 index 0000000000..2d8619bb93 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/certunittest/certunittest.cpp @@ -0,0 +1,1259 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class CertUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void checkSystemStore(); + void nullCert(); + void noSuchFile(); + void CAcertstest(); + void derCAcertstest(); + void qualitysslcatest(); + void checkExpiredClientCerts(); + void checkClientCerts(); + void altName(); + void extXMPP(); + void checkExpiredServerCerts(); + void checkServerCerts(); + void altNames76(); + void sha256cert(); + void crl(); + void crl2(); + void csr(); + void csr2(); + void cleanupTestCase(); + +private: + QCA::Initializer *m_init; +}; + +void CertUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void CertUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void CertUnitTest::nullCert() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate nullCert; + QVERIFY(nullCert.isNull()); + // This is copied on purpose to check the assignment operator + QCA::Certificate anotherNullCert = nullCert; // NOLINT(performance-unnecessary-copy-initialization) + QVERIFY(anotherNullCert.isNull()); + QCOMPARE(nullCert, anotherNullCert); + } + } +} + +void CertUnitTest::noSuchFile() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultNoFile; + QCA::Certificate cert = QCA::Certificate::fromPEMFile( + QStringLiteral("thisIsJustaFileNameThatWeDontHave"), &resultNoFile, provider); + QCOMPARE(resultNoFile, QCA::ErrorFile); + QVERIFY(cert.isNull()); + } + } +} + +void CertUnitTest::CAcertstest() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/RootCAcert.pem"), &resultca1, provider); + + QCOMPARE(resultca1, QCA::ConvertGood); + QCOMPARE(ca1.isNull(), false); + QCOMPARE(ca1.pathLimit(), 0); + QCOMPARE(ca1.isCA(), true); + QCOMPARE(ca1.isSelfSigned(), true); + + QCOMPARE(ca1.serialNumber(), QCA::BigInteger(0)); + + QCOMPARE(ca1.commonName(), QStringLiteral("For Tests Only")); + + QCOMPARE(ca1.notValidBefore().toString(), + QDateTime(QDate(2001, 8, 17), QTime(8, 30, 39), Qt::UTC).toString()); + QCOMPARE(ca1.notValidAfter().toString(), + QDateTime(QDate(2011, 8, 15), QTime(8, 30, 39), Qt::UTC).toString()); + + QCOMPARE(ca1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyCertificateSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::CRLSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(ca1.policies().count(), 0); + } + } +} + +void CertUnitTest::qualitysslcatest() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = QCA::Certificate::fromPEMFile( + QStringLiteral("certs/QualitySSLIntermediateCA.crt"), &resultca1, provider); + + QCOMPARE(resultca1, QCA::ConvertGood); + QCOMPARE(ca1.isNull(), false); + QCOMPARE(ca1.isCA(), true); + QCOMPARE(ca1.isSelfSigned(), false); + + QCOMPARE(ca1.signatureAlgorithm(), QCA::EMSA3_SHA1); + + QCOMPARE(ca1.serialNumber(), QCA::BigInteger("33555098")); + + QCOMPARE(ca1.commonName(), QStringLiteral("Comodo Class 3 Security Services CA")); + + QCOMPARE(ca1.notValidBefore().toString(), + QDateTime(QDate(2002, 8, 27), QTime(19, 02, 00), Qt::UTC).toString()); + QCOMPARE(ca1.notValidAfter().toString(), + QDateTime(QDate(2012, 8, 27), QTime(23, 59, 00), Qt::UTC).toString()); + + QCOMPARE(ca1.pathLimit(), 0); + + QCOMPARE(ca1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyCertificateSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::CRLSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::OCSPSigning) == true, false); + } + } +} + +void CertUnitTest::checkExpiredClientCerts() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultClient1; + QCA::Certificate client1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/User.pem"), &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QCOMPARE(client1.isNull(), false); + QCOMPARE(client1.isCA(), false); + QCOMPARE(client1.isSelfSigned(), false); + + QCOMPARE(client1.serialNumber(), QCA::BigInteger(2)); + + QCOMPARE(client1.commonName(), QStringLiteral("Insecure User Test Cert")); + + QCOMPARE(client1.notValidBefore().toString(), + QDateTime(QDate(2001, 8, 17), QTime(8, 32, 38), Qt::UTC).toString()); + QCOMPARE(client1.notValidAfter().toString(), + QDateTime(QDate(2006, 8, 16), QTime(8, 32, 38), Qt::UTC).toString()); + + QCOMPARE(client1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(client1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(client1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(client1.constraints().contains(QCA::DataEncipherment) == true, true); + QCOMPARE(client1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(client1.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(client1.constraints().contains(QCA::ClientAuth) == true, true); + QCOMPARE(client1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EmailProtection) == true, true); + QCOMPARE(client1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(client1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(client1.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(client1.policies().count(), 0); + + QCA::CertificateInfo subject1 = client1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QCOMPARE(subject1.contains(QCA::Country, QStringLiteral("de")) == true, true); + QCOMPARE(subject1.contains(QCA::Organization, QStringLiteral("InsecureTestCertificate")) == true, true); + QCOMPARE(subject1.contains(QCA::CommonName, QStringLiteral("Insecure User Test Cert")) == true, true); + + QCA::CertificateInfo issuer1 = client1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QCOMPARE(issuer1.contains(QCA::Country, QStringLiteral("de")) == true, true); + QCOMPARE(issuer1.contains(QCA::Organization, QStringLiteral("InsecureTestCertificate")) == true, true); + QCOMPARE(issuer1.contains(QCA::CommonName, QStringLiteral("For Tests Only")) == true, true); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("889E7EF729719D7B280F361AAE6D00D39DE1AADB")).toByteArray(); + QCOMPARE(client1.subjectKeyId(), subjectKeyID); + QCOMPARE(QCA::Hex().arrayToString(client1.issuerKeyId()), + QStringLiteral("bf53438278d09ec380e51b67ca0500dfb94883a5")); + + QCA::PublicKey pubkey1 = client1.subjectPublicKey(); + QCOMPARE(pubkey1.isNull(), false); + QCOMPARE(pubkey1.isRSA(), true); + QCOMPARE(pubkey1.isDSA(), false); + QCOMPARE(pubkey1.isDH(), false); + QCOMPARE(pubkey1.isPublic(), true); + QCOMPARE(pubkey1.isPrivate(), false); + QCOMPARE(pubkey1.bitSize(), 1024); + + QCOMPARE(client1.pathLimit(), 0); + + QCOMPARE(client1.signatureAlgorithm(), QCA::EMSA3_MD5); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(client1.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/RootCAcert.pem"), &resultca1, provider); + QCOMPARE(resultca1, QCA::ConvertGood); + trusted.addCertificate(ca1); + + QCOMPARE(client1.validate(trusted, untrusted), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageAny), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageTLSServer), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageTLSClient), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageCodeSigning), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageTimeStamping), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageEmailProtection), QCA::ErrorExpired); + QCOMPARE(client1.validate(trusted, untrusted, QCA::UsageCRLSigning), QCA::ErrorExpired); + QByteArray derClient1 = client1.toDER(); + QCOMPARE(derClient1.isEmpty(), false); + QCA::Certificate fromDer1 = QCA::Certificate::fromDER(derClient1, &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QVERIFY(fromDer1 == client1); + + QString pemClient1 = client1.toPEM(); + QCOMPARE(pemClient1.isEmpty(), false); + QCA::Certificate fromPem1 = QCA::Certificate::fromPEM(pemClient1, &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QVERIFY(fromPem1 == client1); + QCOMPARE(fromPem1 != fromDer1, false); + } + } +} + +void CertUnitTest::checkClientCerts() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultClient2; + QCA::Certificate client2 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/QcaTestClientCert.pem"), &resultClient2, provider); + QCOMPARE(resultClient2, QCA::ConvertGood); + QCOMPARE(client2.isNull(), false); + QCOMPARE(client2.isCA(), false); + QCOMPARE(client2.isSelfSigned(), false); + + QCOMPARE(client2.serialNumber(), QCA::BigInteger("13149359243510447488")); + + QCOMPARE(client2.commonName(), QStringLiteral("Qca Test Client Certificate")); + + QCOMPARE(client2.notValidBefore().toString(), + QDateTime(QDate(2013, 7, 31), QTime(15, 14, 28), Qt::UTC).toString()); + QCOMPARE(client2.notValidAfter().toString(), + QDateTime(QDate(2033, 7, 26), QTime(15, 14, 28), Qt::UTC).toString()); + + QCOMPARE(client2.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(client2.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(client2.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(client2.constraints().contains(QCA::DataEncipherment) == true, true); + QCOMPARE(client2.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(client2.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(client2.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(client2.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(client2.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(client2.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(client2.constraints().contains(QCA::ClientAuth) == true, true); + QCOMPARE(client2.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(client2.constraints().contains(QCA::EmailProtection) == true, true); + QCOMPARE(client2.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(client2.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(client2.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(client2.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(client2.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(client2.policies().count(), 0); + + QCA::CertificateInfo subject2 = client2.subjectInfo(); + QCOMPARE(subject2.isEmpty(), false); + QVERIFY(subject2.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(subject2.contains(QCA::Organization, QStringLiteral("Qca Development and Test"))); + QVERIFY(subject2.contains(QCA::OrganizationalUnit, QStringLiteral("Certificate Generation Section"))); + QVERIFY(subject2.contains(QCA::CommonName, QStringLiteral("Qca Test Client Certificate"))); + + QCA::CertificateInfo issuer2 = client2.issuerInfo(); + QCOMPARE(issuer2.isEmpty(), false); + QVERIFY(issuer2.contains(QCA::Country, QStringLiteral("AU"))); + QVERIFY(issuer2.contains(QCA::Organization, QStringLiteral("Qca Development and Test"))); + QVERIFY(issuer2.contains(QCA::CommonName, QStringLiteral("Qca Test Root Certificate"))); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("1e604e03127d287ba40427a961b428a2d09b50d1")).toByteArray(); + QCOMPARE(client2.subjectKeyId(), subjectKeyID); + QCOMPARE(QCA::Hex().arrayToString(client2.issuerKeyId()), + QStringLiteral("f61c451de1b0458138c60568c1a7cb0f7ade0363")); + + QCA::PublicKey pubkey2 = client2.subjectPublicKey(); + QCOMPARE(pubkey2.isNull(), false); + QCOMPARE(pubkey2.isRSA(), true); + QCOMPARE(pubkey2.isDSA(), false); + QCOMPARE(pubkey2.isDH(), false); + QCOMPARE(pubkey2.isPublic(), true); + QCOMPARE(pubkey2.isPrivate(), false); + QCOMPARE(pubkey2.bitSize(), 1024); + + QCOMPARE(client2.pathLimit(), 0); + + QCOMPARE(client2.signatureAlgorithm(), QCA::EMSA3_SHA1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(client2.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::ConvertResult resultca2; + QCA::Certificate ca2 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/QcaTestRootCert.pem"), &resultca2, provider); + QCOMPARE(resultca2, QCA::ConvertGood); + trusted.addCertificate(ca2); + + QCOMPARE(client2.validate(trusted, untrusted), QCA::ValidityGood); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageAny), QCA::ValidityGood); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageTLSServer), QCA::ErrorInvalidPurpose); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageTLSClient), QCA::ValidityGood); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageCodeSigning), QCA::ErrorInvalidPurpose); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageTimeStamping), QCA::ErrorInvalidPurpose); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageEmailProtection), QCA::ValidityGood); + QCOMPARE(client2.validate(trusted, untrusted, QCA::UsageCRLSigning), QCA::ErrorInvalidPurpose); + QByteArray derClient2 = client2.toDER(); + QCOMPARE(derClient2.isEmpty(), false); + QCA::Certificate fromDer2 = QCA::Certificate::fromDER(derClient2, &resultClient2, provider); + QCOMPARE(resultClient2, QCA::ConvertGood); + QVERIFY(fromDer2 == client2); + + QString pemClient2 = client2.toPEM(); + QCOMPARE(pemClient2.isEmpty(), false); + QCA::Certificate fromPem2 = QCA::Certificate::fromPEM(pemClient2, &resultClient2, provider); + QCOMPARE(resultClient2, QCA::ConvertGood); + QVERIFY(fromPem2 == client2); + QCOMPARE(fromPem2 != fromDer2, false); + } + } +} + +void CertUnitTest::derCAcertstest() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QFile f(QStringLiteral("certs/ov-root-ca-cert.crt")); + QVERIFY(f.open(QFile::ReadOnly)); + QByteArray der = f.readAll(); + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = QCA::Certificate::fromDER(der, &resultca1, provider); + + QCOMPARE(resultca1, QCA::ConvertGood); + + QCOMPARE(ca1.pathLimit(), 0); + + QCOMPARE(ca1.isNull(), false); + QCOMPARE(ca1.isCA(), true); + + QCOMPARE(ca1.isSelfSigned(), true); + + QCOMPARE(ca1.serialNumber(), QCA::BigInteger(0)); + + QCOMPARE(ca1.commonName(), QStringLiteral("For Tests Only")); + + QCA::CertificateInfo si = ca1.subjectInfo(); + QCOMPARE(si.isEmpty(), false); + QCOMPARE(si.value(QCA::CommonName), QStringLiteral("For Tests Only")); + QCOMPARE(si.value(QCA::Organization), QStringLiteral("InsecureTestCertificate")); + QCOMPARE(si.value(QCA::Country), QStringLiteral("de")); + + QCA::CertificateInfo ii = ca1.issuerInfo(); + QCOMPARE(ii.isEmpty(), false); + QCOMPARE(ii.value(QCA::CommonName), QStringLiteral("For Tests Only")); + QCOMPARE(ii.value(QCA::Organization), QStringLiteral("InsecureTestCertificate")); + QCOMPARE(ii.value(QCA::Country), QStringLiteral("de")); + + QCOMPARE(ca1.notValidBefore().toString(), + QDateTime(QDate(2001, 8, 17), QTime(8, 30, 39), Qt::UTC).toString()); + QCOMPARE(ca1.notValidAfter().toString(), + QDateTime(QDate(2011, 8, 15), QTime(8, 30, 39), Qt::UTC).toString()); + + QCOMPARE(ca1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::KeyCertificateSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::CRLSign) == true, true); + QCOMPARE(ca1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(ca1.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(ca1.policies().count(), 0); + + QCOMPARE(ca1.signatureAlgorithm(), QCA::EMSA3_MD5); + } + } +} + +void CertUnitTest::altName() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultClient1; + QCA::Certificate client1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/altname.pem"), &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QCOMPARE(client1.isNull(), false); + QCOMPARE(client1.isCA(), false); + QCOMPARE(client1.isSelfSigned(), false); + + QCOMPARE(client1.serialNumber(), QCA::BigInteger(1)); + + QCOMPARE(client1.commonName(), QStringLiteral("Valid RFC822 nameConstraints EE Certificate Test21")); + + QCOMPARE(client1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(client1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(client1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(client1.constraints().contains(QCA::DataEncipherment) == true, true); + QCOMPARE(client1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(client1.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::ServerAuth) == true, false); + QCOMPARE(client1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(client1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(client1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(client1.constraints().contains(QCA::OCSPSigning) == true, false); + + QCOMPARE(client1.policies().count(), 1); + QCOMPARE(client1.policies().at(0), QStringLiteral("2.16.840.1.101.3.2.1.48.1")); + + QCA::CertificateInfo subject1 = client1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QVERIFY(subject1.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(subject1.contains(QCA::Organization, QStringLiteral("Test Certificates"))); + QVERIFY(subject1.contains(QCA::CommonName, + QStringLiteral("Valid RFC822 nameConstraints EE Certificate Test21"))); + QVERIFY(subject1.contains(QCA::Email, QStringLiteral("Test21EE@mailserver.testcertificates.gov"))); + + QCA::CertificateInfo issuer1 = client1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QVERIFY(issuer1.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(issuer1.contains(QCA::Organization, QStringLiteral("Test Certificates"))); + QVERIFY(issuer1.contains(QCA::CommonName, QStringLiteral("nameConstraints RFC822 CA1"))); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("b4200d42cd95ea87d463d54f0ed6d10fe5b73bfb")).toByteArray(); + QCOMPARE(client1.subjectKeyId(), subjectKeyID); + QCOMPARE(QCA::Hex().arrayToString(client1.issuerKeyId()), + QStringLiteral("e37f857a8ea23b9eeeb8121d7913aac4bd2e59ad")); + + QCA::PublicKey pubkey1 = client1.subjectPublicKey(); + QCOMPARE(pubkey1.isNull(), false); + QCOMPARE(pubkey1.isRSA(), true); + QCOMPARE(pubkey1.isDSA(), false); + QCOMPARE(pubkey1.isDH(), false); + QCOMPARE(pubkey1.isPublic(), true); + QCOMPARE(pubkey1.isPrivate(), false); + QCOMPARE(pubkey1.bitSize(), 1024); + + QCOMPARE(client1.pathLimit(), 0); + + QCOMPARE(client1.signatureAlgorithm(), QCA::EMSA3_SHA1); + } + } +} + +void CertUnitTest::extXMPP() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultClient1; + QCA::Certificate client1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/xmppcert.pem"), &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QCOMPARE(client1.isNull(), false); + QCOMPARE(client1.isCA(), false); + QCOMPARE(client1.isSelfSigned(), true); + + QCOMPARE(client1.serialNumber(), QCA::BigInteger("9635301556349760241")); + + QCOMPARE(client1.commonName(), QStringLiteral("demo.jabber.com")); + + QCA::CertificateInfo subject1 = client1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QVERIFY(subject1.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(subject1.contains(QCA::Organization, QStringLiteral("Jabber, Inc."))); + QVERIFY(subject1.contains(QCA::Locality, QStringLiteral("Denver"))); + QVERIFY(subject1.contains(QCA::State, QStringLiteral("Colorado"))); + QVERIFY(subject1.contains(QCA::CommonName, QStringLiteral("demo.jabber.com"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("demo.jabber.com"))); + QVERIFY(subject1.contains(QCA::XMPP, QStringLiteral("demo.jabber.com"))); + + QCA::CertificateInfo issuer1 = client1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QVERIFY(issuer1.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(issuer1.contains(QCA::Organization, QStringLiteral("Jabber, Inc."))); + QVERIFY(issuer1.contains(QCA::Locality, QStringLiteral("Denver"))); + QVERIFY(issuer1.contains(QCA::State, QStringLiteral("Colorado"))); + QVERIFY(issuer1.contains(QCA::CommonName, QStringLiteral("demo.jabber.com"))); + } + } +} + +void CertUnitTest::altNames76() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultClient1; + QCA::Certificate client1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/76.pem"), &resultClient1, provider); + QCOMPARE(resultClient1, QCA::ConvertGood); + QCOMPARE(client1.isNull(), false); + QCOMPARE(client1.isCA(), false); + QCOMPARE(client1.isSelfSigned(), false); + + QCOMPARE(client1.serialNumber(), QCA::BigInteger(118)); + + QCOMPARE(client1.commonName(), QStringLiteral("sip1.su.se")); + + QCOMPARE(client1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(client1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(client1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(client1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(client1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(client1.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(client1.constraints().contains(QCA::ServerAuth) == true, true); + QCOMPARE(client1.constraints().contains(QCA::ClientAuth) == true, true); + QCOMPARE(client1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(client1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(client1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(client1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(client1.constraints().contains(QCA::OCSPSigning) == true, false); + + QCOMPARE(client1.policies().count(), 1); + + QCA::CertificateInfo subject1 = client1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QVERIFY(subject1.contains(QCA::Country, QStringLiteral("SE"))); + QVERIFY(subject1.contains(QCA::Organization, QStringLiteral("Stockholms universitet"))); + QVERIFY(subject1.contains(QCA::CommonName, QStringLiteral("sip1.su.se"))); + QCOMPARE(subject1.values(QCA::Email).count(), 0); // clazy:exclude=container-anti-pattern + QCOMPARE(subject1.values(QCA::DNS).count(), 8); // clazy:exclude=container-anti-pattern + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("incomingproxy.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("incomingproxy1.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("outgoingproxy.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("outgoingproxy1.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("out.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("appserver.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("appserver1.sip.su.se"))); + QVERIFY(subject1.contains(QCA::DNS, QStringLiteral("sip1.su.se"))); + + QVERIFY(client1.matchesHostName(QStringLiteral("incomingproxy.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("incomingproxy1.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("outgoingproxy.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("outgoingproxy1.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("out.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("appserver.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("appserver1.sip.su.se"))); + QVERIFY(client1.matchesHostName(QStringLiteral("sip1.su.se"))); + + QCA::CertificateInfo issuer1 = client1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QVERIFY(issuer1.contains(QCA::Country, QStringLiteral("SE"))); + QVERIFY(issuer1.contains(QCA::Organization, QStringLiteral("Stockholms universitet"))); + QVERIFY(issuer1.contains(QCA::CommonName, QStringLiteral("Stockholm University CA"))); + QVERIFY(issuer1.contains(QCA::URI, QStringLiteral("http://ca.su.se"))); + QVERIFY(issuer1.contains(QCA::Email, QStringLiteral("ca@su.se"))); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("3a5c5cd1cc2c9edf73f73bd81b59b1eab83035c5")).toByteArray(); + QCOMPARE(client1.subjectKeyId(), subjectKeyID); + QCOMPARE(QCA::Hex().arrayToString(client1.issuerKeyId()), + QStringLiteral("9e2e30ba37d95144c99dbf1821f1bd7eeeb58648")); + + QCA::PublicKey pubkey1 = client1.subjectPublicKey(); + QCOMPARE(pubkey1.isNull(), false); + QCOMPARE(pubkey1.isRSA(), true); + QCOMPARE(pubkey1.isDSA(), false); + QCOMPARE(pubkey1.isDH(), false); + QCOMPARE(pubkey1.isPublic(), true); + QCOMPARE(pubkey1.isPrivate(), false); + QCOMPARE(pubkey1.bitSize(), 1024); + + QCOMPARE(client1.pathLimit(), 0); + + QCOMPARE(client1.signatureAlgorithm(), QCA::EMSA3_SHA1); + } + } +} + +void CertUnitTest::sha256cert() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QFile f(QStringLiteral("certs/RAIZ2007_CERTIFICATE_AND_CRL_SIGNING_SHA256.crt")); + QVERIFY(f.open(QFile::ReadOnly)); + QByteArray der = f.readAll(); + QCA::ConvertResult resultcert; + QCA::Certificate cert = QCA::Certificate::fromDER(der, &resultcert, provider); + + QCOMPARE(resultcert, QCA::ConvertGood); + QCOMPARE(cert.isNull(), false); + QCOMPARE(cert.isCA(), true); + QCOMPARE(cert.isSelfSigned(), true); + + QCA::PublicKey pubkey = cert.subjectPublicKey(); + QCOMPARE(pubkey.isNull(), false); + QCOMPARE(pubkey.isRSA(), true); + QCOMPARE(pubkey.isDSA(), false); + QCOMPARE(pubkey.isDH(), false); + QCOMPARE(pubkey.isPublic(), true); + QCOMPARE(pubkey.isPrivate(), false); + QCOMPARE(pubkey.bitSize(), 4096); + + QCOMPARE(cert.pathLimit(), 0); + + QCOMPARE(cert.signatureAlgorithm(), QCA::EMSA3_SHA256); + } + } +} + +void CertUnitTest::checkExpiredServerCerts() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultServer1; + QCA::Certificate server1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/Server.pem"), &resultServer1, provider); + QCOMPARE(resultServer1, QCA::ConvertGood); + QCOMPARE(server1.isNull(), false); + QCOMPARE(server1.isCA(), false); + QCOMPARE(server1.isSelfSigned(), false); + + QCOMPARE(server1.serialNumber(), QCA::BigInteger(4)); + + QCOMPARE(server1.commonName(), QStringLiteral("Insecure Server Cert")); + + QCOMPARE(server1.notValidBefore().toString(), + QDateTime(QDate(2001, 8, 17), QTime(8, 46, 24), Qt::UTC).toString()); + QCOMPARE(server1.notValidAfter().toString(), + QDateTime(QDate(2006, 8, 16), QTime(8, 46, 24), Qt::UTC).toString()); + + QCOMPARE(server1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(server1.constraints().contains(QCA::NonRepudiation) == true, false); + QCOMPARE(server1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(server1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(server1.constraints().contains(QCA::KeyAgreement) == true, true); + QCOMPARE(server1.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(server1.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(server1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(server1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(server1.constraints().contains(QCA::ServerAuth) == true, true); + QCOMPARE(server1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(server1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(server1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(server1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(server1.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(server1.policies().count(), 0); + + QCA::CertificateInfo subject1 = server1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QCOMPARE(subject1.contains(QCA::Country, QStringLiteral("de")) == true, true); + QCOMPARE(subject1.contains(QCA::Organization, QStringLiteral("InsecureTestCertificate")) == true, true); + QCOMPARE(subject1.contains(QCA::CommonName, QStringLiteral("Insecure Server Cert")) == true, true); + + QCA::CertificateInfo issuer1 = server1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QCOMPARE(issuer1.contains(QCA::Country, QStringLiteral("de")) == true, true); + QCOMPARE(issuer1.contains(QCA::Organization, QStringLiteral("InsecureTestCertificate")) == true, true); + QCOMPARE(issuer1.contains(QCA::CommonName, QStringLiteral("For Tests Only")) == true, true); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("0234E2C906F6E0B44253BE04C0CBA7823A6DB509")).toByteArray(); + QCOMPARE(server1.subjectKeyId(), subjectKeyID); + QByteArray authorityKeyID = + QCA::Hex().stringToArray(QStringLiteral("BF53438278D09EC380E51B67CA0500DFB94883A5")).toByteArray(); + QCOMPARE(server1.issuerKeyId(), authorityKeyID); + + QCA::PublicKey pubkey1 = server1.subjectPublicKey(); + QCOMPARE(pubkey1.isNull(), false); + QCOMPARE(pubkey1.isRSA(), true); + QCOMPARE(pubkey1.isDSA(), false); + QCOMPARE(pubkey1.isDH(), false); + QCOMPARE(pubkey1.isPublic(), true); + QCOMPARE(pubkey1.isPrivate(), false); + QCOMPARE(pubkey1.bitSize(), 1024); + + QCOMPARE(server1.pathLimit(), 0); + + QCOMPARE(server1.signatureAlgorithm(), QCA::EMSA3_MD5); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(server1.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/RootCAcert.pem"), &resultca1, provider); + QCOMPARE(resultca1, QCA::ConvertGood); + trusted.addCertificate(ca1); + QCOMPARE(server1.validate(trusted, untrusted), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageAny), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTLSServer), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTLSClient), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageCodeSigning), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTimeStamping), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageEmailProtection), QCA::ErrorExpired); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageCRLSigning), QCA::ErrorExpired); + + QByteArray derServer1 = server1.toDER(); + QCOMPARE(derServer1.isEmpty(), false); + QCA::Certificate fromDer1 = QCA::Certificate::fromDER(derServer1, &resultServer1, provider); + QCOMPARE(resultServer1, QCA::ConvertGood); + QCOMPARE(fromDer1 == server1, true); + } + } +} + +void CertUnitTest::checkServerCerts() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultServer1; + QCA::Certificate server1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/QcaTestServerCert.pem"), &resultServer1, provider); + QCOMPARE(resultServer1, QCA::ConvertGood); + QCOMPARE(server1.isNull(), false); + QCOMPARE(server1.isCA(), false); + QCOMPARE(server1.isSelfSigned(), false); + + QCOMPARE(server1.serialNumber(), QCA::BigInteger("13149359243510447489")); + + QCOMPARE(server1.commonName(), QStringLiteral("Qca Server Test certificate")); + + QCOMPARE(server1.notValidBefore().toString(), + QDateTime(QDate(2013, 7, 31), QTime(15, 23, 25), Qt::UTC).toString()); + QCOMPARE(server1.notValidAfter().toString(), + QDateTime(QDate(2033, 7, 26), QTime(15, 23, 25), Qt::UTC).toString()); + + QCOMPARE(server1.constraints().contains(QCA::DigitalSignature) == true, true); + QCOMPARE(server1.constraints().contains(QCA::NonRepudiation) == true, true); + QCOMPARE(server1.constraints().contains(QCA::KeyEncipherment) == true, true); + QCOMPARE(server1.constraints().contains(QCA::DataEncipherment) == true, false); + QCOMPARE(server1.constraints().contains(QCA::KeyAgreement) == true, false); + QCOMPARE(server1.constraints().contains(QCA::KeyCertificateSign) == true, false); + QCOMPARE(server1.constraints().contains(QCA::CRLSign) == true, false); + QCOMPARE(server1.constraints().contains(QCA::EncipherOnly) == true, false); + QCOMPARE(server1.constraints().contains(QCA::DecipherOnly) == true, false); + QCOMPARE(server1.constraints().contains(QCA::ServerAuth) == true, true); + QCOMPARE(server1.constraints().contains(QCA::ClientAuth) == true, false); + QCOMPARE(server1.constraints().contains(QCA::CodeSigning) == true, false); + QCOMPARE(server1.constraints().contains(QCA::EmailProtection) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecEndSystem) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecTunnel) == true, false); + QCOMPARE(server1.constraints().contains(QCA::IPSecUser) == true, false); + QCOMPARE(server1.constraints().contains(QCA::TimeStamping) == true, false); + QCOMPARE(server1.constraints().contains(QCA::OCSPSigning) == true, false); + + // no policies on this cert + QCOMPARE(server1.policies().count(), 0); + + QCA::CertificateInfo subject1 = server1.subjectInfo(); + QCOMPARE(subject1.isEmpty(), false); + QVERIFY(subject1.contains(QCA::Country, QStringLiteral("IL"))); + QVERIFY(subject1.contains(QCA::Organization, QStringLiteral("Qca Development and Test"))); + QVERIFY(subject1.contains(QCA::OrganizationalUnit, QStringLiteral("Server Management Section"))); + QVERIFY(subject1.contains(QCA::CommonName, QStringLiteral("Qca Server Test certificate"))); + + QCA::CertificateInfo issuer1 = server1.issuerInfo(); + QCOMPARE(issuer1.isEmpty(), false); + QVERIFY(issuer1.contains(QCA::Country, QStringLiteral("AU"))); + QVERIFY(issuer1.contains(QCA::Organization, QStringLiteral("Qca Development and Test"))); + QVERIFY(issuer1.contains(QCA::OrganizationalUnit, QStringLiteral("Certificate Generation Section"))); + QVERIFY(issuer1.contains(QCA::CommonName, QStringLiteral("Qca Test Root Certificate"))); + + QByteArray subjectKeyID = + QCA::Hex().stringToArray(QStringLiteral("819870c8b81eab53e72d0446b65790aa0d3eab1a")).toByteArray(); + QCOMPARE(server1.subjectKeyId(), subjectKeyID); + QByteArray authorityKeyID = + QCA::Hex().stringToArray(QStringLiteral("f61c451de1b0458138c60568c1a7cb0f7ade0363")).toByteArray(); + QCOMPARE(server1.issuerKeyId(), authorityKeyID); + + QCA::PublicKey pubkey1 = server1.subjectPublicKey(); + QCOMPARE(pubkey1.isNull(), false); + QCOMPARE(pubkey1.isRSA(), true); + QCOMPARE(pubkey1.isDSA(), false); + QCOMPARE(pubkey1.isDH(), false); + QCOMPARE(pubkey1.isPublic(), true); + QCOMPARE(pubkey1.isPrivate(), false); + QCOMPARE(pubkey1.bitSize(), 1024); + + QCOMPARE(server1.pathLimit(), 0); + + QCOMPARE(server1.signatureAlgorithm(), QCA::EMSA3_SHA1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(server1.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::ConvertResult resultca1; + QCA::Certificate ca1 = + QCA::Certificate::fromPEMFile(QStringLiteral("certs/QcaTestRootCert.pem"), &resultca1, provider); + QCOMPARE(resultca1, QCA::ConvertGood); + trusted.addCertificate(ca1); + QCOMPARE(server1.validate(trusted, untrusted), QCA::ValidityGood); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageAny), QCA::ValidityGood); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTLSServer), QCA::ValidityGood); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTLSClient), QCA::ErrorInvalidPurpose); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageCodeSigning), QCA::ErrorInvalidPurpose); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageTimeStamping), QCA::ErrorInvalidPurpose); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageEmailProtection), QCA::ErrorInvalidPurpose); + QCOMPARE(server1.validate(trusted, untrusted, QCA::UsageCRLSigning), QCA::ErrorInvalidPurpose); + + QByteArray derServer1 = server1.toDER(); + QCOMPARE(derServer1.isEmpty(), false); + QCA::Certificate fromDer1 = QCA::Certificate::fromDER(derServer1, &resultServer1, provider); + QCOMPARE(resultServer1, QCA::ConvertGood); + QCOMPARE(fromDer1 == server1, true); + } + } +} + +void CertUnitTest::checkSystemStore() +{ + if (QCA::isSupported("cert") && QCA::isSupported("crl")) { + QCOMPARE(QCA::haveSystemStore(), true); + + QCA::CertificateCollection collection1; + collection1 = QCA::systemStore(); + // Do we have any certs? + QVERIFY(collection1.certificates().count() > 0); + } else { + QCOMPARE(QCA::haveSystemStore(), false); + } +} + +void CertUnitTest::crl() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("crl", provider)) + QWARN((QStringLiteral("Certificate revocation not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::CRL emptyCRL; + QVERIFY(emptyCRL.isNull()); + + QCA::ConvertResult resultCrl; + QCA::CRL crl1 = QCA::CRL::fromPEMFile(QStringLiteral("certs/Test_CRL.crl"), &resultCrl, provider); + QCOMPARE(resultCrl, QCA::ConvertGood); + QCOMPARE(crl1.isNull(), false); + + QCA::CertificateInfo issuer = crl1.issuerInfo(); + QCOMPARE(issuer.isEmpty(), false); + QVERIFY(issuer.contains(QCA::Country, QStringLiteral("de"))); + QVERIFY(issuer.contains(QCA::Organization, QStringLiteral("InsecureTestCertificate"))); + QVERIFY(issuer.contains(QCA::CommonName, QStringLiteral("For Tests Only"))); + + // No keyid extension on this crl + QCOMPARE(QCA::arrayToHex(crl1.issuerKeyId()), QLatin1String("")); + + QCOMPARE(crl1.thisUpdate(), QDateTime(QDate(2001, 8, 17), QTime(11, 12, 03), Qt::UTC)); + QCOMPARE(crl1.nextUpdate(), QDateTime(QDate(2006, 8, 16), QTime(11, 12, 03), Qt::UTC)); + + QCOMPARE(crl1.signatureAlgorithm(), QCA::EMSA3_MD5); + + QCOMPARE(crl1.issuerKeyId(), QByteArray("")); + QCOMPARE(crl1, QCA::CRL(crl1)); + QCOMPARE(crl1 == QCA::CRL(), false); + QCOMPARE(crl1.number(), -1); + + QList revokedList = crl1.revoked(); + QCOMPARE(revokedList.size(), 2); + std::sort(revokedList.begin(), revokedList.end()); + QCOMPARE(revokedList[0].serialNumber(), QCA::BigInteger("3")); + QCOMPARE(revokedList[1].serialNumber(), QCA::BigInteger("5")); + QCOMPARE(revokedList[0].reason(), QCA::CRLEntry::Unspecified); + QCOMPARE(revokedList[1].reason(), QCA::CRLEntry::Unspecified); + QCOMPARE(revokedList[0].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 10, 39), Qt::UTC)); + QCOMPARE(revokedList[1].time(), QDateTime(QDate(2001, 8, 17), QTime(11, 11, 59), Qt::UTC)); + + // convert to DER + QByteArray derCRL1 = crl1.toDER(); + // check we got something, at least + QCOMPARE(derCRL1.isEmpty(), false); + // convert back from DER + QCA::CRL fromDer1 = QCA::CRL::fromDER(derCRL1, &resultCrl, provider); + // check the conversion at least appeared to work + QCOMPARE(resultCrl, QCA::ConvertGood); + // check the result is the same as what we started with + QCOMPARE(fromDer1, crl1); + } + } +} + +void CertUnitTest::crl2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("crl", provider)) + QWARN((QStringLiteral("Certificate revocation not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult resultCrl; + QCA::CRL crl1 = QCA::CRL::fromPEMFile(QStringLiteral("certs/GoodCACRL.pem"), &resultCrl, provider); + QCOMPARE(resultCrl, QCA::ConvertGood); + QCOMPARE(crl1.isNull(), false); + QCOMPARE(crl1.provider()->name(), provider); + + QCA::CertificateInfo issuer = crl1.issuerInfo(); + QCOMPARE(issuer.isEmpty(), false); + QVERIFY(issuer.contains(QCA::Country, QStringLiteral("US"))); + QVERIFY(issuer.contains(QCA::Organization, QStringLiteral("Test Certificates"))); + QVERIFY(issuer.contains(QCA::CommonName, QStringLiteral("Good CA"))); + + QCOMPARE(crl1.thisUpdate(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC)); + QCOMPARE(crl1.nextUpdate(), QDateTime(QDate(2011, 4, 19), QTime(14, 57, 20), Qt::UTC)); + + QCOMPARE(crl1.signatureAlgorithm(), QCA::EMSA3_SHA1); + + QCOMPARE(QCA::arrayToHex(crl1.issuerKeyId()), QStringLiteral("b72ea682cbc2c8bca87b2744d73533df9a1594c7")); + QCOMPARE(crl1.number(), 1); + QCOMPARE(crl1, QCA::CRL(crl1)); + QCOMPARE(crl1 == QCA::CRL(), false); + + QList revokedList = crl1.revoked(); + QCOMPARE(revokedList.size(), 2); + std::sort(revokedList.begin(), revokedList.end()); + QCOMPARE(revokedList[0].serialNumber(), QCA::BigInteger("14")); + QCOMPARE(revokedList[1].serialNumber(), QCA::BigInteger("15")); + QCOMPARE(revokedList[0].reason(), QCA::CRLEntry::KeyCompromise); + QCOMPARE(revokedList[1].reason(), QCA::CRLEntry::KeyCompromise); + QCOMPARE(revokedList[0].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC)); + QCOMPARE(revokedList[1].time(), QDateTime(QDate(2001, 4, 19), QTime(14, 57, 20), Qt::UTC)); + + // convert to DER + QByteArray derCRL1 = crl1.toDER(); + // check we got something, at least + QCOMPARE(derCRL1.isEmpty(), false); + // convert back from DER + QCA::CRL fromDer1 = QCA::CRL::fromDER(derCRL1, &resultCrl, provider); + // check the conversion at least appeared to work + QCOMPARE(resultCrl, QCA::ConvertGood); + // check the result is the same as what we started with + QCOMPARE(fromDer1, crl1); + + // convert to PEM + QString pemCRL1 = crl1.toPEM(); + // check we got something, at least + QCOMPARE(pemCRL1.isEmpty(), false); + // convert back from PEM + QCA::CRL fromPEM1 = QCA::CRL::fromPEM(pemCRL1, &resultCrl, provider); + // check the conversion at least appeared to work + QCOMPARE(resultCrl, QCA::ConvertGood); + // check the result is the same as what we started with + QCOMPARE(fromPEM1, crl1); + } + } +} + +void CertUnitTest::csr() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("csr", provider)) + QWARN((QStringLiteral("Certificate signing requests not supported for ") + provider) + .toLocal8Bit() + .constData()); + else { + QCA::CertificateRequest nullCSR; + QVERIFY(nullCSR.isNull()); + // This is copied on purpose to check the assignment operator + QCA::CertificateRequest anotherNullCSR = nullCSR; // NOLINT(performance-unnecessary-copy-initialization) + QVERIFY(anotherNullCSR.isNull()); + QCOMPARE(nullCSR, anotherNullCSR); + + QCA::ConvertResult resultCsr; + QCA::CertificateRequest csr1 = + QCA::CertificateRequest::fromPEMFile(QStringLiteral("certs/csr1.pem"), &resultCsr, provider); + QCOMPARE(resultCsr, QCA::ConvertGood); + QCOMPARE(csr1.isNull(), false); + QCOMPARE(csr1.provider()->name(), provider); + QCA::CertificateInfo subject = csr1.subjectInfo(); + QCOMPARE(subject.isEmpty(), false); + QVERIFY(subject.contains(QCA::Country, QStringLiteral("AU"))); + QVERIFY(subject.contains(QCA::State, QStringLiteral("Victoria"))); + QVERIFY(subject.contains(QCA::Locality, QStringLiteral("Mitcham"))); + QVERIFY(subject.contains(QCA::Organization, QStringLiteral("GE Interlogix"))); + QVERIFY(subject.contains(QCA::OrganizationalUnit, QStringLiteral("Engineering"))); + QVERIFY(subject.contains(QCA::CommonName, QStringLiteral("coldfire"))); + + QCA::PublicKey pkey = csr1.subjectPublicKey(); + QCOMPARE(pkey.isNull(), false); + QVERIFY(pkey.isRSA()); + + QCA::RSAPublicKey rsaPkey = pkey.toRSA(); + QCOMPARE(rsaPkey.isNull(), false); + QCOMPARE(rsaPkey.e(), QCA::BigInteger(65537)); + QCOMPARE(rsaPkey.n(), + QCA::BigInteger("104853561647822232509211983664549572246855698961210758585652966258891659217901732" + "470712446421431206166165309547771124747713609923038218156616083520796442797276676" + "074122658684367500665423564881889504308700315044585826841844654287577169905826705" + "891670004942854611681809539126326134927995969418712881512819058439")); + + QCOMPARE(csr1.signatureAlgorithm(), QCA::EMSA3_MD5); + } + } +} + +void CertUnitTest::csr2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-botan"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("csr", provider)) + QWARN((QStringLiteral("Certificate signing requests not supported for ") + provider) + .toLocal8Bit() + .constData()); + else { + QCA::ConvertResult resultCsr; + QCA::CertificateRequest csr1 = + QCA::CertificateRequest::fromPEMFile(QStringLiteral("certs/newreq.pem"), &resultCsr, provider); + QCOMPARE(resultCsr, QCA::ConvertGood); + QCOMPARE(csr1.isNull(), false); + QCOMPARE(csr1.provider()->name(), provider); + QCA::CertificateInfo subject = csr1.subjectInfo(); + QCOMPARE(subject.isEmpty(), false); + QVERIFY(subject.contains(QCA::Country, QStringLiteral("AI"))); + QVERIFY(subject.contains(QCA::State, QStringLiteral("Hutt River Province"))); + QVERIFY(subject.contains(QCA::Locality, QStringLiteral("Lesser Internet"))); + QVERIFY(subject.contains(QCA::Organization, QStringLiteral("My Company Ltd"))); + QVERIFY(subject.contains(QCA::OrganizationalUnit, QStringLiteral("Backwater Branch Office"))); + QVERIFY(subject.contains(QCA::CommonName, QStringLiteral("FirstName Surname"))); + + QCA::PublicKey pkey = csr1.subjectPublicKey(); + QCOMPARE(pkey.isNull(), false); + QVERIFY(pkey.isRSA()); + + QCA::RSAPublicKey rsaPkey = pkey.toRSA(); + QCOMPARE(rsaPkey.isNull(), false); + QCOMPARE(rsaPkey.e(), QCA::BigInteger(65537)); + QCOMPARE(rsaPkey.n(), + QCA::BigInteger("151872780463004414908584891835397365176526767139347372444365914360701714510188717" + "169754430290680734981291754624394094502297070722505032645306680495915914243593438" + "796635264236530526146243919417744996366836534380790370421346490191416041004278161" + "146551997010463199760480957900518811859984176646089981367745961681")); + + QCOMPARE(csr1.signatureAlgorithm(), QCA::EMSA3_MD5); + + // convert to DER + QByteArray derCSR1 = csr1.toDER(); + // check we got something, at least + QCOMPARE(derCSR1.isEmpty(), false); + // convert back from DER + QCA::CertificateRequest fromDer1 = QCA::CertificateRequest::fromDER(derCSR1, &resultCsr, provider); + // check the conversion at least appeared to work + QCOMPARE(resultCsr, QCA::ConvertGood); + // check the result is the same as what we started with + QCOMPARE(fromDer1, csr1); + + // convert to PEM + QString pemCSR1 = csr1.toPEM(); + // check we got something, at least + QCOMPARE(pemCSR1.isEmpty(), false); + // convert back from PEM + QCA::CertificateRequest fromPEM1 = QCA::CertificateRequest::fromPEM(pemCSR1, &resultCsr, provider); + // check the conversion at least appeared to work + QCOMPARE(resultCsr, QCA::ConvertGood); + // check the result is the same as what we started with + QCOMPARE(fromPEM1, csr1); + } + } +} +QTEST_MAIN(CertUnitTest) + +#include "certunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/checkall b/local/recipes/libs/qca/source/unittest/checkall new file mode 100644 index 0000000000..308c254e50 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/checkall @@ -0,0 +1,28 @@ +#!/bin/sh +export LD_LIBRARY_PATH="../../lib:$LD_LIBRARY_PATH" +cd base64unittest && make test && cd .. && \ +cd bigintunittest && make test && cd .. && \ +cd certunittest && make test && cd .. && \ +cd cipherunittest && make test && cd .. && \ +cd clientplugin && make test && cd .. && \ +cd cms && make test && cd .. && \ +cd dsaunittest && make test && cd .. && \ +#cd filewatchunittest && make test && cd .. && \ +cd hashunittest && make test && cd .. && \ +cd hexunittest && make test && cd .. && \ +cd kdfunittest && make test && cd .. && \ +cd keybundle && make test && cd .. && \ +cd keygenunittest && make test && cd .. && \ +cd keylengthunittest && make test && cd .. && \ +cd keystore && make test && cd .. && \ +cd macunittest && make test && cd .. && \ +cd metatype && make test && cd .. && \ +cd pgpunittest && make test && cd .. && \ +cd pipeunittest && make test && cd .. && \ +cd pkits && make test && cd .. && \ +cd rsaunittest && make test && cd .. && \ +cd securearrayunittest && make test && cd .. && \ +cd staticunittest && make test && cd .. && \ +cd symmetrickeyunittest && make test && cd .. && \ +cd tls && make test && cd .. #&& \ +cd velox && make test && cd .. diff --git a/local/recipes/libs/qca/source/unittest/cipherunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/cipherunittest/CMakeLists.txt new file mode 100644 index 0000000000..5986735cb4 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cipherunittest/CMakeLists.txt @@ -0,0 +1,10 @@ +enable_testing() + +set(cipherunittest_bin_HDRS cipherunittest.h) +set(cipherunittest_bin_SRCS cipherunittest.cpp) + +add_executable(cipherunittest ${cipherunittest_bin_SRCS} ${EXTRA_SRCS} ${cipherunittest_bin_HDRS}) + +target_link_qca_test_libraries(cipherunittest) + +add_qca_test(cipherunittest "SymmetricCipher") diff --git a/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.cpp b/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.cpp new file mode 100644 index 0000000000..87ba27b057 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.cpp @@ -0,0 +1,3075 @@ +/** + * Copyright (C) 2004-2007 Brad Hards + * Copyright (C) 2013-2016 Ivan Romanov + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include "cipherunittest.h" + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +void CipherUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; + const auto providers = QCA::providers(); + for (QCA::Provider *provider : providers) + providersToTest << provider->name(); +} + +void CipherUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void CipherUnitTest::aes128_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + // Not sure where this came from... + QTest::newRow("mystery") << QStringLiteral("506812a45f08c889b97f5980038b8359") + << QStringLiteral("d8f532538289ef7d06b506a4fd5be9c9") + << QStringLiteral("00010203050607080a0b0c0d0f101112"); + + // From FIPS 197 Appendix C.1 + QTest::newRow("FIPS197 App C.1") << QStringLiteral("00112233445566778899aabbccddeeff") + << QStringLiteral("69c4e0d86a7b0430d8cdb78070b4c55a") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); + + // These are from the Botan test suite + QTest::newRow("1") << QStringLiteral("506812a45f08c889b97f5980038b8359") + << QStringLiteral("d8f532538289ef7d06b506a4fd5be9c9") + << QStringLiteral("00010203050607080a0b0c0d0f101112"); + QTest::newRow("2") << QStringLiteral("5c6d71ca30de8b8b00549984d2ec7d4b") + << QStringLiteral("59ab30f4d4ee6e4ff9907ef65b1fb68c") + << QStringLiteral("14151617191a1b1c1e1f202123242526"); + QTest::newRow("3") << QStringLiteral("53f3f4c64f8616e4e7c56199f48f21f6") + << QStringLiteral("bf1ed2fcb2af3fd41443b56d85025cb1") + << QStringLiteral("28292a2b2d2e2f30323334353738393a"); + QTest::newRow("4") << QStringLiteral("a1eb65a3487165fb0f1c27ff9959f703") + << QStringLiteral("7316632d5c32233edcb0780560eae8b2") + << QStringLiteral("3c3d3e3f41424344464748494b4c4d4e"); + QTest::newRow("5") << QStringLiteral("3553ecf0b1739558b08e350a98a39bfa") + << QStringLiteral("408c073e3e2538072b72625e68b8364b") + << QStringLiteral("50515253555657585a5b5c5d5f606162"); + QTest::newRow("6") << QStringLiteral("67429969490b9711ae2b01dc497afde8") + << QStringLiteral("e1f94dfa776597beaca262f2f6366fea") + << QStringLiteral("64656667696a6b6c6e6f707173747576"); + QTest::newRow("7") << QStringLiteral("93385c1f2aec8bed192f5a8e161dd508") + << QStringLiteral("f29e986c6a1c27d7b29ffd7ee92b75f1") + << QStringLiteral("78797a7b7d7e7f80828384858788898a"); + QTest::newRow("8") << QStringLiteral("3e23b3bc065bcc152407e23896d77783") + << QStringLiteral("1959338344e945670678a5d432c90b93") + << QStringLiteral("54555657595a5b5c5e5f606163646566"); + QTest::newRow("9") << QStringLiteral("79f0fba002be1744670e7e99290d8f52") + << QStringLiteral("e49bddd2369b83ee66e6c75a1161b394") + << QStringLiteral("68696a6b6d6e6f70727374757778797a"); + QTest::newRow("10") << QStringLiteral("da23fe9d5bd63e1d72e3dafbe21a6c2a") + << QStringLiteral("d3388f19057ff704b70784164a74867d") + << QStringLiteral("7c7d7e7f81828384868788898b8c8d8e"); + QTest::newRow("11") << QStringLiteral("e3f5698ba90b6a022efd7db2c7e6c823") + << QStringLiteral("23aa03e2d5e4cd24f3217e596480d1e1") + << QStringLiteral("a4a5a6a7a9aaabacaeafb0b1b3b4b5b6"); + QTest::newRow("12") << QStringLiteral("bdc2691d4f1b73d2700679c3bcbf9c6e") + << QStringLiteral("c84113d68b666ab2a50a8bdb222e91b9") + << QStringLiteral("e0e1e2e3e5e6e7e8eaebecedeff0f1f2"); + QTest::newRow("13") << QStringLiteral("ba74e02093217ee1ba1b42bd5624349a") + << QStringLiteral("ac02403981cd4340b507963db65cb7b6") + << QStringLiteral("08090a0b0d0e0f10121314151718191a"); + QTest::newRow("14") << QStringLiteral("b5c593b5851c57fbf8b3f57715e8f680") + << QStringLiteral("8d1299236223359474011f6bf5088414") + << QStringLiteral("6c6d6e6f71727374767778797b7c7d7e"); +} + +void CipherUnitTest::aes128() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-ecb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("aes128"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(forwardCipher.blockSize(), 16); + QCOMPARE(forwardCipher.keyLength().minimum(), 16); + QCOMPARE(forwardCipher.keyLength().maximum(), 16); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("aes128"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(reverseCipher.blockSize(), 16); + QCOMPARE(reverseCipher.keyLength().minimum(), 16); + QCOMPARE(reverseCipher.keyLength().maximum(), 16); + + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 ECB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes128_cbc_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b273bed6b8e3c1743b7116e69e" + "222295163ff1caa1681fac09120eca307586e1a7") + << QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes128_cbc() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-cbc", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes128"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes128"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 CBC:" << providersToTest; +} + +// These were generated using OpenSSL's enc command +void CipherUnitTest::aes128_cbc_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QString(QLatin1String("")) << QStringLiteral("18fe62efa4dc4b21a4127b225855b475") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("2") << QStringLiteral("610a") << QStringLiteral("92823eab12924cd168f54d3f4baa9a4d") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("3") << QStringLiteral("6162636465666768696a0a") << QStringLiteral("9d41b355abd61e3dfa482f3c1aeaae49") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size - 1") << QStringLiteral("6162636465666768696a6b6c6d6e0a") + << QStringLiteral("c86b53850815cae7ae4a6e7529a87587") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size") << QStringLiteral("6162636465666768696a6b6c6d6e310a") + << QStringLiteral("26fb0474b70d118f2b1d5b74e58c97bf3bb81bece1250509c5c68771ae23ceac") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size+1") << QStringLiteral("6162636465666768696a6b6c6d6e6f310a") + << QStringLiteral("656f5c5693741967e059149e9239452fa286ac7c86ef653182d226d543d53013") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF") + << QStringLiteral("00001111222233334444555566667777"); +} + +void CipherUnitTest::aes128_cbc_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-cbc-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher(QStringLiteral("aes128"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Encode, + key, + iv, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes128"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Decode, + key, + iv, + provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 CBC with PKCS7 padding:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes128_cfb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "3b3fd92eb72dad20333449f8e83cfb4ac8a64537a0b3a93fcde3cdad9f1ce58b26751f67a3cbb140b1808cf1" + "87a4f4dfc04b05357c5d1c0eeac4c66f9ff7f2e6") + << QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes128_cfb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-cfb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes128"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes128"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 CFB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes128_ofb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a8" + "2260edcc304c6528f659c77866a510d9c1d6ae5e") + << QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes128_ofb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-ofb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes128"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes128"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 OFB:" << providersToTest; +} + +void CipherUnitTest::aes128_ctr_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "3b3fd92eb72dad20333449f8e83cfb4a010c041999e03f36448624483e582d0ea62293cfa6df74535c354181" + "168774df2d55a54706273c50d7b4f8a8cddc6ed7") + << QStringLiteral("2b7e151628aed2a6abf7158809cf4f3c") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes128_ctr() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes128-ctr", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes128"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes128"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 CTR:" << providersToTest; +} + +void CipherUnitTest::aes128_gcm_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("payload"); + QTest::addColumn("tag"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("short") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("a9f2558b9a74e6fc551f") + << QStringLiteral("f8ebf75f108c6f74e6fe49035d268d43") + << QStringLiteral("1f491f8ddf4856ae4bff9039d418175a") + << QStringLiteral("f85f8aad39164daf64a12ad9b3fc8a3a"); + + QTest::newRow("long") << QStringLiteral( + "54484520515549434b2042524f574e20464f58204a554d504544204f56455220544845204c415a5920444" + "f472753204241434b2031323334353637383930") + << QStringLiteral( + "04e321a8870b6b9cd6846239c27a63fb41d0a7b8994f1514c066f0427fa9ed6707ea6e3b4f161fdff0eb5" + "fc087ed3827b569cd72456c697b5a3a62c9e767") + << QStringLiteral("b0ad4aa545ea25fc3117cbed955ff155") + << QStringLiteral("56341f2b431d3b0dbad787db003f2215") + << QStringLiteral("bfcd3a7252f7f199bf788df8cf61032a"); + + QTest::newRow("wrongtag") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("a9f2558b9a74e6fc551f") + << QStringLiteral("f8ebf75f108c6f74e6fe49035d268d44") + << QStringLiteral("1f491f8ddf4856ae4bff9039d418175a") + << QStringLiteral("f85f8aad39164daf64a12ad9b3fc8a3a"); +} + +void CipherUnitTest::aes128_gcm() +{ + bool anyProviderTested = false; + foreach (const QString &provider, providersToTest) { + if (QCA::isSupported("aes128-gcm", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, payload); + QFETCH(QString, tag); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::AuthTag authTag(16); + QCA::Cipher forwardCipher(QStringLiteral("aes128"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + iv, + authTag, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + update += QCA::arrayToHex(forwardCipher.final().toByteArray()); + authTag = forwardCipher.tag(); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(QCA::arrayToHex(authTag.toByteArray()), tag); + QCOMPARE(update, payload); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes128"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + iv, + QCA::AuthTag(QCA::hexToArray(tag)), + provider); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(payload)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + update += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(update, plainText); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES128 GCM:" << providersToTest; +} + +void CipherUnitTest::aes128_ccm_data() +{ +} + +void CipherUnitTest::aes128_ccm() +{ + // For future implementation +} + +void CipherUnitTest::aes192_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + // From FIPS 197 Appendix C.2 + QTest::newRow("FIPS197 App C.2") << QStringLiteral("00112233445566778899aabbccddeeff") + << QStringLiteral("dda97ca4864cdfe06eaf70a0ec0d7191") + << QStringLiteral("000102030405060708090A0B0C0D0E0F1011121314151617"); + + // These are from the Botan test suite + QTest::newRow("1") << QStringLiteral("fec1c04f529bbd17d8cecfcc4718b17f") + << QStringLiteral("62564c738f3efe186e1a127a0c4d3c61") + << QStringLiteral("4a4b4c4d4f50515254555657595a5b5c5e5f606163646566"); + QTest::newRow("2") << QStringLiteral("32df99b431ed5dc5acf8caf6dc6ce475") + << QStringLiteral("07805aa043986eb23693e23bef8f3438") + << QStringLiteral("68696a6b6d6e6f70727374757778797a7c7d7e7f81828384"); + QTest::newRow("3") << QStringLiteral("7fdc2b746f3f665296943b83710d1f82") + << QStringLiteral("df0b4931038bade848dee3b4b85aa44b") + << QStringLiteral("868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2"); + QTest::newRow("4") << QStringLiteral("8fba1510a3c5b87e2eaa3f7a91455ca2") + << QStringLiteral("592d5fded76582e4143c65099309477c") + << QStringLiteral("a4a5a6a7a9aaabacaeafb0b1b3b4b5b6b8b9babbbdbebfc0"); + QTest::newRow("5") << QStringLiteral("2c9b468b1c2eed92578d41b0716b223b") + << QStringLiteral("c9b8d6545580d3dfbcdd09b954ed4e92") + << QStringLiteral("c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde"); + QTest::newRow("6") << QStringLiteral("0a2bbf0efc6bc0034f8a03433fca1b1a") + << QStringLiteral("5dccd5d6eb7c1b42acb008201df707a0") + << QStringLiteral("e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfc"); + QTest::newRow("7") << QStringLiteral("25260e1f31f4104d387222e70632504b") + << QStringLiteral("a2a91682ffeb6ed1d34340946829e6f9") + << QStringLiteral("fefe01010304050608090a0b0d0e0f10121314151718191a"); + QTest::newRow("8") << QStringLiteral("c527d25a49f08a5228d338642ae65137") + << QStringLiteral("e45d185b797000348d9267960a68435d") + << QStringLiteral("1c1d1e1f21222324262728292b2c2d2e3031323335363738"); + QTest::newRow("9") << QStringLiteral("3b49fc081432f5890d0e3d87e884a69e") + << QStringLiteral("45e060dae5901cda8089e10d4f4c246b") + << QStringLiteral("3a3b3c3d3f40414244454647494a4b4c4e4f505153545556"); + QTest::newRow("10") << QStringLiteral("d173f9ed1e57597e166931df2754a083") + << QStringLiteral("f6951afacc0079a369c71fdcff45df50") + << QStringLiteral("58595a5b5d5e5f60626364656768696a6c6d6e6f71727374"); + QTest::newRow("11") << QStringLiteral("8c2b7cafa5afe7f13562daeae1adede0") + << QStringLiteral("9e95e00f351d5b3ac3d0e22e626ddad6") + << QStringLiteral("767778797b7c7d7e80818283858687888a8b8c8d8f909192"); + QTest::newRow("12") << QStringLiteral("aaf4ec8c1a815aeb826cab741339532c") + << QStringLiteral("9cb566ff26d92dad083b51fdc18c173c") + << QStringLiteral("94959697999a9b9c9e9fa0a1a3a4a5a6a8a9aaabadaeafb0"); + QTest::newRow("13") << QStringLiteral("40be8c5d9108e663f38f1a2395279ecf") + << QStringLiteral("c9c82766176a9b228eb9a974a010b4fb") + << QStringLiteral("d0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebec"); + QTest::newRow("14") << QStringLiteral("0c8ad9bc32d43e04716753aa4cfbe351") + << QStringLiteral("d8e26aa02945881d5137f1c1e1386e88") + << QStringLiteral("2a2b2c2d2f30313234353637393a3b3c3e3f404143444546"); + QTest::newRow("15") << QStringLiteral("1407b1d5f87d63357c8dc7ebbaebbfee") + << QStringLiteral("c0e024ccd68ff5ffa4d139c355a77c55") + << QStringLiteral("48494a4b4d4e4f50525354555758595a5c5d5e5f61626364"); +} + +void CipherUnitTest::aes192() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-ecb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("aes192"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(forwardCipher.blockSize(), 16); + QCOMPARE(forwardCipher.keyLength().minimum(), 24); + QCOMPARE(forwardCipher.keyLength().maximum(), 24); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("aes192"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(reverseCipher.blockSize(), 16); + QCOMPARE(reverseCipher.keyLength().minimum(), 24); + QCOMPARE(reverseCipher.keyLength().maximum(), 24); + + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 ECB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes192_cbc_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "4f021db243bc633d7178183a9fa071e8b4d9ada9ad7dedf4e5e738763f69145a571b242012fb7ae07fa9baac" + "3df102e008b0e27988598881d920a9e64f5615cd") + << QStringLiteral("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes192_cbc() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-cbc", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes192"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes192"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 CBC:" << providersToTest; +} + +// These were generated using OpenSSL's enc command +void CipherUnitTest::aes192_cbc_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QString(QLatin1String("")) << QStringLiteral("49c1da70f461d1bb5147ded60f0f01ef") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("2") << QStringLiteral("610a") << QStringLiteral("42e5a030df8b6bf896899853744e480c") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("3") << QStringLiteral("6162636465666768696a0a") << QStringLiteral("160a3b6ff48d6850906ffa6b8291f511") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size - 1") << QStringLiteral("6162636465666768696a6b6c6d6e0a") + << QStringLiteral("b113c5aec849e49dc8487f66ce29bab0") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size") << QStringLiteral("6162636465666768696a6b6c6d6e310a") + << QStringLiteral("80c4a001f93c468b7dd3525cc46020b470e3ac39a13be57ab18c7903d121a266") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size+1") << QStringLiteral("6162636465666768696a6b6c6d6e6f310a") + << QStringLiteral("f0f9982e4118287cda37062f5acfd7b2f27741ddac7bd3882c7b4e4872b81047") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF0011223344556677") + << QStringLiteral("00001111222233334444555566667777"); +} + +void CipherUnitTest::aes192_cbc_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-cbc-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher(QStringLiteral("aes192"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Encode, + key, + iv, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes192"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Decode, + key, + iv, + provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 CBC with PKCS7 padding:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes192_cfb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "cdc80d6fddf18cab34c25909c99a417467ce7f7f81173621961a2b70171d3d7a2e1e8a1dd59b88b1c8e60fed" + "1efac4c9c05f9f9ca9834fa042ae8fba584b09ff") + << QStringLiteral("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes192_cfb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-cfb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes192"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes192"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 CFB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::aes192_ofb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4d" + "af59a5f26d9f200857ca6c3e9cac524bd9acc92a") + << QStringLiteral("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes192_ofb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-ofb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes192"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes192"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 OFB:" << providersToTest; +} + +void CipherUnitTest::aes192_ctr_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "cdc80d6fddf18cab34c25909c99a417437d8a639171fdcca63ebd17ce2d7321a79a0c96b53c7eeecd9ed7157" + "c444fc7a845c37b2f511697b0e89d5ed60c4d49e") + << QStringLiteral("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes192_ctr() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes192-ctr", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes192"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes192"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 CTR:" << providersToTest; +} + +void CipherUnitTest::aes192_gcm_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("payload"); + QTest::addColumn("tag"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("short") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("01ca25ff74121917f397") + << QStringLiteral("b90e97706d8eacbabc0be5e0a671b4e4") + << QStringLiteral("7ecb21a647fae54a0996ad281ab0c1a00cb905d9e2eb3b82") + << QStringLiteral("f85f8aad39164daf64a12ad9b3fc8a3a"); + + QTest::newRow("long") << QStringLiteral( + "54484520515549434b2042524f574e20464f58204a554d504544204f56455220544845204c415a5920444" + "f472753204241434b2031323334353637383930") + << QStringLiteral( + "4c1c5874877f0bee6efd450ec341b1c591e1e100da40bd4744e1035ed0ed0fb458f8efdb7c4b0b2101e29" + "c950c56dc2489c2febec2d7062da28b9a033173") + << QStringLiteral("af3ea1b7f275ea1e4d4e1fdce63f83fe") + << QStringLiteral("7ecb21a647fae54a0996ad281ab0c1a00cb905d9e2eb3b82") + << QStringLiteral("bfcd3a7252f7f199bf788df8cf61032a"); + + QTest::newRow("wrongtag") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("773c3d06b94727c04afc") + << QStringLiteral("c558aca7f19050db49d94d99119277af") + << QStringLiteral("7ecb21a647fae54a0996ad281ab0c1a00cb905d9e2eb3b82") + << QStringLiteral("bfcd3a7252f7f199bf788df8cf61032a"); +} + +void CipherUnitTest::aes192_gcm() +{ + bool anyProviderTested = false; + foreach (const QString &provider, providersToTest) { + if (QCA::isSupported("aes192-gcm", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, payload); + QFETCH(QString, tag); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::AuthTag authTag(16); + QCA::Cipher forwardCipher(QStringLiteral("aes192"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + iv, + authTag, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + update += QCA::arrayToHex(forwardCipher.final().toByteArray()); + authTag = forwardCipher.tag(); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(QCA::arrayToHex(authTag.toByteArray()), tag); + QCOMPARE(update, payload); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes192"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + iv, + QCA::AuthTag(QCA::hexToArray(tag)), + provider); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(payload)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + update += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(update, plainText); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES192 GCM:" << providersToTest; +} + +void CipherUnitTest::aes192_ccm_data() +{ +} + +void CipherUnitTest::aes192_ccm() +{ + // For future implementation +} + +void CipherUnitTest::aes256_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + // From FIPS 197 Appendix C.3 + QTest::newRow("FIPS197 App C.3") << QStringLiteral("00112233445566778899aabbccddeeff") + << QStringLiteral("8ea2b7ca516745bfeafc49904b496089") + << QStringLiteral( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + + // These are from the Botan test suite + QTest::newRow("1") << QStringLiteral("e51aa0b135dba566939c3b6359a980c5") + << QStringLiteral("8cd9423dfc459e547155c5d1d522e540") + << QStringLiteral("e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506"); + + QTest::newRow("2") << QStringLiteral("069a007fc76a459f98baf917fedf9521") + << QStringLiteral("080e9517eb1677719acf728086040ae3") + << QStringLiteral("08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e"); + + QTest::newRow("3") << QStringLiteral("726165c1723fbcf6c026d7d00b091027") + << QStringLiteral("7c1700211a3991fc0ecded0ab3e576b0") + << QStringLiteral("30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556"); + + QTest::newRow("4") << QStringLiteral("d7c544de91d55cfcde1f84ca382200ce") + << QStringLiteral("dabcbcc855839251db51e224fbe87435") + << QStringLiteral("58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e"); + + QTest::newRow("5") << QStringLiteral("fed3c9a161b9b5b2bd611b41dc9da357") + << QStringLiteral("68d56fad0406947a4dd27a7448c10f1d") + << QStringLiteral("80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6"); + + QTest::newRow("6") << QStringLiteral("4f634cdc6551043409f30b635832cf82") + << QStringLiteral("da9a11479844d1ffee24bbf3719a9925") + << QStringLiteral("a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce"); + + QTest::newRow("7") << QStringLiteral("109ce98db0dfb36734d9f3394711b4e6") + << QStringLiteral("5e4ba572f8d23e738da9b05ba24b8d81") + << QStringLiteral("d0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6"); + + QTest::newRow("8") << QStringLiteral("4ea6dfaba2d8a02ffdffa89835987242") + << QStringLiteral("a115a2065d667e3f0b883837a6e903f8") + << QStringLiteral("70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596"); + + QTest::newRow("9") << QStringLiteral("5ae094f54af58e6e3cdbf976dac6d9ef") + << QStringLiteral("3e9e90dc33eac2437d86ad30b137e66e") + << QStringLiteral("98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe"); + + QTest::newRow("10") << QStringLiteral("764d8e8e0f29926dbe5122e66354fdbe") + << QStringLiteral("01ce82d8fbcdae824cb3c48e495c3692") + << QStringLiteral("c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6"); + + QTest::newRow("11") << QStringLiteral("3f0418f888cdf29a982bf6b75410d6a9") + << QStringLiteral("0c9cff163ce936faaf083cfd3dea3117") + << QStringLiteral("e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e"); + + QTest::newRow("12") << QStringLiteral("e4a3e7cb12cdd56aa4a75197a9530220") + << QStringLiteral("5131ba9bd48f2bba85560680df504b52") + << QStringLiteral("10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536"); + + QTest::newRow("13") << QStringLiteral("211677684aac1ec1a160f44c4ebf3f26") + << QStringLiteral("9dc503bbf09823aec8a977a5ad26ccb2") + << QStringLiteral("38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e"); + + QTest::newRow("14") << QStringLiteral("d21e439ff749ac8f18d6d4b105e03895") + << QStringLiteral("9a6db0c0862e506a9e397225884041d7") + << QStringLiteral("60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586"); + + QTest::newRow("15") << QStringLiteral("d9f6ff44646c4725bd4c0103ff5552a7") + << QStringLiteral("430bf9570804185e1ab6365fc6a6860c") + << QStringLiteral("88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae"); + + QTest::newRow("16") << QStringLiteral("0b1256c2a00b976250cfc5b0c37ed382") + << QStringLiteral("3525ebc02f4886e6a5a3762813e8ce8a") + << QStringLiteral("b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6"); + + QTest::newRow("17") << QStringLiteral("b056447ffc6dc4523a36cc2e972a3a79") + << QStringLiteral("07fa265c763779cce224c7bad671027b") + << QStringLiteral("d8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe"); + + QTest::newRow("18") << QStringLiteral("5e25ca78f0de55802524d38da3fe4456") + << QStringLiteral("e8b72b4e8be243438c9fff1f0e205872") + << QStringLiteral("00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526"); + + QTest::newRow("19") << QStringLiteral("a5bcf4728fa5eaad8567c0dc24675f83") + << QStringLiteral("109d4f999a0e11ace1f05e6b22cbcb50") + << QStringLiteral("28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e"); + + QTest::newRow("20") << QStringLiteral("814e59f97ed84646b78b2ca022e9ca43") + << QStringLiteral("45a5e8d4c3ed58403ff08d68a0cc4029") + << QStringLiteral("50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576"); + + QTest::newRow("21") << QStringLiteral("15478beec58f4775c7a7f5d4395514d7") + << QStringLiteral("196865964db3d417b6bd4d586bcb7634") + << QStringLiteral("78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e"); +} + +void CipherUnitTest::aes256() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-ecb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("aes256"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(forwardCipher.blockSize(), 16); + QCOMPARE(forwardCipher.keyLength().minimum(), 32); + QCOMPARE(forwardCipher.keyLength().maximum(), 32); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("aes256"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(reverseCipher.blockSize(), 16); + QCOMPARE(reverseCipher.keyLength().minimum(), 32); + QCOMPARE(reverseCipher.keyLength().maximum(), 32); + + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 ECB:" << providersToTest; +} + +// These are from the Botan test suite +void CipherUnitTest::aes256_cbc_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "f58c4c04d6e5f1ba779eabfb5f7bfbd69cfc4e967edb808d679f777bc6702c7d39f23369a9d9bacfa530e263" + "04231461b2eb05e2c39be9fcda6c19078c6a9d1b") + << QStringLiteral("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes256_cbc() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-cbc", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes256"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes256"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 CBC:" << providersToTest; +} + +// These were generated using OpenSSL's enc command +void CipherUnitTest::aes256_cbc_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QString(QLatin1String("")) << QStringLiteral("99fac653629ddb546d65ac699d7323ba") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("2") << QStringLiteral("610a") << QStringLiteral("1dd0366efe719f6bf0e2c30e8cc168fd") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("3") << QStringLiteral("6162636465666768696a0a") << QStringLiteral("a433fb0dc673093f726d748c8f76cf0d") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size - 1") << QStringLiteral("6162636465666768696a6b6c6d6e0a") + << QStringLiteral("b5cfa68d21ad91649eafc35dee06f007") + << QStringLiteral( + "0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size") << QStringLiteral("6162636465666768696a6b6c6d6e310a") + << QStringLiteral("45c4b50e4d4433b011187983da5034fe14cf12c04cfc3bceb57a88c455491f46") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); + + QTest::newRow("block size+1") << QStringLiteral("6162636465666768696a6b6c6d6e6f310a") + << QStringLiteral("4ef5702f0c16bbfda9b57e6e98186763325c81c99b6cdd8e4bc34dcaa82d00e9") + << QStringLiteral("0123456789ABCDEF0123456789ABCDEF00112233445566778899AABBCCDDEEFF") + << QStringLiteral("00001111222233334444555566667777"); +} + +void CipherUnitTest::aes256_cbc_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-cbc-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher(QStringLiteral("aes256"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Encode, + key, + iv, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes256"), + QCA::Cipher::CBC, + QCA::Cipher::DefaultPadding, + QCA::Decode, + key, + iv, + provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 CBC with PKCS7 padding:" << providersToTest; +} + +// These are from the Botan test suite +void CipherUnitTest::aes256_cfb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "dc7e84bfda79164b7ecd8486985d386039ffed143b28b1c832113c6331e5407bdf10132415e54b92a13ed0a8" + "267ae2f975a385741ab9cef82031623d55b1e471") + << QStringLiteral("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes256_cfb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-cfb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes256"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes256"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 CFB:" << providersToTest; +} + +void CipherUnitTest::aes256_ofb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "dc7e84bfda79164b7ecd8486985d38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5b" + "ba97c4080126141d67f37be8538f5a8be740e484") + << QStringLiteral("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes256_ofb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-ofb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes256"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes256"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 OFB:" << providersToTest; +} + +void CipherUnitTest::aes256_ctr_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral( + "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc119" + "1a0a52eff69f2445df4f9b17ad2b417be66c3710") + << QStringLiteral( + "dc7e84bfda79164b7ecd8486985d3860d577788b8d8a85745513a5d50f821f30ffe96d5cf54b238dcc8d6783" + "a87f3beae9af546344cb9ca4d1e553ffc06bc73e") + << QStringLiteral("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") + << QStringLiteral("000102030405060708090a0b0c0d0e0f"); +} + +void CipherUnitTest::aes256_ctr() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("aes256-ctr", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("aes256"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("aes256"), QCA::Cipher::CTR, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 CTR:" << providersToTest; +} + +void CipherUnitTest::aes256_gcm_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("payload"); + QTest::addColumn("tag"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("short") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("4ce2f4df041252820847") + << QStringLiteral("1c570805832dfe7babc1b386c26bcd04") + << QStringLiteral("3fa609690bf07a81a75839b0a4c0add774f54eb804d4f02df488691910298b04") + << QStringLiteral("f85f8aad39164daf64a12ad9b3fc8a3a"); + + QTest::newRow("long") << QStringLiteral( + "54484520515549434b2042524f574e20464f58204a554d504544204f56455220544845204c415a5920444" + "f472753204241434b2031323334353637383930") + << QStringLiteral( + "e516c267146d6cfd3af3300e24aba7ac23ab3c5cb4765937a6c0156e454cae357e14f4c0dfb0def9624f4" + "f70de90ad2bc9cd555171c4551c26b6346922ed") + << QStringLiteral("f59aac31ab9dace3fcc693e114dd6610") + << QStringLiteral("3fa609690bf07a81a75839b0a4c0add774f54eb804d4f02df488691910298b04") + << QStringLiteral("bfcd3a7252f7f199bf788df8cf61032a"); + + QTest::newRow("wrongtag") << QStringLiteral("6f6820526f6d656d6f21") << QStringLiteral("4ce2f4df041252820847") + << QStringLiteral("1c570805833dfe7babc1b386c26bcd04") + << QStringLiteral("3fa609690bf07a81a75839b0a4c0add774f54eb804d4f02df488691910298b04") + << QStringLiteral("f85f8aad39164daf64a12ad9b3fc8a3a"); +} + +void CipherUnitTest::aes256_gcm() +{ + bool anyProviderTested = false; + foreach (const QString &provider, providersToTest) { + if (QCA::isSupported("aes256-gcm", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, payload); + QFETCH(QString, tag); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::AuthTag authTag(16); + QCA::Cipher forwardCipher(QStringLiteral("aes256"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + iv, + authTag, + provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + update += QCA::arrayToHex(forwardCipher.final().toByteArray()); + authTag = forwardCipher.tag(); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(QCA::arrayToHex(authTag.toByteArray()), tag); + QCOMPARE(update, payload); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher(QStringLiteral("aes256"), + QCA::Cipher::GCM, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + iv, + QCA::AuthTag(QCA::hexToArray(tag)), + provider); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(payload)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + update += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QCOMPARE(update, plainText); + QEXPECT_FAIL("wrongtag", "It's OK", Continue); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports AES256 GCM:" << providersToTest; +} + +void CipherUnitTest::aes256_ccm_data() +{ +} + +void CipherUnitTest::aes256_ccm() +{ + // For future implementation +} + +void CipherUnitTest::tripleDES_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + QTest::newRow("1") << QStringLiteral("42fd443059577fa2") << QStringLiteral("af37fb421f8c4095") + << QStringLiteral("04b915ba43feb5b604b915ba43feb5b604b915ba43feb5b6"); + + QTest::newRow("2") << QStringLiteral("736f6d6564617461") << QStringLiteral("18d748e563620572") + << QStringLiteral("0123456789abcdef5555555555555555fedcba9876543210"); + QTest::newRow("3") << QStringLiteral("7371756967676c65") << QStringLiteral("c07d2a0fa566fa30") + << QStringLiteral("0352020767208217860287665908219864056abdfea93457"); + QTest::newRow("4") << QStringLiteral("0123456789abcde7") << QStringLiteral("de0b7c06ae5e0ed5") + << QStringLiteral("0123456789abcdeffedcba987654321089abcdef01234567"); + QTest::newRow("5") << QStringLiteral("0123456789abcde7") << QStringLiteral("7f1d0a77826b8aff") + << QStringLiteral("0123456789abcdeffedcba98765432100123456789abcdef"); + QTest::newRow("6") << QStringLiteral("4115e551299a5c4b") << QStringLiteral("f7a0822fc310686c") + << QStringLiteral("1ef743a68d629f68a5e3136c36ad7953a835cf849bb4ec3c"); + QTest::newRow("7") << QStringLiteral("d5ab44e0fe46e1b5") << QStringLiteral("02aed9bf72eca222") + << QStringLiteral("b7d560be49c3936728ef0bf57b602d2eb7e5c631dd7f753e"); + QTest::newRow("8") << QStringLiteral("b4077dfdb721d88c") << QStringLiteral("f76aba838b1c4372") + << QStringLiteral("d2d98706e9ab867647d244bdcdbcd5ef8b4dbc9cf4f35493"); + QTest::newRow("9") << QStringLiteral("890e98ab385fa1a1") << QStringLiteral("187087c77790c3b2") + << QStringLiteral("153b963004101d12683e8f87116001b8c5526475510b5036"); + QTest::newRow("10") << QStringLiteral("02d5da6d5f247cd2") << QStringLiteral("89fc7df1e7913163") + << QStringLiteral("45e4275dccc5d8b5a27993c16d9960ca939c023e2763216a"); + QTest::newRow("11") << QStringLiteral("5af9e5a3525e3f7d") << QStringLiteral("8fcc7a8bc337e484") + << QStringLiteral("f6c2474b33934ea76e6c841d9b1e86e37189095a895a3e5a"); + QTest::newRow("12") << QStringLiteral("12864dde8e694bd1") << QStringLiteral("5b4dde8f000a5a9b") + << QStringLiteral("5b4f6d3185efbae97d58ed9cc75e2bae655d2cefb2dd09cd"); + QTest::newRow("13") << QStringLiteral("0123456789abcde7") << QStringLiteral("c95744256a5ed31d") + << QStringLiteral("0123456789abcdef0123456789abcdef0123456789abcdef"); + QTest::newRow("14") << QStringLiteral("68652074696d6520") << QStringLiteral("6a271787ab8883f9") + << QStringLiteral("0123456789abcdef0123456789abcdef0123456789abcdef"); + + QTest::newRow("15") << QStringLiteral("4e6f772069732074") << QStringLiteral("3fa40e8a984d4815") + << QStringLiteral("0123456789abcdef0123456789abcdef0123456789abcdef"); + + // These are from the Botan test suite + QTest::newRow("16") << QStringLiteral("0123456789abcde7") << QStringLiteral("7f1d0a77826b8aff") + << QStringLiteral("0123456789abcdeffedcba9876543210"); + QTest::newRow("17") << QStringLiteral("4e6f772069732074") << QStringLiteral("3fa40e8a984d4815") + << QStringLiteral("0123456789abcdef0123456789abcdef"); + QTest::newRow("18") << QStringLiteral("42fd443059577fa2") << QStringLiteral("af37fb421f8c4095") + << QStringLiteral("04b915ba43feb5b604b915ba43feb5b6"); + QTest::newRow("19") << QStringLiteral("afa4284fcceaa61a") << QStringLiteral("32527d5701d92b90") + << QStringLiteral("4bc59e2c68aca60767a9a4b623bbbccc"); + QTest::newRow("20") << QStringLiteral("50b503a331d5b5cc") << QStringLiteral("e46a59e18b0c41e3") + << QStringLiteral("b955bb7861fde77e7dc6418475457fe1"); + QTest::newRow("21") << QStringLiteral("3404435d5df2cb47") << QStringLiteral("644dd68ea73053ae") + << QStringLiteral("c0557629eaa72abd4c102c5dc9ce8b47"); + QTest::newRow("22") << QStringLiteral("c7d80e955d1b6627") << QStringLiteral("9fe1c5a12cce6dd9") + << QStringLiteral("9eaa94da916f30092e79dacdcdcc45c0"); + QTest::newRow("23") << QStringLiteral("bdcbe8929cd0e12f") << QStringLiteral("f2b6430450ab348b") + << QStringLiteral("a55279671807d9b71fe62a77341249f8"); + QTest::newRow("24") << QStringLiteral("4b7a96b7051c64fc") << QStringLiteral("1555f08b2de690a0") + << QStringLiteral("672e20826ad49c3df7579fab3752479e"); + QTest::newRow("25") << QStringLiteral("902f4edd44eaf3c1") << QStringLiteral("3ce357eba0fb3e26") + << QStringLiteral("0ce61ede2659b413ab9f717ae4afad3e"); + QTest::newRow("26") << QStringLiteral("39c0f8e4c85cd70d") << QStringLiteral("882de9b6d0209a58") + << QStringLiteral("e878020815ae517cd2808b6571eac2b4"); + QTest::newRow("27") << QStringLiteral("f77a1947a921b209") << QStringLiteral("e10dbee5615f312e") + << QStringLiteral("d891ca20919f06a054ba3943c7daba16"); + QTest::newRow("28") << QStringLiteral("06d0416e0f0db7ce") << QStringLiteral("0cec5d1e59d7e347") + << QStringLiteral("4909aed1f94eb77b6cacbcae2b25689a"); + QTest::newRow("29") << QStringLiteral("f7bb3a396d73d8a8") << QStringLiteral("f893b6b2a15d3fce") + << QStringLiteral("8b9a5c13b0b118a1ee35eb912866ffa6"); + QTest::newRow("30") << QStringLiteral("bd35e3134b90ccbc") << QStringLiteral("12a7af172fd0ca7f") + << QStringLiteral("fa7911d664326074b42e2f38e599b288"); + QTest::newRow("31") << QStringLiteral("e046b7f5707da4fc") << QStringLiteral("32b6a3fc72c7c480") + << QStringLiteral("406903b340b8637928fde8058bdd6710"); + QTest::newRow("32") << QStringLiteral("58eb1dc16c482213") << QStringLiteral("a6c6234a8bbaa116") + << QStringLiteral("37a2b53e2af8f6c9a73b39f919d969de"); + QTest::newRow("33") << QStringLiteral("4bd0f4854297fbde") << QStringLiteral("f4ab771861457dc6") + << QStringLiteral("711f2cecdb92b2e201dfefa79fa7ba2f"); +} + +// TODO: ECB-PKCS7 +void CipherUnitTest::tripleDES() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("tripledes-ecb", provider)) { + anyProviderTested = true; + QCA::Cipher cipherObj1(QStringLiteral("tripledes"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + QCA::SymmetricKey(24), + QCA::InitializationVector(), + provider); + // checking minimum is a bit hairy, because it depends on whether you are + // doing 2 key or 3 key triple DES. + QCOMPARE(cipherObj1.keyLength().minimum(), 16); + QCOMPARE(cipherObj1.keyLength().maximum(), 24); + QCOMPARE(cipherObj1.blockSize(), 8); + + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("tripledes"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("tripledes"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Triple DES, ECB:" << providersToTest; +} + +// These are from the Botan test suite - its ECB mode, no padding +void CipherUnitTest::des_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + QTest::newRow("") << QStringLiteral("059b5e0851cf143a") << QStringLiteral("86a560f10ec6d85b") + << QStringLiteral("0113b970fd34f2ce"); + QTest::newRow("") << QStringLiteral("4e6f772069732074") << QStringLiteral("3fa40e8a984d4815") + << QStringLiteral("0123456789abcdef"); + QTest::newRow("") << QStringLiteral("666f7220616c6c20") << QStringLiteral("893d51ec4b563b53") + << QStringLiteral("0123456789abcdef"); + QTest::newRow("") << QStringLiteral("68652074696d6520") << QStringLiteral("6a271787ab8883f9") + << QStringLiteral("0123456789abcdef"); + QTest::newRow("") << QStringLiteral("5cd54ca83def57da") << QStringLiteral("7a389d10354bd271") + << QStringLiteral("0131d9619dc1376e"); + QTest::newRow("") << QStringLiteral("0756d8e0774761d2") << QStringLiteral("0cd3da020021dc09") + << QStringLiteral("0170f175468fb5e6"); + QTest::newRow("") << QStringLiteral("1d9d5c5018f728c2") << QStringLiteral("5f4c038ed12b2e41") + << QStringLiteral("018310dc409b26d6"); + QTest::newRow("") << QStringLiteral("480d39006ee762f2") << QStringLiteral("a1f9915541020b56") + << QStringLiteral("025816164629b007"); + QTest::newRow("") << QStringLiteral("26955f6835af609a") << QStringLiteral("5c513c9c4886c088") + << QStringLiteral("04689104c2fd3b2f"); + QTest::newRow("") << QStringLiteral("42fd443059577fa2") << QStringLiteral("af37fb421f8c4095") + << QStringLiteral("04b915ba43feb5b6"); + QTest::newRow("") << QStringLiteral("0248d43806f67172") << QStringLiteral("868ebb51cab4599a") + << QStringLiteral("07a1133e4a0b2686"); + QTest::newRow("") << QStringLiteral("3bdd119049372802") << QStringLiteral("dfd64a815caf1a0f") + << QStringLiteral("07a7137045da2a16"); + QTest::newRow("") << QStringLiteral("16393bcdd6560506") << QStringLiteral("9966adcfc53bf968") + << QStringLiteral("0a3fddc8350aff39"); + QTest::newRow("") << QStringLiteral("dc7fc6cf0358ecc0") << QStringLiteral("a47a7485661f7085") + << QStringLiteral("10dd6dcd5c89e151"); + QTest::newRow("") << QStringLiteral("305532286d6f295a") << QStringLiteral("63fac0d034d9f793") + << QStringLiteral("1c587f1c13924fef"); + QTest::newRow("") << QStringLiteral("f786d02413c574fc") << QStringLiteral("54c160d369f62ae3") + << QStringLiteral("1eb00767bdee584e"); + QTest::newRow("") << QStringLiteral("6b056e18759f5cca") << QStringLiteral("ef1bf03e5dfa575a") + << QStringLiteral("1f08260d1ac2465e"); + QTest::newRow("") << QStringLiteral("905ea29aeea26e07") << QStringLiteral("2292e9aebee6a4b6") + << QStringLiteral("28ee445d8a21c534"); + QTest::newRow("") << QStringLiteral("164d5e404f275232") << QStringLiteral("0a2aeeae3ff4ab77") + << QStringLiteral("37d06bb516cb7546"); + QTest::newRow("") << QStringLiteral("51454b582ddf440a") << QStringLiteral("7178876e01f19b2a") + << QStringLiteral("3849674c2602319e"); + QTest::newRow("") << QStringLiteral("68ff9d6068c71513") << QStringLiteral("84595f5b9d046132") + << QStringLiteral("3cde816ef9ef8edb"); + QTest::newRow("") << QStringLiteral("762514b829bf486a") << QStringLiteral("ea676b2cb7db2b7a") + << QStringLiteral("43297fad38e373fe"); + QTest::newRow("") << QStringLiteral("437540c8698f3cfa") << QStringLiteral("6fbf1cafcffd0556") + << QStringLiteral("49793ebc79b3258f"); + QTest::newRow("") << QStringLiteral("02fe55778117f12a") << QStringLiteral("5a6b612cc26cce4a") + << QStringLiteral("49e95d6d4ca229bf"); + QTest::newRow("") << QStringLiteral("1f508a50adb3d6e2") << QStringLiteral("470204969876604a") + << QStringLiteral("4bb53ecfefb38dde"); + QTest::newRow("") << QStringLiteral("072d43a077075292") << QStringLiteral("2f22e49bab7ca1ac") + << QStringLiteral("4fb05e1515ab73a7"); + QTest::newRow("") << QStringLiteral("004bd6ef09176062") << QStringLiteral("88bf0db6d70dee56") + << QStringLiteral("584023641aba6176"); + QTest::newRow("") << QStringLiteral("5aa1d62806ae0ead") << QStringLiteral("6db0f280fef2b564") + << QStringLiteral("5f2b51f59e781d9c"); + QTest::newRow("") << QStringLiteral("7e1b1c6776833772") << QStringLiteral("eb11cd3c72f7e90e") + << QStringLiteral("699c920d7ce1e0b1"); + QTest::newRow("") << QStringLiteral("5dbfb47c5f471136") << QStringLiteral("9c8b904d4d772be7") + << QStringLiteral("7ac2fdeee4c79746"); + QTest::newRow("") << QStringLiteral("01a1d6d039776742") << QStringLiteral("690f5b0d9a26939b") + << QStringLiteral("7ca110454a1a6e57"); + QTest::newRow("") << QStringLiteral("4de2f0926cf598d7") << QStringLiteral("ba107655991df529") + << QStringLiteral("7fc92c3098ecf14a"); + QTest::newRow("") << QStringLiteral("f45e6819e3108559") << QStringLiteral("f0c76ba556283b2f") + << QStringLiteral("9ab645e268430854"); + QTest::newRow("") << QStringLiteral("51d4eaaac6d76553") << QStringLiteral("bf3c6e8fd15ba861") + << QStringLiteral("a6b0ae88f980011a"); + QTest::newRow("") << QStringLiteral("6a89626ea8038511") << QStringLiteral("1067b36913cbcc47") + << QStringLiteral("bafebafafeaeeaff"); + QTest::newRow("") << QStringLiteral("7b0313c0d3a866f9") << QStringLiteral("e49e15e4f46f10e9") + << QStringLiteral("bb2420b5fee5a6a1"); + QTest::newRow("") << QStringLiteral("9d4a44aefce79965") << QStringLiteral("77b2ecc9278e9714") + << QStringLiteral("bebafbeabaffeaaf"); + QTest::newRow("") << QStringLiteral("59bcdfc253424cb5") << QStringLiteral("0a50abbbcd07061a") + << QStringLiteral("c38c6f20230d9ed5"); + QTest::newRow("") << QStringLiteral("d6c059a85ee2b13e") << QStringLiteral("25977533635beb5b") + << QStringLiteral("c6f974504d954c7e"); + QTest::newRow("") << QStringLiteral("f9e4821dfcaa5466") << QStringLiteral("48ec3a79399e9a00") + << QStringLiteral("cb959b7ffd94f734"); + QTest::newRow("") << QStringLiteral("35e8554bad60fb29") << QStringLiteral("993a3af0bc0d77a4") + << QStringLiteral("cfb23034323cd19a"); + QTest::newRow("") << QStringLiteral("9f97210d75b7e6df") << QStringLiteral("4729e3396e57ae4e") + << QStringLiteral("d4d861035745f2c8"); + QTest::newRow("") << QStringLiteral("ffffffffffffffff") << QStringLiteral("b5ce4f28fdeb21e8") + << QStringLiteral("e36972fc4bec7587"); + QTest::newRow("") << QStringLiteral("323837024123c918") << QStringLiteral("7f28bf28adfa1cf0") + << QStringLiteral("e91a71a7ed5eb0ef"); + QTest::newRow("") << QStringLiteral("37dfe527086af0a0") << QStringLiteral("5f53c6c87760256e") + << QStringLiteral("ebbbbaebfbbefaba"); + QTest::newRow("") << QStringLiteral("20678f45b5b8ac00") << QStringLiteral("7cc8ecf2638cc808") + << QStringLiteral("ebbeeeaebbbbffff"); + QTest::newRow("") << QStringLiteral("78481ed0c5a7c93e") << QStringLiteral("4ca3a08300ea6afc") + << QStringLiteral("fbeaffeeffeeabab"); + QTest::newRow("") << QStringLiteral("e2ccd415ac25412a") << QStringLiteral("bd85b3b659ab7276") + << QStringLiteral("fd8a675c0ed08301"); + // weak key + QTest::newRow("") << QStringLiteral("cccc5bdfd9029507") << QStringLiteral("da57553d7d55775f") + << QStringLiteral("ffffffffffffffff"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("23083a3ca70dd027") + << QStringLiteral("d5d44ff720683d0d"); + QTest::newRow("") << QStringLiteral("0100000000000000") << QStringLiteral("6f353e3388abe2ef") + << QStringLiteral("d5d44ff720683d0d"); + // weak keys till next comment. + QTest::newRow("") << QStringLiteral("95f8a5e5dd31d900") << QStringLiteral("8000000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("95f8a5e5dd31d900") << QStringLiteral("8000000000000000") + << QStringLiteral("0000000000000000"); + QTest::newRow("") << QStringLiteral("dd7f121ca5015619") << QStringLiteral("4000000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("2e8653104f3834ea") << QStringLiteral("2000000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("4bd388ff6cd81d4f") << QStringLiteral("1000000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("20b9e767b2fb1456") << QStringLiteral("0800000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("20b9e767b2fb1456") << QStringLiteral("0800000000000000") + << QStringLiteral("0001010101010100"); + QTest::newRow("") << QStringLiteral("55579380d77138ef") << QStringLiteral("0400000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("6cc5defaaf04512f") << QStringLiteral("0200000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("0d9f279ba5d87260") << QStringLiteral("0100000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("d9031b0271bd5a0a") << QStringLiteral("0080000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("424250b37c3dd951") << QStringLiteral("0040000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("b8061b7ecd9a21e5") << QStringLiteral("0020000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("f15d0f286b65bd28") << QStringLiteral("0010000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("add0cc8d6e5deba1") << QStringLiteral("0008000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e6d5f82752ad63d1") << QStringLiteral("0004000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("ecbfe3bd3f591a5e") << QStringLiteral("0002000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("f356834379d165cd") << QStringLiteral("0001000000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("2b9f982f20037fa9") << QStringLiteral("0000800000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("889de068a16f0be6") << QStringLiteral("0000400000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e19e275d846a1298") << QStringLiteral("0000200000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("329a8ed523d71aec") << QStringLiteral("0000100000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e7fce22557d23c97") << QStringLiteral("0000080000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("12a9f5817ff2d65d") << QStringLiteral("0000040000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("a484c3ad38dc9c19") << QStringLiteral("0000020000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("fbe00a8a1ef8ad72") << QStringLiteral("0000010000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("750d079407521363") << QStringLiteral("0000008000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("64feed9c724c2faf") << QStringLiteral("0000004000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("f02b263b328e2b60") << QStringLiteral("0000002000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("9d64555a9a10b852") << QStringLiteral("0000001000000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("d106ff0bed5255d7") << QStringLiteral("0000000800000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e1652c6b138c64a5") << QStringLiteral("0000000400000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e428581186ec8f46") << QStringLiteral("0000000200000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("aeb5f5ede22d1a36") << QStringLiteral("0000000100000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e943d7568aec0c5c") << QStringLiteral("0000000080000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("df98c8276f54b04b") << QStringLiteral("0000000040000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("b160e4680f6c696f") << QStringLiteral("0000000020000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("fa0752b07d9c4ab8") << QStringLiteral("0000000010000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("ca3a2b036dbc8502") << QStringLiteral("0000000008000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("5e0905517bb59bcf") << QStringLiteral("0000000004000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("814eeb3b91d90726") << QStringLiteral("0000000002000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("4d49db1532919c9f") << QStringLiteral("0000000001000000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("25eb5fc3f8cf0621") << QStringLiteral("0000000000800000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("ab6a20c0620d1c6f") << QStringLiteral("0000000000400000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("79e90dbc98f92cca") << QStringLiteral("0000000000200000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("866ecedd8072bb0e") << QStringLiteral("0000000000100000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("8b54536f2f3e64a8") << QStringLiteral("0000000000080000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("ea51d3975595b86b") << QStringLiteral("0000000000040000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("caffc6ac4542de31") << QStringLiteral("0000000000020000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("8dd45a2ddf90796c") << QStringLiteral("0000000000010000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("1029d55e880ec2d0") << QStringLiteral("0000000000008000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("5d86cb23639dbea9") << QStringLiteral("0000000000004000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("1d1ca853ae7c0c5f") << QStringLiteral("0000000000002000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("ce332329248f3228") << QStringLiteral("0000000000001000") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("8405d1abe24fb942") << QStringLiteral("0000000000000800") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e643d78090ca4207") << QStringLiteral("0000000000000400") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("48221b9937748a23") << QStringLiteral("0000000000000200") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("dd7c0bbd61fafd54") << QStringLiteral("0000000000000100") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("2fbc291a570db5c4") << QStringLiteral("0000000000000080") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("e07c30d7e4e26e12") << QStringLiteral("0000000000000040") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("0953e2258e8e90a1") << QStringLiteral("0000000000000020") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("5b711bc4ceebf2ee") << QStringLiteral("0000000000000010") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("cc083f1e6d9e85f6") << QStringLiteral("0000000000000008") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("d2fd8867d50d2dfe") << QStringLiteral("0000000000000004") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("06e7ea22ce92708f") << QStringLiteral("0000000000000002") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("166b40b44aba4bd6") << QStringLiteral("0000000000000001") + << QStringLiteral("0101010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("95a8d72813daa94d") + << QStringLiteral("8001010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("0eec1487dd8c26d5") + << QStringLiteral("4001010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("7ad16ffb79c45926") + << QStringLiteral("2001010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("d3746294ca6a6cf3") + << QStringLiteral("1001010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("809f5f873c1fd761") + << QStringLiteral("0801010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("c02faffec989d1fc") + << QStringLiteral("0401010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("4615aa1d33e72f10") + << QStringLiteral("0201010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("2055123350c00858") + << QStringLiteral("0180010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("df3b99d6577397c8") + << QStringLiteral("0140010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("31fe17369b5288c9") + << QStringLiteral("0120010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("dfdd3cc64dae1642") + << QStringLiteral("0110010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("178c83ce2b399d94") + << QStringLiteral("0108010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("50f636324a9b7f80") + << QStringLiteral("0104010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("a8468ee3bc18f06d") + << QStringLiteral("0102010101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("a2dc9e92fd3cde92") + << QStringLiteral("0101800101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("cac09f797d031287") + << QStringLiteral("0101400101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("90ba680b22aeb525") + << QStringLiteral("0101200101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("ce7a24f350e280b6") + << QStringLiteral("0101100101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("882bff0aa01a0b87") + << QStringLiteral("0101080101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("25610288924511c2") + << QStringLiteral("0101040101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("c71516c29c75d170") + << QStringLiteral("0101020101010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("5199c29a52c9f059") + << QStringLiteral("0101018001010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("c22f0a294a71f29f") + << QStringLiteral("0101014001010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("ee371483714c02ea") + << QStringLiteral("0101012001010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("a81fbd448f9e522f") + << QStringLiteral("0101011001010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("4f644c92e192dfed") + << QStringLiteral("0101010801010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("1afa9a66a6df92ae") + << QStringLiteral("0101010401010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("b3c1cc715cb879d8") + << QStringLiteral("0101010201010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("19d032e64ab0bd8b") + << QStringLiteral("0101010180010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("3cfaa7a7dc8720dc") + << QStringLiteral("0101010140010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("b7265f7f447ac6f3") + << QStringLiteral("0101010120010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("9db73b3c0d163f54") + << QStringLiteral("0101010110010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("8181b65babf4a975") + << QStringLiteral("0101010108010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("93c9b64042eaa240") + << QStringLiteral("0101010104010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("5570530829705592") + << QStringLiteral("0101010102010101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("8638809e878787a0") + << QStringLiteral("0101010101800101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("41b9a79af79ac208") + << QStringLiteral("0101010101400101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("7a9be42f2009a892") + << QStringLiteral("0101010101200101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("29038d56ba6d2745") + << QStringLiteral("0101010101100101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("5495c6abf1e5df51") + << QStringLiteral("0101010101080101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("ae13dbd561488933") + << QStringLiteral("0101010101040101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("024d1ffa8904e389") + << QStringLiteral("0101010101020101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("d1399712f99bf02e") + << QStringLiteral("0101010101018001"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("14c1d7c1cffec79e") + << QStringLiteral("0101010101014001"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("1de5279dae3bed6f") + << QStringLiteral("0101010101012001"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("e941a33f85501303") + << QStringLiteral("0101010101011001"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("da99dbbc9a03f379") + << QStringLiteral("0101010101010801"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("b7fc92f91d8e92e9") + << QStringLiteral("0101010101010401"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("ae8e5caa3ca04e85") + << QStringLiteral("0101010101010201"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("9cc62df43b6eed74") + << QStringLiteral("0101010101010180"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("d863dbb5c59a91a0") + << QStringLiteral("0101010101010140"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("a1ab2190545b91d7") + << QStringLiteral("0101010101010120"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("0875041e64c570f7") + << QStringLiteral("0101010101010110"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("5a594528bebef1cc") + << QStringLiteral("0101010101010108"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("fcdb3291de21f0c0") + << QStringLiteral("0101010101010104"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("869efd7f9f265a09") + << QStringLiteral("0101010101010102"); + // end of weak keys + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("88d55e54f54c97b4") + << QStringLiteral("1046913489980131"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("0c0cc00c83ea48fd") + << QStringLiteral("1007103489988020"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("83bc8ef3a6570183") + << QStringLiteral("10071034c8980120"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("df725dcad94ea2e9") + << QStringLiteral("1046103489988020"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("e652b53b550be8b0") + << QStringLiteral("1086911519190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("af527120c485cbb0") + << QStringLiteral("1086911519580101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("0f04ce393db926d5") + << QStringLiteral("5107b01519580101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("c9f00ffc74079067") + << QStringLiteral("1007b01519190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("7cfd82a593252b4e") + << QStringLiteral("3107915498080101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("cb49a2f9e91363e3") + << QStringLiteral("3107919498080101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("00b588be70d23f56") + << QStringLiteral("10079115b9080140"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("406a9a6ab43399ae") + << QStringLiteral("3107911598090140"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("6cb773611dca9ada") + << QStringLiteral("1007d01589980101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("67fd21c17dbb5d70") + << QStringLiteral("9107911589980101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("9592cb4110430787") + << QStringLiteral("9107d01589190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("a6b7ff68a318ddd3") + << QStringLiteral("1007d01598980120"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("4d102196c914ca16") + << QStringLiteral("1007940498190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("2dfa9f4573594965") + << QStringLiteral("0107910491190401"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("b46604816c0e0774") + << QStringLiteral("0107910491190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("6e7e6221a4f34e87") + << QStringLiteral("0107940491190401"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("aa85e74643233199") + << QStringLiteral("19079210981a0101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("2e5a19db4d1962d6") + << QStringLiteral("1007911998190801"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("23a866a809d30894") + << QStringLiteral("10079119981a0801"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("d812d961f017d320") + << QStringLiteral("1007921098190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("055605816e58608f") + << QStringLiteral("100791159819010b"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("abd88e8b1b7716f1") + << QStringLiteral("1004801598190101"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("537ac95be69da1e1") + << QStringLiteral("1004801598190102"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("aed0f6ae3c25cdd8") + << QStringLiteral("1004801598190108"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("b3e35a5ee53e7b8d") + << QStringLiteral("1002911598100104"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("61c79c71921a2ef8") + << QStringLiteral("1002911598190104"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("e2f5728f0995013c") + << QStringLiteral("1002911598100201"); + QTest::newRow("") << QStringLiteral("0000000000000000") << QStringLiteral("1aeac39a61f0a464") + << QStringLiteral("1002911698100101"); + QTest::newRow("") << QStringLiteral("059b5e0851cf143a") << QStringLiteral("86a560f10ec6d85b") + << QStringLiteral("0113b970fd34f2ce"); + QTest::newRow("") << QStringLiteral("4e6f772069732074") << QStringLiteral("3fa40e8a984d4815") + << QStringLiteral("0123456789abcdef"); +} + +void CipherUnitTest::des() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-ecb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("des"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(forwardCipher.blockSize(), 8); + QCOMPARE(forwardCipher.keyLength().minimum(), 8); + QCOMPARE(forwardCipher.keyLength().maximum(), 8); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("des"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + + QCOMPARE(reverseCipher.blockSize(), 8); + QCOMPARE(reverseCipher.keyLength().minimum(), 8); + QCOMPARE(reverseCipher.keyLength().maximum(), 8); + + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES ECB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::des_cbc_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("4e6f77206973207468652074696d6520666f7220616c6c20") + << QStringLiteral("e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6") + << QStringLiteral("0123456789abcdef") << QStringLiteral("1234567890abcdef"); +} + +void CipherUnitTest::des_cbc() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-cbc", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("des"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("des"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES CBC:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::des_cfb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("") << QStringLiteral("5eef8199471c2a7ef97509623cae32c35a90245b70a21ce36e") + << QStringLiteral("658b25e25df23948847afa4c9ffdd5b3ddf35d801cbe945168") + << QStringLiteral("add9ce7bcf48c44b") << QStringLiteral("0f90e78835ba3183"); + QTest::newRow("") << QStringLiteral("4e6f77206973207468652074696d6520666f7220616c6c20") + << QStringLiteral("f3096249c7f46e51a69e839b1a92f78403467133898ea622") + << QStringLiteral("0123456789abcdef") << QStringLiteral("1234567890abcdef"); + QTest::newRow("") << QStringLiteral("d14fd67a9b4d7b0f65b7ca3da91741603da446") + << QStringLiteral("0cb8929a854e61ab3beb72ce0f13ba328ba73a") << QStringLiteral("7132d895529a7aff") + << QStringLiteral("fa1fe8f921706c75"); + QTest::newRow("") << QStringLiteral("16") << QStringLiteral("e1") << QStringLiteral("f51cf13fd55f33b8") + << QStringLiteral("10e61c7f8276132e"); + QTest::newRow("") << QStringLiteral("b8f7") << QStringLiteral("9f09") << QStringLiteral("6a2306397e6399af") + << QStringLiteral("6791874e16642dd8"); + QTest::newRow("") << QStringLiteral("914aa4") << QStringLiteral("1cddad") << QStringLiteral("08d3b08cb02e2547") + << QStringLiteral("b35072a53fa36190"); + QTest::newRow("") << QStringLiteral("252f0616") << QStringLiteral("e22a706a") << QStringLiteral("454a9aca108ad24c") + << QStringLiteral("64dadb33ccf1debd"); + QTest::newRow("") << QStringLiteral("f06f376c6e") << QStringLiteral("c2f054e435") + << QStringLiteral("087fc9f0b8be08f3") << QStringLiteral("5e511251c063b3c7"); + QTest::newRow("") << QStringLiteral("9a181afec04c") << QStringLiteral("c49218c8a25b") + << QStringLiteral("fe1ea0f0ac5f2c02") << QStringLiteral("a247e69ced4a2bf1"); + QTest::newRow("") << QStringLiteral("ac465cbd745341") << QStringLiteral("768b6f5bfa9c24") + << QStringLiteral("1e7c7274307edb90") << QStringLiteral("afb634941c366c1d"); + QTest::newRow("") << QStringLiteral("52bdfd51e3434e94") << QStringLiteral("c5d84483756ac360") + << QStringLiteral("53e241e43aad03e7") << QStringLiteral("be0a4ae59056d8fe"); + QTest::newRow("") << QStringLiteral("a62c02059afe67cd7f") << QStringLiteral("032a99be4df6b63f97") + << QStringLiteral("487c9fbd140ef278") << QStringLiteral("43f88de155e98523"); + QTest::newRow("") << QStringLiteral("32d3c8a283257f6276c3") << QStringLiteral("bcfa26efe2d93a4b1364") + << QStringLiteral("8b068595d5b79177") << QStringLiteral("7129287761d94d9f"); + QTest::newRow("") << QStringLiteral("17cb11a60f880c16d6cc3a") << QStringLiteral("3dc099d927b8aa66b2a5c8") + << QStringLiteral("750c87995afd65ee") << QStringLiteral("a61398fff559faad"); + QTest::newRow("") << QStringLiteral("eaa91cede4efc60f02b1e0ee") << QStringLiteral("75614ea2fd5474fdfe3a5612") + << QStringLiteral("08a5f56200ac9300") << QStringLiteral("9f9ed0928b8cd2dd"); + QTest::newRow("") << QStringLiteral("68db8992e91d759256ab373748") << QStringLiteral("9d0e14f0b2be2d3b47103da75f") + << QStringLiteral("b11dfa915ad86ff9") << QStringLiteral("3885ecf48a611dc5"); + QTest::newRow("") << QStringLiteral("d75acdd3e4040dfda924ce09e627") + << QStringLiteral("a878ce766412a9c387ad61642fb7") << QStringLiteral("fbf9e6d9344b0f2c") + << QStringLiteral("6917f8fe1ac12101"); + QTest::newRow("") << QStringLiteral("38b667a6e4458c8732aae6f4d0ac36") + << QStringLiteral("5bcfd93d6b4b45d9d0d03162fa8fb9") << QStringLiteral("8616d2ea6e6106b3") + << QStringLiteral("cfe4dfa7044f56ab"); + QTest::newRow("") << QStringLiteral("0b439a72a4430b3d15e234034ba2c066") + << QStringLiteral("1adae0a4a0d582b70b60ed1c859a07b3") << QStringLiteral("e255e4a4c3606081") + << QStringLiteral("3f160dff918c3f78"); + QTest::newRow("") << QStringLiteral("82e27182fc22cd8918dddbdb850034a4f2") + << QStringLiteral("9767881b1909db5e146caaf5fc6a118814") << QStringLiteral("b9cdd5442e1c7fd7") + << QStringLiteral("5d1b1eceb7335274"); +} + +void CipherUnitTest::des_cfb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-cfb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("des"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("des"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES CFB:" << providersToTest; +} + +// This is from the Botan test suite +void CipherUnitTest::des_ofb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("4e6f77206973207468652074696d6520666f7220616c6c20") + << QStringLiteral("f3096249c7f46e5135f24a242eeb3d3f3d6d5be3255af8c3") + << QStringLiteral("0123456789abcdef") << QStringLiteral("1234567890abcdef"); + QTest::newRow("2") << QStringLiteral("b25330d1cab11fddff278192aa2c935a9c7745733e6da8") + << QStringLiteral("39b9bf284d6da6e639b8040b8da01e469dba4c6e50b1ab") + << QStringLiteral("f871822c7fd1d6a3") << QStringLiteral("b311792c8bc02ee8"); + QTest::newRow("3") << QStringLiteral("73ad356623a1d6e0717e838b9344b4fff21bda") + << QStringLiteral("0c06e63e9e81d9976e16d2009255f917797d51") << QStringLiteral("5860f4a413de6c68") + << QStringLiteral("527a1e050a9d71f0"); + QTest::newRow("4") << QStringLiteral("08a6091fa2987fdc682a8199a6d6bd1f") + << QStringLiteral("640b5033dcf26873fa8a34db644f2bf2") << QStringLiteral("3307042dc775035e") + << QStringLiteral("99de32ff0351509b"); +} + +void CipherUnitTest::des_ofb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-ofb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("des"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("des"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES OFB:" << providersToTest; +} + +// These are from the Botan test suite +void CipherUnitTest::des_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + QTest::newRow("") << QString(QLatin1String("")) << QStringLiteral("705fdf4dc7abfbfc") + << QStringLiteral("02d863a4885d417a"); + QTest::newRow("") << QStringLiteral("fa") << QStringLiteral("2281ac7cfa703ba9") + << QStringLiteral("05add235b01bbda7"); + QTest::newRow("") << QStringLiteral("b895") << QStringLiteral("8c3bf9ab9d16c8cf") + << QStringLiteral("93f04843afc3a191"); + QTest::newRow("") << QStringLiteral("8e97de") << QStringLiteral("be38bd2afe108d2a") + << QStringLiteral("1f4e2c013314b55a"); + QTest::newRow("") << QStringLiteral("c1dae88e") << QStringLiteral("998341e8b0cce82e") + << QStringLiteral("0f59c05186431e13"); + QTest::newRow("") << QStringLiteral("a6e0360e88") << QStringLiteral("f5e88fcc387b8883") + << QStringLiteral("e68bf7b98d61fed0"); + QTest::newRow("") << QStringLiteral("55e67a79f043") << QStringLiteral("a868b107bd96f35c") + << QStringLiteral("ae3ab00a0ba38be0"); + QTest::newRow("") << QStringLiteral("d77c93b63d6d5b") << QStringLiteral("19da07a34fa683c4") + << QStringLiteral("9b661c7a536afc6d"); + QTest::newRow("") << QStringLiteral("328d09508e747ae1") << QStringLiteral("9c75845c6bff94438eb7e7e4c77342f0") + << QStringLiteral("8e1c689280575f05"); + QTest::newRow("") << QStringLiteral("421d4bdc3869e59f07") << QStringLiteral("8df60dc27a2e2ee23360be31343fcbdb") + << QStringLiteral("eb4a6b437572e1e7"); + QTest::newRow("") << QStringLiteral("160e525583c3e4fbc4fe") << QStringLiteral("9b649660dfe5b875cd81180ad627943f") + << QStringLiteral("ffe58726b90c9f97"); + QTest::newRow("") << QStringLiteral("e873b3c2b31130719e6469") << QStringLiteral("6e33ae2af48cc39697800a3aa357cc5e") + << QStringLiteral("560ee1ed2cc2bffb"); + QTest::newRow("") << QStringLiteral("405915adc0111eb8af225612") + << QStringLiteral("569be1f2ae91785b0634f8dd4ec1dff2") << QStringLiteral("012a7de9cbfbd230"); + QTest::newRow("") << QStringLiteral("e923c535186730f309cdea6dea") + << QStringLiteral("846d7314f76e00902054bd2b2ae1f580") << QStringLiteral("3d5d56ca2e8e359c"); + QTest::newRow("") << QStringLiteral("116053a5820f9d36650eef49a05b") + << QStringLiteral("9bd56c43036485b648efe6d31e69f0c6") << QStringLiteral("2ad63a5312bf4259"); + QTest::newRow("") << QStringLiteral("b6dcd40077fe89138b5a2ed35e1b3d") + << QStringLiteral("2fbe419bada6d4bf3f6c7bb2a1aac329") << QStringLiteral("7ff12d4d8a9ef138"); + QTest::newRow("") << QStringLiteral("08f0aa208f8a06c6292838a8cee9104e") + << QStringLiteral("44bfca2722d274504af482e9261cdb7b16918be77a461b3b") + << QStringLiteral("f71a3b1aabd660bd"); + QTest::newRow("") << QStringLiteral("878412f6255ff4360a22772711289fd351") + << QStringLiteral("9c92fdde178d3b6c895aad1b8dc886176910b021d5b3aa77") + << QStringLiteral("1ed8b08898872631"); + QTest::newRow("") << QStringLiteral("1399a0cd9f2778bcfba9c0f7e7c89ca069e3") + << QStringLiteral("5972f89d8c161dd30a409bcdbf43b20bb104e8a293c48fdd") + << QStringLiteral("0dcb3527035253a5"); + QTest::newRow("") << QStringLiteral("ea1cc272d3725e4c5dc56079fa3c9f26a1373a") + << QStringLiteral("d1b2fcc83cbf11e022c058fcb988cbbbc3843517f5e9d900") + << QStringLiteral("bf4b260909243b2f"); + QTest::newRow("") << QStringLiteral("098dd47ea5784d307c115824cfc3443983fdf58b") + << QStringLiteral("77dfae7f46af6db0d0e5775859943e2875854a680b54b59b") + << QStringLiteral("5d869f3486dfe1a1"); +} + +// This is DES ECB, PKCS7 padding +void CipherUnitTest::des_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-ecb-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + // just a filler + QCA::InitializationVector iv; + QCA::Cipher forwardCipher( + QStringLiteral("des"), QCA::Cipher::ECB, QCA::Cipher::PKCS7, QCA::Encode, key, iv, provider); + + QCOMPARE(forwardCipher.keyLength().minimum(), 8); + QCOMPARE(forwardCipher.keyLength().maximum(), 8); + QCOMPARE(forwardCipher.blockSize(), 8); + + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(update, cipherText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("des"), QCA::Cipher::ECB, QCA::Cipher::PKCS7, QCA::Decode, key, iv, provider); + + QCOMPARE(reverseCipher.keyLength().minimum(), 8); + QCOMPARE(reverseCipher.keyLength().maximum(), 8); + QCOMPARE(reverseCipher.blockSize(), 8); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES OFB with PKCS7 padding:" << providersToTest; +} + +// These are from the Botan test suite +void CipherUnitTest::des_cbc_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("4e6f77206973207468652074696d6520666f7220616c6c20") + << QStringLiteral("e5c7cdde872bf27c43e934008c389c0f683788499a7c05f662c16a27e4fcf277") + << QStringLiteral("0123456789abcdef") << QStringLiteral("1234567890abcdef"); + QTest::newRow("2") << QString(QLatin1String("")) << QStringLiteral("ff4903e653af83c4") + << QStringLiteral("46b534fbffdae457") << QStringLiteral("297873b948a44b5f"); + QTest::newRow("3") << QStringLiteral("69") << QStringLiteral("60fa7b46523aa51f") + << QStringLiteral("d581a1d0c70f94a1") << QStringLiteral("c1ddd7447249ef80"); + QTest::newRow("4") << QStringLiteral("02b7") << QStringLiteral("63c1c1ef79555ed8") + << QStringLiteral("a415b62e7e94caf2") << QStringLiteral("57fa9b2f95f57401"); + QTest::newRow("5") << QStringLiteral("568960") << QStringLiteral("d0321483090f524d") + << QStringLiteral("5dcbe42db374090e") << QStringLiteral("b6215a095582763f"); + QTest::newRow("6") << QStringLiteral("b6eaf23c") << QStringLiteral("88e289e1de3e6451") + << QStringLiteral("8fe92291c654ec9b") << QStringLiteral("0c054bbd31a9f623"); + QTest::newRow("7") << QStringLiteral("60a658cbbd") << QStringLiteral("89bffa9e36ff1780") + << QStringLiteral("dbcee35e86088501") << QStringLiteral("11a8928bc6d0d117"); + QTest::newRow("8") << QStringLiteral("7e10cbd9e95c") << QStringLiteral("afc5cdf559abc6d3") + << QStringLiteral("72338f946012ced5") << QStringLiteral("eaaa48b0c2ee2f3f"); + QTest::newRow("9") << QStringLiteral("d907ce88f077fa") << QStringLiteral("3476402272856ea8") + << QStringLiteral("837fbb3167f0ccaa") << QStringLiteral("cd399dd3e402f8f2"); + QTest::newRow("10") << QStringLiteral("9476e85b198c9aee") << QStringLiteral("1af298a150514ca70d252f88271b3ca7") + << QStringLiteral("308d1c02e7a4e09d") << QStringLiteral("6baa74f7f1a72e1f"); + QTest::newRow("11") << QStringLiteral("5c11285270e9606cdf") << QStringLiteral("78665abfe3def34f8bd55796825ee915") + << QStringLiteral("126aff39882542ea") << QStringLiteral("51badb479de66a73"); + QTest::newRow("12") << QStringLiteral("d1d3d8675e42a4242fba") << QStringLiteral("e77bb4a24b4ee8c9ebda4971c2e60d10") + << QStringLiteral("0ae8510bb0fb3994") << QStringLiteral("6c7293a8427bcb3b"); + QTest::newRow("13") << QStringLiteral("65026a8a41edc1d880f6c9") + << QStringLiteral("45a6ef4acd49f9f1d892a808fa7b6f28") << QStringLiteral("0be9277b3504d524") + << QStringLiteral("e47ec7a77db94755"); + QTest::newRow("14") << QStringLiteral("d72e81f4130107e396d5fb27") + << QStringLiteral("a88eff91876a1b6958d52f99fe9b18fb") << QStringLiteral("2f03c36de4f78e13") + << QStringLiteral("99fd2e8848f33fe7"); + QTest::newRow("15") << QStringLiteral("c8a3971efda18af1b18bfad98f") + << QStringLiteral("54ff90bd90f6213d761f4b3ff89a8ded") << QStringLiteral("69329672e546c969") + << QStringLiteral("294922cbe7e12341"); + QTest::newRow("16") << QStringLiteral("bb9a90f11551531de512dd48270e") + << QStringLiteral("9ba7908e56edb1bef992faee40f5b1ca") << QStringLiteral("3007d71e86d8eaf2") + << QStringLiteral("d7e300e168f60063"); + QTest::newRow("17") << QStringLiteral("77d6c182e4ddd444d614bcff98fb13") + << QStringLiteral("cb50dec4728fc2f1a1a5dfb84fa1bd25") << QStringLiteral("f73c8c3355092eb6") + << QStringLiteral("2e0db2552bb83ad3"); + QTest::newRow("18") << QStringLiteral("40aed22f93dcfcb1d734b7e4657dd31a") + << QStringLiteral("66d17a6e9d5be3281e857b4c7e497988ca684524fd994882") + << QStringLiteral("dd006f15e727cb62") << QStringLiteral("b256dc4fdb58451b"); + QTest::newRow("19") << QStringLiteral("bb25564c7ea1e5bd22016915805c27b51b") + << QStringLiteral("b7ceb5f5ed2945f131064bbb9213694b19a04fbd1f138866") + << QStringLiteral("df70ff987582ccfe") << QStringLiteral("88bb3b9bb2ea56d7"); + QTest::newRow("20") << QStringLiteral("49dab8d85ea753cf4ae2ece7a80f0784e42b") + << QStringLiteral("d7fce9e5bed161ad7d950e453677e5bee422b7542afc0bd3") + << QStringLiteral("747e09fa9ba257dc") << QStringLiteral("f1bbd406191de0d1"); + QTest::newRow("21") << QStringLiteral("dc13a6abaa35ceb3e6650f825a67942114af2e") + << QStringLiteral("bafdb50e16c9ff4449bf336d410441d56e1e5335b54c9f11") + << QStringLiteral("cdad411d0fa80e9d") << QStringLiteral("c83d55b1196958c4"); + QTest::newRow("22") << QStringLiteral("a8896d88907ad77ae790828c0a3384c1614e07d9") + << QStringLiteral("70a9eb1c11bfd1b1d68c20a6b72c869dac5372a8ed46aa07") + << QStringLiteral("642d12c591f6a4f4") << QStringLiteral("c17d0c69067af296"); + QTest::newRow("23") << QStringLiteral("b3fec4cc29dc1abbcf7d86f01d2c02c2a723e7c2f8") + << QStringLiteral("48ed5583a04d333ffac9d6462fd96bf79222eeec70a6ae70") + << QStringLiteral("62c62f54c426c59f") << QStringLiteral("cb6252ca271ff303"); + QTest::newRow("24") << QStringLiteral("ac0b4d5752d2009bdcd42314d9723716294146424542") + << QStringLiteral("8a284713f8c9873ad5f558b995c5a67a66557a52601975d1") + << QStringLiteral("386dcad5eae86830") << QStringLiteral("48153b966c8d686d"); + QTest::newRow("25") << QStringLiteral("ea331f6e518a8aeab2ef0a4e92e0d198df5dd0cc74369e") + << QStringLiteral("6d3d7de9938935f9fb9af839e416ef6f842f2ed827334bfb") + << QStringLiteral("782545ea65d89b01") << QStringLiteral("c2ce203020aabb0a"); + QTest::newRow("26") << QStringLiteral("b292d3a3fdc5d709709c87ef91122761847871f9b4e33426") + << QStringLiteral("21dae17d157192146b52c49d90f898b25d0d1dfe677e8cd5b568814e9c6bb6a8") + << QStringLiteral("ecc650e1ed1ce8a0") << QStringLiteral("aebc43ab811ab5f1"); + QTest::newRow("27") << QStringLiteral("65026a8a41edc1d880f6c90be9277b3504d524e47ec7a77db9") + << QStringLiteral("a3b6404c4d87f72d5e0995d7cc20ece742d9705d48524cfa2820317087faf578") + << QStringLiteral("4755b8639fd7c8a1") << QStringLiteral("4152e22f14baaf0a"); + QTest::newRow("28") << QStringLiteral("d1d3d8675e42a4242fba0ae8510bb0fb39946c7293a8427bcb3b") + << QStringLiteral("db621f2fac9a924c83ed0b9e8acec9f1e23bf3ff2ad6efa814903f2ce293107b") + << QStringLiteral("92a18b78a25c4b7a") << QStringLiteral("c3aabc68ceeb22d9"); + QTest::newRow("29") << QStringLiteral("c8a3971efda18af1b18bfad98f69329672e546c969294922cbe7e1") + << QStringLiteral("940c610a41f04e7d9be0a74d5d00fe97a2647d3d16e9b76ff0db5bbdc197c82a") + << QStringLiteral("2341239c09c73427") << QStringLiteral("c4d5b2b6863db060"); + QTest::newRow("30") << QStringLiteral("d72e81f4130107e396d5fb272f03c36de4f78e1399fd2e8848f33fe7") + << QStringLiteral("7d495cba50c4127347e3ad29e3b8c098a3312782e3d45abfa1621f64bf8b8a06") + << QStringLiteral("166ea8ed9d29e1b0") << QStringLiteral("2be993c1be8fe9ed"); + QTest::newRow("31") << QStringLiteral("77d6c182e4ddd444d614bcff98fb13f73c8c3355092eb62e0db2552bb8") + << QStringLiteral("9d926142271e814ba4603509187c9020daa0d50f15af6e698e384644e9468c11") + << QStringLiteral("3ad3301094b2f471") << QStringLiteral("8638489af44732f0"); + QTest::newRow("32") << QStringLiteral("bb9a90f11551531de512dd48270e3007d71e86d8eaf2d7e300e168f60063") + << QStringLiteral("44858416f946c7fbdffd720282881630803803ab91ceab1af4f68f50e9c16dce") + << QStringLiteral("04bbfd95ac12e6ff") << QStringLiteral("30cb120d13391c44"); + QTest::newRow("33") << QStringLiteral("8eb8faf49126ad5b8a0aa6df8b52dbe50dd5aed271641ef983bd650da69816") + << QStringLiteral("5b4622f1c4faa817ee3ac181b969a7afed7117e23f68bc6017519a7d1399cfe9") + << QStringLiteral("35501029e137d63d") << QStringLiteral("c1e0e3a06b357b51"); +} + +void CipherUnitTest::des_cbc_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("des-cbc-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("des"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Encode, key, iv, provider); + + QCOMPARE(forwardCipher.keyLength().minimum(), 8); + QCOMPARE(forwardCipher.keyLength().maximum(), 8); + QCOMPARE(forwardCipher.blockSize(), 8); + + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(update, cipherText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("des"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Decode, key, iv, provider); + + QCOMPARE(reverseCipher.keyLength().minimum(), 8); + QCOMPARE(reverseCipher.keyLength().maximum(), 8); + QCOMPARE(reverseCipher.blockSize(), 8); + + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports DES CBC with PKCS7 padding:" << providersToTest; +} + +#if 0 +if (!QCA::isSupported("des-ecb-pkcs7") ) +QWARN("DES, ECB mode with PKCS7 padding not supported!"); +else { +QCA::Cipher cipherObj1( QStringLiteral( "des" ), + QCA::Cipher::ECB, + QCA::Cipher::PKCS7, + QCA::Encode, + QCA::SymmetricKey( 8 ) ); +QCOMPARE( cipherObj1.keyLength().minimum(), 8 ); +QCOMPARE( cipherObj1.keyLength().maximum(), 8 ); +QCOMPARE( cipherObj1.blockSize(), 8 ); + +for (int n = 0; (0 != desEcbPkcs7TestValues[n].plaintext); n++) { + QCA::SymmetricKey key( QCA::hexToArray( desEcbPkcs7TestValues[n].key ) ); + QCA::DES forwardCipher( QCA::Cipher::ECB, QCA::Cipher::PKCS7, QCA::Encode, key); + QCOMPARE( QCA::arrayToHex( forwardCipher.update( QCA::hexToArray( desEcbPkcs7TestValues[n].plaintext ) ).toByteArray() ), + QString( desEcbPkcs7TestValues[n].ciphertext ) ); + QCOMPARE( forwardCipher.ok(), true ); + QCOMPARE( QCA::arrayToHex( forwardCipher.final().toByteArray() ), QLatin1String( "" ) ); + QCOMPARE( forwardCipher.ok(), true ); + + QCA::DES reverseCipher( QCA::Cipher::ECB, QCA::Cipher::PKCS7, QCA::Decode, key); + + QCOMPARE( QCA::arrayToHex( reverseCipher.update( QCA::hexToArray( desEcbPkcs7TestValues[n].ciphertext ) ).toByteArray() ), + QString( desEcbPkcs7TestValues[n].plaintext ) ); + QCOMPARE( reverseCipher.ok(), true ); + QCOMPARE( QCA::arrayToHex( reverseCipher.final().toByteArray() ), QLatin1String( "" ) ); + QCOMPARE( reverseCipher.ok(), true ); +} +} +#endif + +// These are from the Botan test suite. They match the test vectors from Bruce's site +void CipherUnitTest::blowfish_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + QTest::newRow("1") << QStringLiteral("0000000000000000") << QStringLiteral("245946885754369a") + << QStringLiteral("0123456789abcdef"); + QTest::newRow("2") << QStringLiteral("0000000000000000") << QStringLiteral("4ef997456198dd78") + << QStringLiteral("0000000000000000"); + QTest::newRow("3") << QStringLiteral("0000000000000000") << QStringLiteral("f21e9a77b71c49bc") + << QStringLiteral("ffffffffffffffff"); + QTest::newRow("4") << QStringLiteral("004bd6ef09176062") << QStringLiteral("452031c1e4fada8e") + << QStringLiteral("584023641aba6176"); + QTest::newRow("5") << QStringLiteral("0123456789abcdef") << QStringLiteral("0aceab0fc6a0a28d") + << QStringLiteral("fedcba9876543210"); + QTest::newRow("6") << QStringLiteral("0123456789abcdef") << QStringLiteral("7d0cc630afda1ec7") + << QStringLiteral("1111111111111111"); + QTest::newRow("7") << QStringLiteral("0123456789abcdef") << QStringLiteral("a790795108ea3cae") + << QStringLiteral("1f1f1f1f0e0e0e0e"); + QTest::newRow("8") << QStringLiteral("0123456789abcdef") << QStringLiteral("c39e072d9fac631d") + << QStringLiteral("e0fee0fef1fef1fe"); + QTest::newRow("9") << QStringLiteral("0123456789abcdef") << QStringLiteral("fa34ec4847b268b2") + << QStringLiteral("0101010101010101"); + QTest::newRow("10") << QStringLiteral("01a1d6d039776742") << QStringLiteral("59c68245eb05282b") + << QStringLiteral("7ca110454a1a6e57"); + QTest::newRow("11") << QStringLiteral("0248d43806f67172") << QStringLiteral("1730e5778bea1da4") + << QStringLiteral("07a1133e4a0b2686"); + QTest::newRow("12") << QStringLiteral("02fe55778117f12a") << QStringLiteral("cf9c5d7a4986adb5") + << QStringLiteral("49e95d6d4ca229bf"); + QTest::newRow("13") << QStringLiteral("059b5e0851cf143a") << QStringLiteral("48f4d0884c379918") + << QStringLiteral("0113b970fd34f2ce"); + QTest::newRow("14") << QStringLiteral("072d43a077075292") << QStringLiteral("7a8e7bfa937e89a3") + << QStringLiteral("4fb05e1515ab73a7"); + QTest::newRow("15") << QStringLiteral("0756d8e0774761d2") << QStringLiteral("432193b78951fc98") + << QStringLiteral("0170f175468fb5e6"); + QTest::newRow("16") << QStringLiteral("1000000000000001") << QStringLiteral("7d856f9a613063f2") + << QStringLiteral("3000000000000000"); + QTest::newRow("17") << QStringLiteral("1111111111111111") << QStringLiteral("2466dd878b963c9d") + << QStringLiteral("1111111111111111"); + QTest::newRow("18") << QStringLiteral("1111111111111111") << QStringLiteral("61f9c3802281b096") + << QStringLiteral("0123456789abcdef"); + QTest::newRow("19") << QStringLiteral("164d5e404f275232") << QStringLiteral("5f99d04f5b163969") + << QStringLiteral("37d06bb516cb7546"); + QTest::newRow("20") << QStringLiteral("1d9d5c5018f728c2") << QStringLiteral("d1abb290658bc778") + << QStringLiteral("018310dc409b26d6"); + QTest::newRow("21") << QStringLiteral("26955f6835af609a") << QStringLiteral("d887e0393c2da6e3") + << QStringLiteral("04689104c2fd3b2f"); + QTest::newRow("22") << QStringLiteral("305532286d6f295a") << QStringLiteral("55cb3774d13ef201") + << QStringLiteral("1c587f1c13924fef"); + QTest::newRow("23") << QStringLiteral("3bdd119049372802") << QStringLiteral("2eedda93ffd39c79") + << QStringLiteral("07a7137045da2a16"); + QTest::newRow("24") << QStringLiteral("42fd443059577fa2") << QStringLiteral("353882b109ce8f1a") + << QStringLiteral("04b915ba43feb5b6"); + QTest::newRow("25") << QStringLiteral("437540c8698f3cfa") << QStringLiteral("53c55f9cb49fc019") + << QStringLiteral("49793ebc79b3258f"); + QTest::newRow("26") << QStringLiteral("480d39006ee762f2") << QStringLiteral("7555ae39f59b87bd") + << QStringLiteral("025816164629b007"); + QTest::newRow("27") << QStringLiteral("51454b582ddf440a") << QStringLiteral("a25e7856cf2651eb") + << QStringLiteral("3849674c2602319e"); + QTest::newRow("28") << QStringLiteral("5cd54ca83def57da") << QStringLiteral("b1b8cc0b250f09a0") + << QStringLiteral("0131d9619dc1376e"); + QTest::newRow("29") << QStringLiteral("6b056e18759f5cca") << QStringLiteral("4a057a3b24d3977b") + << QStringLiteral("1f08260d1ac2465e"); + QTest::newRow("30") << QStringLiteral("762514b829bf486a") << QStringLiteral("13f04154d69d1ae5") + << QStringLiteral("43297fad38e373fe"); + QTest::newRow("31") << QStringLiteral("ffffffffffffffff") << QStringLiteral("014933e0cdaff6e4") + << QStringLiteral("0000000000000000"); + QTest::newRow("32") << QStringLiteral("ffffffffffffffff") << QStringLiteral("51866fd5b85ecb8a") + << QStringLiteral("ffffffffffffffff"); + QTest::newRow("33") << QStringLiteral("ffffffffffffffff") << QStringLiteral("6b5c5a9c5d9e0a5a") + << QStringLiteral("fedcba9876543210"); + QTest::newRow("34") << QStringLiteral("0123456789abcdef1111111111111111") + << QStringLiteral("7d0cc630afda1ec72466dd878b963c9d") << QStringLiteral("1111111111111111"); + QTest::newRow("35") << QStringLiteral("fedcba9876543210") << QStringLiteral("cc91732b8022f684") + << QStringLiteral("57686f206973204a6f686e2047616c743f"); + QTest::newRow("36") << QStringLiteral("424c4f5746495348") << QStringLiteral("324ed0fef413a203") + << QStringLiteral("6162636465666768696a6b6c6d6e6f707172737475767778797a"); + QTest::newRow("37") << QStringLiteral("fedcba9876543210") << QStringLiteral("f9ad597c49db005e") + << QStringLiteral("f0"); + QTest::newRow("38") << QStringLiteral("fedcba9876543210") << QStringLiteral("e91d21c1d961a6d6") + << QStringLiteral("f0e1"); + QTest::newRow("39") << QStringLiteral("fedcba9876543210") << QStringLiteral("e9c2b70a1bc65cf3") + << QStringLiteral("f0e1d2"); + QTest::newRow("40") << QStringLiteral("fedcba9876543210") << QStringLiteral("be1e639408640f05") + << QStringLiteral("f0e1d2c3"); + QTest::newRow("41") << QStringLiteral("fedcba9876543210") << QStringLiteral("b39e44481bdb1e6e") + << QStringLiteral("f0e1d2c3b4"); + QTest::newRow("42") << QStringLiteral("fedcba9876543210") << QStringLiteral("9457aa83b1928c0d") + << QStringLiteral("f0e1d2c3b4a5"); + QTest::newRow("43") << QStringLiteral("fedcba9876543210") << QStringLiteral("8bb77032f960629d") + << QStringLiteral("f0e1d2c3b4a596"); + QTest::newRow("44") << QStringLiteral("fedcba9876543210") << QStringLiteral("e87a244e2cc85e82") + << QStringLiteral("f0e1d2c3b4a59687"); + QTest::newRow("45") << QStringLiteral("fedcba9876543210") << QStringLiteral("15750e7a4f4ec577") + << QStringLiteral("f0e1d2c3b4a5968778"); + QTest::newRow("46") << QStringLiteral("fedcba9876543210") << QStringLiteral("122ba70b3ab64ae0") + << QStringLiteral("f0e1d2c3b4a596877869"); + QTest::newRow("47") << QStringLiteral("fedcba9876543210") << QStringLiteral("3a833c9affc537f6") + << QStringLiteral("f0e1d2c3b4a5968778695a"); + QTest::newRow("48") << QStringLiteral("fedcba9876543210") << QStringLiteral("9409da87a90f6bf2") + << QStringLiteral("f0e1d2c3b4a5968778695a4b"); + QTest::newRow("49") << QStringLiteral("fedcba9876543210") << QStringLiteral("884f80625060b8b4") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c"); + QTest::newRow("50") << QStringLiteral("fedcba9876543210") << QStringLiteral("1f85031c19e11968") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d"); + QTest::newRow("51") << QStringLiteral("fedcba9876543210") << QStringLiteral("79d9373a714ca34f") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e"); + QTest::newRow("52") << QStringLiteral("fedcba9876543210") << QStringLiteral("93142887ee3be15c") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f"); + QTest::newRow("53") << QStringLiteral("fedcba9876543210") << QStringLiteral("03429e838ce2d14b") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f00"); + QTest::newRow("54") << QStringLiteral("fedcba9876543210") << QStringLiteral("a4299e27469ff67b") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f0011"); + QTest::newRow("55") << QStringLiteral("fedcba9876543210") << QStringLiteral("afd5aed1c1bc96a8") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f001122"); + QTest::newRow("56") << QStringLiteral("fedcba9876543210") << QStringLiteral("10851c0e3858da9f") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f00112233"); + QTest::newRow("57") << QStringLiteral("fedcba9876543210") << QStringLiteral("e6f51ed79b9db21f") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344"); + QTest::newRow("58") << QStringLiteral("fedcba9876543210") << QStringLiteral("64a6e14afd36b46f") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455"); + QTest::newRow("59") << QStringLiteral("fedcba9876543210") << QStringLiteral("80c7d7d45a5479ad") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566"); + QTest::newRow("60") << QStringLiteral("fedcba9876543210") << QStringLiteral("05044b62fa52d080") + << QStringLiteral("f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677"); +} + +void CipherUnitTest::blowfish() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("blowfish-ecb", provider)) { + anyProviderTested = true; + QCA::Cipher cipherObj1(QStringLiteral("blowfish"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + QCA::SymmetricKey(16), + QCA::InitializationVector(), + provider); + + // TODO: add some test for min and max keysizes + QCOMPARE(cipherObj1.blockSize(), 8); + + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::Cipher forwardCipher(QStringLiteral("blowfish"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Encode, + key, + QCA::InitializationVector(), + provider); + + QString afterEncodeText = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + + afterEncodeText += QCA::arrayToHex(forwardCipher.final().toByteArray()); + QVERIFY(forwardCipher.ok()); + + QCOMPARE(afterEncodeText, cipherText); + + QCA::Cipher reverseCipher(QStringLiteral("blowfish"), + QCA::Cipher::ECB, + QCA::Cipher::NoPadding, + QCA::Decode, + key, + QCA::InitializationVector(), + provider); + QString afterDecodeText = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + + afterDecodeText += QCA::arrayToHex(reverseCipher.final().toByteArray()); + QVERIFY(reverseCipher.ok()); + + QCOMPARE(afterDecodeText, plainText); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Blowfish ECB:" << providersToTest; +} + +// From the Eric Young test vectors on Bruce's site. I modified +// them to remove the incomplete block. +void CipherUnitTest::blowfish_cbc_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("37363534333231204e6f77206973207468652074696d6520") + << QStringLiteral("6b77b4d63006dee605b156e27403979358deb9e7154616d9") + << QStringLiteral("0123456789abcdeff0e1d2c3b4a59687") << QStringLiteral("fedcba9876543210"); + QTest::newRow("pkcs7") << QStringLiteral("37363534333231204e6f77206973207468652074696d6520666f722000030303") + << QStringLiteral("6b77b4d63006dee605b156e27403979358deb9e7154616d9749decbec05d264b") + << QStringLiteral("0123456789abcdeff0e1d2c3b4a59687") << QStringLiteral("fedcba9876543210"); +} + +void CipherUnitTest::blowfish_cbc() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("blowfish-cbc", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("blowfish"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("blowfish"), QCA::Cipher::CBC, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Blowfish CBC:" << providersToTest; +} + +// I can't find any independent test vectors. I used the no padding case, with hand padding added, +// as a poor check. +void CipherUnitTest::blowfish_cbc_pkcs7_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("37363534333231204e6f77206973207468652074696d6520666f722000") + << QStringLiteral("6b77b4d63006dee605b156e27403979358deb9e7154616d9749decbec05d264b") + << QStringLiteral("0123456789abcdeff0e1d2c3b4a59687") << QStringLiteral("fedcba9876543210"); +} + +void CipherUnitTest::blowfish_cbc_pkcs7() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("blowfish-cbc-pkcs7", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("blowfish"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(update, cipherText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("blowfish"), QCA::Cipher::CBC, QCA::Cipher::PKCS7, QCA::Decode, key, iv, provider); + update = QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()); + QVERIFY(reverseCipher.ok()); + QCOMPARE(update, plainText.left(update.size())); + QCOMPARE(QString(update + QCA::arrayToHex(reverseCipher.final().toByteArray())), plainText); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Blowfish CBC with PKCS7 padding:" << providersToTest; +} + +// From the Eric Young test vectors on Bruce's site: +void CipherUnitTest::blowfish_cfb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("37363534333231204e6f77206973207468652074696d6520666f722000") + << QStringLiteral("e73214a2822139caf26ecf6d2eb9e76e3da3de04d1517200519d57a6c3") + << QStringLiteral("0123456789abcdeff0e1d2c3b4a59687") << QStringLiteral("fedcba9876543210"); +} + +void CipherUnitTest::blowfish_cfb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("blowfish-cfb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("blowfish"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("blowfish"), QCA::Cipher::CFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Blowfish CFB:" << providersToTest; +} + +// From the Eric Young test vectors on Bruce's site: +void CipherUnitTest::blowfish_ofb_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + QTest::addColumn("ivText"); + + QTest::newRow("1") << QStringLiteral("37363534333231204e6f77206973207468652074696d6520666f722000") + << QStringLiteral("e73214a2822139ca62b343cc5b65587310dd908d0c241b2263c2cf80da") + << QStringLiteral("0123456789abcdeff0e1d2c3b4a59687") << QStringLiteral("fedcba9876543210"); +} + +void CipherUnitTest::blowfish_ofb() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("blowfish-ofb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + QFETCH(QString, ivText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv(QCA::hexToArray(ivText)); + QCA::Cipher forwardCipher( + QStringLiteral("blowfish"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("blowfish"), QCA::Cipher::OFB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Blowfish OFB:" << providersToTest; +} + +// From RFC2144 Appendix B +void CipherUnitTest::cast5_data() +{ + QTest::addColumn("plainText"); + QTest::addColumn("cipherText"); + QTest::addColumn("keyText"); + + QTest::newRow("128-bit") << QStringLiteral("0123456789abcdef") << QStringLiteral("238b4fe5847e44b2") + << QStringLiteral("0123456712345678234567893456789A"); + + QTest::newRow("80-bit") << QStringLiteral("0123456789abcdef") << QStringLiteral("eb6a711a2c02271b") + << QStringLiteral("01234567123456782345"); + + QTest::newRow("40-bit") << QStringLiteral("0123456789abcdef") << QStringLiteral("7ac816d16e9b302e") + << QStringLiteral("0123456712"); +} + +void CipherUnitTest::cast5() +{ + bool anyProviderTested = false; + foreach (const QString provider, providersToTest) { + if (QCA::isSupported("cast5-ecb", provider)) { + anyProviderTested = true; + QFETCH(QString, plainText); + QFETCH(QString, cipherText); + QFETCH(QString, keyText); + + QCA::SymmetricKey key(QCA::hexToArray(keyText)); + QCA::InitializationVector iv; + QCA::Cipher forwardCipher( + QStringLiteral("cast5"), QCA::Cipher::ECB, QCA::Cipher::NoPadding, QCA::Encode, key, iv, provider); + QString update = QCA::arrayToHex(forwardCipher.update(QCA::hexToArray(plainText)).toByteArray()); + QVERIFY(forwardCipher.ok()); + QCOMPARE(QString(update + QCA::arrayToHex(forwardCipher.final().toByteArray())), cipherText); + QVERIFY(forwardCipher.ok()); + + QCA::Cipher reverseCipher( + QStringLiteral("cast5"), QCA::Cipher::ECB, QCA::Cipher::NoPadding, QCA::Decode, key, iv, provider); + + QCOMPARE(QCA::arrayToHex(reverseCipher.update(QCA::hexToArray(cipherText)).toByteArray()), plainText); + QVERIFY(reverseCipher.ok()); + QCOMPARE(QCA::arrayToHex(reverseCipher.final().toByteArray()), QLatin1String("")); + QVERIFY(reverseCipher.ok()); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports CAST5:" << providersToTest; +} + +QTEST_MAIN(CipherUnitTest) diff --git a/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.h b/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.h new file mode 100644 index 0000000000..1ade1abf68 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cipherunittest/cipherunittest.h @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2004-2007 Brad Hards + * Copyright (C) 2013-2016 Ivan Romanov + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef CIPHERUNITTEST_H +#define CIPHERUNITTEST_H + +#include + +class CipherUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void aes128_data(); + void aes128(); + void aes128_cbc_data(); + void aes128_cbc(); + void aes128_cbc_pkcs7_data(); + void aes128_cbc_pkcs7(); + void aes128_cfb_data(); + void aes128_cfb(); + void aes128_ofb_data(); + void aes128_ofb(); + void aes128_ctr_data(); + void aes128_ctr(); + void aes128_gcm_data(); + void aes128_gcm(); + void aes128_ccm_data(); + void aes128_ccm(); + + void aes192_data(); + void aes192(); + void aes192_cbc_data(); + void aes192_cbc(); + void aes192_cbc_pkcs7_data(); + void aes192_cbc_pkcs7(); + void aes192_cfb_data(); + void aes192_cfb(); + void aes192_ofb_data(); + void aes192_ofb(); + void aes192_ctr_data(); + void aes192_ctr(); + void aes192_gcm_data(); + void aes192_gcm(); + void aes192_ccm_data(); + void aes192_ccm(); + + void aes256_data(); + void aes256(); + void aes256_cbc_data(); + void aes256_cbc(); + void aes256_cbc_pkcs7_data(); + void aes256_cbc_pkcs7(); + void aes256_cfb_data(); + void aes256_cfb(); + void aes256_ofb_data(); + void aes256_ofb(); + void aes256_ctr_data(); + void aes256_ctr(); + void aes256_gcm_data(); + void aes256_gcm(); + void aes256_ccm_data(); + void aes256_ccm(); + + void tripleDES_data(); + void tripleDES(); + + void des_data(); + void des(); + void des_pkcs7_data(); + void des_pkcs7(); + void des_cbc_data(); + void des_cbc(); + void des_cbc_pkcs7_data(); + void des_cbc_pkcs7(); + void des_cfb_data(); + void des_cfb(); + void des_ofb_data(); + void des_ofb(); + + void blowfish_data(); + void blowfish(); + void blowfish_cbc_data(); + void blowfish_cbc(); + void blowfish_cbc_pkcs7_data(); + void blowfish_cbc_pkcs7(); + void blowfish_cfb_data(); + void blowfish_cfb(); + void blowfish_ofb_data(); + void blowfish_ofb(); + + void cast5_data(); + void cast5(); + +private: + QCA::Initializer *m_init; + QStringList providersToTest; +}; + +#endif // CIPHERUNITTEST_H diff --git a/local/recipes/libs/qca/source/unittest/clientplugin/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/clientplugin/CMakeLists.txt new file mode 100644 index 0000000000..686e4d4829 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/clientplugin/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set( clientplugin_bin_SRCS clientplugin.cpp ) + +add_executable(clientplugin ${clientplugin_bin_SRCS} ) + +target_link_qca_test_libraries(clientplugin) + +add_qca_test(clientplugin "ClientSidePlugin") diff --git a/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.cpp b/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.cpp new file mode 100644 index 0000000000..67496cf62a --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.cpp @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include "clientplugin.h" + +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +void ClientPlugin::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void ClientPlugin::cleanupTestCase() +{ + delete m_init; +} + +static const QLatin1String providerName("testClientSideProvider"); + +class TestClientProvider : public QObject, public QCA::Provider +{ + Q_OBJECT +public: + int qcaVersion() const override + { + return QCA_VERSION; + } + + QString name() const override + { + return providerName; + } + + QStringList features() const override + { + QStringList list; + list += QStringLiteral("testClientSideProviderFeature1"); + list += QStringLiteral("testClientSideProviderFeature2"); + return list; + } + + Provider::Context *createContext(const QString &type) override + { + if (type == QLatin1String("testClientSideProviderFeature1")) + // return new Feature1Context(this); + return nullptr; + else if (type == QLatin1String("testClientSideProviderFeature2")) + // return new Feature2Context(this); + return nullptr; + else + return nullptr; + } +}; + +void ClientPlugin::testInsertRemovePlugin() +{ + QPointer provider = new TestClientProvider; + + QVERIFY(QCA::insertProvider(provider, 10)); + QCOMPARE(QCA::findProvider(providerName), provider.data()); + QCOMPARE(QCA::providerPriority(providerName), 10); + + QVERIFY(QCA::unloadProvider(providerName)); + QCOMPARE(QCA::findProvider(providerName), static_cast(nullptr)); + QVERIFY(provider.isNull()); +} + +QTEST_MAIN(ClientPlugin) + +#include "clientplugin.moc" diff --git a/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.h b/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.h new file mode 100644 index 0000000000..3c00b66f07 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/clientplugin/clientplugin.h @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +#ifndef CLIENTPLUGIN_H +#define CLIENTPLUGIN_H + +#include +#include + +class ClientPlugin : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testInsertRemovePlugin(); + +private: + QCA::Initializer *m_init; +}; + +#endif diff --git a/local/recipes/libs/qca/source/unittest/cms/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/cms/CMakeLists.txt new file mode 100644 index 0000000000..e23abb3745 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cms/CMakeLists.txt @@ -0,0 +1,15 @@ +ENABLE_TESTING() + +set(cms_bin_SRCS cms.cpp) + +add_executable(cms ${cms_bin_SRCS} ) + +target_link_qca_test_libraries(cms) +#Remove once we stop supporting openssl < 1.1.1i +target_link_libraries(cms OpenSSL::SSL OpenSSL::Crypto) + +FOREACH( testFileName QcaTestRootCert.pem QcaTestClientCert.pem QcaTestClientKey.pem ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +add_qca_test(cms "CryptographicMessageSyntax") diff --git a/local/recipes/libs/qca/source/unittest/cms/QcaTestClientCert.pem b/local/recipes/libs/qca/source/unittest/cms/QcaTestClientCert.pem new file mode 100644 index 0000000000..eea2bcea61 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cms/QcaTestClientCert.pem @@ -0,0 +1,72 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Aug 7 12:26:00 2013 GMT + Not After : Aug 2 12:26:00 2033 GMT + Subject: C=US, ST=Kalifornia, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Client Certificate/emailAddress=client@test.example.com, L=QcaLand + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:bf:38:f0:71:72:32:8a:f7:31:07:79:d1:35:31: + fe:04:51:10:8c:ca:6d:d0:83:5d:04:05:24:6e:6e: + 24:fe:95:fe:c2:f8:4b:92:39:2c:e8:c3:c8:0d:b3: + c6:a2:76:33:66:13:38:29:11:fb:62:92:71:b8:08: + 2b:6c:43:32:de:67:4e:46:7d:b6:0b:d4:f7:8c:26: + 29:7d:96:71:a5:8d:ca:01:b4:63:bd:eb:70:62:02: + 3a:3c:e0:e6:81:f1:2b:d3:a5:7d:aa:72:7f:3c:9e: + 1f:df:9c:4e:5e:d7:09:fe:f6:9e:9f:8f:4a:25:f2: + 27:b9:c8:90:76:b0:f1:e2:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + X509v3 Subject Key Identifier: + 99:1B:6A:FD:E7:CF:B3:A1:B8:7C:8B:E7:21:75:65:74:31:62:A8:F5 + X509v3 Authority Key Identifier: + keyid:C5:B1:01:67:2C:CE:84:23:BD:7C:6B:29:38:D5:47:25:AD:09:DF:67 + + X509v3 Subject Alternative Name: + email:client@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Signature Algorithm: sha1WithRSAEncryption + d1:8d:8a:30:9b:d6:a4:5b:85:be:8d:12:ab:6e:ec:69:66:0a: + cc:3b:df:4f:35:5a:b1:d0:a8:5d:12:3a:de:0d:e5:47:7c:d3: + 7f:65:0a:7e:93:8a:a9:82:4a:74:04:e8:f6:30:67:e8:7b:41: + 7b:bd:b6:41:7f:bc:ff:f0:57:77:10:2e:20:5c:d4:9e:04:03: + a4:78:cb:df:90:da:51:bc:d7:9f:be:12:62:d7:bd:ea:98:af: + a1:6b:64:9d:da:57:de:d3:18:fa:cd:a0:7f:70:e1:c6:7b:f2: + d5:b4:ce:0d:1f:fe:d7:52:bd:df:22:87:32:ea:d9:5b:a8:71: + db:bb +-----BEGIN CERTIFICATE----- +MIID2TCCA0KgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBzjELMAkGA1UEBhMCQVUx +JTAjBgNVBAgMHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnkxITAfBgNVBAoM +GFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECwweQ2VydGlmaWNhdGUg +R2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDDBlRY2EgVGVzdCBSb290IENlcnRp +ZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0LmV4YW1wbGUuY29t +MB4XDTEzMDgwNzEyMjYwMFoXDTMzMDgwMjEyMjYwMFowgc4xCzAJBgNVBAYTAlVT +MRMwEQYDVQQIDApLYWxpZm9ybmlhMSEwHwYDVQQKDBhRY2EgRGV2ZWxvcG1lbnQg +YW5kIFRlc3QxJzAlBgNVBAsMHkNlcnRpZmljYXRlIEdlbmVyYXRpb24gU2VjdGlv +bjEkMCIGA1UEAwwbUWNhIFRlc3QgQ2xpZW50IENlcnRpZmljYXRlMSYwJAYJKoZI +hvcNAQkBFhdjbGllbnRAdGVzdC5leGFtcGxlLmNvbTEQMA4GA1UEBwwHUWNhTGFu +ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvzjwcXIyivcxB3nRNTH+BFEQ +jMpt0INdBAUkbm4k/pX+wvhLkjks6MPIDbPGonYzZhM4KRH7YpJxuAgrbEMy3mdO +Rn22C9T3jCYpfZZxpY3KAbRjvetwYgI6PODmgfEr06V9qnJ/PJ4f35xOXtcJ/vae +n49KJfInuciQdrDx4p0CAwEAAaOBxDCBwTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE +8DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwHQYDVR0OBBYEFJkbav3n +z7OhuHyL5yF1ZXQxYqj1MB8GA1UdIwQYMBaAFMWxAWcszoQjvXxrKTjVRyWtCd9n +MCIGA1UdEQQbMBmBF2NsaWVudEB0ZXN0LmV4YW1wbGUuY29tMCQGA1UdEgQdMBuB +GXRlc3Rvbmx5QHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADgYEA0Y2K +MJvWpFuFvo0Sq27saWYKzDvfTzVasdCoXRI63g3lR3zTf2UKfpOKqYJKdATo9jBn +6HtBe722QX+8//BXdxAuIFzUngQDpHjL35DaUbzXn74SYte96pivoWtkndpX3tMY ++s2gf3Dhxnvy1bTODR/+11K93yKHMurZW6hx27s= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/cms/QcaTestClientKey.pem b/local/recipes/libs/qca/source/unittest/cms/QcaTestClientKey.pem new file mode 100644 index 0000000000..7afa960486 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cms/QcaTestClientKey.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,40932B6AC97B24F3 + +X134DPKLmgy2u5HzlHFIpr1fxx40jW1EmvFABIe/VKcdTywmLcGTVCVoPuv305x7 +IfnnhTPkwM1v5rgm7zyq/KHkYp1Jens81/zBlUUd6ixxq//AzaEUC/42ZF+2l8/+ +KMVHm3NCtJjBXXx6yOFH6ov7A+OYZnK/4rFLYW3cUo4spRr31tDSBiNaEuI/zhgU +8V5ag9LuvIC+qmtWMSeLWUjPZknEPWi06/Uw2D9Ahi0WL1vaDOf5zsEIbnNupzoe +pAVqnWX5TtUFcRUXkXhKmdfq9V7yI4VdPEB8BP9yxGU919az30EQnoenaSVK8zDs +6g/rroy2nhSZE0Ni3eOCyeLBQoR/oFe6DP/Jgis0ITSTRmstB4nE86GJh1AcnUTM +MsBwcdXg6yYXn8qDTC2O0/KMKNaUC0/M0Aco+4M/bRWuc7FTjF6JmW6zlbG0IL0t +Oi/3xbFMJFX0hkfC3EKm1KYRHGOTeA9523UVHuxO0tQ5g8648DimXxEkwaFxTn87 +A0rCIb+XDFuARXVoA7NJs88kg6hYA2+DCmmN5TLmaoTYyMx08UvQJhhV7cDPmjyB +N2f6tDVzVBhzs3x/gnvdnMF3eGgElhmJhXy4T61a+UEHpjc8EXx1daI5ahcUw0vS +gyl9spsMVZ6UOIkbFPm6jwe5csaz9OPQ5leWfKv8mkxdZHxWadSLOAPzoytvBarl +DYFaeScsw0aaBNlZ0mIH3GYa4pw3xEl8QNGtgqacZEytP4ZGxhv8/bES4IaXCALF +ZUxcWAW3EqF4skTkE5rwmirNJQeSFHhBZPwUHrEQuD8opCwCsWVovQ== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/cms/QcaTestRootCert.pem b/local/recipes/libs/qca/source/unittest/cms/QcaTestRootCert.pem new file mode 100644 index 0000000000..dd43588e5f --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cms/QcaTestRootCert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyjCCAzOgAwIBAgIJANsTWPQabIWbMA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECAwcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UECgwYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLDB5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMMGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMTMwODA3MTIxOTM5WhcNMzMwODAyMTIxOTM5WjCBzjELMAkG +A1UEBhMCQVUxJTAjBgNVBAgMHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnkx +ITAfBgNVBAoMGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECwweQ2Vy +dGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDDBlRY2EgVGVzdCBS +b290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0LmV4 +YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlHuDm+lmgdoPj +4SvWJ12o9ZXliYVQwaEPgkuSrNrBqnoHjF6c3MdmG5snKaB8quiuyENtmOVz8a/h +Tmb/9TWqnxUsJbdwDgQRWQj88RYgRflna3xZnoSrqDuGAgGOg4B78qw3TEhhiall +bIw4xzsZ6n1nX0IMQP9u0SSOPD1mzwIDAQABo4GtMIGqMB0GA1UdDgQWBBTFsQFn +LM6EI718ayk41UclrQnfZzAfBgNVHSMEGDAWgBTFsQFnLM6EI718ayk41UclrQnf +ZzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB5jAkBgNVHREEHTAbgRl0ZXN0 +b25seUB0ZXN0LmV4YW1wbGUuY29tMCQGA1UdEgQdMBuBGXRlc3Rvbmx5QHRlc3Qu +ZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADgYEAyb7uwIvotXTIulHZRwobG2W5 +uzL3Cvdp24cJ2c7R2QyTappJCgpUzb7PcGb7SE/sseiaALiBsRBdIRvgXlXv1BtJ +hcLlpIUxRSx14pfzto+AVYcyT3ZJL5qXN4tvy5OhzZWdkdzchcgnT8Wq1fS9MsZU +pWaSYVphpjxjddnHWyo= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/cms/cms.cpp b/local/recipes/libs/qca/source/unittest/cms/cms.cpp new file mode 100644 index 0000000000..854994a4bd --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/cms/cms.cpp @@ -0,0 +1,522 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +#include + +class CMSut : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void xcrypt_data(); + void xcrypt(); + void signverify_data(); + void signverify(); + void signverify_message_data(); + void signverify_message(); + void signverify_message_invalid_data(); + void signverify_message_invalid(); + +private: + QCA::Initializer *m_init; +}; + +void CMSut::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void CMSut::cleanupTestCase() +{ + delete m_init; +} + +void CMSut::xcrypt_data() +{ + QTest::addColumn("testText"); + + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("0") << QByteArray("0"); + QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01"); + QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()"); +} + +void CMSut::xcrypt() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData()); + else if (!QCA::isSupported("cms", provider)) + QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate pubCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), nullptr, provider); + QCOMPARE(pubCert.isNull(), false); + + QCA::SecureMessageKey secMsgKey; + QCA::CertificateChain chain; + chain += pubCert; + secMsgKey.setX509CertificateChain(chain); + + QCA::CMS cms; + QCA::SecureMessage msg(&cms); + QCOMPARE(msg.canClearsign(), false); + QCOMPARE(msg.canSignAndEncrypt(), false); + QCOMPARE(msg.type(), QCA::SecureMessage::CMS); + + msg.setRecipient(secMsgKey); + + QFETCH(QByteArray, testText); + + msg.startEncrypt(); + msg.update(testText); + msg.end(); + + msg.waitForFinished(-1); + + QByteArray encryptedResult1 = msg.read(); + QCOMPARE(encryptedResult1.isEmpty(), false); + + msg.reset(); + msg.setRecipient(secMsgKey); + msg.startEncrypt(); + msg.update(testText); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.success()); + + QByteArray encryptedResult2 = msg.read(); + QCOMPARE(encryptedResult2.isEmpty(), false); + + QCA::ConvertResult res; + QCA::SecureArray passPhrase = "start"; + QCA::PrivateKey privKey = + QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res); + QCOMPARE(res, QCA::ConvertGood); + + secMsgKey.setX509PrivateKey(privKey); + QCA::SecureMessageKeyList privKeyList; + privKeyList += secMsgKey; + QCA::CMS cms2; + cms2.setPrivateKeys(privKeyList); + + QCA::SecureMessage msg2(&cms2); + + msg2.startDecrypt(); + msg2.update(encryptedResult1); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray decryptedResult1 = msg2.read(); + QCOMPARE(decryptedResult1, testText); + + msg2.reset(); + msg2.startDecrypt(); + msg2.update(encryptedResult1); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray decryptedResult2 = msg2.read(); + + QCOMPARE(decryptedResult1, decryptedResult2); + + QCOMPARE(msg2.canClearsign(), false); + QCOMPARE(msg2.canSignAndEncrypt(), false); + QCOMPARE(msg2.type(), QCA::SecureMessage::CMS); + } + } +} + +void CMSut::signverify_data() +{ + QTest::addColumn("testText"); + + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("0") << QByteArray("0"); + QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01"); + QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()"); +} + +// This one tests Detached format. +void CMSut::signverify() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData()); + else if (!QCA::isSupported("cms", provider)) + QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult res; + QCA::SecureArray passPhrase = "start"; + QCA::PrivateKey privKey = + QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider); + QCOMPARE(res, QCA::ConvertGood); + + QCA::Certificate pubCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCOMPARE(pubCert.isNull(), false); + + QCA::CertificateChain chain; + chain += pubCert; + QCA::SecureMessageKey secMsgKey; + secMsgKey.setX509CertificateChain(chain); + secMsgKey.setX509PrivateKey(privKey); + + QCA::SecureMessageKeyList privKeyList; + privKeyList += secMsgKey; + QCA::CMS cms2; + cms2.setPrivateKeys(privKeyList); + + QCA::SecureMessage msg2(&cms2); + msg2.setSigners(privKeyList); + QCOMPARE(msg2.canClearsign(), false); + QCOMPARE(msg2.canSignAndEncrypt(), false); + QCOMPARE(msg2.type(), QCA::SecureMessage::CMS); + + QFETCH(QByteArray, testText); + + msg2.startSign(QCA::SecureMessage::Detached); + msg2.update(testText); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray signedResult1 = msg2.signature(); + QCOMPARE(signedResult1.isEmpty(), false); + + msg2.reset(); + + msg2.setSigners(privKeyList); + msg2.startSign(QCA::SecureMessage::Detached); + msg2.update(testText); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray signedResult2 = msg2.signature(); + + QCOMPARE(signedResult2.isEmpty(), false); + + QCA::CMS cms; + QCA::Certificate caCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCA::CertificateCollection caCertCollection; + caCertCollection.addCertificate(caCert); + + cms.setTrustedCertificates(caCertCollection); + QCA::SecureMessage msg(&cms); + QCOMPARE(msg.canClearsign(), false); + QCOMPARE(msg.canSignAndEncrypt(), false); + QCOMPARE(msg.type(), QCA::SecureMessage::CMS); + + msg.startVerify(signedResult1); + msg.update(testText); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); +#if OPENSSL_VERSION_NUMBER < 0x1010109fL + QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue); +#endif + QVERIFY(msg.verifySuccess()); + + msg.reset(); + + msg.startVerify(signedResult2); + msg.update(testText); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); +#if OPENSSL_VERSION_NUMBER < 0x1010109fL + QEXPECT_FAIL("empty", "We don't seem to be able to verify signature of a zero length message", Continue); +#endif + QVERIFY(msg.verifySuccess()); + + msg.reset(); + + // This tests junk on the end of the signature - should fail + msg.startVerify(signedResult2 + "junk"); + msg.update(testText); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); +#if OPENSSL_VERSION_NUMBER >= 0x1010109fL + QEXPECT_FAIL("empty", "On newer openssl verifaction of zero length message always succeeds", Continue); +#endif + QCOMPARE(msg.verifySuccess(), false); + + msg.reset(); + + // This tests junk on the end of the message - should fail + msg.startVerify(signedResult2); + msg.update(testText + "junk"); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); + QCOMPARE(msg.verifySuccess(), false); + } + } +} + +void CMSut::signverify_message_data() +{ + QTest::addColumn("testText"); + + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("0") << QByteArray("0"); + QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01"); + QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()"); +} + +// This one tests Message format +void CMSut::signverify_message() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData()); + else if (!QCA::isSupported("cms", provider)) + QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult res; + QCA::SecureArray passPhrase = "start"; + QCA::PrivateKey privKey = + QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider); + QCOMPARE(res, QCA::ConvertGood); + + QCA::Certificate pubCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCOMPARE(pubCert.isNull(), false); + + QCA::CertificateChain chain; + chain += pubCert; + QCA::SecureMessageKey secMsgKey; + secMsgKey.setX509CertificateChain(chain); + secMsgKey.setX509PrivateKey(privKey); + + QCA::SecureMessageKeyList privKeyList; + privKeyList += secMsgKey; + QCA::CMS cms2; + cms2.setPrivateKeys(privKeyList); + + QCA::SecureMessage msg2(&cms2); + msg2.setSigners(privKeyList); + QCOMPARE(msg2.canClearsign(), false); + QCOMPARE(msg2.canSignAndEncrypt(), false); + QCOMPARE(msg2.type(), QCA::SecureMessage::CMS); + + QFETCH(QByteArray, testText); + + msg2.startSign(QCA::SecureMessage::Message); + msg2.update(testText); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray signedResult1 = msg2.read(); + QCOMPARE(signedResult1.isEmpty(), false); + + msg2.reset(); + + msg2.setSigners(privKeyList); + msg2.startSign(QCA::SecureMessage::Message); + msg2.update(testText); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray signedResult2 = msg2.read(); + + QCOMPARE(signedResult2.isEmpty(), false); + + QCA::CMS cms; + QCA::Certificate caCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + + QCA::CertificateCollection caCertCollection; + caCertCollection.addCertificate(caCert); + + cms.setTrustedCertificates(caCertCollection); + QCA::SecureMessage msg(&cms); + QCOMPARE(msg.canClearsign(), false); + QCOMPARE(msg.canSignAndEncrypt(), false); + QCOMPARE(msg.type(), QCA::SecureMessage::CMS); + + msg.startVerify(); + msg.update(signedResult1); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); + QVERIFY(msg.verifySuccess()); + + msg.reset(); + + msg.startVerify(); + msg.update(signedResult2); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); + QVERIFY(msg.verifySuccess()); + + msg.reset(); + + msg.startVerify(); + msg.update(signedResult2); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); + QCOMPARE(msg.verifySuccess(), true); + } + } +} + +void CMSut::signverify_message_invalid_data() +{ + QTest::addColumn("testText"); + + QTest::newRow("empty") << QByteArray(""); + QTest::newRow("0") << QByteArray("0"); + QTest::newRow("07") << QByteArray("07899847jkjjfasjaJKJLJkljklj&kjlj;/**-+.01"); + QTest::newRow("dubious") << QByteArray("~!#**$#&&%^@#^&()"); +} + +// This one tests Message format +void CMSut::signverify_message_invalid() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate not supported for ") + provider).toLocal8Bit().constData()); + else if (!QCA::isSupported("cms", provider)) + QWARN((QStringLiteral("CMS not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::ConvertResult res; + QCA::SecureArray passPhrase = "start"; + QCA::PrivateKey privKey = + QCA::PrivateKey::fromPEMFile(QStringLiteral("QcaTestClientKey.pem"), passPhrase, &res, provider); + QCOMPARE(res, QCA::ConvertGood); + + QCA::Certificate pubCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestClientCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCOMPARE(pubCert.isNull(), false); + + QCA::CertificateChain chain; + chain += pubCert; + QCA::SecureMessageKey secMsgKey; + secMsgKey.setX509CertificateChain(chain); + secMsgKey.setX509PrivateKey(privKey); + + QCA::SecureMessageKeyList privKeyList; + privKeyList += secMsgKey; + QCA::CMS cms2; + cms2.setPrivateKeys(privKeyList); + + QCA::SecureMessage msg2(&cms2); + msg2.setSigners(privKeyList); + QCOMPARE(msg2.canClearsign(), false); + QCOMPARE(msg2.canSignAndEncrypt(), false); + QCOMPARE(msg2.type(), QCA::SecureMessage::CMS); + + QFETCH(QByteArray, testText); + + msg2.startSign(QCA::SecureMessage::Message); + msg2.update(testText); + msg2.end(); + msg2.waitForFinished(-1); + QVERIFY(msg2.success()); + QByteArray signedResult1 = msg2.read(); + QCOMPARE(signedResult1.isEmpty(), false); + + QCA::CMS cms; + QCA::Certificate caCert = + QCA::Certificate::fromPEMFile(QStringLiteral("QcaTestRootCert.pem"), &res, provider); + QCOMPARE(res, QCA::ConvertGood); + + QCA::CertificateCollection caCertCollection; + caCertCollection.addCertificate(caCert); + + cms.setTrustedCertificates(caCertCollection); + QCA::SecureMessage msg(&cms); + QCOMPARE(msg.canClearsign(), false); + QCOMPARE(msg.canSignAndEncrypt(), false); + QCOMPARE(msg.type(), QCA::SecureMessage::CMS); + + // This is just to break things + // signedResult1[30] = signedResult1[30] + 1; + if (signedResult1.at(signedResult1.size() - 2) != 0) { + signedResult1[signedResult1.size() - 2] = 0x00; + } else { + signedResult1[signedResult1.size() - 2] = 0x01; + } + + msg.startVerify(); + msg.update(signedResult1); + msg.end(); + + msg.waitForFinished(-1); + QVERIFY(msg.wasSigned()); + QVERIFY(msg.success()); + QCOMPARE(msg.verifySuccess(), false); + } + } +} + +QTEST_MAIN(CMSut) + +#include "cms.moc" diff --git a/local/recipes/libs/qca/source/unittest/dsaunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/dsaunittest/CMakeLists.txt new file mode 100644 index 0000000000..5f2c11d312 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/dsaunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set( dsaunittest_bin_SRCS dsaunittest.cpp) + +add_executable( dsaunittest ${dsaunittest_bin_SRCS} ) + +target_link_qca_test_libraries(dsaunittest) + +add_qca_test(dsaunittest "DigitalSignatureAlgorithm") diff --git a/local/recipes/libs/qca/source/unittest/dsaunittest/dsaunittest.cpp b/local/recipes/libs/qca/source/unittest/dsaunittest/dsaunittest.cpp new file mode 100644 index 0000000000..6abc66b07b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/dsaunittest/dsaunittest.cpp @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2005, 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class DSAUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testdsa(); + +private: + QCA::Initializer *m_init; +}; + +void DSAUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void DSAUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void DSAUnitTest::testdsa() +{ + if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DSA) || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::DSA)) { + QSKIP("DSA not supported!"); + } + + if (!QCA::DLGroup::supportedGroupSets().contains(QCA::DSA_1024)) { + QSKIP("DSA_1024 discrete logarithm group sets not supported!"); + } + + QCA::KeyGenerator keygen; + QCOMPARE(keygen.isBusy(), false); + QCOMPARE(keygen.blockingEnabled(), true); + QCA::DLGroup group = keygen.createDLGroup(QCA::DSA_1024); + QCOMPARE(group.isNull(), false); + + QCA::PrivateKey dsaKey = keygen.createDSA(group); + QCOMPARE(dsaKey.isNull(), false); + QCOMPARE(dsaKey.isRSA(), false); + QCOMPARE(dsaKey.isDSA(), true); + QCOMPARE(dsaKey.isDH(), false); + QCOMPARE(dsaKey.isPrivate(), true); + QCOMPARE(dsaKey.isPublic(), false); + QCOMPARE(dsaKey.canSign(), true); + QCOMPARE(dsaKey.canDecrypt(), false); + + QCOMPARE(dsaKey.bitSize(), 1024); + QCA::DSAPrivateKey dsaPrivKey = dsaKey.toDSA(); + QCOMPARE(dsaPrivKey.bitSize(), 1024); + + QCA::SecureArray dsaDER = dsaKey.toDER(); + QCOMPARE(dsaDER.isEmpty(), false); + + QString dsaPEM = dsaKey.toPEM(); + QCOMPARE(dsaPEM.isEmpty(), false); + + QCA::ConvertResult checkResult; + QCA::PrivateKey fromPEMkey = QCA::PrivateKey::fromPEM(dsaPEM, QCA::SecureArray(), &checkResult); + QCOMPARE(checkResult, QCA::ConvertGood); + QCOMPARE(fromPEMkey.isNull(), false); + QCOMPARE(fromPEMkey.isRSA(), false); + QCOMPARE(fromPEMkey.isDSA(), true); + QCOMPARE(fromPEMkey.isDH(), false); + QCOMPARE(fromPEMkey.isPrivate(), true); + QCOMPARE(fromPEMkey.isPublic(), false); + QVERIFY(dsaKey == fromPEMkey); + + QCA::PrivateKey fromDERkey = QCA::PrivateKey::fromDER(dsaDER, QCA::SecureArray(), &checkResult); + QCOMPARE(checkResult, QCA::ConvertGood); + QCOMPARE(fromDERkey.isNull(), false); + QCOMPARE(fromDERkey.isRSA(), false); + QCOMPARE(fromDERkey.isDSA(), true); + QCOMPARE(fromDERkey.isDH(), false); + QCOMPARE(fromDERkey.isPrivate(), true); + QCOMPARE(fromDERkey.isPublic(), false); + QVERIFY(dsaKey == fromDERkey); +} + +QTEST_MAIN(DSAUnitTest) + +#include "dsaunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/filewatchunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/filewatchunittest/CMakeLists.txt new file mode 100644 index 0000000000..50b28a2cb8 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/filewatchunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(SOURCES "filewatchunittest.cpp") + +add_executable( filewatchunittest ${SOURCES}) + +target_link_qca_test_libraries(filewatchunittest) + +add_qca_test(filewatchunittest "FileWatch") diff --git a/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.cpp b/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.cpp new file mode 100644 index 0000000000..cb28a96589 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.cpp @@ -0,0 +1,98 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +#include "filewatchunittest.h" + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +void FileWatchUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void FileWatchUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void FileWatchUnitTest::filewatchTest() +{ + QWARN("Unittest will take about 10 seconds. Please wait."); + + QCA::FileWatch watcher; + QCOMPARE(watcher.fileName(), QString()); + + QSignalSpy spy(&watcher, &QCA::FileWatch::changed); + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 0); + + QTemporaryFile *tempFile = new QTemporaryFile; + + tempFile->open(); + + watcher.setFileName(tempFile->fileName()); + QCOMPARE(watcher.fileName(), tempFile->fileName()); + QVERIFY(!spy.wait(2000)); + QCOMPARE(spy.count(), 0); + tempFile->close(); + QVERIFY(!spy.wait(2000)); + QCOMPARE(spy.count(), 0); + + tempFile->open(); + tempFile->write("foo"); + tempFile->flush(); + QVERIFY(spy.wait(2000)); + QCOMPARE(spy.count(), 1); + + tempFile->close(); + QVERIFY(!spy.wait(2000)); + QCOMPARE(spy.count(), 1); + + tempFile->open(); + tempFile->write("foo"); + tempFile->flush(); + QVERIFY(spy.wait(2000)); + QCOMPARE(spy.count(), 2); + + tempFile->write("bar"); + tempFile->flush(); + QVERIFY(spy.wait(2000)); + QCOMPARE(spy.count(), 3); + + tempFile->close(); + QVERIFY(!spy.wait(2000)); + + QCOMPARE(spy.count(), 3); + + delete tempFile; + QVERIFY(spy.wait(2000)); + QCOMPARE(spy.count(), 4); +} + +QTEST_MAIN(FileWatchUnitTest) diff --git a/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.h b/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.h new file mode 100644 index 0000000000..8f3ba8c770 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/filewatchunittest/filewatchunittest.h @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ +#ifndef FILEWATCHUNITTEST_H +#define FILEWATCHUNITTEST_H + +#include +#include + +class FileWatchUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void filewatchTest(); + +private: + QCA::Initializer *m_init; +}; + +#endif diff --git a/local/recipes/libs/qca/source/unittest/hashunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/hashunittest/CMakeLists.txt new file mode 100644 index 0000000000..c98e93eac4 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/hashunittest/CMakeLists.txt @@ -0,0 +1,15 @@ +ENABLE_TESTING() + +set(hashunittest_bin_SRCS hashunittest.cpp) + +add_executable( hashunittest ${hashunittest_bin_SRCS} ) + +target_compile_definitions(hashunittest PRIVATE TEST_DATA_DIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") +target_link_qca_test_libraries(hashunittest) + + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/data/empty ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/data/empty COPYONLY) +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/data/twobytes ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/data/twobytes COPYONLY) +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/data/twohundredbytes ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/data/twohundredbytes COPYONLY) + +add_qca_test(hashunittest "Hashing") diff --git a/local/recipes/libs/qca/source/unittest/hashunittest/data/empty b/local/recipes/libs/qca/source/unittest/hashunittest/data/empty new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/hashunittest/data/twobytes b/local/recipes/libs/qca/source/unittest/hashunittest/data/twobytes new file mode 100644 index 0000000000..bb2a610e24 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/hashunittest/data/twobytes @@ -0,0 +1 @@ +3w \ No newline at end of file diff --git a/local/recipes/libs/qca/source/unittest/hashunittest/data/twohundredbytes b/local/recipes/libs/qca/source/unittest/hashunittest/data/twohundredbytes new file mode 100644 index 0000000000..7319f27767 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/hashunittest/data/twohundredbytes differ diff --git a/local/recipes/libs/qca/source/unittest/hashunittest/hashunittest.cpp b/local/recipes/libs/qca/source/unittest/hashunittest/hashunittest.cpp new file mode 100644 index 0000000000..dc06c7ce86 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/hashunittest/hashunittest.cpp @@ -0,0 +1,862 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class HashUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void md2test_data(); + void md2test(); + void md4test_data(); + void md4test(); + void md5test_data(); + void md5test(); + void md5filetest(); + void sha0test_data(); + void sha0test(); + void sha0longtest(); + void sha1test_data(); + void sha1test(); + void sha1longtest(); + void sha224test_data(); + void sha224test(); + void sha224longtest(); + void sha256test_data(); + void sha256test(); + void sha256longtest(); + void sha384test_data(); + void sha384test(); + void sha384longtest(); + void sha512test_data(); + void sha512test(); + void sha512longtest(); + void rmd160test_data(); + void rmd160test(); + void rmd160longtest(); + void whirlpooltest_data(); + void whirlpooltest(); + void whirlpoollongtest(); + +private: + QCA::Initializer *m_init; + QStringList providersToTest; +}; + +void HashUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; + const auto providers = QCA::providers(); + for (QCA::Provider *provider : providers) + providersToTest << provider->name(); + providersToTest << QCA::defaultProvider()->name(); +} + +void HashUnitTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void HashUnitTest::md2test_data() +{ + // These are as specified in RFC 1319 + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("md2()") << QByteArray("") << QStringLiteral("8350e5a3e24c153df2275c9f80692773"); + QTest::newRow("md2(a)") << QByteArray("a") << QStringLiteral("32ec01ec4a6dac72c0ab96fb34c0b5d1"); + QTest::newRow("md2(abc)") << QByteArray("abc") << QStringLiteral("da853b0d3f88d99b30283a69e6ded6bb"); + QTest::newRow("md2(messageDigest)") << QByteArray("message digest") + << QStringLiteral("ab4f496bfb2a530b219ff33031fe06b0"); + QTest::newRow("md2([a-z])") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral("4e8ddff3650292ab5a4108c3aa47940b"); + QTest::newRow("md2([A-z,0-9])") << QByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + << QStringLiteral("da33def2a42df13975352846c30338cd"); + QTest::newRow("md2(nums)") + << QByteArray("12345678901234567890123456789012345678901234567890123456789012345678901234567890") + << QStringLiteral("d5976f79d83d3a0dc9806c3c66f3efd8"); +} + +void HashUnitTest::md2test() +{ + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + bool anyProviderTested = false; + foreach (QString provider, providersToTest) { + if (QCA::isSupported("md2", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("md2"), provider); + QCA::Hash copy = hash; + copy.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports MD2:" << providersToTest; +} + +void HashUnitTest::md4test_data() +{ + // These are as specified in RFC 1320 + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("md4()") << QByteArray("") << QStringLiteral("31d6cfe0d16ae931b73c59d7e0c089c0"); + QTest::newRow("md4(a)") << QByteArray("a") << QStringLiteral("bde52cb31de33e46245e05fbdbd6fb24"); + QTest::newRow("md4(abc)") << QByteArray("abc") << QStringLiteral("a448017aaf21d8525fc10ae87aa6729d"); + QTest::newRow("md4(messageDigest)") << QByteArray("message digest") + << QStringLiteral("d9130a8164549fe818874806e1c7014b"); + QTest::newRow("md4([a-z])") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral("d79e1c308aa5bbcdeea8ed63df412da9"); + QTest::newRow("md4([A-z,0-9])") << QByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + << QStringLiteral("043f8582f241db351ce627e153e7f0e4"); + QTest::newRow("md4(nums)") + << QByteArray("12345678901234567890123456789012345678901234567890123456789012345678901234567890") + << QStringLiteral("e33b4ddc9c38f2199c3e7b164fcc0536"); +} + +void HashUnitTest::md4test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("md4", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("md4"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports MD4:" << providersToTest; +} + +void HashUnitTest::md5test_data() +{ + // These are as specified in RFC 1321 + // They also match Australian Standard (AS) 2805.1.3.2-2000 Appendix A + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("md5()") << QByteArray("") << QStringLiteral("d41d8cd98f00b204e9800998ecf8427e"); + QTest::newRow("md5(a)") << QByteArray("a") << QStringLiteral("0cc175b9c0f1b6a831c399e269772661"); + QTest::newRow("md5(abc)") << QByteArray("abc") << QStringLiteral("900150983cd24fb0d6963f7d28e17f72"); + QTest::newRow("md5(messageDigest)") << QByteArray("message digest") + << QStringLiteral("f96b697d7cb7938d525a2f31aaf161d0"); + QTest::newRow("md5([a-z])") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral("c3fcd3d76192e4007dfb496cca67e13b"); + QTest::newRow("md5([A-z,0-9])") << QByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + << QStringLiteral("d174ab98d277d9f5a5611c2c9f419d9f"); + QTest::newRow("md5(nums)") + << QByteArray("12345678901234567890123456789012345678901234567890123456789012345678901234567890") + << QStringLiteral("57edf4a22be3c955ac49da2e2107b67a"); +} + +void HashUnitTest::md5test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("md5", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("md5"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports MD2:" << providersToTest; +} + +void HashUnitTest::md5filetest() +{ + foreach (QString provider, providersToTest) { + if (!QCA::isSupported("md5", provider)) { + QFile f1(QStringLiteral(TEST_DATA_DIR "/data/empty")); + QVERIFY(f1.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("md5"), provider); + hashObj.update(&f1); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("d41d8cd98f00b204e9800998ecf8427e")); + } + + QFile f2(QStringLiteral(TEST_DATA_DIR "/data/twobytes")); + QVERIFY(f2.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("md5"), provider); + hashObj.update(&f2); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("5fc9808ed18e442ab4164c59f151e757")); + } + + QFile f3(QStringLiteral(TEST_DATA_DIR "/data/twohundredbytes")); + QVERIFY(f3.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("md5"), provider); + hashObj.update(&f3); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("b91c1f114d942520ecdf7e84e580cda3")); + } + } + } +} + +void HashUnitTest::sha0test_data() +{ + // These are extracted from OpenOffice.org 1.1.2, in sal/workben/t_digest.c + // Check FIPS 180-1? + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("sha0(abc)") << QByteArray("abc") << QStringLiteral("0164b8a914cd2a5e74c4f7ff082c4d97f1edf880"); + QTest::newRow("sha0(abc)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral("d2516ee1acfa5baf33dfc1c471e438449ef134c8"); +} + +void HashUnitTest::sha0test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha0", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha0"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA0:" << providersToTest; +} + +void HashUnitTest::sha0longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + // This test extracted from OpenOffice.org 1.1.2, in sal/workben/t_digest.c + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha0", provider)) { + QCA::Hash shaHash(QStringLiteral("sha0"), provider); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("3232affa48628a26653b5aaa44541fd90d690603")); + + shaHash.clear(); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("3232affa48628a26653b5aaa44541fd90d690603")); + } + } +} + +void HashUnitTest::sha1test_data() +{ + // These are as specified in FIPS 180-2. Matches RFC3174 + // Some additions from Australian Standard (AS) 2805.13.3-2000 + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + // FIPS 180-2, Appendix A.1 + QTest::newRow("sha1(abc)") << QByteArray("abc") << QStringLiteral("a9993e364706816aba3e25717850c26c9cd0d89d"); + + // FIPS 180-2, Appendix A.2 + QTest::newRow("sha1(a-q)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral("84983e441c3bd26ebaae4aa1f95129e5e54670f1"); + + // AS 2805.13.3-200 Appendix A + // also has some duplicates from FIPS 180-2 + QTest::newRow("sha1()") << QByteArray("") << QStringLiteral("da39a3ee5e6b4b0d3255bfef95601890afd80709"); + QTest::newRow("sha1(a)") << QByteArray("a") << QStringLiteral("86f7e437faa5a7fce15d1ddcb9eaeaea377667b8"); + QTest::newRow("sha1(a-z)") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral("32d10c7b8cf96570ca04ce37f2a19d84240d3a89"); +} + +void HashUnitTest::sha1test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha1", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha1"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA1:" << providersToTest; +} + +void HashUnitTest::sha1longtest() +{ + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha1", provider)) { + // QTime t; + // t.start(); + QByteArray fillerString; + fillerString.fill('a', 1000); + + // This test extracted from OpenOffice.org 1.1.2, in sal/workben/t_digest.c + // It basically reflects FIPS 180-2, Appendix A.3 + // Also as per AS 2805.13.3-2000 Appendix A + QCA::Hash shaHash(QStringLiteral("sha1"), provider); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("34aa973cd4c4daa4f61eeb2bdbad27316534016f")); + + QFile f1(QStringLiteral(TEST_DATA_DIR "/data/empty")); + QVERIFY(f1.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("sha1"), provider); + hashObj.update(&f1); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("da39a3ee5e6b4b0d3255bfef95601890afd80709")); + } + + QFile f2(QStringLiteral(TEST_DATA_DIR "/data/twobytes")); + QVERIFY(f2.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("sha1"), provider); + hashObj.update(&f2); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("efbd6de3c51ca16094391e837bf52f7452593e5c")); + } + + QFile f3(QStringLiteral(TEST_DATA_DIR "/data/twohundredbytes")); + QVERIFY(f3.open(QIODevice::ReadOnly)); + { + QCA::Hash hashObj(QStringLiteral("sha1"), provider); + hashObj.update(&f3); + QCOMPARE(QString(QCA::arrayToHex(hashObj.final().toByteArray())), + QStringLiteral("d636519dfb18d913acbe69fc3ee5a4c7ac870297")); + } + } + } +} + +void HashUnitTest::sha224test_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + // These are as specified in FIPS 180-2, change notice 1 + + // FIPS 180-2, Appendix B.1 + QTest::newRow("sha224(abc)") << QByteArray("abc") + << QStringLiteral("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"); + + // FIPS 180-2, Appendix B.2 + QTest::newRow("sha224(aq)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral("75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"); +} + +void HashUnitTest::sha224test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha224", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha224"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA224:" << providersToTest; +} + +void HashUnitTest::sha224longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha224", provider)) { + QCA::Hash shaHash(QStringLiteral("sha224"), provider); + + // This basically reflects FIPS 180-2, change notice 1, section 3 + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")); + + shaHash.clear(); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")); + } + } +} + +void HashUnitTest::sha256test_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + // These are as specified in FIPS 180-2 + + // FIPS 180-2, Appendix B.1 + QTest::newRow("sha256(abc)") << QByteArray("abc") + << QStringLiteral("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + + // FIPS 180-2, Appendix B.2 + QTest::newRow("sha256(abc)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); +} + +void HashUnitTest::sha256test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha256", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha256"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA256:" << providersToTest; +} + +void HashUnitTest::sha256longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha256", provider)) { + QCA::Hash shaHash(QStringLiteral("sha256"), provider); + + // This basically reflects FIPS 180-2, change notice 1, section 3 + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")); + + shaHash.clear(); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")); + } + } +} + +void HashUnitTest::sha384test_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + // These are as specified in FIPS 180-2, and from Aaron Gifford's SHA2 tests + + // FIPS 180-2, Appendix B.1 + QTest::newRow("sha384(abc)") + << QByteArray("abc") + << QStringLiteral( + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"); + + // FIPS 180-2, Appendix B.2 + QTest::newRow("sha384(a-u)") + << QByteArray( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrs" + "tnopqrstu") + << QStringLiteral( + "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"); + + // Aaron Gifford, vector002.info + QTest::newRow("sha384(a-q)") + << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral( + "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b"); +} + +void HashUnitTest::sha384test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha384", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha384"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA384:" << providersToTest; +} + +void HashUnitTest::sha384longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha384", provider)) { + // QTime t; + // t.start(); + QCA::Hash shaHash(QStringLiteral("sha384"), provider); + + // This basically reflects FIPS 180-2, change notice 1, section 3 + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae" + "97ddd87f3d8985")); + + shaHash.clear(); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae" + "97ddd87f3d8985")); + // qDebug() << "SHA384: " << provider << " elapsed " << t.elapsed(); + } + } +} + +// These are as specified in FIPS 180-2, and from Aaron Gifford's SHA2 tests +void HashUnitTest::sha512test_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + // FIPS 180-2, Appendix C.1 + QTest::newRow("sha512(abc)") << QByteArray("abc") + << QStringLiteral( + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1" + "a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); + // FIPS 180-2, Appendix C.2 + QTest::newRow("sha512(a-u)") << QByteArray( + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmno" + "pqklmnopqrlmnopqrsmnopqrstnopqrstu") + << QStringLiteral( + "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7" + "e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"); + + // Aaron Gifford, vector002.info + QTest::newRow("sha512(a-q)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral( + "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07" + "f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445"); +} + +void HashUnitTest::sha512test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha512", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("sha512"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports SHA512:" << providersToTest; +} + +void HashUnitTest::sha512longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("sha512", provider)) { + QCA::Hash shaHash(QStringLiteral("sha512"), provider); + + // This basically reflects FIPS 180-2, change notice 1, section 3 + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4c" + "b0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")); + + shaHash.clear(); + for (int i = 0; i < 1000; i++) + shaHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(shaHash.final().toByteArray())), + QStringLiteral("e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4c" + "b0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")); + } + } +} + +// These are as specified in http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html +// ISO/IEC 10118-3 costs a bit of money. +void HashUnitTest::rmd160test_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("rmd160()") << QByteArray("") << QStringLiteral("9c1185a5c5e9fc54612808977ee8f548b2258d31"); + QTest::newRow("rmd160(a)") << QByteArray("a") << QStringLiteral("0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"); + QTest::newRow("rmd160(abc)") << QByteArray("abc") << QStringLiteral("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); + QTest::newRow("rmd160(md)") << QByteArray("message digest") + << QStringLiteral("5d0689ef49d2fae572b881b123a85ffa21595f36"); + QTest::newRow("rmd160(a-z)") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral("f71c27109c692c1b56bbdceb5b9d2865b3708dbc"); + QTest::newRow("rmd160(a-q)") << QByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") + << QStringLiteral("12a053384a9c0c88e405a06c27dcf49ada62eb2b"); + QTest::newRow("rmd160(A-9)") << QByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + << QStringLiteral("b0e20b6e3116640286ed3a87a5713079b21f5189"); + QTest::newRow("rmd160(1-0)") + << QByteArray("12345678901234567890123456789012345678901234567890123456789012345678901234567890") + << QStringLiteral("9b752e45573d4b39f4dbd3323cab82bf63326bfb"); +} + +void HashUnitTest::rmd160test() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("ripemd160", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("ripemd160"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports RIPEMD160:" << providersToTest; +} + +void HashUnitTest::rmd160longtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("ripemd160", provider)) { + QCA::Hash rmdHash(QStringLiteral("ripemd160"), provider); + + // This is the "million times 'a' test" + for (int i = 0; i < 1000; i++) + rmdHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("52783243c1697bdbe16d37f97f68f08325dc1528")); + + rmdHash.clear(); + for (int i = 0; i < 1000; i++) + rmdHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("52783243c1697bdbe16d37f97f68f08325dc1528")); + + // This is the "8 rounds of 1234567890" test. + // It also ensure that we can re-use hash objects correctly. + static char bindata[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}; + QByteArray fillerArray(bindata, sizeof(bindata)); // "1234567890" + rmdHash.clear(); + for (int i = 0; i < 8; i++) + rmdHash.update(fillerArray); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("9b752e45573d4b39f4dbd3323cab82bf63326bfb")); + } + } +} + +// These are from the documentation pack at http://paginas.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html +void HashUnitTest::whirlpooltest_data() +{ + QTest::addColumn("input"); + QTest::addColumn("expectedHash"); + + QTest::newRow("whirlpool()") << QByteArray("") + << QStringLiteral( + "19fa61d75522a4669b44e39c1d2e1726c530232130d407f89afee0964997f7a73e83be698b288f" + "ebcf88e3e03c4f0757ea8964e59b63d93708b138cc42a66eb3"); + QTest::newRow("whirlpool(a)") << QByteArray("a") + << QStringLiteral( + "8aca2602792aec6f11a67206531fb7d7f0dff59413145e6973c45001d0087b42d11bc645413ae" + "ff63a42391a39145a591a92200d560195e53b478584fdae231a"); + QTest::newRow("whirlpool(abc)") << QByteArray("abc") + << QStringLiteral( + "4e2448a4c6f486bb16b6562c73b4020bf3043e3a731bce721ae1b303d97e6d4c7181eebdb6c" + "57e277d0e34957114cbd6c797fc9d95d8b582d225292076d4eef5"); + QTest::newRow("whirlpool(md)") << QByteArray("message digest") + << QStringLiteral( + "378c84a4126e2dc6e56dcc7458377aac838d00032230f53ce1f5700c0ffb4d3b8421557659ef" + "55c106b4b52ac5a4aaa692ed920052838f3362e86dbd37a8903e"); + QTest::newRow("whirlpool(a-k)") << QByteArray("abcdbcdecdefdefgefghfghighijhijk") + << QStringLiteral( + "2a987ea40f917061f5d6f0a0e4644f488a7a5a52deee656207c562f988e95c6916bdc8031bc" + "5be1b7b947639fe050b56939baaa0adff9ae6745b7b181c3be3fd"); + QTest::newRow("whirlpool(a-z)") << QByteArray("abcdefghijklmnopqrstuvwxyz") + << QStringLiteral( + "f1d754662636ffe92c82ebb9212a484a8d38631ead4238f5442ee13b8054e41b08bf2a9251c" + "30b6a0b8aae86177ab4a6f68f673e7207865d5d9819a3dba4eb3b"); + QTest::newRow("whirlpool(A-9)") << QByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + << QStringLiteral( + "dc37e008cf9ee69bf11f00ed9aba26901dd7c28cdec066cc6af42e40f82f3a1e08eba266291" + "29d8fb7cb57211b9281a65517cc879d7b962142c65f5a7af01467"); + QTest::newRow("whirlpool(1-0)") + << QByteArray("12345678901234567890123456789012345678901234567890123456789012345678901234567890") + << QStringLiteral( + "466ef18babb0154d25b9d38a6414f5c08784372bccb204d6549c4afadb6014294d5bd8df2a6c44e538cd047b2681a51a2c60481" + "e88c5a20b2c2a80cf3a9a083b"); +} + +void HashUnitTest::whirlpooltest() +{ + bool anyProviderTested = false; + QFETCH(QByteArray, input); + QFETCH(QString, expectedHash); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("whirlpool", provider)) { + anyProviderTested = true; + + QCA::Hash hash = QCA::Hash(QStringLiteral("whirlpool"), provider); + QCA::Hash copy = hash; + hash.context(); // detach + + QCOMPARE(hash.hashToString(input), expectedHash); + QCOMPARE(copy.hashToString(input), expectedHash); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports Whirlpool:" << providersToTest; +} + +void HashUnitTest::whirlpoollongtest() +{ + QByteArray fillerString; + fillerString.fill('a', 1000); + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("whirlpool", provider)) { + QCA::Hash rmdHash(QStringLiteral("whirlpool"), provider); + + // This is the "million times 'a' test" + for (int i = 0; i < 1000; i++) + rmdHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("0c99005beb57eff50a7cf005560ddf5d29057fd86b20bfd62deca0f1ccea4af51fc15490eddc47af32" + "bb2b66c34ff9ad8c6008ad677f77126953b226e4ed8b01")); + + rmdHash.clear(); + for (int i = 0; i < 1000; i++) + rmdHash.update(fillerString); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("0c99005beb57eff50a7cf005560ddf5d29057fd86b20bfd62deca0f1ccea4af51fc15490eddc47af32" + "bb2b66c34ff9ad8c6008ad677f77126953b226e4ed8b01")); + + // This is the "8 rounds of 1234567890" test. + // It also ensure that we can re-use hash objects correctly. + static char bindata[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30}; + QByteArray fillerArray(bindata, sizeof(bindata)); // "1234567890" + rmdHash.clear(); + for (int i = 0; i < 8; i++) + rmdHash.update(fillerArray); + QCOMPARE(QString(QCA::arrayToHex(rmdHash.final().toByteArray())), + QStringLiteral("466ef18babb0154d25b9d38a6414f5c08784372bccb204d6549c4afadb6014294d5bd8df2a6c44e538" + "cd047b2681a51a2c60481e88c5a20b2c2a80cf3a9a083b")); + } + } +} + +QTEST_MAIN(HashUnitTest) + +#include "hashunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/hexunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/hexunittest/CMakeLists.txt new file mode 100644 index 0000000000..6dff3499f1 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/hexunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(hexunittest_bin_SRCS hexunittest.cpp) + +add_executable( hexunittest ${hexunittest_bin_SRCS} ) + +target_link_qca_test_libraries(hexunittest) + +add_qca_test(hexunittest "HexadecimalConversion") diff --git a/local/recipes/libs/qca/source/unittest/hexunittest/hexunittest.cpp b/local/recipes/libs/qca/source/unittest/hexunittest/hexunittest.cpp new file mode 100644 index 0000000000..59ab327d76 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/hexunittest/hexunittest.cpp @@ -0,0 +1,123 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class HexUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testHexString_data(); + void testHexString(); + void testIncrementalUpdate(); + void testBrokenInput(); + +private: + QCA::Initializer *m_init; +}; + +void HexUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void HexUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void HexUnitTest::testHexString_data() +{ + QTest::addColumn("raw"); + QTest::addColumn("encoded"); + + QTest::newRow("abcd") << QStringLiteral("abcd") << QStringLiteral("61626364"); + QTest::newRow("ABCD") << QStringLiteral("ABCD") << QStringLiteral("41424344"); + QTest::newRow("empty") << QString(QLatin1String("")) << QString(QLatin1String("")); + QTest::newRow("abcddef") << QStringLiteral("abcddef") << QStringLiteral("61626364646566"); + QTest::newRow("empty too") << QString::fromLatin1("\0") // clazy:exclude=qstring-allocations + << QString::fromLatin1(""); // Empty QString. clazy:exclude=qstring-allocations + QTest::newRow("BEL") << QStringLiteral("\a") << QStringLiteral("07"); // BEL + QTest::newRow("BS") << QStringLiteral("\b") << QStringLiteral("08"); // BS + QTest::newRow("HT") << QStringLiteral("\t") << QStringLiteral("09"); // HT + QTest::newRow("LF") << QStringLiteral("\n") << QStringLiteral("0a"); // LF + QTest::newRow("VT") << QStringLiteral("\v") << QStringLiteral("0b"); // VT + QTest::newRow("FF") << QStringLiteral("\f") << QStringLiteral("0c"); // FF + QTest::newRow("CR") << QStringLiteral("\r") << QStringLiteral("0d"); // CR + QTest::newRow("bug126735") << QStringLiteral("@ABCDEFGHIJKLMNO") + << QStringLiteral("404142434445464748494a4b4c4d4e4f"); +} + +void HexUnitTest::testHexString() +{ + QCA::Hex hexObject; + QFETCH(QString, raw); + QFETCH(QString, encoded); + QCOMPARE(hexObject.encodeString(raw), encoded); + QCOMPARE(hexObject.decodeString(encoded), raw); +} + +void HexUnitTest::testIncrementalUpdate() +{ + QCA::Hex hexObject; + + hexObject.setup(QCA::Encode); + hexObject.clear(); + QCA::SecureArray result1 = hexObject.update(QCA::SecureArray("ab")); + QVERIFY(hexObject.ok()); + QCOMPARE(result1[0], '6'); + QCOMPARE(result1[1], '1'); + QCOMPARE(result1[2], '6'); + QCOMPARE(result1[3], '2'); + QCA::SecureArray result2 = hexObject.update(QCA::SecureArray("cd")); + QCOMPARE(hexObject.ok(), true); + QCOMPARE(result2[0], '6'); + QCOMPARE(result2[1], '3'); + QCOMPARE(result2[2], '6'); + QCOMPARE(result2[3], '4'); + QCOMPARE(QCA::SecureArray(), QCA::SecureArray(hexObject.final())); + QCOMPARE(hexObject.ok(), true); +} + +void HexUnitTest::testBrokenInput() +{ + QCA::Hex hexObject; + + hexObject.setup(QCA::Decode); + hexObject.update(QCA::SecureArray("-=")); + QCOMPARE(hexObject.ok(), false); +} + +QTEST_MAIN(HexUnitTest) + +#include "hexunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/kdfunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/kdfunittest/CMakeLists.txt new file mode 100644 index 0000000000..0438c1a6b1 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/kdfunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set( kdfunittest_bin_SRCS kdfunittest.cpp) + +add_executable( kdfunittest ${kdfunittest_bin_SRCS} ) + +target_link_qca_test_libraries(kdfunittest) + +add_qca_test(kdfunittest "KeyDerivationFunction") diff --git a/local/recipes/libs/qca/source/unittest/kdfunittest/kdfunittest.cpp b/local/recipes/libs/qca/source/unittest/kdfunittest/kdfunittest.cpp new file mode 100644 index 0000000000..d446f7dc00 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/kdfunittest/kdfunittest.cpp @@ -0,0 +1,492 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class KDFUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void pbkdf1md2Tests_data(); + void pbkdf1md2Tests(); + void pbkdf1sha1Tests_data(); + void pbkdf1sha1Tests(); + void pbkdf1sha1TimeTest(); + void pbkdf2Tests_data(); + void pbkdf2Tests(); + void pbkdf2TimeTest(); + void pbkdf2extraTests(); + void hkdfTests_data(); + void hkdfTests(); + +private: + QCA::Initializer *m_init; + QStringList providersToTest; +}; + +void KDFUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; + + const auto providers = QCA::providers(); + for (QCA::Provider *provider : providers) + providersToTest << provider->name(); +} + +void KDFUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void KDFUnitTest::pbkdf1md2Tests_data() +{ + QTest::addColumn("secret"); // usually a password or passphrase + QTest::addColumn("output"); // the key you get back + QTest::addColumn("salt"); // a salt or initialisation vector + QTest::addColumn("outputLength"); // if the algo supports variable length keys, len + QTest::addColumn("iterationCount"); // number of iterations + + // These are from Botan's test suite + QTest::newRow("1") << QStringLiteral("71616c7a73656774") << QStringLiteral("7c1991f3f38a09d70cf3b1acadb70bc6") + << QStringLiteral("40cf117c3865e0cf") << static_cast(16) + << static_cast(1000); + + QTest::newRow("2") << QStringLiteral("766e68617a6a66736978626f6d787175") + << QStringLiteral("677500eda9f0c5e96e0a11f90fb9") << QStringLiteral("3a2484ce5d3e1b4d") + << static_cast(14) << static_cast(1); + + QTest::newRow("3") << QStringLiteral("66686565746e657162646d7171716e797977696f716a666c6f6976636371756a") + << QStringLiteral("91a5b689156b441bf27dd2bdd276") + << QStringLiteral("5d838b0f4fa22bfa2157f9083d87f8752e0495bb2113012761ef11b66e87c3cb") + << static_cast(14) << static_cast(15); + + QTest::newRow("4") << QStringLiteral("736e6279696e6a7075696b7176787867726c6b66") + << QStringLiteral("49516935cc9f438bafa30ff038fb") + << QStringLiteral("f22d341361b47e3390107bd973fdc0d3e0bc02a3") << static_cast(14) + << static_cast(2); +} + +void KDFUnitTest::pbkdf1md2Tests() +{ + QFETCH(QString, secret); + QFETCH(QString, output); + QFETCH(QString, salt); + QFETCH(unsigned int, outputLength); + QFETCH(unsigned int, iterationCount); + + bool anyProviderTested = false; + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf1(md2)", provider)) { + anyProviderTested = true; + QCA::SecureArray password = QCA::hexToArray(secret); + QCA::InitializationVector iv(QCA::hexToArray(salt)); + QCA::SymmetricKey key = + QCA::PBKDF1(QStringLiteral("md2"), provider).makeKey(password, iv, outputLength, iterationCount); + QCOMPARE(QCA::arrayToHex(key.toByteArray()), output); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports PBKDF version 1 with MD2:" << providersToTest; +} + +void KDFUnitTest::pbkdf1sha1Tests_data() +{ + QTest::addColumn("secret"); // usually a password or passphrase + QTest::addColumn("output"); // the key you get back + QTest::addColumn("salt"); // a salt or initialisation vector + QTest::addColumn("outputLength"); // if the algo supports variable length keys, len + QTest::addColumn("iterationCount"); // number of iterations + + // These are from Botan's test suite + QTest::newRow("1") << QStringLiteral("66746c6b6662786474626a62766c6c7662776977") + << QStringLiteral("768b277dc970f912dbdd3edad48ad2f065d25d") + << QStringLiteral("40ac5837560251c275af5e30a6a3074e57ced38e") << static_cast(19) + << static_cast(6); + + QTest::newRow("2") << QStringLiteral("786e736f736d6b766867677a7370636e63706f63") + << QStringLiteral("4d90e846a4b6aaa02ac548014a00e97e506b2afb") + << QStringLiteral("7008a9dc1b9a81470a2360275c19dab77f716824") << static_cast(20) + << static_cast(6); + + QTest::newRow("3") << QStringLiteral("6f74696c71776c756b717473") + << QStringLiteral("71ed1a995e693efcd33155935e800037da74ea28") + << QStringLiteral("ccfc44c09339040e55d3f7f76ca6ef838fde928717241deb9ac1a4ef45a27711") + << static_cast(20) << static_cast(2001); + + QTest::newRow("4") << QStringLiteral("6b7a6e657166666c6274767374686e6663746166") + << QStringLiteral("f345fb8fbd880206b650266661f6") + << QStringLiteral("8108883fc04a01feb10661651516425dad1c93e0") << static_cast(14) + << static_cast(10000); + + QTest::newRow("5") << QStringLiteral("716b78686c7170656d7868796b6d7975636a626f") + << QStringLiteral("2d54dfed0c7ef7d20b0945ba414a") + << QStringLiteral("bc8bc53d4604977c3adb1d19c15e87b77a84c2f6") << static_cast(14) + << static_cast(10000); +} + +void KDFUnitTest::pbkdf1sha1Tests() +{ + QFETCH(QString, secret); + QFETCH(QString, output); + QFETCH(QString, salt); + QFETCH(unsigned int, outputLength); + QFETCH(unsigned int, iterationCount); + + bool anyProviderTested = false; + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf1(sha1)", provider)) { + anyProviderTested = true; + QCA::SecureArray password = QCA::hexToArray(secret); + QCA::InitializationVector iv(QCA::hexToArray(salt)); + QCA::PBKDF1 pbkdf = QCA::PBKDF1(QStringLiteral("sha1"), provider); + QCA::PBKDF1 copy = pbkdf; + copy.context(); // detach + QCA::SymmetricKey key = pbkdf.makeKey(password, iv, outputLength, iterationCount); + QCOMPARE(QCA::arrayToHex(key.toByteArray()), output); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports PBKDF version 1 with SHA1:" << providersToTest; +} + +void KDFUnitTest::pbkdf1sha1TimeTest() +{ + QCA::SecureArray password("secret"); + QCA::InitializationVector iv(QByteArray("salt")); + unsigned int outputLength = 20; + int timeInterval = 200; + unsigned int iterationCount; + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf1(sha1)", provider)) { + QCA::SymmetricKey key1(QCA::PBKDF1(QStringLiteral("sha1"), provider) + .makeKey(password, iv, outputLength, timeInterval, &iterationCount)); + + QCA::SymmetricKey key2( + QCA::PBKDF1(QStringLiteral("sha1"), provider).makeKey(password, iv, outputLength, iterationCount)); + + QCOMPARE(key1, key2); + } + } +} + +void KDFUnitTest::pbkdf2Tests_data() +{ + QTest::addColumn("secret"); // usually a password or passphrase + QTest::addColumn("output"); // the key you get back + QTest::addColumn("salt"); // a salt or initialisation vector + QTest::addColumn("outputLength"); // if the algo supports variable length keys, len + QTest::addColumn("iterationCount"); // number of iterations + + // These are from Botan's test suite + QTest::newRow("1") << QStringLiteral("6a79756571677872736367676c707864796b6366") + << QStringLiteral("df6d9d72872404bf73e708cf3b7d") + << QStringLiteral("9b56e55328a4c97a250738f8dba1b992e8a1b508") << static_cast(14) + << static_cast(10000); + + QTest::newRow("2") << QStringLiteral("61717271737a6e7a76767a67746b73616d6d676f") + << QStringLiteral( + "fa13f40af1ade2a30f2fffd66fc8a659ef95e6388c1682fc0fe4d15a70109517a32942e39c371440") + << QStringLiteral("57487813cdd2220dfc485d932a2979ee8769ea8b") << static_cast(40) + << static_cast(101); + + QTest::newRow("3") << QStringLiteral("6c7465786d666579796c6d6c62727379696b6177") + << QStringLiteral("027afadd48f4be8dcc4f") + << QStringLiteral("ed1f39a0a7f3889aaf7e60743b3bc1cc2c738e60") << static_cast(10) + << static_cast(1000); + + QTest::newRow("4") << QStringLiteral("6378676e7972636772766c6c796c6f6c736a706f") + << QStringLiteral("7c0d009fc91b48cb6d19bafbfccff3e2ccabfe725eaa234e56bde1d551c132f2") + << QStringLiteral("94ac88200743fb0f6ac51be62166cbef08d94c15") << static_cast(32) + << static_cast(1); + + QTest::newRow("5") << QStringLiteral("7871796668727865686965646c6865776e76626a") + << QStringLiteral("4661301d3517ca4443a6a607b32b2a63f69996299df75db75f1e0b98dd0eb7d8") + << QStringLiteral("24a1a50b17d63ee8394b69fc70887f4f94883d68") << static_cast(32) + << static_cast(5); + + QTest::newRow("6") << QStringLiteral("616e6461716b706a7761627663666e706e6a6b6c") + << QStringLiteral("82fb44a521448d5aac94b5158ead1e4dcd7363081a747b9f7626752bda2d") + << QStringLiteral("9316c80801623cc2734af74bec42cf4dbaa3f6d5") << static_cast(30) + << static_cast(100); + + QTest::newRow("7") << QStringLiteral("687361767679766f636c6f79757a746c736e6975") + << QStringLiteral("f8ec2b0ac817896ac8189d787c6424ed24a6d881436687a4629802c0ecce") + << QStringLiteral("612cc61df3cf2bdb36e10c4d8c9d73192bddee05") << static_cast(30) + << static_cast(100); + + QTest::newRow("8") << QStringLiteral("6561696d72627a70636f706275736171746b6d77") + << QStringLiteral("c9a0b2622f13916036e29e7462e206e8ba5b50ce9212752eb8ea2a4aa7b40a4cc1bf") + << QStringLiteral("45248f9d0cebcb86a18243e76c972a1f3b36772a") << static_cast(34) + << static_cast(100); + + QTest::newRow("9") << QStringLiteral("67777278707178756d7364736d626d6866686d666463766c63766e677a6b6967") + << QStringLiteral( + "4c9db7ba24955225d5b845f65ef24ef1b0c6e86f2e39c8ddaa4b8abd26082d1f350381fadeaeb560dc447afc" + "68a6b47e6ea1e7412f6cf7b2d82342fccd11d3b4") + << QStringLiteral("a39b76c6eec8374a11493ad08c246a3e40dfae5064f4ee3489c273646178") + << static_cast(64) << static_cast(1000); +} + +void KDFUnitTest::pbkdf2Tests() +{ + QFETCH(QString, secret); + QFETCH(QString, output); + QFETCH(QString, salt); + QFETCH(unsigned int, outputLength); + QFETCH(unsigned int, iterationCount); + + bool anyProviderTested = false; + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf2(sha1)", provider)) { + anyProviderTested = true; + QCA::SecureArray password = QCA::hexToArray(secret); + QCA::InitializationVector iv(QCA::hexToArray(salt)); + QCA::PBKDF2 pbkdf = QCA::PBKDF2(QStringLiteral("sha1"), provider); + QCA::PBKDF2 copy = pbkdf; + copy.context(); // detach + QCA::SymmetricKey key = pbkdf.makeKey(password, iv, outputLength, iterationCount); + QCOMPARE(QCA::arrayToHex(key.toByteArray()), output); + } + } + + if (!anyProviderTested) + qWarning() << "NONE of the providers supports PBKDF version 2 with SHA1:" << providersToTest; +} + +void KDFUnitTest::pbkdf2TimeTest() +{ + QCA::SecureArray password("secret"); + QCA::InitializationVector iv(QByteArray("salt")); + unsigned int outputLength = 20; + int timeInterval = 200; + unsigned int iterationCount; + + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf2(sha1)", provider)) { + QCA::SymmetricKey key1(QCA::PBKDF2(QStringLiteral("sha1"), provider) + .makeKey(password, iv, outputLength, timeInterval, &iterationCount)); + + QCA::SymmetricKey key2( + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, iv, outputLength, iterationCount)); + + QCOMPARE(key1, key2); + } + } +} + +void KDFUnitTest::pbkdf2extraTests() +{ + foreach (QString provider, providersToTest) { + if (QCA::isSupported("pbkdf2(sha1)", provider)) { + // Not sure where this one came from... + { + QCA::InitializationVector salt(QCA::SecureArray("what do ya want for nothing?")); + QCA::SecureArray password("Jefe"); + int iterations = 1000; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("6349e09cb6b8c1485cfa9780ee3264df")); + } + + // RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn")); + QCA::SecureArray password("password"); + int iterations = 1; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("cdedb5281bb2f801565a1122b2563515")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("cdedb5281bb2f801565a1122b25635150ad1f7a04bb9f3a333ecc0e2e1f70837")); + } + + // RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn")); + QCA::SecureArray password("password"); + int iterations = 2; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("01dbee7f4a9e243e988b62c73cda935d")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86")); + } + + // RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn")); + QCA::SecureArray password("password"); + int iterations = 1200; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512b")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13")); + } + + // RFC3211 and RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::hexToArray(QStringLiteral("1234567878563412"))); + QCA::SecureArray password("password"); + int iterations = 5; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("d1daa78615f287e6a1c8b120d7062a49")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee")); + passwordOut = QCA::PBKDF2().makeKey(password, salt, 8, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), QStringLiteral("d1daa78615f287e6")); + } + + // RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::SecureArray("pass phrase equals block size")); + QCA::SecureArray password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + int iterations = 1200; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("139c30c0966bc32ba55fdbf212530ac9")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1")); + } + + // RFC3962, Appendix B + { + try { + QCA::InitializationVector salt(QCA::SecureArray("pass phrase exceeds block size")); + QCA::SecureArray password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + int iterations = 1200; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("9ccad6d468770cd51b10e6a68721be61")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a")); + } catch (std::exception &) { + if (provider == QLatin1String("qca-botan")) + qDebug() << "You should use a later version of Botan"; + else + QFAIL("exception"); + } + } + + // RFC3962, Appendix B + { + QCA::InitializationVector salt(QCA::SecureArray("EXAMPLE.COMpianist")); + QCA::SecureArray password(QCA::hexToArray(QStringLiteral("f09d849e"))); + int iterations = 50; + QCA::SymmetricKey passwordOut = + QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39")); + passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations); + QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), + QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39e7fe37a0c41e02c281ff3069e1e94f52")); + } + } + } +} + +void KDFUnitTest::hkdfTests_data() +{ + QTest::addColumn("secret"); // usually a password or passphrase + QTest::addColumn("salt"); // a salt or initialisation vector + QTest::addColumn("info"); // an additional info + QTest::addColumn("output"); // the key you get back + + // RFC 5869, Appendix A + QTest::newRow("1") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + << QStringLiteral("000102030405060708090a0b0c") << QStringLiteral("f0f1f2f3f4f5f6f7f8f9") + << QStringLiteral( + "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"); + + QTest::newRow("2") << QStringLiteral( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b" + "2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f") + << QStringLiteral( + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b" + "8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") + << QStringLiteral( + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb" + "dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") + << QStringLiteral( + "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c6" + "5e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"); + + QTest::newRow("3") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") << QString() << QString() + << QStringLiteral( + "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"); +} + +void KDFUnitTest::hkdfTests() +{ + QFETCH(QString, secret); + QFETCH(QString, salt); + QFETCH(QString, info); + QFETCH(QString, output); + + bool anyProviderTested = false; + foreach (QString provider, providersToTest) { + if (QCA::isSupported("hkdf(sha256)", provider)) { + anyProviderTested = true; + QCA::SecureArray password = QCA::hexToArray(secret); + QCA::InitializationVector saltv(QCA::hexToArray(salt)); + QCA::InitializationVector infov(QCA::hexToArray(info)); + QCA::HKDF hkdf = QCA::HKDF(QStringLiteral("sha256"), provider); + QCA::HKDF copy = hkdf; + copy.context(); // detach + + QCA::SymmetricKey key = hkdf.makeKey(password, saltv, infov, output.size() / 2); + QCOMPARE(QCA::arrayToHex(key.toByteArray()), output); + } + } + if (!anyProviderTested) + qWarning() << "NONE of the providers supports HKDF version 1 with SHA256:" << providersToTest; +} + +QTEST_MAIN(KDFUnitTest) + +#include "kdfunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/keybundle/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/keybundle/CMakeLists.txt new file mode 100644 index 0000000000..1c4690e7d3 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/CMakeLists.txt @@ -0,0 +1,14 @@ +ENABLE_TESTING() + +set(keybundleunittest_bin_SRCS keybundle.cpp) + +add_executable( keybundle ${keybundleunittest_bin_SRCS} ) + +target_link_qca_test_libraries(keybundle) + +FOREACH( testFileName RootCA2cert.pem servergood2.p12 + user2goodcert.pem user2goodkey.pem user2good.p12 ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +add_qca_test(keybundle "KeyBundle") diff --git a/local/recipes/libs/qca/source/unittest/keybundle/RootCA2cert.pem b/local/recipes/libs/qca/source/unittest/keybundle/RootCA2cert.pem new file mode 100644 index 0000000000..2629509a90 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/RootCA2cert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF3zCCA8egAwIBAgIUa/l2uvB/7C6vd5lph5a3oIVaQ10wDQYJKoZIhvcNAQEL +BQAwfzELMAkGA1UEBhMCZGUxIDAeBgNVBAoMF0luc2VjdXJlVGVzdENlcnRpZmlj +YXRlMScwJQYDVQQDDB5Gb3IgVGVzdHMgT25seSBuZXh0IGdlbmVyYXRpb24xJTAj +BgkqhkiG9w0BCQEWFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwHhcNMjMxMjIyMTQw +NjUzWhcNMzMxMjE5MTQwNjUzWjB/MQswCQYDVQQGEwJkZTEgMB4GA1UECgwXSW5z +ZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMMHkZvciBUZXN0cyBPbmx5IG5l +eHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVzdC5pbnNl +Y3VyZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALrrWSGmtqLvG7Qr +KiITgsvZTZ9+xp+nIhz40BuV38irsJyuoimhp/0LGI7AMF8R0crFrWWUBNLDlC4c +sjn4mU3dzCBZii3Iek0D7ExnjvPmIU1wfAgj4eZNrfsl2o+RHrIyFI70LuRl6J8v +nqEBr6m2LoIKW4O1OGQ1ISKM+VrD206Qb5gvaBseoKuSBR6J20v5pAL7UiU4B62L +vseGqXq6oHIWCn+Dp3AudRbitO7qMZu++7Kh4ltCm6+W3oAW/JypJk0Wj5kQgGsf +2PKz4Prws7NwlqnwkUikvERmcysbMmtgyYYHbMHh8YdL/ESftjarCyfCtUMEPY4l +inoftgrBIB5qrgdh5B3UZtfM0zBNm59jPnqKJHoaDu184WyFkK1Iy3ArNQNOVA4W +iEhqeZ1QLBJnIuvr2Q923qCi99JasKM/+iFSUNtK8auOkB/frLsKzpVEeHyYY+64 +Um02XAvfpHO97/iHHX4wjBwmSpfw62IapEylzVZm7bzo7OhWSTyckEtU6o8YP7I1 +TpQJ/J+LKRthRYhpmUhxCVuU4JK06mc05sXHof4Tj5UIG1rTJTJqXlmqOSRPz+uu +tLaOvklplYcDBOVpnNPIxkU0MVl7iAXVMokX7yxRcX0Ucu2hMxPRvDpTcpAyauJZ +LJNUIKKqYBxi1qGxzYeL8pT2xoe3AgMBAAGjUzBRMB0GA1UdDgQWBBRLuI+MWufi +daLPUSzi2MFyznnREzAfBgNVHSMEGDAWgBRLuI+MWufidaLPUSzi2MFyznnREzAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAH4kJO4ZVpzhccNskv +Dt/n+53tIheQHh82stzvJehRTF2ZZlTC62xhJzJ00T5WzR3OeUc58RxrWpPmviTV +2kHE5alVSHfIDPdFDMMXFIYnty4l3EeyjrPkRLTgNELeBMuos3DUlbHTxffseK0A +WCf34yrcV6aKXPDY2FwuBvq+9JV8rLrFu9oP6POFT/UZQ9i6oX1/DLtWOjfOc5on +R9CqUV04YckviBHQcyhBAhsNnbv8Hid/Lis0YfSQonV+U8S5h0NsBBZjGAp0F/uz +P8d3kSRwgZH2ItQsnmBxn1IiD3MWyVdiMWmSongnQVgb8gyrJvRUyl9mZ9vUn7g7 +Cb4C8mS5vzsCkonFrAad5DJPCf66blPolTkgZLc3W8anpKWw7y/GCzuGBA/XoQdr +ihimLAtrsFtNMejRTAdMvgtdIRIi60X31ZehK3pex/MFuYACTlaSsbRXvmE8j+eQ +DtZRLUq/YE8AODHM/x4vTGjrZ3agz9u52zrIdw33E3WtqwRk4ywdmkalGcFFFh8/ +QAQX9EvSy/Rgv+CO/LywaJKTZ9X5SRi7orgUwBDDxI0b9UjkeSQ2YKEzd6fsmkU/ +RV26QYR07Qe+HQB3npBD91rdZ/XrZDAydCHjHODFnz5nCE+5Bq2BWbDl0GsFqbYx +PYjtqbrig+MSUEn8whpWkqjTgw== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/keybundle/RootCA2key.pem b/local/recipes/libs/qca/source/unittest/keybundle/RootCA2key.pem new file mode 100644 index 0000000000..b9d4b399c6 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/RootCA2key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC661khprai7xu0 +KyoiE4LL2U2ffsafpyIc+NAbld/Iq7CcrqIpoaf9CxiOwDBfEdHKxa1llATSw5Qu +HLI5+JlN3cwgWYotyHpNA+xMZ47z5iFNcHwII+HmTa37JdqPkR6yMhSO9C7kZeif +L56hAa+pti6CCluDtThkNSEijPlaw9tOkG+YL2gbHqCrkgUeidtL+aQC+1IlOAet +i77Hhql6uqByFgp/g6dwLnUW4rTu6jGbvvuyoeJbQpuvlt6AFvycqSZNFo+ZEIBr +H9jys+D68LOzcJap8JFIpLxEZnMrGzJrYMmGB2zB4fGHS/xEn7Y2qwsnwrVDBD2O +JYp6H7YKwSAeaq4HYeQd1GbXzNMwTZufYz56iiR6Gg7tfOFshZCtSMtwKzUDTlQO +FohIanmdUCwSZyLr69kPdt6govfSWrCjP/ohUlDbSvGrjpAf36y7Cs6VRHh8mGPu +uFJtNlwL36Rzve/4hx1+MIwcJkqX8OtiGqRMpc1WZu286OzoVkk8nJBLVOqPGD+y +NU6UCfyfiykbYUWIaZlIcQlblOCStOpnNObFx6H+E4+VCBta0yUyal5ZqjkkT8/r +rrS2jr5JaZWHAwTlaZzTyMZFNDFZe4gF1TKJF+8sUXF9FHLtoTMT0bw6U3KQMmri +WSyTVCCiqmAcYtahsc2Hi/KU9saHtwIDAQABAoICAEF/uOL+3V7o9MdEnOYF+j5e +bkHmlclaMqz+T0ZrVVinOSMeWrrF5+zW14smM40M3Hv2mxVOMgZ8/E7QRW/k+it7 +/kyTs8TpTFnydvorC7/Rs3fEY+IiWMVwEPhBwn2ud5gvzl5tmIT2ZPZrJGX9BkYt +Dc0JvhnABfuvVmYaCkLRAOdd24zzh8KBEAIvD9YsrojH+L4GvTlHkgExR+/48yiL +fy+bI6CdTK4VyXf0hzx1Gl8eJGrrKTubcpyr/FncNDbdWwuGTVlwm99t8ILTn5Gv +iPjnChSQtQhEmahKUi8Xv6o650MtFOI3v4AOk16krKApfaY4J3ZNZRiLdSPoOsye +N7UWguve/aAA7ewakITvr6BwtJ4Ji1IGfH06LDUosXU8lQefeVi/s2Z/v/ME/L2n +adbOZ9R6983JnAZRWthidWN865uDqHmrZTTBCFuH+twjxzg73WrUKfVhLWHsMOKb +6vwzKl21XEgejzupg4NUijY1QMbTSX2+FfPg3t0IJOFXhKxD1Bw33lWIaRaFZ2C6 +jhmj546lJV/6thG9Ef7Ex9mEjWcZ5e1C5pgV+nvAKo7Y5+2tYk31ntNOBr1Fz+4S +GjyyqQ42dbhkDASaWp6yXQSOnOx/xNWPe7xywspL3hcwClh7by3lQuS1zI3aFKeM +TBVeANdFnE1B4JdyZ6+RAoIBAQDrj/xF1NYez+9Zp9bp3plLr/lM2Xc972DEn+fs +fu57f+HcbVFlB0u+LxdaFoQoRO4m86Snf8fsS4T6bfav2iQumN8JGiJ0dGb7xNSB +7NLwhB6ChW7Q2rrmgRIqn8HS5tMLAhViePWYKpA2NxxuVpXO1n7kgfUPHS4yhJqO +4viVelTwoBk3Hb8zzCPXmICqtSQ1M6UARlZy8tcEEEGfKcT6bKYFb6Hjbt6Y2H5J +n5pteceCvOpwTGL5Su9Ux7dy+98sZBZx5qe9hPu1R7vlNuYVfv8G6Cv5GMWqhj0z +pABxdiMQBg7oWCgAXZE3W+19Cz9XR5Enk/DR678oJoqSflZPAoIBAQDLIvanztUN +PhWuda/Iptp91wCcnqiwmM5bxVP9XjVCUdROrd3NLfLbBRGiE2gPJ0RKCGoW6g/H +dL2gMR/frygkyF04WGqDnKd0ecny0bv7F9gsy4ewfv5DavcYDQpTEsgTrWRdMpQ4 +caAmA8bHzYSimAocVthzq6zrUhIUF34sF33M48qHeSOhwvGDjLsRcv/vUMTBljx9 +bAeAjB6Swvecm/upAaDRIyh6K6shwXtGqk1+KAtAv0rUsCkTh4psJvdA1bt3pimc +wUwcrNi36t272eKXkALuJzGTYqlFccGDyP18TUzaFEtodCQOMVJqx+ru6DwbNZyo +xiOBtQo2ocYZAoIBAC3qBLv/vjSHRxnskwFGuA5+oFMQWCOkUvJAUM5R913vETEL +xb+xalwJhb2zgdLvjJPfDYrwZyFxntvJLzobhM3oUiDODUUxoxkTxnAEnyDuP5wl +MfJXj/J52fag6QCYqS4OG+jztrsQIMfQeiQvkEeem2Eiy4dEosqJ+i47o0RPcdrs ++b06eRg5hArz2LBtWj9cb57cFuGU38AVAxVo6NH+92U72wwfghe8qvDiwRDxmaer +9u4olWoN5xRZUTKCUX+viohs8ukH0KAG+WK2DqbF+CN6gYeuAmk4fRlhsAxtgGwR +Ijq7ZCCeHD30Fxg2ZwQ2GN7kAR6JmtrSmFPxeBUCggEATpFjXVw+QzT0JdoW90Cx +2WJDNlCXZlZz2kLkTWcWqmQD/bp5w1Y2TEgVnd5rrRC+9PN0NRCqsbaRcVgOv/F7 +UV69z4FDEUyR6BcC6Qv97Qw37Ht8K+OybFj+4SqKB7+H6zRxUSqy8XHhQ1LKm5T9 +6/VqU7OzXGnWI95GZ8b+Ygdj/M9OEj/kbDh+OSdBY2pbWzCeKVH2a3xRGoMXgCQw +qT4bhC7BCKLUkQw60H+JMrfD6TuLvqs+Qi0wdgFCpLodf9IrBAgcqCiLS7v+xoPs +5y9K2Nw2he5a2mqaleV9t38Rq/Yp919KG0hweZzSB8LzNxxTwyJlSVH5gb2ICcFg +YQKCAQEAziBaNoQWQahkylJxltAku5iKZ/VLQ93FUMnGxggBBM9VT2CI9rbqZpeQ +MUOzb1dSXvmlRx3e2FWWSJYbX1Xiz5+9D7cpVJA0pGTPHYpINFf59/aG8QK+uwKy +NzG1YAS4nFa5d76WPDUIcWFIBpSZEpDpusP4RJvZbJj37WGm0YGLiLIeNffWtPp4 +e3bqL7emZ0lF62dgkBNL/E8LnbcScNCUXzs7rx8VV4DSGTDhGOMeC+DVcXZH4nSL +D/h3Q4axp64q83QEqnIvg0RRHRr418l5doAlEm9iSLuJfBH1vuYr9guuJb1UbV8O +S8/HTaK14slPqJ6qOL/pOxWl8zQJsg== +-----END PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/keybundle/generate_data.sh b/local/recipes/libs/qca/source/unittest/keybundle/generate_data.sh new file mode 100644 index 0000000000..fcd8b74852 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/generate_data.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# Generate CA key + certificate +openssl req -x509 -newkey rsa:4096 -keyout RootCA2key.pem -out RootCA2cert.pem -sha256 -days 3650 -nodes -subj "/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/emailAddress=insecure@test.insecure" +# Generate user key + certificate, signed by ^ +openssl req -x509 -CA RootCA2cert.pem -CAkey RootCA2key.pem -newkey rsa:4096 -keyout user2goodkey.pem -out user2goodcert.pem -sha256 -days 3650 -nodes -subj "/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/emailAddress=insecure@test.insecure" +# Put ^ into a pkcs#12 file +openssl pkcs12 -export -inkey user2goodkey.pem -in user2goodcert.pem -out user2good.p12 -password pass:start +# Same for the server +openssl req -x509 -CA RootCA2cert.pem -CAkey RootCA2key.pem -newkey rsa:4096 -keyout servergood2key.pem -out servergood2cert.pem -sha256 -days 3650 -nodes -subj "/C=de/O=InsecureTestCertificate/CN=For Tests Only next generation/emailAddress=insecure@test.insecure" +openssl pkcs12 -export -inkey servergood2key.pem -in servergood2cert.pem -out servergood2.p12 -password pass:start +# Remove unneeded intermediate files +rm servergood2cert.pem servergood2key.pem diff --git a/local/recipes/libs/qca/source/unittest/keybundle/keybundle.cpp b/local/recipes/libs/qca/source/unittest/keybundle/keybundle.cpp new file mode 100644 index 0000000000..0da1ac2ae4 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/keybundle.cpp @@ -0,0 +1,207 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +#include + +class KeyBundleTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void nullBundle(); + void fromFile(); + void names(); + void certChain(); + void privKey(); + void createBundle(); + +private: + QCA::Initializer *m_init; +}; + +void KeyBundleTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void KeyBundleTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void KeyBundleTest::nullBundle() +{ + QCA::KeyBundle nullBundle; + QVERIFY(nullBundle.isNull()); + QCOMPARE(nullBundle.name(), QString()); + QVERIFY(nullBundle.certificateChain().isEmpty()); + QVERIFY(nullBundle.privateKey().isNull()); + + QCA::KeyBundle nullCopy = nullBundle; // NOLINT(performance-unnecessary-copy-initialization) This is copied on + // purpose to check the assignment operator + QVERIFY(nullCopy.isNull()); + QCOMPARE(nullCopy.name(), QString()); + QVERIFY(nullCopy.certificateChain().isEmpty()); + QVERIFY(nullCopy.privateKey().isNull()); + + QCA::KeyBundle nullAssigned(nullCopy); // NOLINT(performance-unnecessary-copy-initialization) This is copied on + // purpose to check the copy constructor + QVERIFY(nullAssigned.isNull()); + QCOMPARE(nullAssigned.name(), QString()); + QVERIFY(nullAssigned.certificateChain().isEmpty()); + QVERIFY(nullAssigned.privateKey().isNull()); +} + +void KeyBundleTest::fromFile() +{ + if (QCA::isSupported("pkcs12")) { + // "start" is the passphrase, but you wouldn't normally + // code it in like this + QCA::KeyBundle userBundle(QStringLiteral("user2good.p12"), "start"); + QCOMPARE(userBundle.isNull(), false); + QCOMPARE(userBundle.name(), QString()); + QCOMPARE(userBundle.certificateChain().isEmpty(), false); + QCOMPARE(userBundle.privateKey().isNull(), false); + + QCA::KeyBundle userBundleCopy = userBundle; // NOLINT(performance-unnecessary-copy-initialization) This is + // copied on purpose to check the assignment operator + QCOMPARE(userBundleCopy.isNull(), false); + QCOMPARE(userBundleCopy.name(), QString()); + QCOMPARE(userBundleCopy.certificateChain().isEmpty(), false); + QCOMPARE(userBundleCopy.privateKey().isNull(), false); + + QCA::KeyBundle userBundleAssign(userBundleCopy); // NOLINT(performance-unnecessary-copy-initialization) This is + // copied on purpose to check the copy constructor + QCOMPARE(userBundleAssign.isNull(), false); + QCOMPARE(userBundleAssign.name(), QString()); + QCOMPARE(userBundleAssign.certificateChain().isEmpty(), false); + QCOMPARE(userBundleAssign.privateKey().isNull(), false); + } +} + +void KeyBundleTest::names() +{ + if (QCA::isSupported("pkcs12")) { + QCA::KeyBundle serverBundle(QStringLiteral("servergood2.p12"), "start"); + QCOMPARE(serverBundle.isNull(), false); + QCOMPARE(serverBundle.name(), QString()); + + serverBundle.setName(QStringLiteral("Some Server Bundle")); + QCOMPARE(serverBundle.name(), QStringLiteral("Some Server Bundle")); + } +} + +void KeyBundleTest::certChain() +{ + if (QCA::isSupported("pkcs12")) { + QCA::KeyBundle serverBundle(QStringLiteral("servergood2.p12"), "start"); + QCOMPARE(serverBundle.isNull(), false); + QCOMPARE(serverBundle.certificateChain().size(), 1); + } +} + +void KeyBundleTest::privKey() +{ + if (QCA::isSupported("pkcs12")) { + QCA::KeyBundle serverBundle(QStringLiteral("servergood2.p12"), "start"); + QCOMPARE(serverBundle.isNull(), false); + QCOMPARE(serverBundle.privateKey().isNull(), false); + } +} +void KeyBundleTest::createBundle() +{ + std::unique_ptr newBundle(new QCA::KeyBundle); + + QVERIFY(newBundle->isNull()); + + if (!QCA::isSupported("certificate")) + return; + + QCA::Certificate ca(QStringLiteral("RootCA2cert.pem")); + QCOMPARE(ca.isNull(), false); + + QCA::Certificate primary(QStringLiteral("user2goodcert.pem")); + QCOMPARE(primary.isNull(), false); + + QCA::PrivateKey key(QStringLiteral("user2goodkey.pem")); + QCOMPARE(key.isNull(), false); + + QCA::CertificateChain chain(primary); + chain.append(ca); + + newBundle->setCertificateChainAndKey(chain, key); + newBundle->setName(QStringLiteral("My New Key Bundle")); + + QCOMPARE(newBundle->certificateChain(), chain); + QCOMPARE(newBundle->privateKey(), key); + QCOMPARE(newBundle->name(), QStringLiteral("My New Key Bundle")); + + // Try round tripping the bundle + foreach (const QCA::Provider *thisProvider, QCA::providers()) { + QString provider = thisProvider->name(); + if (QCA::isSupported("pkcs12", provider)) { + qDebug() << "Testing " << provider; + QByteArray bundleArray = newBundle->toArray("reel secrut", provider); + QCOMPARE(bundleArray.isNull(), false); + + QCA::ConvertResult res; + QCA::KeyBundle bundleFromArray = QCA::KeyBundle::fromArray(bundleArray, "reel secrut", &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCOMPARE(bundleFromArray.isNull(), false); + QCOMPARE(bundleFromArray.name(), QStringLiteral("My New Key Bundle")); + QCOMPARE(bundleFromArray.certificateChain(), chain); + QCOMPARE(bundleFromArray.privateKey(), key); + + QTemporaryFile tempFile; + QVERIFY(tempFile.open()); + + bool result = newBundle->toFile(tempFile.fileName(), "file passphrase", provider); + QVERIFY(result); + + QCA::KeyBundle bundleFromFile = + QCA::KeyBundle::fromFile(tempFile.fileName(), "file passphrase", &res, provider); + QCOMPARE(res, QCA::ConvertGood); + QCOMPARE(bundleFromFile.isNull(), false); + QCOMPARE(bundleFromFile.name(), QStringLiteral("My New Key Bundle")); + QCOMPARE(bundleFromFile.certificateChain(), chain); + QCOMPARE(bundleFromFile.privateKey(), key); + } + } +} + +QTEST_MAIN(KeyBundleTest) + +#include "keybundle.moc" diff --git a/local/recipes/libs/qca/source/unittest/keybundle/servergood2.p12 b/local/recipes/libs/qca/source/unittest/keybundle/servergood2.p12 new file mode 100644 index 0000000000..75425ba320 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/keybundle/servergood2.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/keybundle/user2good.p12 b/local/recipes/libs/qca/source/unittest/keybundle/user2good.p12 new file mode 100644 index 0000000000..17a84760c3 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/keybundle/user2good.p12 differ diff --git a/local/recipes/libs/qca/source/unittest/keybundle/user2goodcert.pem b/local/recipes/libs/qca/source/unittest/keybundle/user2goodcert.pem new file mode 100644 index 0000000000..f408664129 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/user2goodcert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF3zCCA8egAwIBAgIUYkoRGrc8Kj4DgVUHqncHnopyD14wDQYJKoZIhvcNAQEL +BQAwfzELMAkGA1UEBhMCZGUxIDAeBgNVBAoMF0luc2VjdXJlVGVzdENlcnRpZmlj +YXRlMScwJQYDVQQDDB5Gb3IgVGVzdHMgT25seSBuZXh0IGdlbmVyYXRpb24xJTAj +BgkqhkiG9w0BCQEWFmluc2VjdXJlQHRlc3QuaW5zZWN1cmUwHhcNMjMxMjIyMTQw +NjUzWhcNMzMxMjE5MTQwNjUzWjB/MQswCQYDVQQGEwJkZTEgMB4GA1UECgwXSW5z +ZWN1cmVUZXN0Q2VydGlmaWNhdGUxJzAlBgNVBAMMHkZvciBUZXN0cyBPbmx5IG5l +eHQgZ2VuZXJhdGlvbjElMCMGCSqGSIb3DQEJARYWaW5zZWN1cmVAdGVzdC5pbnNl +Y3VyZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM5b28XOwALtwOID +3PwYBYWnizXYotowk7/YiHj7iBzUD53tsh1rFBnuNF53B3Ofk2azffmZUpjT7nMk +EZJXse+6rEualSegNXLtLYsanh41mi7UyKRW7QbKjbhJG9XPDyLLSbsburnIR0gG +eLzSGDA1kYTDUFtNNl5ZylWYt6w3blO9Oc5OeQKVTTM7XYfrPCLRUST/tudDCvig +UrdEM4iAcS3FvkW/3Untw41u4I5TvxltE/JuDPSCvPs99xvpkcd9X7zN9VpNJJB4 +wtpPIZJWiCTggPx+QN1YI9L3VBoQu+BwgR+8LEGo14m5HGGAeHPDADKNZcxvQMQU +T4L82UjBhfq/VeRi30+zl67hNnTgT7fiasZzuCoQ98qWpw2RlD5z0+frQDXZovyk +LfRl6BN//HES/N1s2fgZztvhyM9rxarQHd/Ax2e9RZcMayy85mJaWRBZBV+Bkh7q +zimjkX+vsHamRWXP0IVqs3RUQgAPWbf6KSuL3J8Z4xSF/GIwXMo/l7L8OQK0e79D +rJ71Bir6vs6vlxP2cB6lyqCc0Duc01NJnimn3SxzqOGUCQb4JEafoGjOEA9Y/8Te +NuBj8mJPKwPNOxh/XT7Ns+qfiSOabtjsRpL/dLepAepP06hpQfBv2g2XUQ1FCx8W +p0t1kcPffKqEK82+/VYm8z3vFPlJAgMBAAGjUzBRMB0GA1UdDgQWBBTvNKDdBoKN +NWwUfQqjiSC2JbYP+jAfBgNVHSMEGDAWgBRLuI+MWufidaLPUSzi2MFyznnREzAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCVs2j3Vt1OVEraHoK7 +i/F9ft9sdP9fWfh5tslXxEXCtEnE1qE+5q6+UjS/+vgBZvca4xVP06e+9acLBHFC +84mVac82CRJI7Z4OvyR9dlyRSIQrYnXoFQNAxVG6CGhD1iZ4MN3x3QkVgn4XiuBr +11Oy9BBg3+16AOy1ieEd/mqaKOLLO2s1lIrmIgbM5s/iIeaR9QbqHZgfsPu/+a7I +KHM7B8U45mHWsGpgZPWL/VfwzqATT/Q78AIZIWm7Kcy9Zusqvx7necMGG/IaHNf4 +4dEPF6yOXahGbSbl67vxIkAtBO3XQXspuLGknI9OttF98CICbGD5GsmjDbNuKkmR +K3xnXRSw8yXeWojpwkUP9kLz1xVLzRGcvYjwxiuLW5AxlETGwkNf49xOToC+PQIv +lZ4HHV1kSGAnlG/DV5PUDMLgsZZsfGwMhRgkEcq/jtGX7DLB2RR3MM1TyDNghMX0 +V/HgIzTVd9cS0pQV0FcnPPrAdqMEZLYj+ZhzOdHB+9jQMS7VqMDG/Gi2tq0unSpM +TPpo5CFlD5KdrYXBZZmkeddQ2Tgelr0wRvR8Z0USKtl+VaXDC8l6mZbpO7HWek1m +4pxSTphPOc3BA3oinqWRYecWZyKvju/z6me9AFcB8v/2MGFGf6JGskhzM7g55+Q0 +i1jvjmFLCh613TD5h3MU0dsOKw== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/keybundle/user2goodkey.pem b/local/recipes/libs/qca/source/unittest/keybundle/user2goodkey.pem new file mode 100644 index 0000000000..240276af46 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keybundle/user2goodkey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDOW9vFzsAC7cDi +A9z8GAWFp4s12KLaMJO/2Ih4+4gc1A+d7bIdaxQZ7jRedwdzn5Nms335mVKY0+5z +JBGSV7HvuqxLmpUnoDVy7S2LGp4eNZou1MikVu0Gyo24SRvVzw8iy0m7G7q5yEdI +Bni80hgwNZGEw1BbTTZeWcpVmLesN25TvTnOTnkClU0zO12H6zwi0VEk/7bnQwr4 +oFK3RDOIgHEtxb5Fv91J7cONbuCOU78ZbRPybgz0grz7Pfcb6ZHHfV+8zfVaTSSQ +eMLaTyGSVogk4ID8fkDdWCPS91QaELvgcIEfvCxBqNeJuRxhgHhzwwAyjWXMb0DE +FE+C/NlIwYX6v1XkYt9Ps5eu4TZ04E+34mrGc7gqEPfKlqcNkZQ+c9Pn60A12aL8 +pC30ZegTf/xxEvzdbNn4Gc7b4cjPa8Wq0B3fwMdnvUWXDGssvOZiWlkQWQVfgZIe +6s4po5F/r7B2pkVlz9CFarN0VEIAD1m3+ikri9yfGeMUhfxiMFzKP5ey/DkCtHu/ +Q6ye9QYq+r7Or5cT9nAepcqgnNA7nNNTSZ4pp90sc6jhlAkG+CRGn6BozhAPWP/E +3jbgY/JiTysDzTsYf10+zbPqn4kjmm7Y7EaS/3S3qQHqT9OoaUHwb9oNl1ENRQsf +FqdLdZHD33yqhCvNvv1WJvM97xT5SQIDAQABAoICAFbo7h8Zq9mv63/lE6GitlSr +kyBa/H97XQa7+gJGIXXOxEMF1HG6Ys1m+uxcIinKp+hlqSVBsz1FaNRaeQIS6BBo +pN70nGQDf+9Gv9spmzVq6uRVXqmEKLCnB1f5hn0ehyfmyUdB7vsGxCqr+xa/P0uy +i/aH0eSaGM9U7rftKVIhSFiBRgLDHwj8+3YbxxES/BFH6e50ukIdBNZgo2WnFjMj +sUcPVMsIevkDZ8w9ydp3n/Dj9TYxrkgeddw0pUm+rdSAU51veqmM+tzT13DdSezZ +f95UJU7yF3yBfhkAbI3LxWzJxUAp3tPKefh5m1/fHRvYIVGpJpoaswLB8RjgR9ww +GNOFmhpBAXLECJIRcZcDR/TiWJn2Vs6tOajJcQ30iO4Z1hWV+yDv7k/TR/Ryj5jI +8dIh6B1s3uqp3R3/5EA03IFhdYovUqkfoGHgBUf4eUZcVtj8n2RQ0Jes7htaqqcf +boPEZR/Ufcg6UnE1T8G/Va33wX2AIU92wxhodOcatU+xKhzDzyYMKNuvAya/cfyq +rOdx2VDaIc8DxizcJZv9HCfhr3SrvC6gMogCd4ehVB6zDt97GevwYlZk5tTziIwl +LhpFopmWYC4TQ7EdPKi66LYD9vmIv1f0EYLrJBa/5lVF6GAedrx2FIWyatp3LSvn +sPuP6jsIkRzcL7UA3jJfAoIBAQD0a7gbhyKUZFcDHZJOUoGqHDlBczwAv66e+cC1 +Kwll4y0vqRmG0X/dcRQ+O36iHDuP5dx4vop496K3CV3PGvSDf/rhI0MMByVSJ1+y +WWboQb8IAksSIJoPpt6iS37ciyUbmgFbqpEAOm7vmpd0ft+3rFyqc4waddsEwkjt +WnX3QMDzbK8cptAaC1iBzCITWeOqe9hMpjohOdsnNbONQ8SGAToOueqs6yUDm+Zm +7uORtWaKwy5zpGFkm+wQYxD2aYPi+XREmbc1bmt1B8gNzD8JCJm8uq3v4YbKNJxT +RYTYSPl919rlCYVDwObp8ijVUZhZ7RNoynDySUtasCLsrs6PAoIBAQDYIohKQyrJ +pXKhd5exWPw5M6yJWUIDVNAy2cKHQ8UWPp+rg+a3C9imPOaZGZkJdsVz4gmmLFsF +nU4aOu1nVUPwfN7SqK5sHJwVyN50Bg8HtB1XMnFOqZbG0TUXyXbO0M2AoLd1h6Tn +uRpe5TTIkOz1fCQ4JHba5mo6Hs3kKgC+ICyAH3pVIXaNe6Or0XSbgtjD1b2YHHWd +JgpiPZtLlJt1XgTmqdkj+pAuxKY1j3be2wUYhu3+WGpOPgas3Mj5TCiZ0Hee9McJ +8qSDdHDNqjHtziwcQA3kLwVD8KMn+bSCXlUkqW7I+fFxfh+kqKlif1S+vv8Qrda8 +8aauq4nk7SanAoIBAEXlC+frU+slanB8o1r8YxH3MjRSNKVuKwxRFVd5cB2Pwlsv +uxn/jNYRQR2uu7613h5/N/XbXxPKlOBMsGPKLIPyNBbvk3u8C2Mb2VTSFghyzKMI +rNkJM6UoLeAxQJzmuXzUJHFHLGHpU9H23jq1EVqf0nv3wOfMLg6FVH9zb+p9vO+f +c8/4r+fSuMOdUV1BRkZ5VdhNbLAVsGLdC3RpHajIbwbJCZ/bOmF20oM66x6+xg0G +VaFCL4uqvu3MtowQjmN4vFPltSt1YQs9Z2ryrk/yAqyioZzIXFg0hUOWzK9g5t+i +u3jlqRM/9YiO9DhUNgH5NqSvx26xoPfVCJewQWcCggEABssvFYZ+9c+phsHHlt+B +LhsdtUOE+63SzYZiwvWyYDyfsDh5LA/HQ5JufSl80ftVwYq9WufSBJ8pMVHg3Hql +pA2Iw35h3SwZC+ZAd80o88kJkxAW164k+yLgVFsUzPNrQjvLCHq3CEGdPpZdzmAf +0qeQS+N5iO/tLt6BAkb/tvoz6+MRaVOf8lqMjn4K+Ehon988EmfymnnzoZrmIr4N +FOdbqBR2qtbZaV7tConz5pVj152GJZSJ4uO4Of7Gom9uZ0dSO0DecMWbvjYOxagv +4ZW1dT3eMen4dGY/+qWystZcPsbEoLSajkK0o+xZRqtR8pz2T4PnWBEQeDUUJIn/ +yQKCAQB+4pKbEGEj32LwLnK6S33AnLj4UZTo9Nji2w3FgFkRtdTfH2sOOgUhUs/9 +qdbQFYNT71pKeDBcVuXjI5coC3GYjGqxpL67DpxZ2e+/B30PQmfySmw67lGUP8Iv +22DblUPyJ5/V8Q3tKFeSdWINn3nfAO43VgKYhKWbTxMdXYKnNvWtkzboyCScrTjn +QvXOtt7P8ErERzZ5kA63c4s3iTUnsIItL7gWqiqER5qRsSztICoZBcZijNl0x9A3 +wA73EYons7xIT3l+KHLYWksvJEV6AC614PVF+ccweO1FgiEkxtqX/gsq9OQS5w2R +KEbBBEU+V34RMCfYL3ICIV80TB2a +-----END PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/keygenunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/keygenunittest/CMakeLists.txt new file mode 100644 index 0000000000..3f1e681a32 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keygenunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set( keygenunittest_bin_SRCS keygenunittest.cpp) + +add_executable( keygenunittest ${keygenunittest_bin_SRCS} ) + +target_link_qca_test_libraries(keygenunittest) + +add_qca_test(keygenunittest "KeyGeneration") diff --git a/local/recipes/libs/qca/source/unittest/keygenunittest/keygenunittest.cpp b/local/recipes/libs/qca/source/unittest/keygenunittest/keygenunittest.cpp new file mode 100644 index 0000000000..385e0e069b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keygenunittest/keygenunittest.cpp @@ -0,0 +1,151 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class KeyGenUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testRSA(); + void testDSA(); + void testDH(); + +private: + QCA::Initializer *m_init; +}; + +void KeyGenUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void KeyGenUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void KeyGenUnitTest::testRSA() +{ + QCA::KeyGenerator keygen; + QCOMPARE(keygen.isBusy(), false); + QCOMPARE(keygen.blockingEnabled(), true); + + if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::RSA) || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) + QSKIP("RSA not supported!"); + + QCA::PrivateKey priv1 = keygen.createRSA(1024, 65537); + QCA::RSAPrivateKey rsa1 = priv1.toRSA(); + QCOMPARE(rsa1.isNull(), false); + QCOMPARE(rsa1.e(), QCA::BigInteger(65537)); + QCOMPARE(rsa1.bitSize(), 1024); + + priv1 = keygen.createRSA(512, 17); + rsa1 = priv1.toRSA(); + QCOMPARE(rsa1.isNull(), false); + QCOMPARE(rsa1.e(), QCA::BigInteger(17)); + QCOMPARE(rsa1.bitSize(), 512); + + priv1 = keygen.createRSA(512, 3); + rsa1 = priv1.toRSA(); + QCOMPARE(rsa1.isNull(), false); + QCOMPARE(rsa1.e(), QCA::BigInteger(3)); + QCOMPARE(rsa1.bitSize(), 512); +} + +void KeyGenUnitTest::testDSA() +{ + QCA::KeyGenerator keygen; + QCOMPARE(keygen.isBusy(), false); + QCOMPARE(keygen.blockingEnabled(), true); + + if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DSA) || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::DSA)) + QSKIP("DSA not supported!"); + + QCA::DLGroup group; + QCA::PrivateKey priv2; + QCA::DSAPrivateKey dsa1; + + if (QCA::DLGroup::supportedGroupSets().contains(QCA::DSA_512)) { + group = keygen.createDLGroup(QCA::DSA_512); + priv2 = keygen.createDSA(group); + dsa1 = priv2.toDSA(); + QCOMPARE(dsa1.isNull(), false); + QCOMPARE(dsa1.bitSize(), 512); + } + + if (QCA::DLGroup::supportedGroupSets().contains(QCA::DSA_768)) { + group = keygen.createDLGroup(QCA::DSA_768); + priv2 = keygen.createDSA(group); + dsa1 = priv2.toDSA(); + QCOMPARE(dsa1.isNull(), false); + QCOMPARE(dsa1.bitSize(), 768); + } + + if (QCA::DLGroup::supportedGroupSets().contains(QCA::DSA_1024)) { + group = keygen.createDLGroup(QCA::DSA_1024); + priv2 = keygen.createDSA(group); + dsa1 = priv2.toDSA(); + QCOMPARE(dsa1.isNull(), false); + QCOMPARE(dsa1.bitSize(), 1024); + } +} + +void KeyGenUnitTest::testDH() +{ + QCA::KeyGenerator keygen; + QCOMPARE(keygen.isBusy(), false); + QCOMPARE(keygen.blockingEnabled(), true); + + if (!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::DH) || + !QCA::PKey::supportedIOTypes().contains(QCA::PKey::DH)) + QSKIP("DH not supported!"); + + QCA::DLGroup group = keygen.createDLGroup(QCA::IETF_1024); + QCA::PrivateKey priv3 = keygen.createDH(group); + QCA::DHPrivateKey dh1 = priv3.toDH(); + QCOMPARE(dh1.isNull(), false); + QCOMPARE(dh1.bitSize(), 1024); + + group = keygen.createDLGroup(QCA::IETF_2048); + priv3 = keygen.createDH(group); + dh1 = priv3.toDH(); + QCOMPARE(dh1.isNull(), false); + QCOMPARE(dh1.bitSize(), 2048); +} + +QTEST_MAIN(KeyGenUnitTest) + +#include "keygenunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/keylengthunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/keylengthunittest/CMakeLists.txt new file mode 100644 index 0000000000..275f20d9da --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keylengthunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(keylengthunittest_bin_SRCS keylengthunittest.cpp) + +add_executable( keylengthunittest ${keylengthunittest_bin_SRCS} ) + +target_link_qca_test_libraries(keylengthunittest) + +add_qca_test(keylengthunittest "KeyLength") diff --git a/local/recipes/libs/qca/source/unittest/keylengthunittest/keylengthunittest.cpp b/local/recipes/libs/qca/source/unittest/keylengthunittest/keylengthunittest.cpp new file mode 100644 index 0000000000..6c46e6d815 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keylengthunittest/keylengthunittest.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2004, 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class KeyLengthUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void doTest(); + +private: + QCA::Initializer *m_init; +}; + +void KeyLengthUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void KeyLengthUnitTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void KeyLengthUnitTest::doTest() +{ + QCA::KeyLength keylen1(0, 0, 0); + QCOMPARE(keylen1.minimum(), 0); + QCOMPARE(keylen1.maximum(), 0); + QCOMPARE(keylen1.multiple(), 0); + + QCA::KeyLength keylen2(3, 40, 1); + QCOMPARE(keylen2.minimum(), 3); + QCOMPARE(keylen2.maximum(), 40); + QCOMPARE(keylen2.multiple(), 1); + + QCA::KeyLength keylen3(1, INT_MAX, 1); + QCOMPARE(keylen3.minimum(), 1); + QCOMPARE(keylen3.maximum(), INT_MAX); + QCOMPARE(keylen3.multiple(), 1); +} + +QTEST_MAIN(KeyLengthUnitTest) + +#include "keylengthunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/keystore/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/keystore/CMakeLists.txt new file mode 100644 index 0000000000..18cccd890c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keystore/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(keystoreunittest_bin_SRCS keystore.cpp) + +add_executable( keystore ${keystoreunittest_bin_SRCS} ) + +target_link_qca_test_libraries(keystore) + +add_qca_test(keystore "KeyStore") diff --git a/local/recipes/libs/qca/source/unittest/keystore/keystore.cpp b/local/recipes/libs/qca/source/unittest/keystore/keystore.cpp new file mode 100644 index 0000000000..d7abd02984 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/keystore/keystore.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class KeyStore : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void nullKeystore(); + +private: + QCA::Initializer *m_init; +}; + +void KeyStore::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void KeyStore::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void KeyStore::nullKeystore() +{ + QCA::KeyStoreManager manager; + if (QCA::isSupported("keystore")) { + QCA::KeyStore nullStore(QStringLiteral("null store"), &manager); + QVERIFY(nullStore.isValid()); + + QVERIFY(nullStore.entryList().isEmpty()); + + QCOMPARE(nullStore.type(), QCA::KeyStore::User); + + QCOMPARE(nullStore.id(), QStringLiteral("null store")); + QCOMPARE(nullStore.holdsTrustedCertificates(), false); + QCOMPARE(nullStore.holdsIdentities(), false); + QCOMPARE(nullStore.holdsPGPPublicKeys(), false); + } +} + +QTEST_MAIN(KeyStore) + +#include "keystore.moc" diff --git a/local/recipes/libs/qca/source/unittest/logger/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/logger/CMakeLists.txt new file mode 100644 index 0000000000..7e215ef30c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/logger/CMakeLists.txt @@ -0,0 +1,7 @@ +ENABLE_TESTING() + +add_executable(loggerunittest loggerunittest.cpp ) + +target_link_qca_test_libraries(loggerunittest) + +add_qca_test(loggerunittest "Logger") diff --git a/local/recipes/libs/qca/source/unittest/logger/loggerunittest.cpp b/local/recipes/libs/qca/source/unittest/logger/loggerunittest.cpp new file mode 100644 index 0000000000..71951c1431 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/logger/loggerunittest.cpp @@ -0,0 +1,281 @@ +/** + * Copyright (C) 2007 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class LoggerUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void basicSetup(); + void logText1(); + void logText2(); + void logBlob(); + void logLevel(); + +private: + QCA::Initializer *m_init; +}; + +class NullLogger : public QCA::AbstractLogDevice +{ + Q_OBJECT +public: + NullLogger() + : QCA::AbstractLogDevice(QStringLiteral("null logger")) + { + } +}; + +class LastLogger : public QCA::AbstractLogDevice +{ + Q_OBJECT +public: + LastLogger() + : QCA::AbstractLogDevice(QStringLiteral("last logger")) + { + } + + void logTextMessage(const QString &message, enum QCA::Logger::Severity severity) override + { + m_lastMessage = message; + m_messageSeverity = severity; + } + + QString lastMessage() const + { + return m_lastMessage; + } + + void logBinaryMessage(const QByteArray &blob, enum QCA::Logger::Severity severity) override + { + m_lastBlob = blob; + m_blobSeverity = severity; + } + + QByteArray lastBlob() const + { + return m_lastBlob; + } + + QCA::Logger::Severity lastMessageSeverity() const + { + return m_messageSeverity; + } + + QCA::Logger::Severity lastBlobSeverity() const + { + return m_blobSeverity; + } + +private: + QString m_lastMessage; + QByteArray m_lastBlob; + QCA::Logger::Severity m_messageSeverity; + QCA::Logger::Severity m_blobSeverity; +}; + +void LoggerUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void LoggerUnitTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void LoggerUnitTest::basicSetup() +{ + QCA::Logger *logSystem = QCA::logger(); + + QCOMPARE(logSystem->currentLogDevices().count(), 0); + + logSystem->setLevel(QCA::Logger::Debug); + QCOMPARE(logSystem->level(), QCA::Logger::Debug); + + NullLogger *nullLogger = new NullLogger; + + logSystem->registerLogDevice(nullLogger); + QCOMPARE(logSystem->currentLogDevices().count(), 1); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("null logger"))); + logSystem->unregisterLogDevice(QStringLiteral("null logger")); + QCOMPARE(logSystem->currentLogDevices().count(), 0); + + delete nullLogger; +} + +void LoggerUnitTest::logText1() +{ + QCA::Logger *logSystem = QCA::logger(); + + logSystem->logTextMessage(QStringLiteral("Sending with no recipients")); + + LastLogger *lastlogger = new LastLogger; + logSystem->registerLogDevice(lastlogger); + QCOMPARE(logSystem->currentLogDevices().count(), 1); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + logSystem->logTextMessage(QStringLiteral("Sending to system, checking for log device")); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking for log device")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Information); + + logSystem->logTextMessage(QStringLiteral("Sending at Error severity"), QCA::Logger::Error); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending at Error severity")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Error); + + LastLogger *lastlogger2 = new LastLogger; + logSystem->registerLogDevice(lastlogger2); + QCOMPARE(logSystem->currentLogDevices().count(), 2); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + logSystem->logTextMessage(QStringLiteral("Sending to system, checking for two log devices")); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking for two log devices")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Information); + QCOMPARE(lastlogger2->lastMessage(), QStringLiteral("Sending to system, checking for two log devices")); + QCOMPARE(lastlogger2->lastMessageSeverity(), QCA::Logger::Information); + + logSystem->unregisterLogDevice(QStringLiteral("last logger")); // this will remove them both + + QCOMPARE(logSystem->currentLogDevices().count(), 0); + + delete lastlogger; + delete lastlogger2; +} + +// same as above, but use convenience routine. +void LoggerUnitTest::logText2() +{ + QCA_logTextMessage(QStringLiteral("Sending with no recipients"), QCA::Logger::Notice); + + LastLogger *lastlogger = new LastLogger; + + QCA::Logger *logSystem = QCA::logger(); + logSystem->registerLogDevice(lastlogger); + QCOMPARE(logSystem->currentLogDevices().count(), 1); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + QCA_logTextMessage(QStringLiteral("Sending to system, checking for log device"), QCA::Logger::Information); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking for log device")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Information); + + QCA_logTextMessage(QStringLiteral("Sending at Error severity"), QCA::Logger::Error); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending at Error severity")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Error); + + LastLogger *lastlogger2 = new LastLogger; + logSystem->registerLogDevice(lastlogger2); + QCOMPARE(logSystem->currentLogDevices().count(), 2); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + QCA_logTextMessage(QStringLiteral("Sending to system, checking for two log devices"), QCA::Logger::Information); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking for two log devices")); + QCOMPARE(lastlogger->lastMessageSeverity(), QCA::Logger::Information); + QCOMPARE(lastlogger2->lastMessage(), QStringLiteral("Sending to system, checking for two log devices")); + QCOMPARE(lastlogger2->lastMessageSeverity(), QCA::Logger::Information); + + logSystem->unregisterLogDevice(QStringLiteral("last logger")); // this will remove them both + + QCOMPARE(logSystem->currentLogDevices().count(), 0); + + delete lastlogger; + delete lastlogger2; +} + +void LoggerUnitTest::logBlob() +{ + QCA::Logger *logSystem = QCA::logger(); + + QCOMPARE(logSystem->currentLogDevices().count(), 0); + + QByteArray test("abcd\x34"); + logSystem->logBinaryMessage(test); + + LastLogger *lastlogger = new LastLogger; + logSystem->registerLogDevice(lastlogger); + QCOMPARE(logSystem->currentLogDevices().count(), 1); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + logSystem->logBinaryMessage(test); + QCOMPARE(lastlogger->lastBlob(), test); + QCOMPARE(lastlogger->lastBlobSeverity(), QCA::Logger::Information); + + logSystem->logBinaryMessage(test, QCA::Logger::Critical); + QCOMPARE(lastlogger->lastBlob(), test); + QCOMPARE(lastlogger->lastBlobSeverity(), QCA::Logger::Critical); + + LastLogger *lastlogger2 = new LastLogger; + logSystem->registerLogDevice(lastlogger2); + QCOMPARE(logSystem->currentLogDevices().count(), 2); + QVERIFY(logSystem->currentLogDevices().contains(QStringLiteral("last logger"))); + + test += test; + logSystem->logBinaryMessage(test); + QCOMPARE(lastlogger->lastBlob(), test); + QCOMPARE(lastlogger->lastBlobSeverity(), QCA::Logger::Information); + QCOMPARE(lastlogger2->lastBlob(), test); + QCOMPARE(lastlogger2->lastBlobSeverity(), QCA::Logger::Information); + + logSystem->unregisterLogDevice(QStringLiteral("last logger")); // this will remove them both + + QCOMPARE(logSystem->currentLogDevices().count(), 0); + delete lastlogger; + delete lastlogger2; +} + +void LoggerUnitTest::logLevel() +{ + QCA::Logger *logSystem = QCA::logger(); + + LastLogger *lastlogger = new LastLogger; + logSystem->registerLogDevice(lastlogger); + + logSystem->setLevel(QCA::Logger::Error); + QCOMPARE(logSystem->level(), QCA::Logger::Error); + + QCA_logTextMessage(QStringLiteral("Sending to system, checking that it is filtered out"), QCA::Logger::Information); + QEXPECT_FAIL("", "Should fail", Continue); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking that it is filtered out")); + + QCA_logTextMessage(QStringLiteral("Sending to system, checking that it is not filtered out"), QCA::Logger::Error); + QCOMPARE(lastlogger->lastMessage(), QStringLiteral("Sending to system, checking that it is not filtered out")); + + logSystem->setLevel(QCA::Logger::Debug); + + delete lastlogger; +} + +QTEST_MAIN(LoggerUnitTest) + +#include "loggerunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/macunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/macunittest/CMakeLists.txt new file mode 100644 index 0000000000..5b255fc0e6 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/macunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(macunittest_bin_SRCS macunittest.cpp) + +add_executable( macunittest ${macunittest_bin_SRCS} ) + +target_link_qca_test_libraries(macunittest) + +add_qca_test(macunittest "MessageAuthenticationCode") diff --git a/local/recipes/libs/qca/source/unittest/macunittest/macunittest.cpp b/local/recipes/libs/qca/source/unittest/macunittest/macunittest.cpp new file mode 100644 index 0000000000..a27bcc0495 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/macunittest/macunittest.cpp @@ -0,0 +1,686 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class MACUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void HMACMD5(); + void HMACSHA1(); + void HMACSHA256(); + void HMACSHA224(); + void HMACSHA384(); + void HMACSHA512(); + void HMACRMD160(); + +private: + QCA::Initializer *m_init; +}; + +void MACUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void MACUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void MACUnitTest::HMACMD5() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(md5)", provider)) + QWARN((QStringLiteral("HMAC(MD5) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode md5hmacLenTest(QStringLiteral("hmac(md5)"), QCA::SymmetricKey(), provider); + QCOMPARE(md5hmacLenTest.validKeyLength(0), true); + QCOMPARE(md5hmacLenTest.validKeyLength(1), true); + QCOMPARE(md5hmacLenTest.validKeyLength(848888), true); + QCOMPARE(md5hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = md5hmacLenTest; + copy.context(); // detach + + // These tests are from RFC2202, Section 2. + // The first three are also in the Appendix to RFC2104 + QCA::MessageAuthenticationCode md5hmac1(QStringLiteral("hmac(md5)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::SecureArray("Jefe")); + md5hmac1.setup(key1); + QCA::SecureArray data1("what do ya want for nothing?"); + md5hmac1.update(data1); + QCOMPARE(QCA::arrayToHex(md5hmac1.final().toByteArray()), + QStringLiteral("750c783e6ab0b503eaa86e310a5db738")); + + QCA::MessageAuthenticationCode md5hmac2(QStringLiteral("hmac(md5)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + md5hmac2.setup(key2); + QCA::SecureArray data2 = QCA::SecureArray("Hi There"); + md5hmac2.update(data2); + QCOMPARE(QCA::arrayToHex(md5hmac2.final().toByteArray()), + QStringLiteral("9294727a3638bb1c13f48ef8158bfc9d")); + + // test reuse + md5hmac2.clear(); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))); + md5hmac2.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + md5hmac2.update(data3); + QCOMPARE(QCA::arrayToHex(md5hmac2.final().toByteArray()), + QStringLiteral("56be34521d144c88dbb8c733f0e8b3f6")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode md5hmac4(QStringLiteral("hmac(md5)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + md5hmac4.update(data4); + QCOMPARE(QCA::arrayToHex(md5hmac4.final().toByteArray()), + QStringLiteral("697eaf0aca3a3aea3a75164746ffaa79")); + + QCA::MessageAuthenticationCode md5hmac5(QStringLiteral("hmac(md5)"), QCA::SecureArray()); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + md5hmac5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + md5hmac5.update(data5); + QCOMPARE(QCA::arrayToHex(md5hmac5.final().toByteArray()), + QStringLiteral("56461ef2342edc00f9bab995690efd4c")); + + QCA::MessageAuthenticationCode md5hmac6(QStringLiteral("hmac(md5)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(80); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xaa; + md5hmac6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + md5hmac6.update(data6); + QCOMPARE(QCA::arrayToHex(md5hmac6.final().toByteArray()), + QStringLiteral("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd")); + + md5hmac6.clear(); // reuse the same key + QCA::SecureArray data7("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"); + md5hmac6.update(data7); + QCOMPARE(QCA::arrayToHex(md5hmac6.final().toByteArray()), + QStringLiteral("6f630fad67cda0ee1fb1f562db3aa53e")); + } + } +} + +void MACUnitTest::HMACSHA256() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(sha256)", provider)) + QWARN((QStringLiteral("HMAC(SHA256) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode hmacLenTest(QStringLiteral("hmac(sha256)"), QCA::SymmetricKey(), provider); + QCOMPARE(hmacLenTest.validKeyLength(0), true); + QCOMPARE(hmacLenTest.validKeyLength(1), true); + QCOMPARE(hmacLenTest.validKeyLength(848888), true); + QCOMPARE(hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = hmacLenTest; + copy.context(); // detach + + QCA::MessageAuthenticationCode hmac1(QStringLiteral("hmac(sha256)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::SecureArray("Jefe")); + hmac1.setup(key1); + QCA::SecureArray data1("what do ya want for nothing?"); + hmac1.update(data1); + QCOMPARE(QCA::arrayToHex(hmac1.final().toByteArray()), + QStringLiteral("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")); + + QCA::MessageAuthenticationCode hmac2(QStringLiteral("hmac(sha256)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + hmac2.setup(key2); + QCA::SecureArray data2 = QCA::SecureArray("Hi There"); + hmac2.update(data2); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7")); + + // test reuse + hmac2.clear(); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + hmac2.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + hmac2.update(data3); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode hmac4(QStringLiteral("hmac(sha256)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + hmac4.update(data4); + QCOMPARE(QCA::arrayToHex(hmac4.final().toByteArray()), + QStringLiteral("82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b")); + + QCA::MessageAuthenticationCode hmac5(QStringLiteral("hmac(sha256)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + hmac5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + hmac5.update(data5); + QString resultWithTrunc = QCA::arrayToHex(hmac5.final().toByteArray()); + resultWithTrunc.resize(32); + QCOMPARE(resultWithTrunc, QStringLiteral("a3b6167473100ee06e0c796c2955552b")); + + QCA::MessageAuthenticationCode hmac6(QStringLiteral("hmac(sha256)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(131); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xaa; + hmac6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + hmac6.update(data6); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54")); + + hmac6.clear(); // reuse the same key + QCA::SecureArray data7( + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm."); + hmac6.update(data7); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2")); + } + } +} + +void MACUnitTest::HMACSHA224() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(sha224)", provider)) + QWARN((QStringLiteral("HMAC(SHA224) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode hmacLenTest(QStringLiteral("hmac(sha224)"), QCA::SymmetricKey(), provider); + QCOMPARE(hmacLenTest.validKeyLength(0), true); + QCOMPARE(hmacLenTest.validKeyLength(1), true); + QCOMPARE(hmacLenTest.validKeyLength(848888), true); + QCOMPARE(hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = hmacLenTest; + copy.context(); // detach + + QCA::MessageAuthenticationCode hmac1(QStringLiteral("hmac(sha224)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::SecureArray("Jefe")); + hmac1.setup(key1); + QCA::SecureArray data1("what do ya want for nothing?"); + hmac1.update(data1); + QCOMPARE(QCA::arrayToHex(hmac1.final().toByteArray()), + QStringLiteral("a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44")); + + QCA::MessageAuthenticationCode hmac2(QStringLiteral("hmac(sha224)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + hmac2.setup(key2); + QCA::SecureArray data2 = QCA::SecureArray("Hi There"); + hmac2.update(data2); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22")); + + // test reuse + hmac2.clear(); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + hmac2.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + hmac2.update(data3); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode hmac4(QStringLiteral("hmac(sha224)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + hmac4.update(data4); + QCOMPARE(QCA::arrayToHex(hmac4.final().toByteArray()), + QStringLiteral("6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a")); + + QCA::MessageAuthenticationCode hmac5(QStringLiteral("hmac(sha224)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + hmac5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + hmac5.update(data5); + QString resultWithTrunc = QCA::arrayToHex(hmac5.final().toByteArray()); + resultWithTrunc.resize(32); + QCOMPARE(resultWithTrunc, QStringLiteral("0e2aea68a90c8d37c988bcdb9fca6fa8")); + + QCA::MessageAuthenticationCode hmac6(QStringLiteral("hmac(sha224)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(131); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xaa; + hmac6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + hmac6.update(data6); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e")); + + hmac6.clear(); // reuse the same key + QCA::SecureArray data7( + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm."); + hmac6.update(data7); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1")); + } + } +} + +void MACUnitTest::HMACSHA384() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(sha384)", provider)) + QWARN((QStringLiteral("HMAC(SHA384) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode hmacLenTest(QStringLiteral("hmac(sha384)"), QCA::SymmetricKey(), provider); + QCOMPARE(hmacLenTest.validKeyLength(0), true); + QCOMPARE(hmacLenTest.validKeyLength(1), true); + QCOMPARE(hmacLenTest.validKeyLength(848888), true); + QCOMPARE(hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = hmacLenTest; + copy.context(); // detach + + QCA::MessageAuthenticationCode hmac1(QStringLiteral("hmac(sha384)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::SecureArray("Jefe")); + hmac1.setup(key1); + QCA::SecureArray data1("what do ya want for nothing?"); + hmac1.update(data1); + QCOMPARE(QCA::arrayToHex(hmac1.final().toByteArray()), + QStringLiteral("af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b" + "3239ecfab21649")); + + QCA::MessageAuthenticationCode hmac2(QStringLiteral("hmac(sha384)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + hmac2.setup(key2); + QCA::SecureArray data2 = QCA::SecureArray("Hi There"); + hmac2.update(data2); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4a" + "f152e8b2fa9cb6")); + + // test reuse + hmac2.clear(); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + hmac2.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + hmac2.update(data3); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e" + "3ab6e101a34f27")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode hmac4(QStringLiteral("hmac(sha384)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + hmac4.update(data4); + QCOMPARE(QCA::arrayToHex(hmac4.final().toByteArray()), + QStringLiteral("3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679cc" + "f8a386c674cffb")); + + QCA::MessageAuthenticationCode hmac5(QStringLiteral("hmac(sha384)"), QCA::SecureArray(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + hmac5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + hmac5.update(data5); + QString resultWithTrunc = QCA::arrayToHex(hmac5.final().toByteArray()); + resultWithTrunc.resize(32); + QCOMPARE(resultWithTrunc, QStringLiteral("3abf34c3503b2a23a46efc619baef897")); + + QCA::MessageAuthenticationCode hmac6(QStringLiteral("hmac(sha384)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(131); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xaa; + hmac6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + hmac6.update(data6); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296" + "248df163f44952")); + + hmac6.clear(); // reuse the same key + QCA::SecureArray data7( + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm."); + hmac6.update(data7); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d38" + "60e6110c46523e")); + } + } +} + +void MACUnitTest::HMACSHA512() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(sha512)", provider)) + QWARN((QStringLiteral("HMAC(SHA512) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode hmacLenTest(QStringLiteral("hmac(sha512)"), QCA::SymmetricKey(), provider); + QCOMPARE(hmacLenTest.validKeyLength(0), true); + QCOMPARE(hmacLenTest.validKeyLength(1), true); + QCOMPARE(hmacLenTest.validKeyLength(848888), true); + QCOMPARE(hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = hmacLenTest; + copy.context(); // detach + + QCA::MessageAuthenticationCode hmac1(QStringLiteral("hmac(sha512)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::SecureArray("Jefe")); + hmac1.setup(key1); + QCA::SecureArray data1("what do ya want for nothing?"); + hmac1.update(data1); + QCOMPARE(QCA::arrayToHex(hmac1.final().toByteArray()), + QStringLiteral("164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d" + "034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737")); + + QCA::MessageAuthenticationCode hmac2(QStringLiteral("hmac(sha512)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + hmac2.setup(key2); + QCA::SecureArray data2 = QCA::SecureArray("Hi There"); + hmac2.update(data2); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a70203" + "8b274eaea3f4e4be9d914eeb61f1702e696c203a126854")); + + // test reuse + hmac2.clear(); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + hmac2.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + hmac2.update(data3); + QCOMPARE(QCA::arrayToHex(hmac2.final().toByteArray()), + QStringLiteral("fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806" + "b485a47e67c807b946a337bee8942674278859e13292fb")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode hmac4(QStringLiteral("hmac(sha512)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + hmac4.update(data4); + QCOMPARE(QCA::arrayToHex(hmac4.final().toByteArray()), + QStringLiteral("b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d6" + "79275cc5788063a5f19741120c4f2de2adebeb10a298dd")); + + QCA::MessageAuthenticationCode hmac5(QStringLiteral("hmac(sha512)"), QCA::SecureArray(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + hmac5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + hmac5.update(data5); + QString resultWithTrunc = QCA::arrayToHex(hmac5.final().toByteArray()); + resultWithTrunc.resize(32); + QCOMPARE(resultWithTrunc, QStringLiteral("415fad6271580a531d4179bc891d87a6")); + + QCA::MessageAuthenticationCode hmac6(QStringLiteral("hmac(sha512)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(131); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xaa; + hmac6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + hmac6.update(data6); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd" + "0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598")); + + hmac6.clear(); // reuse the same key + QCA::SecureArray data7( + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to " + "be hashed before being used by the HMAC algorithm."); + hmac6.update(data7); + QCOMPARE(QCA::arrayToHex(hmac6.final().toByteArray()), + QStringLiteral("e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d" + "5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58")); + } + } +} + +void MACUnitTest::HMACSHA1() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(sha1)", provider)) + QWARN((QStringLiteral("HMAC(SHA1) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode sha1hmacLenTest(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCOMPARE(sha1hmacLenTest.validKeyLength(0), true); + QCOMPARE(sha1hmacLenTest.validKeyLength(1), true); + QCOMPARE(sha1hmacLenTest.validKeyLength(848888), true); + QCOMPARE(sha1hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = sha1hmacLenTest; + copy.context(); // detach + + // These tests are from RFC2202, Section 3. + QCA::MessageAuthenticationCode test1(QStringLiteral("hmac(sha1)"), QCA::SecureArray()); + QCA::SymmetricKey key1(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + test1.setup(key1); + QCA::SecureArray data1("Hi There"); + test1.update(data1); + QCOMPARE(QCA::arrayToHex(test1.final().toByteArray()), + QStringLiteral("b617318655057264e28bc0b6fb378c8ef146be00")); + + QCA::MessageAuthenticationCode test2(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::SecureArray("Jefe")); + test2.setup(key2); + QCA::SecureArray data2("what do ya want for nothing?"); + test2.update(data2); + QCOMPARE(QCA::arrayToHex(test2.final().toByteArray()), + QStringLiteral("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")); + + QCA::MessageAuthenticationCode test3(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + test3.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + test3.update(data3); + QCOMPARE(QCA::arrayToHex(test3.final().toByteArray()), + QStringLiteral("125d7342b9ac11cd91a39af48aa17b4f63f175d3")); + + QCA::MessageAuthenticationCode test4(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + test4.setup(key4); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + test4.update(data4); + QCOMPARE(QCA::arrayToHex(test4.final().toByteArray()), + QStringLiteral("4c9007f4026250c6bc8414f9bf50c86c2d7235da")); + + QCA::MessageAuthenticationCode test5(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + test5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + test5.update(data5); + QCOMPARE(QCA::arrayToHex(test5.final().toByteArray()), + QStringLiteral("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04")); + + QCA::MessageAuthenticationCode test6(QStringLiteral("hmac(sha1)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(80); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xAA; + test6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + test6.update(data6); + QCOMPARE(QCA::arrayToHex(test6.final().toByteArray()), + QStringLiteral("aa4ae5e15272d00e95705637ce8a3b55ed402112")); + + test6.clear(); // this should reuse the same key + QCA::SecureArray data7("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"); + test6.update(data7); + QCOMPARE(QCA::arrayToHex(test6.final().toByteArray()), + QStringLiteral("e8e99d0f45237d786d6bbaa7965c7808bbff1a91")); + } + } +} + +void MACUnitTest::HMACRMD160() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + providersToTest.append(QStringLiteral("qca-gcrypt")); + providersToTest.append(QStringLiteral("qca-botan")); + providersToTest.append(QStringLiteral("qca-nss")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("hmac(ripemd160)", provider)) + QWARN((QStringLiteral("HMAC(RIPEMD160) not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::MessageAuthenticationCode ripemd160hmacLenTest( + QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCOMPARE(ripemd160hmacLenTest.validKeyLength(0), true); + QCOMPARE(ripemd160hmacLenTest.validKeyLength(1), true); + QCOMPARE(ripemd160hmacLenTest.validKeyLength(848888), true); + QCOMPARE(ripemd160hmacLenTest.validKeyLength(-2), false); + + QCA::MessageAuthenticationCode copy = ripemd160hmacLenTest; + copy.context(); // detach + + // These tests are from RFC2286, Section 2. + QCA::MessageAuthenticationCode test1(QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key1(QCA::hexToArray(QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"))); + test1.setup(key1); + QCA::SecureArray data1("Hi There"); + test1.update(data1); + QCOMPARE(QCA::arrayToHex(test1.final().toByteArray()), + QStringLiteral("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668")); + + QCA::MessageAuthenticationCode test2(QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key2(QCA::SecureArray("Jefe")); + test2.setup(key2); + QCA::SecureArray data2("what do ya want for nothing?"); + test2.update(data2); + QCOMPARE(QCA::arrayToHex(test2.final().toByteArray()), + QStringLiteral("dda6c0213a485a9e24f4742064a7f033b43c4069")); + + QCA::MessageAuthenticationCode test3(QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key3(QCA::hexToArray(QStringLiteral("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))); + test3.setup(key3); + QCA::SecureArray data3(50); + for (int i = 0; i < data3.size(); i++) + data3[i] = (char)0xDD; + test3.update(data3); + QCOMPARE(QCA::arrayToHex(test3.final().toByteArray()), + QStringLiteral("b0b105360de759960ab4f35298e116e295d8e7c1")); + + QCA::SymmetricKey key4( + QCA::hexToArray(QStringLiteral("0102030405060708090a0b0c0d0e0f10111213141516171819"))); + QCA::MessageAuthenticationCode test4(QStringLiteral("hmac(ripemd160)"), key4, provider); + QCA::SecureArray data4(50); + for (int i = 0; i < data4.size(); i++) + data4[i] = (char)0xcd; + test4.update(data4); + QCOMPARE(QCA::arrayToHex(test4.final().toByteArray()), + QStringLiteral("d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4")); + + QCA::MessageAuthenticationCode test5(QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key5(QCA::hexToArray(QStringLiteral("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"))); + test5.setup(key5); + QCA::SecureArray data5("Test With Truncation"); + test5.update(data5); + QCOMPARE(QCA::arrayToHex(test5.final().toByteArray()), + QStringLiteral("7619693978f91d90539ae786500ff3d8e0518e39")); + + QCA::MessageAuthenticationCode test6(QStringLiteral("hmac(ripemd160)"), QCA::SymmetricKey(), provider); + QCA::SymmetricKey key6(80); + for (int i = 0; i < key6.size(); i++) + key6[i] = (char)0xAA; + test6.setup(key6); + QCA::SecureArray data6("Test Using Larger Than Block-Size Key - Hash Key First"); + test6.update(data6); + QCOMPARE(QCA::arrayToHex(test6.final().toByteArray()), + QStringLiteral("6466ca07ac5eac29e1bd523e5ada7605b791fd8b")); + + test6.clear(); // reuse the key + QCA::SecureArray data7("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"); + test6.update(data7); + QCOMPARE(QCA::arrayToHex(test6.final().toByteArray()), + QStringLiteral("69ea60798d71616cce5fd0871e23754cd75d5a0a")); + } + } +} + +QTEST_MAIN(MACUnitTest) + +#include "macunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/metatype/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/metatype/CMakeLists.txt new file mode 100644 index 0000000000..466f7656f1 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/metatype/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(metatype_bin_SRCS metatype.cpp) + +add_executable( metatypeunittest ${metatype_bin_SRCS} ) + +target_link_qca_test_libraries(metatypeunittest) + +add_qca_test(metatypeunittest "MetaTypeUnittest") diff --git a/local/recipes/libs/qca/source/unittest/metatype/metatype.cpp b/local/recipes/libs/qca/source/unittest/metatype/metatype.cpp new file mode 100644 index 0000000000..8775fc2fda --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/metatype/metatype.cpp @@ -0,0 +1,258 @@ +/** + * Copyright (C) 2007 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class TestClass1 : public QObject +{ + Q_OBJECT + +public: + TestClass1() + { + } + TestClass1(const TestClass1 &) + : QObject(nullptr) + { + } + +public Q_SLOTS: + void voidMethod() + { + } + QString qstringMethod() + { + return QString(); + }; + bool boolMethod(const QString &) + { + return true; + }; + QString returnArg(const QString &s) + { + return s; + }; + QByteArray returnArg(const QByteArray &a) + { + return a; + }; + QString returnRepeatArg(const QString &s) + { + return QString(s + s); + }; + QString tenArgs(const QString &s, int, int, int, int, int, int, int, int, int) + { + return QString(s); + }; + QString elevenArgs(const QString &s, int, int, int, int, int, int, int, int, int, int) + { + return QString(s); + }; +}; + +Q_DECLARE_METATYPE(TestClass1) + +class MetaTypeUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void returnTypeTest(); + void invokeMethodTest(); + +private: + QCA::Initializer *m_init; +}; + +void MetaTypeUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void MetaTypeUnitTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void MetaTypeUnitTest::returnTypeTest() +{ + TestClass1 testClass1; + QList args; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // returns a null type name because that is what void does... + QCOMPARE(QMetaType::Void, QCA::methodReturnType(testClass1.metaObject(), QByteArray("voidMethod"), args)); + QCOMPARE(QMetaType::QString, QCA::methodReturnType(testClass1.metaObject(), QByteArray("qstringMethod"), args)); + + // returns a null type, because args don't match + QCOMPARE(QMetaType::UnknownType, QCA::methodReturnType(testClass1.metaObject(), QByteArray("boolMethod"), args)); + + args << "QString"; + QCOMPARE(QMetaType::QString, QCA::methodReturnType(testClass1.metaObject(), QByteArray("returnArg"), args)); + QCOMPARE(QMetaType::Bool, QCA::methodReturnType(testClass1.metaObject(), QByteArray("boolMethod"), args)); + args.clear(); + + args << "QByteArray"; + QCOMPARE(QMetaType::QByteArray, QCA::methodReturnType(testClass1.metaObject(), QByteArray("returnArg"), args)); + args.clear(); + + args << "QString" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int"; + + // wrong number of arguments - has 9, needs 10 + QCOMPARE(QMetaType::UnknownType, QCA::methodReturnType(testClass1.metaObject(), QByteArray("tenArgs"), args)); + + // match + args << "int"; + QCOMPARE(QMetaType::QString, QCA::methodReturnType(testClass1.metaObject(), QByteArray("tenArgs"), args)); + + args << "int"; + QCOMPARE(QMetaType::QString, QCA::methodReturnType(testClass1.metaObject(), QByteArray("elevenArgs"), args)); +#else + // returns a null type name because that is what void does... + QCOMPARE(QByteArray("void"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("voidMethod"), args)); + QCOMPARE(QByteArray("QString"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("qstringMethod"), args)); + + // returns a null type, because args don't match + QCOMPARE(QByteArray(""), QCA::methodReturnType(testClass1.metaObject(), QByteArray("boolMethod"), args)); + + args << "QString"; + QCOMPARE(QByteArray("QString"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("returnArg"), args)); + QCOMPARE(QByteArray("bool"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("boolMethod"), args)); + args.clear(); + + args << "QByteArray"; + QCOMPARE(QByteArray("QByteArray"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("returnArg"), args)); + args.clear(); + + args << "QString" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int" + << "int"; + + // wrong number of arguments - has 9, needs 10 + QCOMPARE(QByteArray(""), QCA::methodReturnType(testClass1.metaObject(), QByteArray("tenArgs"), args)); + + // match + args << "int"; + QCOMPARE(QByteArray("QString"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("tenArgs"), args)); + + args << "int"; + QCOMPARE(QByteArray("QString"), QCA::methodReturnType(testClass1.metaObject(), QByteArray("elevenArgs"), args)); +#endif +} + +void MetaTypeUnitTest::invokeMethodTest() +{ + TestClass1 *testClass1 = new TestClass1; + QVariantList args; + + bool ret; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("voidMethod"), args, nullptr); + QVERIFY(ret); + + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("noSuchMethod"), args, nullptr); + QVERIFY(ret == false); + + QVariant stringRes; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("qstringMethod"), args, &stringRes); + QVERIFY(ret); + QVERIFY(stringRes.isValid()); + + QVariant result(false); + QString fakeArg; + args << fakeArg; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("boolMethod"), args, &result); + QVERIFY(ret); + QCOMPARE(result.toBool(), true); + + result = QByteArray(); + args.clear(); + QByteArray myArray("array"); + args << myArray; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("returnArg"), args, &result); + QVERIFY(ret); + QCOMPARE(result.toByteArray(), myArray); + + result = QString(); + args.clear(); + QString myString = QStringLiteral("test words"); + args << myString; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("returnArg"), args, &result); + QVERIFY(ret); + QCOMPARE(result.toString(), myString); + + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("returnRepeatArg"), args, &result); + QVERIFY(ret); + QCOMPARE(result.toString(), QString(myString + myString)); + + // 9 arguments - no matching method + result = QStringLiteral("unchanged"); + args << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("tenArgs"), args, &result); + QVERIFY(ret == false); + QCOMPARE(result.toString(), QStringLiteral("unchanged")); + + // 10 args + args << 0; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("tenArgs"), args, &result); + QVERIFY(ret); + QCOMPARE(result.toString(), myString); + + // 11 args + result = QStringLiteral("unchanged"); + args << 0; + ret = QCA::invokeMethodWithVariants(testClass1, QByteArray("elevenArgs"), args, &result); + QVERIFY(ret == false); + QCOMPARE(result.toString(), QStringLiteral("unchanged")); + + delete testClass1; +} + +QTEST_MAIN(MetaTypeUnitTest) + +#include "metatype.moc" diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/pgpunittest/CMakeLists.txt new file mode 100644 index 0000000000..7429d6a359 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pgpunittest/CMakeLists.txt @@ -0,0 +1,31 @@ +ENABLE_TESTING() + +set(pgpunittest_bin_SRCS pgpunittest.cpp) + +add_executable(pgpunittest ${pgpunittest_bin_SRCS} ) + +target_link_qca_test_libraries(pgpunittest) + +file(MAKE_DIRECTORY + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys1_work + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys2_work + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys3_work + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys4_expired_subkeys_work) + +FOREACH( testFileName pubring.gpg secring.gpg trustdb.gpg ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/keys1/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys1_work/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +FOREACH( testFileName pubring.gpg trustdb.gpg ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/keys2/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys2_work/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +FOREACH( testFileName pubring.gpg secring.gpg trustdb.gpg ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/keys3/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys3_work/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +FOREACH( testFileName pubring.gpg secring.gpg trustdb.gpg ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/keys4_expired_subkeys/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/keys4_expired_subkeys_work/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +add_qca_test(pgpunittest "PGP") diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/pubring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/pubring.gpg new file mode 100644 index 0000000000..663dec1f55 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/pubring.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/secring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/secring.gpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/trustdb.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/trustdb.gpg new file mode 100644 index 0000000000..fbe2b9e55a Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys1/trustdb.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/pubring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/pubring.gpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/secring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/secring.gpg new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/trustdb.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/trustdb.gpg new file mode 100644 index 0000000000..3c545ffc13 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys2/trustdb.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/pubring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/pubring.gpg new file mode 100644 index 0000000000..231540635a Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/pubring.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/secring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/secring.gpg new file mode 100644 index 0000000000..1202363cf0 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/secring.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/trustdb.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/trustdb.gpg new file mode 100644 index 0000000000..e8ada7fe3e Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys3/trustdb.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/pubring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/pubring.gpg new file mode 100644 index 0000000000..645f2b2096 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/pubring.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/secring.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/secring.gpg new file mode 100644 index 0000000000..2d1fc7e439 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/secring.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/trustdb.gpg b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/trustdb.gpg new file mode 100644 index 0000000000..0f1a01f834 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pgpunittest/keys4_expired_subkeys/trustdb.gpg differ diff --git a/local/recipes/libs/qca/source/unittest/pgpunittest/pgpunittest.cpp b/local/recipes/libs/qca/source/unittest/pgpunittest/pgpunittest.cpp new file mode 100644 index 0000000000..a4a971af69 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pgpunittest/pgpunittest.cpp @@ -0,0 +1,906 @@ +/** + * Copyright (C) 2006-2007 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +// qt did not introduce qputenv until 4.4, so we'll keep a copy here for 4.2 +// compat +bool my_qputenv(const char *varName, const QByteArray &value) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + return _putenv_s(varName, value.constData()) == 0; +#else + QByteArray buffer(varName); + buffer += "="; + buffer += value; + return putenv(qstrdup(buffer.constData())) == 0; +#endif +} + +static int qca_setenv(const char *name, const char *value, int overwrite) +{ + if (!overwrite && qEnvironmentVariableIsSet(name)) + return 0; + + if (my_qputenv(name, QByteArray(value))) + return 0; // success + else + return 1; // error +} + +// Note; in a real application you get this from a user, but this +// is a useful trick for a unit test. +// See the qcatool application or keyloader and eventhandler examples +// for how to do this properly. +class PGPPassphraseProvider : public QObject +{ + Q_OBJECT +public: + PGPPassphraseProvider(QObject *parent = nullptr) + : QObject(parent) + { + connect(&m_handler, &QCA::EventHandler::eventReady, this, &PGPPassphraseProvider::eh_eventReady); + m_handler.start(); + } + +private Q_SLOTS: + void eh_eventReady(int id, const QCA::Event &event) + { + if (event.type() == QCA::Event::Password) { + QCA::SecureArray pass("start"); + m_handler.submitPassword(id, pass); + } else { + m_handler.reject(id); + } + } + +private: + QCA::EventHandler m_handler; +}; + +class PGPPassphraseProviderThread : public QCA::SyncThread +{ + Q_OBJECT +public: + ~PGPPassphraseProviderThread() override + { + stop(); + } + +protected: + void atStart() override + { + prov = new PGPPassphraseProvider; + } + + void atEnd() override + { + delete prov; + } + +private: + PGPPassphraseProvider *prov; +}; + +class PgpUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testKeyRing(); + void testMessageSign(); + void testClearsign(); + void testDetachedSign(); + void testSignaturesWithExpiredSubkeys(); + void testEncryptionWithExpiredSubkeys(); +}; + +void PgpUnitTest::initTestCase() +{ + // Change current directory to executable directory + // it is need to find keys*_work directories + if (!QCoreApplication::applicationDirPath().isEmpty()) + QDir::setCurrent(QCoreApplication::applicationDirPath()); +} + +void PgpUnitTest::cleanupTestCase() +{ +} + +void PgpUnitTest::testKeyRing() +{ + QCA::Initializer *qcaInit = new QCA::Initializer; + + // We test a small keyring - I downloaded a publically available one from + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + // the Amsterdam Internet Exchange. + if (qca_setenv("GNUPGHOME", "./keys1_work", 1) != 0) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + // activate the KeyStoreManager + QCA::KeyStoreManager::start(); + + if (QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + QCOMPARE(pgpStore.name(), QStringLiteral("GnuPG Keyring")); + QCOMPARE(pgpStore.type(), QCA::KeyStore::PGPKeyring); + QCOMPARE(pgpStore.id(), QStringLiteral("qca-gnupg")); + QCOMPARE(pgpStore.isReadOnly(), false); + QCOMPARE(pgpStore.holdsTrustedCertificates(), false); + QCOMPARE(pgpStore.holdsIdentities(), true); + QCOMPARE(pgpStore.holdsPGPPublicKeys(), true); + + QList keylist = pgpStore.entryList(); + QCOMPARE(keylist.count(), 6); + QStringList nameList; + foreach (const QCA::KeyStoreEntry key, keylist) { + QCOMPARE(key.isNull(), false); + QCOMPARE(key.type(), QCA::KeyStoreEntry::TypePGPPublicKey); + QCOMPARE(key.id().length(), 16); // 16 hex digits + QVERIFY(key.keyBundle().isNull()); + QVERIFY(key.certificate().isNull()); + QVERIFY(key.crl().isNull()); + QVERIFY(key.pgpSecretKey().isNull()); + QCOMPARE(key.pgpPublicKey().isNull(), false); + + // We accumulate the names, and check them next + nameList << key.name(); + } + QVERIFY(nameList.contains(QStringLiteral("Steven Bakker "))); + QVERIFY(nameList.contains(QStringLiteral("Romeo Zwart "))); + QVERIFY(nameList.contains(QStringLiteral("Arien Vijn "))); + QVERIFY(nameList.contains(QStringLiteral("Niels Bakker "))); + QVERIFY(nameList.contains(QStringLiteral("Henk Steenman "))); + QVERIFY(nameList.contains(QStringLiteral("Geert Nijpels "))); + + // TODO: We should test removeEntry() and writeEntry() here. + } + + delete qcaInit; + qcaInit = new QCA::Initializer; + + // We now test an empty keyring + if (qca_setenv("GNUPGHOME", "./keys2_work", 1) != 0) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + QCA::KeyStoreManager::start(); + + if (QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + + QList keylist = pgpStore.entryList(); + QCOMPARE(keylist.count(), 0); + // TODO: We should test removeEntry() and writeEntry() here. + } + + if (false == oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } + + delete qcaInit; +} + +void PgpUnitTest::testMessageSign() +{ + QCA::Initializer qcaInit; + + // event handling cannot be used in the same thread as synchronous calls + // which might require event handling. let's put our event handler in + // a side thread so that we can write the unit test synchronously. + PGPPassphraseProviderThread thread; + thread.start(); + + // This keyring has a private / public key pair + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + if (0 != qca_setenv("GNUPGHOME", "./keys3_work", 1)) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + // activate the KeyStoreManager + QCA::KeyStoreManager::start(); + + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + + if (QCA::isSupported(QStringList(QStringLiteral("openpgp")), QStringLiteral("qca-gnupg")) || + QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + + QList keylist = pgpStore.entryList(); + QCOMPARE(keylist.count(), 1); + + const QCA::KeyStoreEntry &myPGPKey = keylist.at(0); + QCOMPARE(myPGPKey.isNull(), false); + QCOMPARE(myPGPKey.name(), + QStringLiteral("Qca Test Key (This key is only for QCA unit tests) ")); + QCOMPARE(myPGPKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(myPGPKey.id(), QStringLiteral("9E946237DAFCCFF4")); + QVERIFY(myPGPKey.keyBundle().isNull()); + QVERIFY(myPGPKey.certificate().isNull()); + QVERIFY(myPGPKey.crl().isNull()); + QCOMPARE(myPGPKey.pgpSecretKey().isNull(), false); + QCOMPARE(myPGPKey.pgpPublicKey().isNull(), false); + + // first make the SecureMessageKey + QCA::SecureMessageKey key; + key.setPGPSecretKey(myPGPKey.pgpSecretKey()); + QVERIFY(key.havePrivate()); + + // our data to sign + QByteArray plain = "Hello, world"; + + // let's do it + QCA::OpenPGP pgp; + QCA::SecureMessage msg(&pgp); + msg.setSigner(key); + msg.setFormat(QCA::SecureMessage::Ascii); + msg.startSign(QCA::SecureMessage::Message); + msg.update(plain); + msg.end(); + msg.waitForFinished(5000); + +#if 0 + QString str = QCA::KeyStoreManager::diagnosticText(); + QCA::KeyStoreManager::clearDiagnosticText(); + QStringList lines = str.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < lines.count(); ++n) + fprintf(stderr, "keystore: %s\n", qPrintable(lines[n])); + + QString out = msg.diagnosticText(); + QStringList msglines = out.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < msglines.count(); ++n) + fprintf(stderr, "message: %s\n", qPrintable(msglines[n])); +#endif + QByteArray messageData; + if (msg.success()) { + messageData = msg.read(); + } else { + qDebug() << "Failure:" << msg.errorCode(); + QFAIL("Failed to sign in Message format"); + } + // qDebug() << "Message format data:" << messageData; + + // OK, now lets verify that the result will verify. + // let's do it + QCA::OpenPGP pgp2; + QCA::SecureMessage msg2(&pgp2); + msg2.setFormat(QCA::SecureMessage::Ascii); + msg2.startVerify(); + msg2.update(messageData); + msg2.end(); + msg2.waitForFinished(5000); + + QVERIFY(msg2.verifySuccess()); + + if (msg2.success()) { + QCOMPARE(msg2.read(), plain); + } else { + qDebug() << "Failure:" << msg2.errorCode(); + QFAIL("Failed to verify message"); + } + + // why is this here? + if (false == oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } + + // now test that if we corrupt the message, it no longer + // verifies correctly. + messageData.replace('T', 't'); + messageData.replace('w', 'W'); + QCA::SecureMessage msg3(&pgp2); + msg3.setFormat(QCA::SecureMessage::Ascii); + msg3.startVerify(); + msg3.update(messageData); + msg3.end(); + msg3.waitForFinished(5000); + + QCOMPARE(msg3.verifySuccess(), false); + QCOMPARE(msg3.errorCode(), QCA::SecureMessage::ErrorUnknown); + } + + if (false == oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } +} + +void PgpUnitTest::testClearsign() +{ + QCA::Initializer qcaInit; + + // event handling cannot be used in the same thread as synchronous calls + // which might require event handling. let's put our event handler in + // a side thread so that we can write the unit test synchronously. + PGPPassphraseProviderThread thread; + thread.start(); + + // This keyring has a private / public key pair + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + if (0 != qca_setenv("GNUPGHOME", "./keys3_work", 1)) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + // activate the KeyStoreManager + QCA::KeyStoreManager::start(); + + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + + if (QCA::isSupported(QStringList(QStringLiteral("openpgp")), QStringLiteral("qca-gnupg")) || + QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + + QList keylist = pgpStore.entryList(); + QCOMPARE(keylist.count(), 1); + + const QCA::KeyStoreEntry &myPGPKey = keylist.at(0); + QCOMPARE(myPGPKey.isNull(), false); + QCOMPARE(myPGPKey.name(), + QStringLiteral("Qca Test Key (This key is only for QCA unit tests) ")); + QCOMPARE(myPGPKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(myPGPKey.id(), QStringLiteral("9E946237DAFCCFF4")); + QVERIFY(myPGPKey.keyBundle().isNull()); + QVERIFY(myPGPKey.certificate().isNull()); + QVERIFY(myPGPKey.crl().isNull()); + QCOMPARE(myPGPKey.pgpSecretKey().isNull(), false); + QCOMPARE(myPGPKey.pgpPublicKey().isNull(), false); + + // first make the SecureMessageKey + QCA::SecureMessageKey key; + key.setPGPSecretKey(myPGPKey.pgpSecretKey()); + QVERIFY(key.havePrivate()); + + // our data to sign + QByteArray plain = "Hello, world"; + + // let's do it + QCA::OpenPGP pgp; + QCA::SecureMessage msg(&pgp); + msg.setSigner(key); + msg.setFormat(QCA::SecureMessage::Ascii); + msg.startSign(QCA::SecureMessage::Clearsign); + msg.update(plain); + msg.end(); + msg.waitForFinished(5000); + +#if 0 + QString str = QCA::KeyStoreManager::diagnosticText(); + QCA::KeyStoreManager::clearDiagnosticText(); + QStringList lines = str.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < lines.count(); ++n) + fprintf(stderr, "keystore: %s\n", qPrintable(lines[n])); + + QString out = msg.diagnosticText(); + QStringList msglines = out.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < msglines.count(); ++n) + fprintf(stderr, "message: %s\n", qPrintable(msglines[n])); +#endif + + QByteArray clearsignedData; + if (msg.success()) { + clearsignedData = msg.read(); + } else { + qDebug() << "Failure:" << msg.errorCode(); + QFAIL("Failed to clearsign"); + } + + // OK, now lets verify that the result will verify. + // let's do it + QCA::OpenPGP pgp2; + QCA::SecureMessage msg2(&pgp2); + msg2.setFormat(QCA::SecureMessage::Ascii); + msg2.startVerify(); + msg2.update(clearsignedData); + msg2.end(); + msg2.waitForFinished(5000); + + QVERIFY(msg2.verifySuccess()); + + if (msg2.success()) { + // The trimmed() call is needed because clearsigning + // trashes whitespace + QCOMPARE(msg2.read().trimmed(), plain.trimmed()); + } else { + qDebug() << "Failure:" << msg2.errorCode(); + QFAIL("Failed to verify clearsigned message"); + } + } + + if (false == oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } +} + +void PgpUnitTest::testDetachedSign() +{ + QCA::Initializer qcaInit; + + // event handling cannot be used in the same thread as synchronous calls + // which might require event handling. let's put our event handler in + // a side thread so that we can write the unit test synchronously. + PGPPassphraseProviderThread thread; + thread.start(); + + // This keyring has a private / public key pair + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + if (0 != qca_setenv("GNUPGHOME", "./keys3_work", 1)) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + // activate the KeyStoreManager + QCA::KeyStoreManager::start(); + + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + + if (QCA::isSupported(QStringList(QStringLiteral("openpgp")), QStringLiteral("qca-gnupg")) || + QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + + QList keylist = pgpStore.entryList(); + QCOMPARE(keylist.count(), 1); + + const QCA::KeyStoreEntry &myPGPKey = keylist.at(0); + QCOMPARE(myPGPKey.isNull(), false); + QCOMPARE(myPGPKey.name(), + QStringLiteral("Qca Test Key (This key is only for QCA unit tests) ")); + QCOMPARE(myPGPKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(myPGPKey.id(), QStringLiteral("9E946237DAFCCFF4")); + QVERIFY(myPGPKey.keyBundle().isNull()); + QVERIFY(myPGPKey.certificate().isNull()); + QVERIFY(myPGPKey.crl().isNull()); + QCOMPARE(myPGPKey.pgpSecretKey().isNull(), false); + QCOMPARE(myPGPKey.pgpPublicKey().isNull(), false); + + // first make the SecureMessageKey + QCA::SecureMessageKey key; + key.setPGPSecretKey(myPGPKey.pgpSecretKey()); + QVERIFY(key.havePrivate()); + + // our data to sign + QByteArray plain = "Hello, world"; + + // let's do it + QCA::OpenPGP pgp; + QCA::SecureMessage msg(&pgp); + msg.setSigner(key); + msg.setFormat(QCA::SecureMessage::Ascii); + msg.startSign(QCA::SecureMessage::Detached); + msg.update(plain); + msg.end(); + msg.waitForFinished(5000); + +#if 0 + QString str = QCA::KeyStoreManager::diagnosticText(); + QCA::KeyStoreManager::clearDiagnosticText(); + QStringList lines = str.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < lines.count(); ++n) + fprintf(stderr, "keystore: %s\n", qPrintable(lines[n])); + + QString out = msg.diagnosticText(); + QStringList msglines = out.split('\n', Qt::SkipEmptyParts); + for(int n = 0; n < msglines.count(); ++n) + fprintf(stderr, "message: %s\n", qPrintable(msglines[n])); +#endif + + QByteArray detachedSignature; + if (msg.success()) { + detachedSignature = msg.signature(); + } else { + qDebug() << "Failure:" << msg.errorCode(); + QFAIL("Failed to create detached signature"); + } + + // qDebug() << "result:" << detachedSignature; + + // OK, now lets verify that the resulting signature will verify. + // let's do it + QCA::OpenPGP pgp2; + QCA::SecureMessage msg2(&pgp2); + msg2.setFormat(QCA::SecureMessage::Ascii); + msg2.startVerify(detachedSignature); + msg2.update(plain); + msg2.end(); + msg2.waitForFinished(2000); + + QVERIFY(msg2.verifySuccess()); + + // If the message is different, it shouldn't verify any more + QCA::SecureMessage msg3(&pgp2); + msg3.setFormat(QCA::SecureMessage::Ascii); + msg3.startVerify(detachedSignature); + msg3.update(plain + '1'); + msg3.end(); + msg3.waitForFinished(2000); + + QCOMPARE(msg3.verifySuccess(), false); + + QCOMPARE(msg3.errorCode(), QCA::SecureMessage::ErrorUnknown); + } + + // Restore things to the way they were.... + if (false == oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } +} + +void PgpUnitTest::testSignaturesWithExpiredSubkeys() +{ + // This previously failing test tests signatures from + // keys with expired subkeys, while assuring no loss + // of functionality. + + QCA::Initializer qcaInit; + + PGPPassphraseProviderThread thread; + thread.start(); + + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + if (qca_setenv("GNUPGHOME", "./keys4_expired_subkeys_work", 1) != 0) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + QCA::KeyStoreManager::start(); + + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + + if (QCA::isSupported(QStringList(QStringLiteral("openpgp")), QStringLiteral("qca-gnupg")) || + QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + + QList keylist = pgpStore.entryList(); + + QCA::KeyStoreEntry validKey; + foreach (const QCA::KeyStoreEntry key, keylist) { + if (key.id() == QLatin1String("DD773CA7E4E22769")) { + validKey = key; + } + } + + QCOMPARE(validKey.isNull(), false); + QCOMPARE(validKey.name(), QStringLiteral("QCA Test Key (Unit test key for expired subkeys) ")); + QCOMPARE(validKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(validKey.id(), QStringLiteral("DD773CA7E4E22769")); + QCOMPARE(validKey.pgpSecretKey().isNull(), false); + QCOMPARE(validKey.pgpPublicKey().isNull(), false); + + // Create a signature with the non-expired primary key first + QByteArray validMessage("Non-expired key signature"); + + QCA::SecureMessageKey secKey; + secKey.setPGPSecretKey(validKey.pgpSecretKey()); + QVERIFY(secKey.havePrivate()); + + QCA::OpenPGP pgp; + QCA::SecureMessage msg(&pgp); + msg.setSigner(secKey); + msg.setFormat(QCA::SecureMessage::Ascii); + msg.startSign(QCA::SecureMessage::Clearsign); + msg.update(validMessage); + msg.end(); + msg.waitForFinished(5000); + + QVERIFY(msg.success()); + + QByteArray nonExpiredKeySignature = msg.read(); + + // Verify it + QCA::OpenPGP pgp1; + QCA::SecureMessage msg1(&pgp1); + msg1.setFormat(QCA::SecureMessage::Ascii); + msg1.startVerify(); + msg1.update(nonExpiredKeySignature); + msg1.end(); + msg1.waitForFinished(5000); + + QByteArray signedResult = msg1.read(); + + QVERIFY(msg1.verifySuccess()); + QCOMPARE(signedResult.trimmed(), validMessage.trimmed()); + + // Test signature made by the expired subkey + QByteArray expiredKeySignature( + "-----BEGIN PGP SIGNED MESSAGE-----\n" + "Hash: SHA1\n" + "\n" + "Expired signature\n" + "-----BEGIN PGP SIGNATURE-----\n" + "Version: GnuPG v1\n" + "\n" + "iQEcBAEBAgAGBQJTaI2VAAoJEPddwMGvBiCrA18H/RMJxnEnyNERd19ffTdSLvHH\n" + "iwsfTEPmFQSpmCUnmjK2IIMXWTi6ofinGTWEsXKHSTqgytz715Q16OICwnFoeHin\n" + "0SnsTgi5lH5QcJPJ5PqoRwgAy8vhy73EpYrv7zqLom1Qm/9NeGtNZsohjp0ECFEk\n" + "4UmZiJF7u5Yn6hBl9btIPRTjI2FrXjr3Zy8jZijRaZMutnz5VveBHCLu00NvJQkG\n" + "PC/ZvvfGOk9SeaApnrnntfdKJ4geKxoT0+r+Yz1kQ1VKG5Af3JziBwwNID6g/FYv\n" + "cDK2no5KD7lyASAt6veCDXBdUmNatBO5Au9eE0jJwsSV6LZCpEYEcgBsnfDwxls=\n" + "=UM6K\n" + "-----END PGP SIGNATURE-----\n"); + + QCA::OpenPGP pgp2; + QCA::SecureMessage msg2(&pgp2); + msg2.setFormat(QCA::SecureMessage::Ascii); + msg2.startVerify(); + msg2.update(expiredKeySignature); + msg2.end(); + msg2.waitForFinished(5000); + + QCOMPARE(msg2.verifySuccess(), false); + QCOMPARE(msg2.errorCode(), QCA::SecureMessage::ErrorSignerExpired); + + // Test signature made by the revoked subkey + QByteArray revokedKeySignature( + "-----BEGIN PGP SIGNED MESSAGE-----\n" + "Hash: SHA1\n" + "\n" + "Revoked signature\n" + "-----BEGIN PGP SIGNATURE-----\n" + "Version: GnuPG v1\n" + "\n" + "iQEcBAEBAgAGBQJTd2AmAAoJEJwx7xWvfHTUCZMH/310hMg68H9kYWqKO12Qvyl7\n" + "SlkHBxRsD1sKIBM10qxh6262582mbdAbObVCSFlHVR5NU2tDN5B67J9NU2KnwCcq\n" + "Ny7Oj06UGEkZRmGA23BZ78w/xhPr2Xg80lckBIfGWCvezjSoAeOonk4WREpqzSUr\n" + "sXX8iioBh98ySuQp4rtzf1j0sGB2Tui/bZybiLwz+/fBzW9ITSV0OXmeT5BfBhJU\n" + "XXnOBXDwPUrJQPHxpGpX0s7iyElfZ2ws/PNqUJiWdmxqwLnndn1y5UECDC2T0FpC\n" + "erOM27tQeEthdrZTjMjV47p1ilNgNJrMI328ovehABYyobK9UlnFHcUnn/1OFRw=\n" + "=sE1o\n" + "-----END PGP SIGNATURE-----\n"); + + QCA::OpenPGP pgp3; + QCA::SecureMessage msg3(&pgp3); + msg3.setFormat(QCA::SecureMessage::Ascii); + msg3.startVerify(); + msg3.update(revokedKeySignature); + msg3.end(); + msg3.waitForFinished(5000); + + QCOMPARE(msg3.verifySuccess(), false); + QCOMPARE(msg3.errorCode(), QCA::SecureMessage::ErrorSignerRevoked); + + // Test expired signature + QByteArray expiredSignature( + "-----BEGIN PGP SIGNED MESSAGE-----\n" + "Hash: SHA1\n" + "\n" + "Valid key, expired signature\n" + "-----BEGIN PGP SIGNATURE-----\n" + "Version: GnuPG v1\n" + "\n" + "iQEiBAEBAgAMBQJTkjUvBYMAAVGAAAoJEN13PKfk4idpItIH/1BpFQkPm8fQV0bd\n" + "37qaXf7IWr7bsPBcb7NjR9EmB6Zl6wnmSKW9mvKvs0ZJ1HxyHx0yC5UQWsgTj3do\n" + "xGDP4nJvi0L7EDUukZApWu98nFwrnTrLEd+JMwlpYDhtaljq2qQo7u7CsqyoE2cL\n" + "nRuPkc+lRbDMlqGXk2QFPL8Wu7gW/ndJ8nQ0Dq+22q77Hh1PcyFlggTBxhLA4Svk\n" + "Hx2I4bUjaUq5P4g9kFeXx6/0n31FCa+uThSkWWjH1OeLEXrUZSH/8nBWcnJ3IGbt\n" + "W2bmHhTUx3tYt9aHc+1kje2bAT01xN974r+wS/XNT4cWw7ZSSvukEIjjieUMP4eQ\n" + "S/H6RmM=\n" + "=9pAJ\n" + "-----END PGP SIGNATURE-----\n"); + + QCA::OpenPGP pgp4; + QCA::SecureMessage msg4(&pgp4); + msg4.setFormat(QCA::SecureMessage::Ascii); + msg4.startVerify(); + msg4.update(expiredSignature); + msg4.end(); + msg4.waitForFinished(5000); + + QCOMPARE(msg4.verifySuccess(), false); + QCOMPARE(msg4.errorCode(), QCA::SecureMessage::ErrorSignatureExpired); + } + + if (!oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } +} + +void PgpUnitTest::testEncryptionWithExpiredSubkeys() +{ + // This previously failing test tests encrypting to + // keys with expired subkeys, while assuring no loss + // of functionality. + + QCA::Initializer qcaInit; + + PGPPassphraseProviderThread thread; + thread.start(); + + QByteArray oldGNUPGHOME = qgetenv("GNUPGHOME"); + if (qca_setenv("GNUPGHOME", "./keys4_expired_subkeys_work", 1) != 0) { + QFAIL("Expected to be able to set the GNUPGHOME environment variable, but couldn't"); + } + + QCA::KeyStoreManager::start(); + + QCA::KeyStoreManager keyManager(this); + keyManager.waitForBusyFinished(); + + if (QCA::isSupported(QStringList(QStringLiteral("openpgp")), QStringLiteral("qca-gnupg")) || + QCA::isSupported(QStringList(QStringLiteral("keystorelist")), QStringLiteral("qca-gnupg"))) { + QStringList storeIds = keyManager.keyStores(); + QVERIFY(storeIds.contains(QStringLiteral("qca-gnupg"))); + + QCA::KeyStore pgpStore(QStringLiteral("qca-gnupg"), &keyManager); + QVERIFY(pgpStore.isValid()); + + QList keylist = pgpStore.entryList(); + + QCA::KeyStoreEntry validKey; + QCA::KeyStoreEntry expiredKey; + QCA::KeyStoreEntry revokedKey; + foreach (const QCA::KeyStoreEntry key, keylist) { + if (key.id() == QLatin1String("FEF97E4C4C870810")) { + validKey = key; + } else if (key.id() == QLatin1String("DD773CA7E4E22769")) { + expiredKey = key; + } else if (key.id() == QLatin1String("1D6A028CC4F444A9")) { + revokedKey = key; + } + } + + QCOMPARE(validKey.isNull(), false); + QCOMPARE(validKey.name(), + QStringLiteral( + "QCA Test Key 2 (Non-expired encryption key with expired encryption subkey) ")); + QCOMPARE(validKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(validKey.id(), QStringLiteral("FEF97E4C4C870810")); + QCOMPARE(validKey.pgpSecretKey().isNull(), false); + QCOMPARE(validKey.pgpPublicKey().isNull(), false); + + QCOMPARE(expiredKey.isNull(), false); + QCOMPARE(expiredKey.name(), + QStringLiteral("QCA Test Key (Unit test key for expired subkeys) ")); + QCOMPARE(expiredKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(expiredKey.id(), QStringLiteral("DD773CA7E4E22769")); + QCOMPARE(expiredKey.pgpSecretKey().isNull(), false); + QCOMPARE(expiredKey.pgpPublicKey().isNull(), false); + + QCOMPARE(revokedKey.isNull(), false); + QCOMPARE(revokedKey.name(), QStringLiteral("QCA Test Key (Revoked unit test key) ")); + QCOMPARE(revokedKey.type(), QCA::KeyStoreEntry::TypePGPSecretKey); + QCOMPARE(revokedKey.id(), QStringLiteral("1D6A028CC4F444A9")); + QCOMPARE(revokedKey.pgpSecretKey().isNull(), false); + QCOMPARE(revokedKey.pgpPublicKey().isNull(), false); + + // Test encrypting to a non-expired key first + QByteArray nonExpiredMessage("Encrypting to non-expired subkey"); + + QCA::SecureMessageKey key; + key.setPGPPublicKey(validKey.pgpPublicKey()); + + QCA::OpenPGP pgp; + QCA::SecureMessage msg(&pgp); + msg.setFormat(QCA::SecureMessage::Ascii); + msg.setRecipient(key); + msg.startEncrypt(); + msg.update(nonExpiredMessage); + msg.end(); + msg.waitForFinished(5000); + + QVERIFY(msg.success()); + QByteArray encResult = msg.read(); + + // Decrypt and compare it + QCA::OpenPGP pgp1; + QCA::SecureMessage msg1(&pgp1); + msg1.startDecrypt(); + msg1.update(encResult); + msg1.end(); + msg1.waitForFinished(5000); + + QVERIFY(msg1.success()); + QByteArray decResult = msg1.read(); + QCOMPARE(decResult, nonExpiredMessage); + + // Test encrypting to the expired key + QByteArray expiredMessage("Encrypting to the expired key"); + + QCA::SecureMessageKey key2; + key2.setPGPPublicKey(expiredKey.pgpPublicKey()); + + QCA::OpenPGP pgp2; + QCA::SecureMessage msg2(&pgp2); + msg2.setFormat(QCA::SecureMessage::Ascii); + msg2.setRecipient(key2); + msg2.startEncrypt(); + msg2.update(expiredMessage); + msg2.end(); + msg2.waitForFinished(5000); + + QCOMPARE(msg2.success(), false); + // Note: If gpg worked as expected, msg.errorCode() should + // equal QCA::SecureMessage::ErrorEncryptExpired, but currently + // it omits the reason for failure, so we check for both values. + QVERIFY((msg2.errorCode() == QCA::SecureMessage::ErrorEncryptExpired) || + (msg2.errorCode() == QCA::SecureMessage::ErrorEncryptInvalid)); + + // Test encrypting to the revoked key + QByteArray revokedMessage("Encrypting to the revoked key"); + + QCA::SecureMessageKey key3; + key3.setPGPPublicKey(expiredKey.pgpPublicKey()); + + QCA::OpenPGP pgp3; + QCA::SecureMessage msg3(&pgp3); + msg3.setFormat(QCA::SecureMessage::Ascii); + msg3.setRecipient(key3); + msg3.startEncrypt(); + msg3.update(revokedMessage); + msg3.end(); + msg3.waitForFinished(5000); + + QCOMPARE(msg3.success(), false); + // Note: If gpg worked as expected, msg.errorCode() should + // equal QCA::SecureMessage::ErrorEncryptRevoked, but currently + // it omits the reason for failure, so we check for both values. + QVERIFY((msg3.errorCode() == QCA::SecureMessage::ErrorEncryptRevoked) || + (msg3.errorCode() == QCA::SecureMessage::ErrorEncryptInvalid)); + } + + if (!oldGNUPGHOME.isNull()) { + qca_setenv("GNUPGHOME", oldGNUPGHOME.data(), 1); + } +} + +QTEST_MAIN(PgpUnitTest) + +#include "pgpunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/pipeunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/pipeunittest/CMakeLists.txt new file mode 100644 index 0000000000..d6baea57cb --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pipeunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(pipeunittest_bin_SRCS pipeunittest.cpp) + +add_executable( pipeunittest ${pipeunittest_bin_SRCS} ) + +target_link_qca_test_libraries(pipeunittest) + +# add_qca_test(pipeunittest "QPipe") diff --git a/local/recipes/libs/qca/source/unittest/pipeunittest/pipeunittest.cpp b/local/recipes/libs/qca/source/unittest/pipeunittest/pipeunittest.cpp new file mode 100644 index 0000000000..a9096f65be --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pipeunittest/pipeunittest.cpp @@ -0,0 +1,267 @@ +/** + * Copyright (C) 2007 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +#include + +class PipeUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void createPipeWithInsecureMemory(); + void createPipeWithSecureMemory(); + void readWrite(); + void readWriteSecure(); + void signalTests(); + void signalTestsSecure(); + +private: + QCA::Initializer *m_init; +}; + +void PipeUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void PipeUnitTest::cleanupTestCase() +{ + QCA::unloadAllPlugins(); + delete m_init; +} + +void PipeUnitTest::createPipeWithInsecureMemory() +{ + QCA::QPipe pipe1; + // we haven't created the pipe yet, so it shouldn't be valid + QCOMPARE(pipe1.readEnd().isValid(), false); + QCOMPARE(pipe1.writeEnd().isValid(), false); + + pipe1.create(); // insecure memory used + QVERIFY(pipe1.readEnd().isValid()); + QVERIFY(pipe1.readEnd().type() == QCA::QPipeDevice::Read); + QVERIFY(pipe1.writeEnd().isValid()); + QVERIFY(pipe1.writeEnd().type() == QCA::QPipeDevice::Write); + + pipe1.reset(); + QCOMPARE(pipe1.readEnd().isValid(), false); + QCOMPARE(pipe1.writeEnd().isValid(), false); +} + +void PipeUnitTest::createPipeWithSecureMemory() +{ + QCA::QPipe pipe1; + // we haven't created the pipe yet, so it shouldn't be valid + QCOMPARE(pipe1.readEnd().isValid(), false); + QCOMPARE(pipe1.writeEnd().isValid(), false); + + pipe1.create(true); // secure memory used + QVERIFY(pipe1.readEnd().isValid()); + QVERIFY(pipe1.readEnd().type() == QCA::QPipeDevice::Read); + QVERIFY(pipe1.writeEnd().isValid()); + QVERIFY(pipe1.writeEnd().type() == QCA::QPipeDevice::Write); + + pipe1.reset(); + QCOMPARE(pipe1.readEnd().isValid(), false); + QCOMPARE(pipe1.writeEnd().isValid(), false); +} + +void PipeUnitTest::readWrite() +{ + QCA::QPipe pipe1; + QByteArray testData1("Down the"); + QByteArray testData2("pipe!"); + + pipe1.create(); + QVERIFY(pipe1.writeEnd().isValid()); + QVERIFY(pipe1.readEnd().isValid()); + + // enable the pipe ends for read/write + pipe1.writeEnd().enable(); + pipe1.readEnd().enable(); + + pipe1.writeEnd().write(testData1); + QTest::qWait(1); // process events + QTest::qWait(1); // process events + QByteArray out1 = pipe1.readEnd().read(); // read all... + QCOMPARE(testData1, out1); + + pipe1.writeEnd().write(testData1); // put it back in + QTest::qWait(1); // process events + QCOMPARE(pipe1.readEnd().bytesAvailable(), testData1.size()); + + pipe1.writeEnd().write(testData2); // add some more data + QTest::qWait(1); // process events + QCOMPARE(pipe1.readEnd().bytesAvailable(), testData1.size() + testData2.size()); + QByteArray thisRead = pipe1.readEnd().read(1); + QCOMPARE(thisRead, QByteArray("D")); + thisRead = pipe1.readEnd().read(3); + QCOMPARE(thisRead, QByteArray("own")); + thisRead = pipe1.readEnd().read(); + QCOMPARE(thisRead, QByteArray(" thepipe!")); +} + +void PipeUnitTest::readWriteSecure() +{ + QCA::QPipe pipe1; + QCA::SecureArray testData1("Down the"); + QCA::SecureArray testData2(" secure pipe!"); + + pipe1.create(true); + QVERIFY(pipe1.writeEnd().isValid()); + QVERIFY(pipe1.readEnd().isValid()); + + // enable the pipe ends for read/write + pipe1.writeEnd().enable(); + pipe1.readEnd().enable(); + + pipe1.writeEnd().writeSecure(testData1); + QTest::qWait(1); // process events + QTest::qWait(1); // process events + QCA::SecureArray out1 = pipe1.readEnd().readSecure(); // read all... + QCOMPARE(testData1, out1); + + pipe1.writeEnd().writeSecure(testData1); // put it back in + QTest::qWait(1); // process events + QCOMPARE(pipe1.readEnd().bytesAvailable(), testData1.size()); + + pipe1.writeEnd().writeSecure(testData2); // add some more data + QTest::qWait(1); // process events + QCOMPARE(pipe1.readEnd().bytesAvailable(), testData1.size() + testData2.size()); + QCA::SecureArray thisRead = pipe1.readEnd().readSecure(1); + QCOMPARE(thisRead, QCA::SecureArray("D")); + thisRead = pipe1.readEnd().readSecure(3); + QCOMPARE(thisRead, QCA::SecureArray("own")); + thisRead = pipe1.readEnd().readSecure(); + QCOMPARE(thisRead, QCA::SecureArray(" the secure pipe!")); +} + +void PipeUnitTest::signalTests() +{ + std::unique_ptr pipe(new QCA::QPipe); + pipe->create(); + + QVERIFY(pipe->writeEnd().isValid()); + pipe->writeEnd().enable(); + QVERIFY(pipe->readEnd().isValid()); + pipe->readEnd().enable(); + + QSignalSpy readyReadSpy(&(pipe->readEnd()), &QCA::QPipeEnd::readyRead); + QVERIFY(readyReadSpy.isValid()); + QSignalSpy bytesWrittenSpy(&(pipe->writeEnd()), &QCA::QPipeEnd::bytesWritten); + QVERIFY(bytesWrittenSpy.isValid()); + QSignalSpy closedWriteSpy(&(pipe->writeEnd()), &QCA::QPipeEnd::closed); + QVERIFY(closedWriteSpy.isValid()); + QSignalSpy closedReadSpy(&(pipe->readEnd()), &QCA::QPipeEnd::closed); + QVERIFY(closedReadSpy.isValid()); + + QCOMPARE(readyReadSpy.count(), 0); + QCOMPARE(bytesWrittenSpy.count(), 0); + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 0); + + QByteArray data("Far better, it is, to dare mighty things"); + pipe->writeEnd().write(data); + QTest::qWait(1); + QTest::qWait(1); + QCOMPARE(readyReadSpy.count(), 1); + QCOMPARE(bytesWrittenSpy.count(), 1); + // this pulls out the first argument to the first signal as an integer + QCOMPARE(bytesWrittenSpy.takeFirst().at(0).toInt(), data.size()); + QCOMPARE(pipe->readEnd().bytesAvailable(), data.size()); + + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 0); + + pipe->readEnd().close(); + QTest::qWait(1); + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 1); + pipe->writeEnd().close(); + QTest::qWait(1); + QCOMPARE(closedWriteSpy.count(), 1); + QCOMPARE(closedReadSpy.count(), 1); +} + +void PipeUnitTest::signalTestsSecure() +{ + std::unique_ptr pipe(new QCA::QPipe); + pipe->create(true); + + QVERIFY(pipe->writeEnd().isValid()); + pipe->writeEnd().enable(); + QVERIFY(pipe->readEnd().isValid()); + pipe->readEnd().enable(); + + QSignalSpy readyReadSpy(&(pipe->readEnd()), &QCA::QPipeEnd::readyRead); + QVERIFY(readyReadSpy.isValid()); + QSignalSpy bytesWrittenSpy(&(pipe->writeEnd()), &QCA::QPipeEnd::bytesWritten); + QVERIFY(bytesWrittenSpy.isValid()); + QSignalSpy closedWriteSpy(&(pipe->writeEnd()), &QCA::QPipeEnd::closed); + QVERIFY(closedWriteSpy.isValid()); + QSignalSpy closedReadSpy(&(pipe->readEnd()), &QCA::QPipeEnd::closed); + QVERIFY(closedReadSpy.isValid()); + + QCOMPARE(readyReadSpy.count(), 0); + QCOMPARE(bytesWrittenSpy.count(), 0); + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 0); + + QCA::SecureArray data("Far better, it is, to dare mighty things"); + pipe->writeEnd().writeSecure(data); + QTest::qWait(1); + QTest::qWait(1); + QCOMPARE(readyReadSpy.count(), 1); + QCOMPARE(bytesWrittenSpy.count(), 1); + // this pulls out the first argument to the first signal as an integer + QCOMPARE(bytesWrittenSpy.takeFirst().at(0).toInt(), data.size()); + QCOMPARE(pipe->readEnd().bytesAvailable(), data.size()); + + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 0); + + pipe->readEnd().close(); + QTest::qWait(1); + QCOMPARE(closedWriteSpy.count(), 0); + QCOMPARE(closedReadSpy.count(), 1); + pipe->writeEnd().close(); + QTest::qWait(1); + QCOMPARE(closedWriteSpy.count(), 1); + QCOMPARE(closedReadSpy.count(), 1); +} + +QTEST_MAIN(PipeUnitTest) + +#include "pipeunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/pkits/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/pkits/CMakeLists.txt new file mode 100644 index 0000000000..d9b7181ad8 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pkits/CMakeLists.txt @@ -0,0 +1,35 @@ +ENABLE_TESTING() + +set(pkits_bin_SRCS pkits.cpp) + +add_executable(pkits ${pkits_bin_SRCS} ) + +target_link_qca_test_libraries(pkits) + + +FOREACH( testFileName BadnotAfterDateCACert.crt RFC3280MandatoryAttributeTypesCACRL.crl BadnotAfterDateCACRL.crl + RFC3280OptionalAttributeTypesCACert.crt BadnotBeforeDateCACert.crt RFC3280OptionalAttributeTypesCACRL.crl + BadnotBeforeDateCACRL.crl RolloverfromPrintableStringtoUTF8StringCACert.crt BadSignedCACert.crt + RolloverfromPrintableStringtoUTF8StringCACRL.crl BadSignedCACRL.crl TrustAnchorRootCertificate.crt + DSACACert.crt TrustAnchorRootCRL.crl DSACACRL.crl UIDCACert.crt DSAParametersInheritedCACert.crt + UIDCACRL.crl DSAParametersInheritedCACRL.crl UTF8StringCaseInsensitiveMatchCACert.crt + GoodCACert.crt UTF8StringCaseInsensitiveMatchCACRL.crl GoodCACRL.crl UTF8StringEncodedNamesCACert.crt + InvalidCAnotAfterDateTest5EE.crt UTF8StringEncodedNamesCACRL.crl InvalidCAnotBeforeDateTest1EE.crt + ValidCertificatePathTest1EE.crt InvalidCASignatureTest2EE.crt ValidDSAParameterInheritanceTest5EE.crt + InvalidDSASignatureTest6EE.crt ValidDSASignaturesTest4EE.crt + InvalidEEnotAfterDateTest6EE.crt ValidGeneralizedTimenotAfterDateTest8EE.crt + InvalidEEnotBeforeDateTest2EE.crt ValidGeneralizedTimenotBeforeDateTest4EE.crt + InvalidEESignatureTest3EE.crt ValidNameChainingCapitalizationTest5EE.crt + InvalidMissingCRLTest1EE.crt ValidNameChainingWhitespaceTest3EE.crt + InvalidNameChainingOrderTest2EE.crt ValidNameChainingWhitespaceTest4EE.crt + InvalidNameChainingTest1EE.crt ValidNameUIDsTest6EE.crt + Invalidpre2000UTCEEnotAfterDateTest7EE.crt Validpre2000UTCnotBeforeDateTest3EE.crt + InvalidRevokedCATest2EE.crt ValidRFC3280MandatoryAttributeTypesTest7EE.crt + InvalidRevokedEETest3EE.crt ValidRFC3280OptionalAttributeTypesTest8EE.crt + NoCRLCACert.crt ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt + RevokedsubCACert.crt ValidUTF8StringCaseInsensitiveMatchTest11EE.crt + RevokedsubCACRL.crl ValidUTF8StringEncodedNamesTest9EE.crt RFC3280MandatoryAttributeTypesCACert.crt ) + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/certs/${testFileName} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/certs/${testFileName} COPYONLY) +ENDFOREACH( testFileName ) + +add_qca_test(pkits "PublicKeyInfrastructure") diff --git a/local/recipes/libs/qca/source/unittest/pkits/README b/local/recipes/libs/qca/source/unittest/pkits/README new file mode 100644 index 0000000000..450516ed50 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pkits/README @@ -0,0 +1,8 @@ +This directory holds PKITS (PKI Test Suite). + +The certificates and CRLs used for the tests are made by the +NIST (http://csrc.nist.gov/groups/ST/crypto_apps_infra/pki/pkitesting.html), +if the certificates are expired (for i.e.: This lib is still used after 10 +years again), you can download the certificates on the NIST's website. + +- PKITS v1.0.1, posted on 2011. diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACRL.crl new file mode 100644 index 0000000000..f7d0c8030a Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACert.crt new file mode 100644 index 0000000000..0a598fcb8e Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadSignedCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACRL.crl new file mode 100644 index 0000000000..21f7c815e5 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACert.crt new file mode 100644 index 0000000000..7a7dcec665 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotAfterDateCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACRL.crl new file mode 100644 index 0000000000..24f368640e Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACert.crt new file mode 100644 index 0000000000..33cfbd7ce8 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/BadnotBeforeDateCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACRL.crl new file mode 100644 index 0000000000..369b597627 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACert.crt new file mode 100644 index 0000000000..14787b0580 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/DSACACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACRL.crl new file mode 100644 index 0000000000..9b5c377a31 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACert.crt new file mode 100644 index 0000000000..5e2fa5bc92 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/DSAParametersInheritedCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACRL.crl new file mode 100644 index 0000000000..d46110c5cf Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACert.crt new file mode 100644 index 0000000000..edbfa648f2 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/GoodCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCASignatureTest2EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCASignatureTest2EE.crt new file mode 100644 index 0000000000..1f4ad3e1a1 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCASignatureTest2EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotAfterDateTest5EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotAfterDateTest5EE.crt new file mode 100644 index 0000000000..a9938aa80e Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotAfterDateTest5EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotBeforeDateTest1EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotBeforeDateTest1EE.crt new file mode 100644 index 0000000000..f15d6a9ed2 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidCAnotBeforeDateTest1EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidDSASignatureTest6EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidDSASignatureTest6EE.crt new file mode 100644 index 0000000000..a1725b19da Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidDSASignatureTest6EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEESignatureTest3EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEESignatureTest3EE.crt new file mode 100644 index 0000000000..9238109b64 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEESignatureTest3EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotAfterDateTest6EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotAfterDateTest6EE.crt new file mode 100644 index 0000000000..af6fdf8c5a Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotAfterDateTest6EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotBeforeDateTest2EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotBeforeDateTest2EE.crt new file mode 100644 index 0000000000..3ddef09cab Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidEEnotBeforeDateTest2EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidMissingCRLTest1EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidMissingCRLTest1EE.crt new file mode 100644 index 0000000000..30b0275903 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidMissingCRLTest1EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingOrderTest2EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingOrderTest2EE.crt new file mode 100644 index 0000000000..6b7d7de29c Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingOrderTest2EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingTest1EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingTest1EE.crt new file mode 100644 index 0000000000..ee18fa08fb Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidNameChainingTest1EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedCATest2EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedCATest2EE.crt new file mode 100644 index 0000000000..8054597114 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedCATest2EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedEETest3EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedEETest3EE.crt new file mode 100644 index 0000000000..455cb0240c Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/InvalidRevokedEETest3EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt new file mode 100644 index 0000000000..4a7e31caf0 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/NoCRLCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/NoCRLCACert.crt new file mode 100644 index 0000000000..71c607dac4 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/NoCRLCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACRL.crl new file mode 100644 index 0000000000..f68a34557c Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACert.crt new file mode 100644 index 0000000000..9c648a30be Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280MandatoryAttributeTypesCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACRL.crl new file mode 100644 index 0000000000..102aad68b7 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACert.crt new file mode 100644 index 0000000000..306303a846 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RFC3280OptionalAttributeTypesCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACRL.crl new file mode 100644 index 0000000000..d5346166d8 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACert.crt new file mode 100644 index 0000000000..25705b2f67 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RevokedsubCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACRL.crl new file mode 100644 index 0000000000..17a3f74124 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt new file mode 100644 index 0000000000..32ddfe3e31 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCRL.crl new file mode 100644 index 0000000000..f6245e4a62 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCertificate.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCertificate.crt new file mode 100644 index 0000000000..04efaa0659 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/TrustAnchorRootCertificate.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACRL.crl new file mode 100644 index 0000000000..76fca88ed9 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACert.crt new file mode 100644 index 0000000000..ec04d74455 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UIDCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACRL.crl new file mode 100644 index 0000000000..4b18abe0f5 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACert.crt new file mode 100644 index 0000000000..2d653ef65b Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringCaseInsensitiveMatchCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACRL.crl b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACRL.crl new file mode 100644 index 0000000000..4411276786 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACRL.crl differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACert.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACert.crt new file mode 100644 index 0000000000..ae2ce8a7b4 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/UTF8StringEncodedNamesCACert.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidCertificatePathTest1EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidCertificatePathTest1EE.crt new file mode 100644 index 0000000000..69ba3019d4 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidCertificatePathTest1EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSAParameterInheritanceTest5EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSAParameterInheritanceTest5EE.crt new file mode 100644 index 0000000000..d8b6ce36d0 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSAParameterInheritanceTest5EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSASignaturesTest4EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSASignaturesTest4EE.crt new file mode 100644 index 0000000000..2fc40a6c2f Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidDSASignaturesTest4EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt new file mode 100644 index 0000000000..f97ed0a3e9 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt new file mode 100644 index 0000000000..2ef73e1f69 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingCapitalizationTest5EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingCapitalizationTest5EE.crt new file mode 100644 index 0000000000..c0a6b3d03e Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingCapitalizationTest5EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest3EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest3EE.crt new file mode 100644 index 0000000000..fc0f65d079 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest3EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest4EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest4EE.crt new file mode 100644 index 0000000000..a8ffc872ca Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameChainingWhitespaceTest4EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameUIDsTest6EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameUIDsTest6EE.crt new file mode 100644 index 0000000000..7d0b706113 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidNameUIDsTest6EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt new file mode 100644 index 0000000000..15825d7eb3 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt new file mode 100644 index 0000000000..60a2031681 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt new file mode 100644 index 0000000000..0a4e150700 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt new file mode 100644 index 0000000000..d1f80a74a4 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringEncodedNamesTest9EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringEncodedNamesTest9EE.crt new file mode 100644 index 0000000000..b14d789b5d Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/ValidUTF8StringEncodedNamesTest9EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/certs/Validpre2000UTCnotBeforeDateTest3EE.crt b/local/recipes/libs/qca/source/unittest/pkits/certs/Validpre2000UTCnotBeforeDateTest3EE.crt new file mode 100644 index 0000000000..15b2928401 Binary files /dev/null and b/local/recipes/libs/qca/source/unittest/pkits/certs/Validpre2000UTCnotBeforeDateTest3EE.crt differ diff --git a/local/recipes/libs/qca/source/unittest/pkits/pkits.cpp b/local/recipes/libs/qca/source/unittest/pkits/pkits.cpp new file mode 100644 index 0000000000..adee2eabc3 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/pkits/pkits.cpp @@ -0,0 +1,1158 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class Pkits : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + + void pkits4_1_1(); + void pkits4_1_2(); + void pkits4_1_3(); + void pkits4_1_4(); + void pkits4_1_5(); + void pkits4_1_6(); + + void pkits4_2_1(); + void pkits4_2_2(); + void pkits4_2_3(); + void pkits4_2_4(); + void pkits4_2_5(); + void pkits4_2_6(); + void pkits4_2_7(); + void pkits4_2_8(); + + void pkits4_3_1(); + void pkits4_3_2(); + void pkits4_3_3(); + void pkits4_3_4(); + void pkits4_3_5(); + void pkits4_3_6(); + void pkits4_3_9(); +#ifdef ALL_PKITS_TESTS + void pkits4_3_7(); + void pkits4_3_8(); + void pkits4_3_10(); + void pkits4_3_11(); +#endif + void pkits4_4_1(); + void pkits4_4_2(); + void pkits4_4_3(); + + void cleanupTestCase(); + +private: + QCA::Initializer *m_init; +}; + +void Pkits::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void Pkits::cleanupTestCase() +{ + delete m_init; +} + +static QCA::Certificate certFromDERFile(const QString &fileName, const QString &provider) +{ + QFile certFile(fileName); + certFile.open(QFile::ReadOnly); + QByteArray certArray = certFile.readAll(); + QCA::ConvertResult resultCert; + QCA::Certificate cert = QCA::Certificate::fromDER(certArray, &resultCert, provider); + return cert; +} + +static QCA::CRL crlFromDERFile(const QString &fileName, const QString &provider) +{ + QFile crlFile(fileName); + crlFile.open(QFile::ReadOnly); + QByteArray crlArray = crlFile.readAll(); + QCA::ConvertResult crlResult; + QCA::CRL crl = QCA::CRL::fromDER(crlArray, &crlResult, provider); + return crl; +} + +void Pkits::pkits4_1_1() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/ValidCertificatePathTest1EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCOMPARE(cert.policies().count(), 1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_1_2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidCASignatureTest2EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCOMPARE(cert.policies().count(), 1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/BadSignedCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/BadSignedCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorSignatureFailed); + } + } +} + +void Pkits::pkits4_1_3() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidEESignatureTest3EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCOMPARE(cert.policies().count(), 1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorSignatureFailed); + } + } +} + +void Pkits::pkits4_1_4() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/ValidDSASignaturesTest4EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCOMPARE(cert.policies().count(), 1); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/DSACACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/DSACACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_1_5() +{ + // openssl has decided that they don't want to support this ¯\_(ツ)_/¯ + // https://github.com/openssl/openssl/issues/20233 +#if 0 + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidDSAParameterInheritanceTest5EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + // QCOMPARE( cert.policies().count(), 1 ); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/DSACACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/DSACACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCA::Certificate params = + certFromDERFile(QStringLiteral("certs/DSAParametersInheritedCACert.crt"), provider); + QCOMPARE(params.isNull(), false); + untrusted.addCertificate(params); + QCA::CRL paramsCRL = crlFromDERFile(QStringLiteral("certs/DSAParametersInheritedCACRL.crl"), provider); + QCOMPARE(paramsCRL.isNull(), false); + untrusted.addCRL(paramsCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +#endif +} + +void Pkits::pkits4_1_6() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidDSASignatureTest6EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/DSACACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/DSACACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorSignatureFailed); + } + } +} + +void Pkits::pkits4_2_1() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/InvalidCAnotBeforeDateTest1EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/BadnotBeforeDateCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/BadnotBeforeDateCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorExpired); + } + } +} + +void Pkits::pkits4_2_2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/InvalidEEnotBeforeDateTest2EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorExpired); + } + } +} + +void Pkits::pkits4_2_3() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/Validpre2000UTCnotBeforeDateTest3EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_2_4() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_2_5() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidCAnotAfterDateTest5EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/BadnotAfterDateCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/BadnotAfterDateCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorExpired); + } + } +} + +void Pkits::pkits4_2_6() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidEEnotAfterDateTest6EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorExpired); + } + } +} + +void Pkits::pkits4_2_7() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorExpired); + } + } +} + +void Pkits::pkits4_2_8() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidGeneralizedTimenotAfterDateTest8EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_3_1() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidNameChainingTest1EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + } + } +} + +void Pkits::pkits4_3_2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/InvalidNameChainingOrderTest2EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + } + } +} + +void Pkits::pkits4_3_3() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidNameChainingWhitespaceTest3EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_3_4() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidNameChainingWhitespaceTest4EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_3_5() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidNameChainingCapitalizationTest5EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +void Pkits::pkits4_3_6() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/ValidNameUIDsTest6EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/UIDCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/UIDCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +#ifdef ALL_PKITS_TESTS +void Pkits::pkits4_3_7() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = + certFromDERFile(QStringLiteral("certs/RFC3280MandatoryAttributeTypesCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/RFC3280MandatoryAttributeTypesCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} +#endif + +#ifdef ALL_PKITS_TESTS +void Pkits::pkits4_3_8() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = + certFromDERFile(QStringLiteral("certs/RFC3280OptionalAttributeTypesCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/RFC3280OptionalAttributeTypesCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} +#endif + +void Pkits::pkits4_3_9() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidUTF8StringEncodedNamesTest9EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/UTF8StringEncodedNamesCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/UTF8StringEncodedNamesCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} + +#ifdef ALL_PKITS_TESTS +void Pkits::pkits4_3_10() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile( + QStringLiteral("certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = + certFromDERFile(QStringLiteral("certs/RolloverfromPrintableStringtoUTF8StringCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = + crlFromDERFile(QStringLiteral("certs/RolloverfromPrintableStringtoUTF8StringCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} +#endif + +#ifdef ALL_PKITS_TESTS +void Pkits::pkits4_3_11() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = + certFromDERFile(QStringLiteral("certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = + certFromDERFile(QStringLiteral("certs/UTF8StringCaseInsensitiveMatchCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/UTF8StringCaseInsensitiveMatchCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + qDebug() << "validity: " << cert.validate(trusted, untrusted); + + QEXPECT_FAIL("", "This should validate, but it doesn't (QCA::ErrorInvalidCA)", Continue); + QCOMPARE(cert.validate(trusted, untrusted), QCA::ValidityGood); + } + } +} +#endif + +void Pkits::pkits4_4_1() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidMissingCRLTest1EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/NoCRLCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + + qDebug() << "validity: " << cert.validate(trusted, untrusted); + + QEXPECT_FAIL("", "This should not validate, but it does", Continue); + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + } + } +} + +void Pkits::pkits4_4_2() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidRevokedCATest2EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + QCA::Certificate subca = certFromDERFile(QStringLiteral("certs/RevokedsubCACert.crt"), provider); + QCOMPARE(subca.isNull(), false); + untrusted.addCertificate(subca); + QCA::CRL subcaCRL = crlFromDERFile(QStringLiteral("certs/RevokedsubCACRL.crl"), provider); + QCOMPARE(subcaCRL.isNull(), false); + untrusted.addCRL(subcaCRL); + + qDebug() << "validity: " << cert.validate(trusted, untrusted); + + QEXPECT_FAIL("", "This should not validate, but it does", Continue); + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + } + } +} + +void Pkits::pkits4_4_3() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("cert", provider)) + QWARN((QStringLiteral("Certificate handling not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::Certificate cert = certFromDERFile(QStringLiteral("certs/InvalidRevokedEETest3EE.crt"), provider); + QCOMPARE(cert.isNull(), false); + + QCA::CertificateCollection trusted; + QCA::CertificateCollection untrusted; + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorInvalidCA); + + QCA::Certificate root = certFromDERFile(QStringLiteral("certs/TrustAnchorRootCertificate.crt"), provider); + QCOMPARE(root.isNull(), false); + trusted.addCertificate(root); + QCA::CRL rootCRL = crlFromDERFile(QStringLiteral("certs/TrustAnchorRootCRL.crl"), provider); + QCOMPARE(rootCRL.isNull(), false); + trusted.addCRL(rootCRL); + + QCA::Certificate ca = certFromDERFile(QStringLiteral("certs/GoodCACert.crt"), provider); + QCOMPARE(ca.isNull(), false); + untrusted.addCertificate(ca); + QCA::CRL caCRL = crlFromDERFile(QStringLiteral("certs/GoodCACRL.crl"), provider); + QCOMPARE(caCRL.isNull(), false); + untrusted.addCRL(caCRL); + + qDebug() << "validity: " << cert.validate(trusted, untrusted); + + QEXPECT_FAIL("", "This should not validate, but it does", Continue); + QCOMPARE(cert.validate(trusted, untrusted), QCA::ErrorUntrusted); + } + } +} + +QTEST_MAIN(Pkits) + +#include "pkits.moc" diff --git a/local/recipes/libs/qca/source/unittest/rsaunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/rsaunittest/CMakeLists.txt new file mode 100644 index 0000000000..708c7785cf --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/rsaunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(rsaunittest_bin_SRCS rsaunittest.cpp) + +add_executable(rsaunittest ${rsaunittest_bin_SRCS} ) + +target_link_qca_test_libraries(rsaunittest) + +add_qca_test(rsaunittest "RSA") diff --git a/local/recipes/libs/qca/source/unittest/rsaunittest/rsaunittest.cpp b/local/recipes/libs/qca/source/unittest/rsaunittest/rsaunittest.cpp new file mode 100644 index 0000000000..7bf1dafb32 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/rsaunittest/rsaunittest.cpp @@ -0,0 +1,220 @@ +/** + * Copyright (C) 2005-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class RSAUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testrsa(); + void testAsymmetricEncryption_data(); + void testAsymmetricEncryption(); + +private: + QCA::Initializer *m_init; +}; + +void RSAUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void RSAUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void RSAUnitTest::testrsa() +{ + QStringList providersToTest; + providersToTest.append(QStringLiteral("qca-ossl")); + // providersToTest.append("qca-gcrypt"); + + foreach (const QString provider, providersToTest) { + if (!QCA::isSupported("pkey", provider) || !QCA::PKey::supportedTypes(provider).contains(QCA::PKey::RSA) || + !QCA::PKey::supportedIOTypes(provider).contains(QCA::PKey::RSA)) + QWARN((QStringLiteral("RSA not supported for ") + provider).toLocal8Bit().constData()); + else { + QCA::KeyGenerator keygen; + QCOMPARE(keygen.isBusy(), false); + QCOMPARE(keygen.blockingEnabled(), true); + + QList keySizes; + keySizes << 512 << 1024 << 768 << 2048; + foreach (int keysize, keySizes) { + QCA::PrivateKey rsaKey = keygen.createRSA(keysize, 65537, provider); + QCOMPARE(rsaKey.isNull(), false); + QCOMPARE(rsaKey.isRSA(), true); + QCOMPARE(rsaKey.isDSA(), false); + QCOMPARE(rsaKey.isDH(), false); + QCOMPARE(rsaKey.isPrivate(), true); + QCOMPARE(rsaKey.isPublic(), false); + QCOMPARE(rsaKey.canSign(), true); + QCOMPARE(rsaKey.canDecrypt(), true); + QCOMPARE(rsaKey.canEncrypt(), true); + + QCA::RSAPrivateKey rsaPrivKey = rsaKey.toRSA(); + QCOMPARE(rsaPrivKey.bitSize(), keysize); + + QString rsaPEM = rsaKey.toPEM(); + QCOMPARE(rsaPEM.isEmpty(), false); + + QCA::ConvertResult checkResult; + QCA::PrivateKey fromPEMkey = QCA::PrivateKey::fromPEM(rsaPEM, QCA::SecureArray(), &checkResult); + QCOMPARE(checkResult, QCA::ConvertGood); + QCOMPARE(fromPEMkey.isNull(), false); + QCOMPARE(fromPEMkey.isRSA(), true); + QCOMPARE(fromPEMkey.isDSA(), false); + QCOMPARE(fromPEMkey.isDH(), false); + QCOMPARE(fromPEMkey.isPrivate(), true); + QCOMPARE(fromPEMkey.isPublic(), false); + QCOMPARE(rsaKey == fromPEMkey, true); + + QCA::SecureArray rsaDER = rsaKey.toDER(QCA::SecureArray("foo")); + QCOMPARE(rsaDER.isEmpty(), false); + + QCA::PrivateKey fromDERkey = QCA::PrivateKey::fromDER(rsaDER, QCA::SecureArray("foo"), &checkResult); + QCOMPARE(checkResult, QCA::ConvertGood); + QCOMPARE(fromDERkey.isNull(), false); + QCOMPARE(fromDERkey.isRSA(), true); + QCOMPARE(fromDERkey.isDSA(), false); + QCOMPARE(fromDERkey.isDH(), false); + QCOMPARE(fromDERkey.isPrivate(), true); + QCOMPARE(fromDERkey.isPublic(), false); + QCOMPARE(rsaKey == fromDERkey, true); + + // same test, without passphrase + rsaDER = rsaKey.toDER(); + QCOMPARE(rsaDER.isEmpty(), false); + + fromDERkey = QCA::PrivateKey::fromDER(rsaDER, QCA::SecureArray(), &checkResult); + QCOMPARE(checkResult, QCA::ConvertGood); + QCOMPARE(fromDERkey.isNull(), false); + QCOMPARE(fromDERkey.isRSA(), true); + QCOMPARE(fromDERkey.isDSA(), false); + QCOMPARE(fromDERkey.isDH(), false); + QCOMPARE(fromDERkey.isPrivate(), true); + QCOMPARE(fromDERkey.isPublic(), false); + QCOMPARE(rsaKey == fromDERkey, true); + + QCA::PublicKey pubKey = rsaKey.toPublicKey(); + QCOMPARE(pubKey.isNull(), false); + QCOMPARE(pubKey.isRSA(), true); + QCOMPARE(pubKey.isDSA(), false); + QCOMPARE(pubKey.isDH(), false); + QCOMPARE(pubKey.isPrivate(), false); + QCOMPARE(pubKey.isPublic(), true); + + QCA::RSAPublicKey RSApubKey = pubKey.toRSA(); + QCOMPARE(RSApubKey.e(), QCA::BigInteger(65537)); + QCOMPARE(RSApubKey.isNull(), false); + QCOMPARE(RSApubKey.isRSA(), true); + QCOMPARE(RSApubKey.isDSA(), false); + QCOMPARE(RSApubKey.isDH(), false); + QCOMPARE(RSApubKey.isPrivate(), false); + QCOMPARE(RSApubKey.isPublic(), true); + } + } + } +} + +Q_DECLARE_METATYPE(QCA::EncryptionAlgorithm) + +void RSAUnitTest::testAsymmetricEncryption_data() +{ + QTest::addColumn("algorithm"); + QTest::addColumn("errorOnFailure"); + QTest::addColumn("encryptWithPrivate"); + + QTest::newRow("PKCS1v15") << QCA::EME_PKCS1v15 << false << true; + QTest::newRow("PKCS1_OAEP") << QCA::EME_PKCS1_OAEP << true << false; +} + +void RSAUnitTest::testAsymmetricEncryption() +{ + if (!QCA::isSupported("pkey", QStringLiteral("qca-ossl")) || + !QCA::PKey::supportedTypes(QStringLiteral("qca-ossl")).contains(QCA::PKey::RSA) || + !QCA::PKey::supportedIOTypes(QStringLiteral("qca-ossl")).contains(QCA::PKey::RSA)) { + QWARN("RSA not supported"); + QSKIP("RSA not supported. skipping"); + } + + QFETCH(QCA::EncryptionAlgorithm, algorithm); + QFETCH(bool, errorOnFailure); + QFETCH(bool, encryptWithPrivate); + + QCA::RSAPrivateKey rsaPrivKey1 = QCA::KeyGenerator().createRSA(512, 65537, QStringLiteral("qca-ossl")).toRSA(); + QCA::RSAPublicKey rsaPubKey1 = rsaPrivKey1.toPublicKey().toRSA(); + + QCA::RSAPrivateKey rsaPrivKey2 = QCA::KeyGenerator().createRSA(512, 65537, QStringLiteral("qca-ossl")).toRSA(); + // QCA::RSAPublicKey rsaPubKey2 = rsaPrivKey2.toPublicKey().toRSA(); + + const QCA::SecureArray clearText = "Hello World !"; + QCA::SecureArray testText; + QCA::SecureArray cipherText; + + // Test keys #1: Enc with public, dec with private + QVERIFY(rsaPubKey1.maximumEncryptSize(algorithm) >= clearText.size()); + cipherText = rsaPubKey1.encrypt(clearText, algorithm); + QVERIFY(rsaPrivKey1.decrypt(cipherText, &testText, algorithm)); + QCOMPARE(clearText, testText); + testText.clear(); + // --- + + // Test keys #2 to decipher key #1 + const bool success = rsaPrivKey2.decrypt(cipherText, &testText, algorithm); + if (errorOnFailure) { + QVERIFY(!success); + QVERIFY(testText.isEmpty()); + } else { + QVERIFY(testText != clearText); + testText.clear(); + } + // --- + + if (encryptWithPrivate) { + // Test keys #2: Enc with private, dec with public + cipherText.clear(); + QVERIFY(rsaPrivKey1.maximumEncryptSize(algorithm) >= clearText.size()); + cipherText = rsaPrivKey1.encrypt(clearText, algorithm); + QVERIFY(rsaPubKey1.decrypt(cipherText, &testText, algorithm)); + QCOMPARE(clearText, testText); + testText.clear(); + // --- + } +} + +QTEST_MAIN(RSAUnitTest) + +#include "rsaunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/securearrayunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/securearrayunittest/CMakeLists.txt new file mode 100644 index 0000000000..2d088f0547 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/securearrayunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(securearrayunittest_bin_SRCS securearrayunittest.cpp) + +add_executable( securearrayunittest ${securearrayunittest_bin_SRCS} ) + +target_link_qca_test_libraries(securearrayunittest) + +add_qca_test(securearrayunittest "SecureArray") diff --git a/local/recipes/libs/qca/source/unittest/securearrayunittest/securearrayunittest.cpp b/local/recipes/libs/qca/source/unittest/securearrayunittest/securearrayunittest.cpp new file mode 100644 index 0000000000..8e3f8ae49b --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/securearrayunittest/securearrayunittest.cpp @@ -0,0 +1,147 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class SecureArrayUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testAll(); + +private: + QCA::Initializer *m_init; +}; + +void SecureArrayUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void SecureArrayUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void SecureArrayUnitTest::testAll() +{ + QCA::SecureArray emptyArray; + QCOMPARE(emptyArray.size(), 0); + QVERIFY(emptyArray.isEmpty()); + + QCA::SecureArray testArray(10); + QCOMPARE(testArray.size(), 10); + QCOMPARE(testArray.isEmpty(), false); + + QCA::SecureArray testArray64(64); + QCOMPARE(testArray64.size(), 64); + QCOMPARE(testArray64.isEmpty(), false); + + // testArray.fill( 'a' ); + for (int i = 0; i < testArray.size(); i++) { + testArray[i] = 0x61; + } + QCOMPARE(QCA::arrayToHex(testArray.toByteArray()), QStringLiteral("61616161616161616161")); + + testArray.fill('b'); + testArray[7] = 0x00; + QCOMPARE(QCA::arrayToHex(testArray.toByteArray()), QStringLiteral("62626262626262006262")); + + QByteArray byteArray(10, 'c'); + QCA::SecureArray secureArray(byteArray); + QCOMPARE(secureArray.size(), 10); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + byteArray.fill('d'); + // it should be a copy, so no effect + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + + QCA::SecureArray copyArray(secureArray); + QCOMPARE(QCA::arrayToHex(copyArray.toByteArray()), QStringLiteral("63636363636363636363")); + copyArray.fill(0x64); + QCOMPARE(QCA::arrayToHex(copyArray.toByteArray()), QStringLiteral("64646464646464646464")); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + + // test for detaching + QCA::SecureArray detachArray1 = secureArray; // currently the same + QCOMPARE(QCA::arrayToHex(detachArray1.toByteArray()), QStringLiteral("63636363636363636363")); + for (int i = 0; i < detachArray1.size(); i++) { + detachArray1[i] = 0x66; // implicit detach + } + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(QCA::arrayToHex(detachArray1.toByteArray()), QStringLiteral("66666666666666666666")); + + QCA::SecureArray detachArray2 = secureArray; // currently the same + QCOMPARE(QCA::arrayToHex(detachArray2.toByteArray()), QStringLiteral("63636363636363636363")); + // implicit detach + for (int i = 0; i < detachArray2.size(); i++) { + detachArray2.data()[i] = 0x67; + } + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(QCA::arrayToHex(detachArray2.toByteArray()), QStringLiteral("67676767676767676767")); + + QCA::SecureArray detachArray3 = secureArray; // implicitly shared copy + QCOMPARE(QCA::arrayToHex(detachArray3.toByteArray()), QStringLiteral("63636363636363636363")); + for (int i = 0; i < detachArray3.size(); i++) { + detachArray3.data()[i] = 0x68; + } + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(QCA::arrayToHex(detachArray3.toByteArray()), QStringLiteral("68686868686868686868")); + + // test for resizing + QCA::SecureArray resizeArray = emptyArray; + QCOMPARE(resizeArray.size(), 0); + resizeArray.resize(20); + QCOMPARE(resizeArray.size(), 20); + resizeArray.resize(40); + QCOMPARE(resizeArray.size(), 40); + resizeArray.resize(10); + QCOMPARE(resizeArray.size(), 10); + + // test for append + QCA::SecureArray appendArray = secureArray; + appendArray.append(QCA::SecureArray()); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QCA::arrayToHex(appendArray.toByteArray())); + appendArray.append(secureArray); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(QCA::arrayToHex(appendArray.toByteArray()), QStringLiteral("6363636363636363636363636363636363636363")); + QCA::SecureArray appendArray2 = secureArray; + QCOMPARE(QCA::arrayToHex(appendArray2.append(secureArray).toByteArray()), + QStringLiteral("6363636363636363636363636363636363636363")); + + // test for a possible problem with operator[] + QVERIFY((secureArray[0] == (char)0x63)); +} + +QTEST_MAIN(SecureArrayUnitTest) + +#include "securearrayunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/staticunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/staticunittest/CMakeLists.txt new file mode 100644 index 0000000000..027e4d03c9 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/staticunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(staticunittest_bin_SRCS staticunittest.cpp) + +add_executable( staticunittest ${staticunittest_bin_SRCS} ) + +target_link_qca_test_libraries(staticunittest) + +add_qca_test(staticunittest "StaticFunctions") diff --git a/local/recipes/libs/qca/source/unittest/staticunittest/staticunittest.cpp b/local/recipes/libs/qca/source/unittest/staticunittest/staticunittest.cpp new file mode 100644 index 0000000000..d65452d2ab --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/staticunittest/staticunittest.cpp @@ -0,0 +1,116 @@ +/** + * Copyright (C) 2004-2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class StaticUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void hexConversions(); + void capabilities(); + void secureMemory(); + +private: + QCA::Initializer *m_init; +}; + +void StaticUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void StaticUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void StaticUnitTest::hexConversions() +{ + QByteArray test(10, 'a'); + + QCOMPARE(QCA::arrayToHex(test), QStringLiteral("61616161616161616161")); + + test.fill('b'); + test[7] = 0x00; + + QCOMPARE(test == QCA::hexToArray(QStringLiteral("62626262626262006262")), true); + + QCA::SecureArray testArray(10); + // testArray.fill( 'a' ); + for (int i = 0; i < testArray.size(); i++) { + testArray[i] = 0x61; + } + QCOMPARE(QCA::arrayToHex(testArray.toByteArray()), QStringLiteral("61616161616161616161")); + // testArray.fill( 'b' ); + for (int i = 0; i < testArray.size(); i++) { + testArray[i] = 0x62; + } + testArray[6] = 0x00; + QCOMPARE(testArray == QCA::hexToArray(QStringLiteral("62626262626200626262")), true); + + QCOMPARE(testArray == QCA::hexToArray(QCA::arrayToHex(testArray.toByteArray())), true); + + testArray[9] = 0x00; + QCOMPARE(testArray == QCA::hexToArray(QCA::arrayToHex(testArray.toByteArray())), true); +} + +void StaticUnitTest::capabilities() +{ + // capabilities are reported as a list - that is a problem for + // doing a direct comparison, since they change + // We try to work around that using contains() + QStringList defaultCapabilities = QCA::defaultFeatures(); + QVERIFY(defaultCapabilities.contains(QStringLiteral("random"))); + QVERIFY(defaultCapabilities.contains(QStringLiteral("sha1"))); + QVERIFY(defaultCapabilities.contains(QStringLiteral("md5"))); + + QStringList capList; + capList << QStringLiteral("random") << QStringLiteral("sha1"); + QCOMPARE(QCA::isSupported(capList), true); + capList.append(QStringLiteral("noSuch")); + QCOMPARE(QCA::isSupported(capList), false); + capList.clear(); + capList.append(QStringLiteral("noSuch")); + QCOMPARE(QCA::isSupported(capList), false); +} + +void StaticUnitTest::secureMemory() +{ + // this should be reliably true + QCOMPARE(QCA::haveSecureMemory(), true); +} + +QTEST_MAIN(StaticUnitTest) + +#include "staticunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/CMakeLists.txt new file mode 100644 index 0000000000..f7d1f52740 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(symmetrickeyunittest_bin_SRCS symmetrickeyunittest.cpp) + +add_executable( symmetrickeyunittest ${symmetrickeyunittest_bin_SRCS} ) + +target_link_qca_test_libraries(symmetrickeyunittest) + +add_qca_test(symmetrickeyunittest "SymmetricKey") diff --git a/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/symmetrickeyunittest.cpp b/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/symmetrickeyunittest.cpp new file mode 100644 index 0000000000..2052b220a0 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/symmetrickeyunittest/symmetrickeyunittest.cpp @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2004, 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class SymmetricKeyUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void test1(); + void weakKey_data(); + void weakKey(); + +private: + QCA::Initializer *m_init; +}; + +void SymmetricKeyUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void SymmetricKeyUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void SymmetricKeyUnitTest::test1() +{ + QCA::SymmetricKey emptyKey; + QCOMPARE(emptyKey.size(), 0); + + QCA::SymmetricKey randomKey(10); + QCOMPARE(randomKey.size(), 10); + + QByteArray byteArray(10, 'c'); + QCA::SecureArray secureArray(byteArray); + QCA::SymmetricKey keyArray = secureArray; + QCOMPARE(secureArray.size(), 10); + QCOMPARE(keyArray.size(), secureArray.size()); + QCOMPARE(QCA::arrayToHex(keyArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + keyArray[3] = 0x00; // test keyArray detaches OK + QCOMPARE(QCA::arrayToHex(keyArray.toByteArray()), QStringLiteral("63636300636363636363")); + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + + QCA::SymmetricKey anotherKey; + anotherKey = keyArray; + QCOMPARE(QCA::arrayToHex(anotherKey.toByteArray()), QStringLiteral("63636300636363636363")); + QCA::SymmetricKey bigKey(100); + anotherKey = bigKey; + QCOMPARE(anotherKey.size(), 100); + anotherKey = secureArray; + QCOMPARE(QCA::arrayToHex(secureArray.toByteArray()), QStringLiteral("63636363636363636363")); + QCOMPARE(anotherKey.size(), 10); + anotherKey = emptyKey; + QCOMPARE(anotherKey.size(), 0); +} + +// These are from the Botan test suite +void SymmetricKeyUnitTest::weakKey_data() +{ + QTest::addColumn("keyText"); + QTest::addColumn("isWeak"); + + QTest::newRow("") << QByteArray("ffffffffffffffff") << true; + QTest::newRow("") << QByteArray("0000000000000000") << true; + QTest::newRow("") << QByteArray("d5d44ff720683d0d") << false; + QTest::newRow("") << QByteArray("d5d44ff720683d0d") << false; + QTest::newRow("") << QByteArray("1046913489980131") << false; + QTest::newRow("") << QByteArray("1007103489988020") << false; + QTest::newRow("") << QByteArray("10071034c8980120") << false; + QTest::newRow("") << QByteArray("1046103489988020") << false; +} + +void SymmetricKeyUnitTest::weakKey() +{ + QFETCH(QByteArray, keyText); + QFETCH(bool, isWeak); + + QCA::SymmetricKey key(QCA::hexToArray(QString::fromLatin1(keyText))); + QCOMPARE(key.isWeakDESKey(), isWeak); +} + +QTEST_MAIN(SymmetricKeyUnitTest) + +#include "symmetrickeyunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA.pl b/local/recipes/libs/qca/source/unittest/testcerts/CA.pl new file mode 100755 index 0000000000..e78b60f338 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA.pl @@ -0,0 +1,189 @@ +#!/usr/bin/perl +# +# CA - wrapper around ca to make it easier to use ... basically ca requires +# some setup stuff to be done before you can use it and this makes +# things easier between now and when Eric is convinced to fix it :-) +# +# CA -newca ... will setup the right stuff +# CA -newreq[-nodes] ... will generate a certificate request +# CA -sign ... will sign the generated request and output +# +# At the end of that grab newreq.pem and newcert.pem (one has the key +# and the other the certificate) and cat them together and that is what +# you want/need ... I'll make even this a little cleaner later. +# +# +# 12-Jan-96 tjh Added more things ... including CA -signcert which +# converts a certificate to a request and then signs it. +# 10-Jan-96 eay Fixed a few more bugs and added the SSLEAY_CONFIG +# environment variable so this can be driven from +# a script. +# 25-Jul-96 eay Cleaned up filenames some more. +# 11-Jun-96 eay Fixed a few filename missmatches. +# 03-May-96 eay Modified to use 'ssleay cmd' instead of 'cmd'. +# 18-Apr-96 tjh Original hacking +# +# Tim Hudson +# tjh@cryptsoft.com +# + +# 27-Apr-98 snh Translation into perl, fix existing CA bug. +# +# +# Steve Henson +# shenson@bigfoot.com + +# default openssl.cnf file has setup as per the following +# demoCA ... where everything is stored + +my $openssl; +if(defined $ENV{OPENSSL}) { + $openssl = $ENV{OPENSSL}; +} else { + $openssl = "openssl"; + $ENV{OPENSSL} = $openssl; +} + +#$SSLEAY_CONFIG=$ENV{"SSLEAY_CONFIG"}; +$DAYS="-days 3650"; # 10 years +$CADAYS="-days 2000"; # ~6 years +$REQ="$openssl req -config ./openssl.cnf"; +$CA="$openssl ca -config ./openssl.cnf"; +$VERIFY="$openssl verify"; +$X509="$openssl x509"; +$PKCS12="$openssl pkcs12"; + +$CATOP="./CA"; +$CAKEY="cakey.pem"; +$CAREQ="careq.pem"; +$CACERT="cacert.pem"; + +$DIRMODE = 0777; + +$RET = 0; + +foreach (@ARGV) { + if ( /^(-\?|-h|-help)$/ ) { + print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n"; + exit 0; + } elsif (/^-newcert$/) { + # create a certificate + system ("$REQ -new -x509 -keyout newkey.pem -out newcert.pem $DAYS"); + $RET=$?; + print "Certificate is in newcert.pem, private key is in newkey.pem\n" + } elsif (/^-newreq$/) { + # create a certificate request + system ("$REQ -new -keyout newkey.pem -out newreq.pem $DAYS"); + $RET=$?; + print "Request is in newreq.pem, private key is in newkey.pem\n"; + } elsif (/^-newreq-nodes$/) { + # create a certificate request + system ("$REQ -new -nodes -keyout newkey.pem -out newreq.pem $DAYS"); + $RET=$?; + print "Request is in newreq.pem, private key is in newkey.pem\n"; + } elsif (/^-newca$/) { + # if explicitly asked for or it doesn't exist then setup the + # directory structure that Eric likes to manage things + $NEW="1"; + if ( "$NEW" || ! -f "${CATOP}/serial" ) { + # create the directory hierarchy + mkdir $CATOP, $DIRMODE; + mkdir "${CATOP}/certs", $DIRMODE; + mkdir "${CATOP}/crl", $DIRMODE ; + mkdir "${CATOP}/newcerts", $DIRMODE; + mkdir "${CATOP}/private", $DIRMODE; + open OUT, ">${CATOP}/index.txt"; + close OUT; + open OUT, ">${CATOP}/crlnumber"; + print OUT "01\n"; + close OUT; + } + if ( ! -f "${CATOP}/private/$CAKEY" ) { + print "CA certificate filename (or enter to create)\n"; + $FILE = ; + + chop $FILE; + + # ask user for existing CA certificate + if ($FILE) { + cp_pem($FILE,"${CATOP}/private/$CAKEY", "PRIVATE"); + cp_pem($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); + $RET=$?; + } else { + print "Making CA certificate ...\n"; + system ("$REQ -new -keyout " . + "${CATOP}/private/$CAKEY -out ${CATOP}/$CAREQ"); + system ("$CA -create_serial " . + "-out ${CATOP}/$CACERT $CADAYS -batch " . + "-keyfile ${CATOP}/private/$CAKEY -selfsign " . + "-extensions v3_ca " . + "-infiles ${CATOP}/$CAREQ "); + $RET=$?; + } + } + } elsif (/^-pkcs12$/) { + my $cname = $ARGV[1]; + $cname = "My Certificate" unless defined $cname; + system ("$PKCS12 -in newcert.pem -inkey newkey.pem " . + "-certfile ${CATOP}/$CACERT -out newcert.p12 " . + "-export -name \"$cname\""); + $RET=$?; + print "PKCS #12 file is in newcert.p12\n"; + exit $RET; + } elsif (/^-xsign$/) { + system ("$CA -policy policy_anything -infiles newreq.pem"); + $RET=$?; + } elsif (/^(-sign|-signreq)$/) { + system ("$CA -policy policy_anything -out newcert.pem " . + "-infiles newreq.pem"); + $RET=$?; + print "Signed certificate is in newcert.pem\n"; + } elsif (/^(-signCA)$/) { + system ("$CA -policy policy_anything -out newcert.pem " . + "-extensions v3_ca -infiles newreq.pem"); + $RET=$?; + print "Signed CA certificate is in newcert.pem\n"; + } elsif (/^-signcert$/) { + system ("$X509 -x509toreq -in newreq.pem -signkey newreq.pem " . + "-out tmp.pem"); + system ("$CA -policy policy_anything -out newcert.pem " . + "-infiles tmp.pem"); + $RET = $?; + print "Signed certificate is in newcert.pem\n"; + } elsif (/^-verify$/) { + if (shift) { + foreach $j (@ARGV) { + system ("$VERIFY -CAfile $CATOP/$CACERT $j"); + $RET=$? if ($? != 0); + } + exit $RET; + } else { + system ("$VERIFY -CAfile $CATOP/$CACERT newcert.pem"); + $RET=$?; + exit 0; + } + } else { + print STDERR "Unknown arg $_\n"; + print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n"; + exit 1; + } +} + +exit $RET; + +sub cp_pem { +my ($infile, $outfile, $bound) = @_; +open IN, $infile; +open OUT, ">$outfile"; +my $flag = 0; +while () { + $flag = 1 if (/^-----BEGIN.*$bound/) ; + print OUT $_ if ($flag); + if (/^-----END.*$bound/) { + close IN; + close OUT; + return; + } +} +} + diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/cacert.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/cacert.pem new file mode 100644 index 0000000000..933e82f79c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/cacert.pem @@ -0,0 +1,83 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b6:7b:e8:90:4d:70:7d:7f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 22 01:48:15 2007 GMT + Not After : Jan 11 01:48:15 2013 GMT + Subject: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a1:a2:3e:9e:53:de:98:2c:2f:9e:fa:12:fa:54: + 6c:0a:0a:e8:23:f4:25:86:24:da:ed:6f:18:e2:6e: + 1e:ae:36:4e:45:63:0d:5b:20:aa:09:70:55:b9:a1: + 08:e3:cb:3d:e3:c3:ca:34:c3:c7:90:30:50:51:d6: + 30:b3:3f:12:70:99:ae:2d:c8:2e:ea:c6:c6:43:e5: + 9f:30:ab:e3:5b:d9:b0:91:92:c2:94:79:79:9b:87: + 05:60:01:8c:f1:0e:75:f7:82:d6:f9:e6:fb:45:b8: + 4d:53:eb:66:a0:98:93:28:d7:1e:db:43:3d:84:9b: + 2b:1f:ee:af:d8:23:b5:a1:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + X509v3 Authority Key Identifier: + keyid:51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + DirName:/C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + serial:B6:7B:E8:90:4D:70:7D:7F + + X509v3 Subject Alternative Name: + email:testonly@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: sha1WithRSAEncryption + 0f:b6:d9:37:b3:d8:bb:69:1e:ce:1a:35:29:1b:ce:d5:38:3e: + 29:13:17:91:5b:1f:9c:59:52:67:d3:05:91:2a:e8:7f:b9:76: + 1a:01:f6:9f:07:74:be:e4:37:87:d0:9b:84:c6:81:3f:c4:96: + 52:46:80:52:a7:7b:14:fd:f6:4d:23:15:b6:7e:2a:a6:d7:90: + 97:4f:22:7c:3e:7d:12:84:28:a4:9a:30:67:77:16:f7:80:0f: + 6a:d0:82:fc:f6:91:39:14:d2:a5:de:18:f1:bb:38:f1:98:88: + 1c:13:63:e9:a3:d7:b5:b0:70:f2:82:58:bd:ef:3c:02:42:a0: + 7e:c9 +-----BEGIN CERTIFICATE----- +MIIFAzCCBGygAwIBAgIJALZ76JBNcH1/MA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECBMcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UEChMYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLEx5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMTGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMDcwNzIyMDE0ODE1WhcNMTMwMTExMDE0ODE1WjCBzjELMAkG +A1UEBhMCQVUxJTAjBgNVBAgTHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnkx +ITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECxMeQ2Vy +dGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDExlRY2EgVGVzdCBS +b290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0LmV4 +YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChoj6eU96YLC+e ++hL6VGwKCugj9CWGJNrtbxjibh6uNk5FYw1bIKoJcFW5oQjjyz3jw8o0w8eQMFBR +1jCzPxJwma4tyC7qxsZD5Z8wq+Nb2bCRksKUeXmbhwVgAYzxDnX3gtb55vtFuE1T +62agmJMo1x7bQz2Emysf7q/YI7WhzQIDAQABo4IB5TCCAeEwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAeYwHQYDVR0OBBYEFFE/8hRuSWrcQbgVtaCG9C7k9UX4 +MIIBAwYDVR0jBIH7MIH4gBRRP/IUbklq3EG4FbWghvQu5PVF+KGB1KSB0TCBzjEL +MAkGA1UEBhMCQVUxJTAjBgNVBAgTHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRv +cnkxITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECxMe +Q2VydGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDExlRY2EgVGVz +dCBSb290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0 +LmV4YW1wbGUuY29tggkAtnvokE1wfX8wJAYDVR0RBB0wG4EZdGVzdG9ubHlAdGVz +dC5leGFtcGxlLmNvbTAkBgNVHRIEHTAbgRl0ZXN0b25seUB0ZXN0LmV4YW1wbGUu +Y29tMBEGCWCGSAGG+EIBAQQEAwIABzA8BglghkgBhvhCAQ0ELxYtVGhpcyBjZXJ0 +aWZpY2F0ZSB3YXMgaXNzdWVkIGZvciB0ZXN0aW5nIG9ubHkhMA0GCSqGSIb3DQEB +BQUAA4GBAA+22Tez2LtpHs4aNSkbztU4PikTF5FbH5xZUmfTBZEq6H+5dhoB9p8H +dL7kN4fQm4TGgT/EllJGgFKnexT99k0jFbZ+KqbXkJdPInw+fRKEKKSaMGd3FveA +D2rQgvz2kTkU0qXeGPG7OPGYiBwTY+mj17WwcPKCWL3vPAJCoH7J +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/careq.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/careq.pem new file mode 100644 index 0000000000..5acea9cf45 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/careq.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICITCCAYoCAQAwgeAxCzAJBgNVBAYTAkFVMSUwIwYDVQQIExxBdXN0cmFsaWFu +IENhcGl0YWwgVGVycml0b3J5MRAwDgYDVQQHEwdRY2FMYW5kMSEwHwYDVQQKExhR +Y2EgRGV2ZWxvcG1lbnQgYW5kIFRlc3QxJzAlBgNVBAsTHkNlcnRpZmljYXRlIEdl +bmVyYXRpb24gU2VjdGlvbjEiMCAGA1UEAxMZUWNhIFRlc3QgUm9vdCBDZXJ0aWZp +Y2F0ZTEoMCYGCSqGSIb3DQEJARYZdGVzdG9ubHlAdGVzdC5leGFtcGxlLmNvbTCB +nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAoaI+nlPemCwvnvoS+lRsCgroI/Ql +hiTa7W8Y4m4erjZORWMNWyCqCXBVuaEI48s948PKNMPHkDBQUdYwsz8ScJmuLcgu +6sbGQ+WfMKvjW9mwkZLClHl5m4cFYAGM8Q5194LW+eb7RbhNU+tmoJiTKNce20M9 +hJsrH+6v2CO1oc0CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAJFcvHZDxAudRtla +dELJWVRXIyijLfDSxt5TVqF3GtGZum9JX7Hj0QETu3VkUL91eOLO3RiiWQrm2Wd6 +huRkzv3AbkifAWlCOIhkXQxFdsqi3KRhXQc1Y+kiRk+1xhftMvsWprtHq64qS8Da +bKT/rF1DmMzynQ0KUr+Z8eXEL7aH +-----END CERTIFICATE REQUEST----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/certs/.keep b/local/recipes/libs/qca/source/unittest/testcerts/CA/certs/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/crl/.keep b/local/recipes/libs/qca/source/unittest/testcerts/CA/crl/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/crlnumber b/local/recipes/libs/qca/source/unittest/testcerts/CA/crlnumber new file mode 100644 index 0000000000..8a0f05e166 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/crlnumber @@ -0,0 +1 @@ +01 diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt new file mode 100644 index 0000000000..ad97880701 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt @@ -0,0 +1,3 @@ +V 130111014815Z B67BE8904D707D7F unknown /C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com +V 120720033029Z B67BE8904D707D80 unknown /C=US/ST=Kalifornia/L=QcaLand/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Client Certificate/emailAddress=client@test.example.com +V 120720060539Z B67BE8904D707D81 unknown /C=IL/ST=Qca Province/L=TLS City/O=Qca Development and Test/OU=Server Management Section/CN=Qca Server Test certificate/emailAddress=server@test.example.com diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr new file mode 100644 index 0000000000..3a7e39e6ee --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr @@ -0,0 +1 @@ +unique_subject = no diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr.old b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr.old new file mode 100644 index 0000000000..3a7e39e6ee --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.attr.old @@ -0,0 +1 @@ +unique_subject = no diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.old b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.old new file mode 100644 index 0000000000..3f9b52300f --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/index.txt.old @@ -0,0 +1,2 @@ +V 130111014815Z B67BE8904D707D7F unknown /C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com +V 120720033029Z B67BE8904D707D80 unknown /C=US/ST=Kalifornia/L=QcaLand/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Client Certificate/emailAddress=client@test.example.com diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D7F.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D7F.pem new file mode 100644 index 0000000000..933e82f79c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D7F.pem @@ -0,0 +1,83 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b6:7b:e8:90:4d:70:7d:7f + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 22 01:48:15 2007 GMT + Not After : Jan 11 01:48:15 2013 GMT + Subject: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a1:a2:3e:9e:53:de:98:2c:2f:9e:fa:12:fa:54: + 6c:0a:0a:e8:23:f4:25:86:24:da:ed:6f:18:e2:6e: + 1e:ae:36:4e:45:63:0d:5b:20:aa:09:70:55:b9:a1: + 08:e3:cb:3d:e3:c3:ca:34:c3:c7:90:30:50:51:d6: + 30:b3:3f:12:70:99:ae:2d:c8:2e:ea:c6:c6:43:e5: + 9f:30:ab:e3:5b:d9:b0:91:92:c2:94:79:79:9b:87: + 05:60:01:8c:f1:0e:75:f7:82:d6:f9:e6:fb:45:b8: + 4d:53:eb:66:a0:98:93:28:d7:1e:db:43:3d:84:9b: + 2b:1f:ee:af:d8:23:b5:a1:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + X509v3 Authority Key Identifier: + keyid:51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + DirName:/C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + serial:B6:7B:E8:90:4D:70:7D:7F + + X509v3 Subject Alternative Name: + email:testonly@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Netscape Comment: + This certificate was issued for testing only! + Signature Algorithm: sha1WithRSAEncryption + 0f:b6:d9:37:b3:d8:bb:69:1e:ce:1a:35:29:1b:ce:d5:38:3e: + 29:13:17:91:5b:1f:9c:59:52:67:d3:05:91:2a:e8:7f:b9:76: + 1a:01:f6:9f:07:74:be:e4:37:87:d0:9b:84:c6:81:3f:c4:96: + 52:46:80:52:a7:7b:14:fd:f6:4d:23:15:b6:7e:2a:a6:d7:90: + 97:4f:22:7c:3e:7d:12:84:28:a4:9a:30:67:77:16:f7:80:0f: + 6a:d0:82:fc:f6:91:39:14:d2:a5:de:18:f1:bb:38:f1:98:88: + 1c:13:63:e9:a3:d7:b5:b0:70:f2:82:58:bd:ef:3c:02:42:a0: + 7e:c9 +-----BEGIN CERTIFICATE----- +MIIFAzCCBGygAwIBAgIJALZ76JBNcH1/MA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECBMcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UEChMYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLEx5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMTGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMDcwNzIyMDE0ODE1WhcNMTMwMTExMDE0ODE1WjCBzjELMAkG +A1UEBhMCQVUxJTAjBgNVBAgTHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnkx +ITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECxMeQ2Vy +dGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDExlRY2EgVGVzdCBS +b290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0LmV4 +YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChoj6eU96YLC+e ++hL6VGwKCugj9CWGJNrtbxjibh6uNk5FYw1bIKoJcFW5oQjjyz3jw8o0w8eQMFBR +1jCzPxJwma4tyC7qxsZD5Z8wq+Nb2bCRksKUeXmbhwVgAYzxDnX3gtb55vtFuE1T +62agmJMo1x7bQz2Emysf7q/YI7WhzQIDAQABo4IB5TCCAeEwDwYDVR0TAQH/BAUw +AwEB/zALBgNVHQ8EBAMCAeYwHQYDVR0OBBYEFFE/8hRuSWrcQbgVtaCG9C7k9UX4 +MIIBAwYDVR0jBIH7MIH4gBRRP/IUbklq3EG4FbWghvQu5PVF+KGB1KSB0TCBzjEL +MAkGA1UEBhMCQVUxJTAjBgNVBAgTHEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRv +cnkxITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECxMe +Q2VydGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSIwIAYDVQQDExlRY2EgVGVz +dCBSb290IENlcnRpZmljYXRlMSgwJgYJKoZIhvcNAQkBFhl0ZXN0b25seUB0ZXN0 +LmV4YW1wbGUuY29tggkAtnvokE1wfX8wJAYDVR0RBB0wG4EZdGVzdG9ubHlAdGVz +dC5leGFtcGxlLmNvbTAkBgNVHRIEHTAbgRl0ZXN0b25seUB0ZXN0LmV4YW1wbGUu +Y29tMBEGCWCGSAGG+EIBAQQEAwIABzA8BglghkgBhvhCAQ0ELxYtVGhpcyBjZXJ0 +aWZpY2F0ZSB3YXMgaXNzdWVkIGZvciB0ZXN0aW5nIG9ubHkhMA0GCSqGSIb3DQEB +BQUAA4GBAA+22Tez2LtpHs4aNSkbztU4PikTF5FbH5xZUmfTBZEq6H+5dhoB9p8H +dL7kN4fQm4TGgT/EllJGgFKnexT99k0jFbZ+KqbXkJdPInw+fRKEKKSaMGd3FveA +D2rQgvz2kTkU0qXeGPG7OPGYiBwTY+mj17WwcPKCWL3vPAJCoH7J +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D80.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D80.pem new file mode 100644 index 0000000000..7dd03bf167 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D80.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b6:7b:e8:90:4d:70:7d:80 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 22 03:30:29 2007 GMT + Not After : Jul 20 03:30:29 2012 GMT + Subject: C=US, ST=Kalifornia, L=QcaLand, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Client Certificate/emailAddress=client@test.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:b0:67:99:c9:d4:42:eb:f5:a6:25:7e:99:31:4e: + d7:71:e2:15:95:8b:6a:e9:13:c6:0a:6e:cd:5d:ce: + 23:c8:b0:4a:af:d6:d3:ef:3d:09:23:97:6d:ed:49: + 0a:2c:e4:9d:a2:50:78:bc:a5:94:79:45:b1:b0:85: + 3a:02:1b:5f:f4:be:94:9e:a1:d1:a4:9c:31:02:ed: + 62:3f:b3:f1:1a:5b:7d:31:27:ae:7b:f1:67:bd:60: + 86:27:34:80:96:53:04:00:4e:d8:f2:b3:bb:6e:62: + ab:51:ee:f9:25:ad:de:3a:4f:e5:1e:d5:42:28:e8: + 73:96:4c:1f:06:42:ee:d8:8b + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL Client, S/MIME + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication, E-mail Protection + Netscape Comment: + This certificate was issued for testing only! + X509v3 Subject Key Identifier: + B2:7F:D3:11:39:23:BE:1D:C4:6F:53:CE:81:AF:F1:D4:80:01:F6:F6 + X509v3 Authority Key Identifier: + keyid:51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + DirName:/C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + serial:B6:7B:E8:90:4D:70:7D:7F + + X509v3 Subject Alternative Name: + email:client@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Signature Algorithm: sha1WithRSAEncryption + 36:9a:0e:7a:a4:d3:6b:e8:d6:1b:ba:34:89:a6:dc:26:01:28: + 71:7d:28:71:22:79:ae:3b:27:2a:d5:6c:d6:99:93:c0:01:45: + 5d:78:2a:83:05:a8:eb:41:be:62:37:92:ff:b9:41:3d:37:4c: + 25:85:4b:c8:c3:ba:cd:71:06:18:12:a3:7f:2d:17:90:b2:87: + e6:ca:86:fb:dc:d0:ef:1d:d6:b3:86:b3:28:72:45:fa:bb:dd: + 32:06:44:b1:ed:35:b6:c4:6b:54:88:49:9d:3a:2e:fa:37:3b: + 84:98:de:68:14:ac:2f:37:42:21:f5:b9:27:18:1b:5d:5e:ba: + 74:09 +-----BEGIN CERTIFICATE----- +MIIFDzCCBHigAwIBAgIJALZ76JBNcH2AMA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECBMcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UEChMYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLEx5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMTGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMDcwNzIyMDMzMDI5WhcNMTIwNzIwMDMzMDI5WjCBzjELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkthbGlmb3JuaWExEDAOBgNVBAcTB1FjYUxhbmQx +ITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEnMCUGA1UECxMeQ2Vy +dGlmaWNhdGUgR2VuZXJhdGlvbiBTZWN0aW9uMSQwIgYDVQQDExtRY2EgVGVzdCBD +bGllbnQgQ2VydGlmaWNhdGUxJjAkBgkqhkiG9w0BCQEWF2NsaWVudEB0ZXN0LmV4 +YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwZ5nJ1ELr9aYl +fpkxTtdx4hWVi2rpE8YKbs1dziPIsEqv1tPvPQkjl23tSQos5J2iUHi8pZR5RbGw +hToCG1/0vpSeodGknDEC7WI/s/EaW30xJ6578We9YIYnNICWUwQATtjys7tuYqtR +7vklrd46T+Ue1UIo6HOWTB8GQu7YiwIDAQABo4IB8TCCAe0wEQYJYIZIAYb4QgEB +BAQDAgWgMAsGA1UdDwQEAwIE8DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwPAYJYIZIAYb4QgENBC8WLVRoaXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBm +b3IgdGVzdGluZyBvbmx5ITAdBgNVHQ4EFgQUsn/TETkjvh3Eb1POga/x1IAB9vYw +ggEDBgNVHSMEgfswgfiAFFE/8hRuSWrcQbgVtaCG9C7k9UX4oYHUpIHRMIHOMQsw +CQYDVQQGEwJBVTElMCMGA1UECBMcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9y +eTEhMB8GA1UEChMYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLEx5D +ZXJ0aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMTGVFjYSBUZXN0 +IFJvb3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3Qu +ZXhhbXBsZS5jb22CCQC2e+iQTXB9fzAiBgNVHREEGzAZgRdjbGllbnRAdGVzdC5l +eGFtcGxlLmNvbTAkBgNVHRIEHTAbgRl0ZXN0b25seUB0ZXN0LmV4YW1wbGUuY29t +MA0GCSqGSIb3DQEBBQUAA4GBADaaDnqk02vo1hu6NImm3CYBKHF9KHEiea47JyrV +bNaZk8ABRV14KoMFqOtBvmI3kv+5QT03TCWFS8jDus1xBhgSo38tF5Cyh+bKhvvc +0O8d1rOGsyhyRfq73TIGRLHtNbbEa1SISZ06Lvo3O4SY3mgUrC83QiH1uScYG11e +unQJ +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D81.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D81.pem new file mode 100644 index 0000000000..a16b2d22b8 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/newcerts/B67BE8904D707D81.pem @@ -0,0 +1,84 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b6:7b:e8:90:4d:70:7d:81 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=AU, ST=Australian Capital Territory, O=Qca Development and Test, OU=Certificate Generation Section, CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + Validity + Not Before: Jul 22 06:05:39 2007 GMT + Not After : Jul 20 06:05:39 2012 GMT + Subject: C=IL, ST=Qca Province, L=TLS City, O=Qca Development and Test, OU=Server Management Section, CN=Qca Server Test certificate/emailAddress=server@test.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:c1:59:ff:39:1d:96:af:d8:55:cd:89:a1:19:14: + a0:63:33:2a:1c:09:92:07:ea:8e:64:91:17:19:3a: + ca:6d:a8:2a:81:7d:a6:48:6a:8c:04:d5:dc:9b:b0: + 86:44:8c:65:27:9c:a6:63:ec:f0:f6:f2:03:76:4e: + 46:72:20:3c:eb:ac:c5:a7:4d:fa:36:84:a7:a1:45: + c2:54:43:b9:5d:88:17:b6:b2:6c:af:ce:9c:e2:2e: + 65:e2:82:4c:02:a4:4d:91:58:7d:16:14:dc:29:1c: + 1c:bc:c5:89:ac:e0:ea:f7:2d:9a:fe:d8:ca:53:98: + ce:ab:3a:c2:60:ad:91:e9:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL Server + X509v3 Key Usage: + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + Netscape Comment: + This certificate was issued for qca server testing only! + X509v3 Subject Key Identifier: + 3C:AA:B3:B7:59:75:DB:2C:95:AF:B4:81:FA:56:40:D8:98:6B:27:CB + X509v3 Authority Key Identifier: + keyid:51:3F:F2:14:6E:49:6A:DC:41:B8:15:B5:A0:86:F4:2E:E4:F5:45:F8 + DirName:/C=AU/ST=Australian Capital Territory/O=Qca Development and Test/OU=Certificate Generation Section/CN=Qca Test Root Certificate/emailAddress=testonly@test.example.com + serial:B6:7B:E8:90:4D:70:7D:7F + + X509v3 Subject Alternative Name: + email:server@test.example.com + X509v3 Issuer Alternative Name: + email:testonly@test.example.com + Signature Algorithm: sha1WithRSAEncryption + 0f:0b:9f:d9:38:62:20:40:a5:ff:0c:7b:d5:21:82:dd:9a:74: + 94:81:72:aa:94:fc:1b:e0:53:56:e1:65:67:ed:a5:97:94:87: + fc:ee:37:66:e5:bf:7e:92:1b:b9:a4:e8:96:4a:5e:67:64:de: + f8:43:47:de:50:85:f6:a6:47:df:b4:ff:e3:93:ef:8e:b1:7c: + 38:52:e4:e4:90:45:d1:85:db:c2:db:91:81:44:5a:41:a8:9b: + 68:f6:dd:4b:c0:88:f0:fb:f0:73:17:9d:c4:9e:2b:1d:ba:6c: + 43:bd:38:a3:f7:3f:55:cb:1a:7b:c4:5e:4a:39:fc:a2:86:ed: + d9:ba +-----BEGIN CERTIFICATE----- +MIIFDjCCBHegAwIBAgIJALZ76JBNcH2BMA0GCSqGSIb3DQEBBQUAMIHOMQswCQYD +VQQGEwJBVTElMCMGA1UECBMcQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeTEh +MB8GA1UEChMYUWNhIERldmVsb3BtZW50IGFuZCBUZXN0MScwJQYDVQQLEx5DZXJ0 +aWZpY2F0ZSBHZW5lcmF0aW9uIFNlY3Rpb24xIjAgBgNVBAMTGVFjYSBUZXN0IFJv +b3QgQ2VydGlmaWNhdGUxKDAmBgkqhkiG9w0BCQEWGXRlc3Rvbmx5QHRlc3QuZXhh +bXBsZS5jb20wHhcNMDcwNzIyMDYwNTM5WhcNMTIwNzIwMDYwNTM5WjCBzDELMAkG +A1UEBhMCSUwxFTATBgNVBAgTDFFjYSBQcm92aW5jZTERMA8GA1UEBxMIVExTIENp +dHkxITAfBgNVBAoTGFFjYSBEZXZlbG9wbWVudCBhbmQgVGVzdDEiMCAGA1UECxMZ +U2VydmVyIE1hbmFnZW1lbnQgU2VjdGlvbjEkMCIGA1UEAxMbUWNhIFNlcnZlciBU +ZXN0IGNlcnRpZmljYXRlMSYwJAYJKoZIhvcNAQkBFhdzZXJ2ZXJAdGVzdC5leGFt +cGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwVn/OR2Wr9hVzYmh +GRSgYzMqHAmSB+qOZJEXGTrKbagqgX2mSGqMBNXcm7CGRIxlJ5ymY+zw9vIDdk5G +ciA866zFp036NoSnoUXCVEO5XYgXtrJsr86c4i5l4oJMAqRNkVh9FhTcKRwcvMWJ +rODq9y2a/tjKU5jOqzrCYK2R6U8CAwEAAaOCAfIwggHuMBEGCWCGSAGG+EIBAQQE +AwIGQDALBgNVHQ8EBAMCBeAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwRwYJYIZIAYb4 +QgENBDoWOFRoaXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBmb3IgcWNhIHNlcnZl +ciB0ZXN0aW5nIG9ubHkhMB0GA1UdDgQWBBQ8qrO3WXXbLJWvtIH6VkDYmGsnyzCC +AQMGA1UdIwSB+zCB+IAUUT/yFG5JatxBuBW1oIb0LuT1RfihgdSkgdEwgc4xCzAJ +BgNVBAYTAkFVMSUwIwYDVQQIExxBdXN0cmFsaWFuIENhcGl0YWwgVGVycml0b3J5 +MSEwHwYDVQQKExhRY2EgRGV2ZWxvcG1lbnQgYW5kIFRlc3QxJzAlBgNVBAsTHkNl +cnRpZmljYXRlIEdlbmVyYXRpb24gU2VjdGlvbjEiMCAGA1UEAxMZUWNhIFRlc3Qg +Um9vdCBDZXJ0aWZpY2F0ZTEoMCYGCSqGSIb3DQEJARYZdGVzdG9ubHlAdGVzdC5l +eGFtcGxlLmNvbYIJALZ76JBNcH1/MCIGA1UdEQQbMBmBF3NlcnZlckB0ZXN0LmV4 +YW1wbGUuY29tMCQGA1UdEgQdMBuBGXRlc3Rvbmx5QHRlc3QuZXhhbXBsZS5jb20w +DQYJKoZIhvcNAQEFBQADgYEADwuf2ThiIECl/wx71SGC3Zp0lIFyqpT8G+BTVuFl +Z+2ll5SH/O43ZuW/fpIbuaTolkpeZ2Te+ENH3lCF9qZH37T/45PvjrF8OFLk5JBF +0YXbwtuRgURaQaibaPbdS8CI8PvwcxedxJ4rHbpsQ704o/c/Vcsae8ReSjn8oobt +2bo= +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/private/cakey.pem b/local/recipes/libs/qca/source/unittest/testcerts/CA/private/cakey.pem new file mode 100644 index 0000000000..79b01cddbc --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/private/cakey.pem @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,F17A1709AFCFEA09 + +N6sF87gUNUp77rz4HIT9DCJcQXJThEjGzzkJzIrPcNRBREdeTo+gYUXs7G730fRK +QAlpGNO4YvRZ2N3X+OyM7r1GYLe4CFRrGPLFwkeoMiCwwc/jl5NbdzOl0By67A1V +WygRavO3B8Tp7jUsNniAA7yr66I6nu2oj3DRjp+DJBowJNBRvc5d2GsoC2odQyKp +Po4P3kMYWZyfhIAp1KeuqQyyG1WVjQlzRtqHUwcs4GZ0xmfaFXfqPA3nFz7GXjzP +QTrOz2eB3+VWGbd7w0UUnMndvz1sJjV/3JCAFlNNC/sqb2CsYYhaEoiu5NlIDhQ/ +z+pZtAGksMqHfULnI3aqomg6/8bS3zyqQCC8bacDV6glNnzypfDOXhomjXRpxUwf +sRGTIj0BsippAYSW503Ab5UMKlpDK2h/6Y3XM52bs+fTi6qnCf8udtpJVNzEwyZj +eem1mzhs8NT0ZRpGVEOUaK8eIVGA7k6sObRT3sXDNjIw6HvKb1RaLDVy28+CYmd6 +WFXv0+YOlZFBdXS4epAnxddap+tfHuEbB17J4mc28FucPtfzfCRkUZ4c3uEbqDDe +tHW2z0xqj2vGKYG9v8yKu7oKOwCxqGNH2PzYOm2ttaD9wIJP4mWtSw74sMOpceKB +HWgSVjvD5FfFNi7vpQ/s1+aC/BF0Dfsy3pg3cwJA6vZQp4QdsAneecC7i+faS+nD +tiN24WM9sXciT3tCVpU9KFF4VSjs5gkyWWyjZiq7KNXvFXS5A75XXRmDcvnG6lEy +q+CMERq6iAuQSpcu+avK7SdZSjCRaWFYx8tTFdYbjtLpNHoJcyw4FA== +-----END RSA PRIVATE KEY----- diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/serial b/local/recipes/libs/qca/source/unittest/testcerts/CA/serial new file mode 100644 index 0000000000..408a338359 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/serial @@ -0,0 +1 @@ +B67BE8904D707D82 diff --git a/local/recipes/libs/qca/source/unittest/testcerts/CA/serial.old b/local/recipes/libs/qca/source/unittest/testcerts/CA/serial.old new file mode 100644 index 0000000000..3afda40388 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/CA/serial.old @@ -0,0 +1 @@ +B67BE8904D707D81 diff --git a/local/recipes/libs/qca/source/unittest/testcerts/README b/local/recipes/libs/qca/source/unittest/testcerts/README new file mode 100644 index 0000000000..2be3c21905 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/README @@ -0,0 +1,11 @@ +These are the tools used to generate test certificates +for unit testing in QCA. + +You need to have openssl installed. + +Do not try to generate certificates blindly. You always need +to read and understand the openssl.cnf options to make any +kind of sensible certificate. + +The PEM passphrase is always "start". + diff --git a/local/recipes/libs/qca/source/unittest/testcerts/openssl.cnf b/local/recipes/libs/qca/source/unittest/testcerts/openssl.cnf new file mode 100644 index 0000000000..59222ff3e1 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/testcerts/openssl.cnf @@ -0,0 +1,292 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./CA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 1825 # how long to certify for +default_crl_days= 300 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_md = sha1 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +# we use PrintableString+UTF8String mask so if pure ASCII texts are used +# the resulting certificates are compatible with Netscape +string_mask = MASK:0x2002 + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Australian Capital Territory + +localityName = Locality Name (eg, city) +localityName_default = QcaLand + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Qca Development and Test + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = Certificate Generation Section + +commonName = Common Name (eg, your name or your server\'s hostname) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = testonly@test.example.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +# not used + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. +# basicConstraints=CA:FALSE + +# For normal client use this is typical +# nsCertType = client, email +nsCertType = server +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment +keyUsage = digitalSignature, nonRepudiation, keyEncipherment +#extendedKeyUsage = clientAuth, emailProtection +extendedKeyUsage = serverAuth +# This will be displayed in Netscape's comment listbox. +# nsComment = "This certificate was issued for testing only!" +nsComment = "This certificate was issued for qca server testing only!" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + +basicConstraints = critical,CA:true +# keyUsage = cRLSign, keyCertSign +keyUsage = cRLSign, keyCertSign, keyEncipherment, nonRepudiation, digitalSignature +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer:always + +# Include email address in subject alt name: another PKIX recommendation +subjectAltName=email:copy +# Copy issuer details +issuerAltName=issuer:copy + +# Some might want this also +nsCertType = sslCA, emailCA, objCA +nsComment = "This certificate was issued for testing only!" + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/local/recipes/libs/qca/source/unittest/tls/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/tls/CMakeLists.txt new file mode 100644 index 0000000000..b4f621ac4e --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/tls/CMakeLists.txt @@ -0,0 +1,9 @@ +ENABLE_TESTING() + +set(tlsunittest_bin_SRCS tlsunittest.cpp) + +add_executable(tlsunittest ${tlsunittest_bin_SRCS} ) + +target_link_qca_test_libraries(tlsunittest) + +add_qca_test(tlsunittest "TransportLayerSecurity") diff --git a/local/recipes/libs/qca/source/unittest/tls/tlsunittest.cpp b/local/recipes/libs/qca/source/unittest/tls/tlsunittest.cpp new file mode 100644 index 0000000000..56d7fc720c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/tls/tlsunittest.cpp @@ -0,0 +1,136 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +#include + +class TLSUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void testCipherList(); + +private: + QCA::Initializer *m_init; +}; + +void TLSUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void TLSUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void TLSUnitTest::testCipherList() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + std::unique_ptr tls(new QCA::TLS(QCA::TLS::Stream, nullptr, QStringLiteral("qca-ossl"))); + QStringList cipherList = tls->supportedCipherSuites(QCA::TLS::TLS_v1); + QVERIFY(cipherList.contains(QStringLiteral("TLS_DHE_RSA_WITH_AES_256_CBC_SHA"))); + QVERIFY(cipherList.contains(QStringLiteral("TLS_RSA_WITH_AES_256_CBC_SHA"))); + QVERIFY(cipherList.contains(QStringLiteral("TLS_DHE_RSA_WITH_AES_128_CBC_SHA"))); + + // openSUSE TW OpenSSL 1.1 does not have this + // QVERIFY( cipherList.contains("TLS_DHE_DSS_WITH_AES_256_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_WITH_AES_128_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_DSS_WITH_AES_128_CBC_SHA") ); + + // Fedora 26 openssl has no this cipher suites. + // QVERIFY( cipherList.contains("TLS_RSA_WITH_RC4_128_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_WITH_RC4_128_MD5") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_RC4_128_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_RC4_128_MD5") ); + + // Fedora 20 openssl has no this cipher suites. + // I just believe that F20 has the most strict patent rules + // and Fedora list is the minimal default list. + // It should fit for every openssl distribuition. + + // QVERIFY( cipherList.contains("TLS_DHE_RSA_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_DSS_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5") ); + // QVERIFY( cipherList.contains("TLS_RSA_EXPORT_WITH_RC4_40_MD5") ); + + // OpenSSL 1.1 in openSUSE TW has it disabled by default + // cipherList = tls->supportedCipherSuites(QCA::TLS::SSL_v3); + // QVERIFY( cipherList.contains("SSL_DHE_RSA_WITH_AES_256_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_DSS_WITH_AES_256_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_AES_256_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_3DES_EDE_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_RSA_WITH_AES_128_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_DSS_WITH_AES_128_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_AES_128_CBC_SHA") ); + + // Fedora 22 has no SSL_RSA_WITH_RC4_128_MD5 + // QVERIFY( cipherList.contains("SSL_RSA_WITH_RC4_128_MD5") ); + + // QVERIFY( cipherList.contains("SSL_DHE_RSA_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_DSS_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_WITH_DES_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA") ); + // QVERIFY( cipherList.contains("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5") ); + // QVERIFY( cipherList.contains("SSL_RSA_EXPORT_WITH_RC4_40_MD5") ); + + // Debian testing (jessie) has no these ciphers. So disable them. + + // cipherList = tls->supportedCipherSuites(QCA::TLS::SSL_v2); + // QVERIFY( cipherList.contains("SSL_CK_DES_192_EDE3_CBC_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_RC4_128_EXPORT40_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_RC2_128_CBC_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_RC4_128_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_DES_64_CBC_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5") ); + // QVERIFY( cipherList.contains("SSL_CK_RC4_128_EXPORT40_WITH_MD5") ); + } +} + +QTEST_MAIN(TLSUnitTest) + +#include "tlsunittest.moc" diff --git a/local/recipes/libs/qca/source/unittest/velox/CMakeLists.txt b/local/recipes/libs/qca/source/unittest/velox/CMakeLists.txt new file mode 100644 index 0000000000..2ccd74d288 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/velox/CMakeLists.txt @@ -0,0 +1,15 @@ +find_package(Qt${QT_MAJOR_VERSION} COMPONENTS Network REQUIRED) + +ENABLE_TESTING() + +set(veloxunittest_bin_SRCS veloxunittest.cpp) + +add_executable(veloxunittest ${veloxunittest_bin_SRCS} ) + +target_link_qca_test_libraries(veloxunittest) +target_link_libraries(veloxunittest Qt${QT_MAJOR_VERSION}::Network) + +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/root.crt ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/root.crt COPYONLY) + +# this will almost always fail. +# add_qca_test(veloxunittest "ServerNameIndication") diff --git a/local/recipes/libs/qca/source/unittest/velox/README b/local/recipes/libs/qca/source/unittest/velox/README new file mode 100644 index 0000000000..e280e942b9 --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/velox/README @@ -0,0 +1,9 @@ +This test is intended to verify the subject hostname indication +extension (see RFC3546 Section 3.1). + +It requires network access, and contacts a public test server +(sni.velox.ch). + +Note that this test requires a suitable backend (plugin). If +you are running this test with OpenSSL 0.9.8 or earlier, then +you can expect it to fail. diff --git a/local/recipes/libs/qca/source/unittest/velox/root.crt b/local/recipes/libs/qca/source/unittest/velox/root.crt new file mode 100644 index 0000000000..be48d0a00c --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/velox/root.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFNDCCAxygAwIBAgIGS2FzcGFyMA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNVBAYT +AkNIMQ4wDAYDVQQKEwVWZWxveDEaMBgGA1UEAxMRVmVsb3ggU05JIFRlc3QgQ0Ew +HhcNMDYwMzEyMTMxNDE1WhcNMTYwMzEyMTMxNDE1WjA5MQswCQYDVQQGEwJDSDEO +MAwGA1UEChMFVmVsb3gxGjAYBgNVBAMTEVZlbG94IFNOSSBUZXN0IENBMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwykLtf/irTZ5PKTlJyhc0SHYStPy +C758o9tGUjNzr0McyLxno2rMzYwl4BoqroxL/XU8wOxFQflLbdFxlJ7Jh6tC7JqJ +9N9BQRPTs4IYxvUeZXKVyXIHBNJ2uIeclZfC2wppVuTY/lkFMUtWT9Lj6Z31DC1m +gEKJTIcIMfR2FWcWAOdIivw7S8S4niD6ThXflh6AGHPN5FSgmQ2ZmC7BHF4nFGqe +ZHtWeO4JZkh0x+99IUqkgOG3M2QtrbAxNluMrq8qTpozwbic9P80hKh0SOH6RBZB +oAyeuWNl9YVUsgEOhFu5wyvo+SEOtyZjnjLIgpojRO4CzhTLgWcjVqwIZbJaNoeo +oc7gkEWLMPlWk0KEw9HpUHfjHPTY58QvJg3mP0YH6VtyLFbYTrfhbsYb0YvbZEsC +goosxxvnKbkcPsRWGwNmK6RXwER29AZgSLlAWYp3LUC7pib+GmuliRjYE/uztUVh +BGeCXFRBfSwT2HkQB349fiqtsm0ystQt1O1/9X98/7+NNXNdwUg5XcjID18BRzff +cRcEv54iXpmowJmBaVJcc4aG2xHZbOFgpUprBsen5x62ImQR9IVlgM97FJ+5OQrk +UGGiWRyg7tuJw5D7qhfS1Ud3VPLIhS4Vdpbnx2HJeluCiINrxqdbrQSuPYBaJwYN +2cguQ2bkx/BAbf8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwHQYDVR0OBBYEFD1VGg/8kE55Hjx0JkgoWBFMj0OBMA0GCSqGSIb3DQEB +BQUAA4ICAQBSM6ID33jBJhvvaPh3ii9CwuA7u+mXxhfL4XmeY/h+dEIvUe6gAvMm +l5SGmsX+VkIhL1fxNGDaiGqo5Zh7QbkRbrftm4hbodDLDSbqhgyVrOpeqbRAKCqH +YUCcrkxOp+q4pYXiQv9MUHI/c72Hp4HSlRtoc2RArfZwMGDeF5tD2QCIRGOt3/eQ +MvmgzB2FGSjPrKBfaffrImqgV6RAEqEqn5HTMheT7ldhT7ZcyLKCiBGd8Jb9Z0/S +/yIct0fYN2EIjw21UhP6Hc62cTurXlutrm8PQmuHpk7Ns0aXZ1xA6rsHejlWw3yR +hSqYUBkOUvN5ovu3xYixX4DJRKwOX6eXpzRTDuGYEfVRXwEWL8inBy1GeJykK9ol +XUZQng4Bgkz+33VuKw0M2InIq+9LtAguU6QfAeWDFuu8G2c1Z4FCKaKkJCl6iFaF +X5Kmeg6xp5j6wadka1gCIbCvF24Kr+mHX9gwSLp/zXZKahWWhsnFlVE9nFVsu8FX ++gn/stOFdSrm6Gpm/Ilh+s2ZALmM7RU7LgrrrIT1S9YAI45ebiY/hqNk8XK9yPeM +3Jzj+ziNpwl0K8aW4xADnHzVvVDaDPccrmh7WKPuU8LQnYu236RscUiWAbBshEO2 +gGGyvlPpRDIX3NTPfovT+igyfSesT9zIwDK8jIMDxRu/UZ46b7ORXg== +-----END CERTIFICATE----- diff --git a/local/recipes/libs/qca/source/unittest/velox/veloxunittest.cpp b/local/recipes/libs/qca/source/unittest/velox/veloxunittest.cpp new file mode 100644 index 0000000000..b1fdbb89df --- /dev/null +++ b/local/recipes/libs/qca/source/unittest/velox/veloxunittest.cpp @@ -0,0 +1,217 @@ +/** + * Copyright (C) 2006 Brad Hards + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include + +#ifdef QT_STATICPLUGIN +#include "import_plugins.h" +#endif + +class TlsTest : public QObject +{ + Q_OBJECT +public: + TlsTest() + { + sock = new QTcpSocket(this); + connect(sock, &QTcpSocket::connected, this, &TlsTest::sock_connected); + connect(sock, &QTcpSocket::readyRead, this, &TlsTest::sock_readyRead); + + ssl = new QCA::TLS(this); + connect(ssl, &QCA::TLS::handshaken, this, &TlsTest::ssl_handshaken); + connect(ssl, &QCA::TLS::readyReadOutgoing, this, &TlsTest::ssl_readyReadOutgoing); + + sync = new QCA::Synchronizer(this); + } + + ~TlsTest() override + { + delete ssl; + delete sock; + } + + void start(const QString &_host, int port) + { + host = _host; + sock->connectToHost(host, port); + } + + void waitForHandshake(int timeout = 20000) + { + sync->waitForCondition(timeout); + } + + bool isHandshaken() + { + return ssl->isHandshaken(); + } + +private Q_SLOTS: + void sock_connected() + { + QCA::CertificateCollection rootCerts; + QCA::ConvertResult resultRootCert; + QCA::Certificate rootCert = QCA::Certificate::fromPEMFile(QStringLiteral("root.crt"), &resultRootCert); + QCOMPARE(resultRootCert, QCA::ConvertGood); + rootCerts.addCertificate(rootCert); + + ssl->setTrustedCertificates(rootCerts); + + ssl->startClient(host); + } + + void sock_readyRead() + { + ssl->writeIncoming(sock->readAll()); + } + + void ssl_handshaken() + { + QCA::TLS::IdentityResult r = ssl->peerIdentityResult(); + + QCOMPARE(r, QCA::TLS::Valid); + + sync->conditionMet(); + } + + void ssl_readyReadOutgoing() + { + sock->write(ssl->readOutgoing()); + } + +private: + QString host; + QTcpSocket *sock; + QCA::TLS *ssl; + QCA::Certificate cert; + QCA::Synchronizer *sync; +}; + +class VeloxUnitTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void sniAlice(); + void sniBob(); + void sniCarol(); + void sniDave(); + void sniMallory(); + void sniIvan(); + +private: + QCA::Initializer *m_init; + QCA::CertificateCollection rootCerts; +}; + +void VeloxUnitTest::initTestCase() +{ + m_init = new QCA::Initializer; +} + +void VeloxUnitTest::cleanupTestCase() +{ + delete m_init; +} + +void VeloxUnitTest::sniAlice() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("alice.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +void VeloxUnitTest::sniBob() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("bob.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +void VeloxUnitTest::sniCarol() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("carol.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +void VeloxUnitTest::sniDave() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("dave.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +void VeloxUnitTest::sniMallory() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("mallory.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +void VeloxUnitTest::sniIvan() +{ + if (!QCA::isSupported("tls", QStringLiteral("qca-ossl"))) + QWARN("TLS not supported for qca-ossl"); + else { + TlsTest *s = new TlsTest; + s->start(QStringLiteral("ivan.sni.velox.ch"), 443); + s->waitForHandshake(); + QVERIFY(s->isHandshaken()); + } +} + +QTEST_MAIN(VeloxUnitTest) + +#include "veloxunittest.moc" diff --git a/recipes/libs/qca b/recipes/libs/qca new file mode 120000 index 0000000000..361c01b3a5 --- /dev/null +++ b/recipes/libs/qca @@ -0,0 +1 @@ +../../local/recipes/libs/qca \ No newline at end of file