diff --git a/.github/workflows/OpenSSL_versions.yml b/.github/workflows/OpenSSL_versions.yml index d6d596ae..2ab4807a 100644 --- a/.github/workflows/OpenSSL_versions.yml +++ b/.github/workflows/OpenSSL_versions.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - branch: [openssl-3.0, openssl-3.1, openssl-3.2, openssl-3.3, openssl-3.4, openssl-3.5, openssl-3.6] + branch: [openssl-4.0, openssl-3.6, openssl-3.5, openssl-3.4, openssl-3.0] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -43,37 +43,43 @@ jobs: echo "OPENSSL_LIB=${{ env.OPENSSL_DIR }}/lib64" >> $GITHUB_ENV echo "${{ env.OPENSSL_DIR }}/bin" >> "$GITHUB_PATH" echo "LD_LIBRARY_PATH=${{ env.OPENSSL_DIR }}/lib64:$LD_LIBRARY_PATH" >> "$GITHUB_ENV" - - name: cmake + - name: cmake build, install, uninstall, Debian run: | cmake . make ./cmpClient -help - if [[ $(openssl version | cut -d' ' -f2 | cut -d'.' -f1) -lt 4 ]]; then - echo "Using OpenSSL version less than 4.0, proceeding build with libcmp" - mkdir build-with-libcmp - cd build-with-libcmp - USE_LIBCMP=1 cmake -S .. -B . - fi - make clean build DESTDIR=tmp make install uninstall make deb + make clean + + - name: cmake out-of-source build build with libcmp + run: | + mkdir build-with-libcmp + cd build-with-libcmp + USE_LIBCMP=1 cmake -S .. -B . + make + ./cmpClient -help + cd .. + - if: ${{ matrix.branch == 'openssl-3.5' }} - name: Create mock test certificates and keys with PQC algorithms + name: When using OpenSSL 3.5, switch Mock test credentials to PQC algorithms run: | cd test/recipes/80-test_cmp_http_data/Mock/ - Algo_used="PQC" ./setup-mock.sh all # sets up fresh test certificates and keys for Mock test using PQC algorithms + # use script to overwrite test keys and certificates for Mock test, this time using PQC algorithms + Algo_used="PQC" ./setup-mock.sh all cd ../../../../ - - name: make + + - name: make (using Makefile_v1) test_Mock run: | - make -f Makefile_v1 - ./cmpClient -help + make -f Makefile_v1 clean make -f Makefile_v1 test_Mock make -f Makefile_v1 clean_all - if [[ $(openssl version | cut -d' ' -f2 | cut -d'.' -f1) -lt 4 ]]; then - USE_LIBCMP=1 STATIC_LIBCMP=1 make -f Makefile_v1 - ./cmpClient -help - make -f Makefile_v1 clean - fi + + - name: make (using Makefile_v1) with static libcmp + run: | + USE_LIBCMP=1 STATIC_LIBCMP=1 make -f Makefile_v1 + ./cmpClient -help + make -f Makefile_v1 clean diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 260ce88e..5c3c3815 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,9 @@ jobs: cmake -DCMAKE_BUILD_TYPE=Debug .. make clean build DESTDIR=tmp make install uninstall + [[ -d tmp/usr/local/lib ]] && (echo "uninstall incomplete: lib/ remains"; false) + [[ -d tmp/usr/local/include ]] && (echo "uninstall incomplete: include/ remains"; false) + [[ -d tmp/usr/local/share ]] && (echo "uninstall incomplete: share/ remains"; false) cd .. mkdir build-with-libcmp diff --git a/CMakeLists.txt b/CMakeLists.txt index 576170ff..4dbf75d1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,13 @@ if(NOT DEFINED GENCMPCLIENT_VERSION) endif() message(STATUS "generic CMP client version " ${GENCMPCLIENT_VERSION}) +set(PROJECT_VERSION ${GENCMPCLIENT_VERSION}) +set(CMAKE_PROJECT_DESCRIPTION "Generic CMP client library with high-level API based on OpenSSL +") +set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/siemens/gencmpclient") +set(pc_req_public "openssl, libsecutils") +set(pc_req_private "") + # Option to build shared or static library (default: SHARED) option(GENCMP_STATIC_LIB "Build static library instead of shared" OFF) if(GENCMP_STATIC_LIB) @@ -225,7 +232,18 @@ endif() # must not add the system OpenSSL include dir before ${CMPOSSL_INC_DIR}/cmp etc. include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR}) -configure_file(${INC_DIR}/genericCMPClient_config.h.in ${INC_DIR}/genericCMPClient_config.h) +configure_file(${INC_DIR}/genericCMPClient_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/genericCMPClient_config.h) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/genericCMPClient_config.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ +) + +configure_file(libgencmp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc @ONLY) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + COMPONENT dev +) if(CMAKE_SYSTEM_NAME MATCHES "Linux") # help CPackDeb please dpkg-shlibdeps @@ -258,7 +276,8 @@ else() add_compile_options(-pedantic) # -Werror is enabled only for development and CI, using Makefile_v1 without NDEBUG add_compile_options( -Wall -Woverflow -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wswitch - -Wsign-compare -Wformat -Wtype-limits -Wundef -Wconversion -Wunused-parameter) + -Wsign-compare -Wformat -Wformat-security -Wtype-limits -Wundef -Wconversion + -Wpointer-arith -Wunused-parameter -Wshadow) add_compile_options(-Wno-c99-extensions -Wno-language-extension-token -Wno-declaration-after-statement -Wno-expansion-to-defined) endif() @@ -367,7 +386,7 @@ endif() if(DEFINED ENV{ROOTFS}) set(CMAKE_INSTALL_PREFIX $ENV{ROOTFS} CACHE PATH "comment" FORCE) endif() -include(GNUInstallDirs) # CMAKE_INSTALL_PREFIX must be set before +include(GNUInstallDirs) # needed for CMAKE_INSTALL_FULL_LIBDIR etc.; any CMAKE_INSTALL_PREFIX must be set before install(FILES doc/Generic_CMP_client_API.pdf DESTINATION ${CMAKE_INSTALL_DOCDIR}-dev @@ -404,6 +423,7 @@ if(NOT TARGET uninstall) COMMAND find . -path "./\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}" -empty | xargs -r rmdir COMMAND rm -vfr "\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/security-utilities" # seems not needed: ${PROJECT_NAME} cmpossl COMMAND find . -path "./\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake" -empty | xargs -r rmdir + COMMAND find . -path "./\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig" -empty | xargs -r rmdir COMMAND find . -path "./\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" -empty | xargs -r rmdir COMMAND rm -vfr "\${DESTDIR}${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DOCDIR}-dev" COMMAND find . -path "./\${DESTDIR}${CMAKE_INSTALL_PREFIX}/share/man/man1" -empty | xargs -r rmdir @@ -468,7 +488,7 @@ if(NOT TARGET clean_all) if(NOT DEFINED CPACK_PACKAGE_NAME) SET(CPACK_PACKAGE_NAME ${PROJECT_NAME}) -SET(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/siemens/gencmpclient") +SET(CPACK_PACKAGE_HOMEPAGE_URL $(CMAKE_PROJECT_HOMEPAGE_URL)) SET(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") SET(CPACK_PACKAGE_VENDOR "Siemens") diff --git a/Makefile_src b/Makefile_src index 33cfa2bb..55b1a77c 100644 --- a/Makefile_src +++ b/Makefile_src @@ -84,19 +84,18 @@ OPENSSL_DLLS = *{crypto,ssl}*.dll CC ?= gcc ifdef NDEBUG override DEBUG_FLAGS ?= -O3 - override DEBUG_FLAGS += -DNDEBUG=1 -Werror + override DEBUG_FLAGS += -DNDEBUG=1 else - override DEBUG_FLAGS ?= -g -O0 -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all # not every compiler(version) supports -Og + override DEBUG_FLAGS ?= -g -O0 -Werror -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all # not every compiler(version) supports -Og endif override CFLAGS += $(DEBUG_FLAGS) -fstack-protector -fno-omit-frame-pointer # override CFLAGS += -std=gnu90 # TODO maybe clean up code and re-enable flag override CFLAGS += \ - -Wall -Woverflow -Wextra -Wswitch -Wmissing-prototypes -Wstrict-prototypes \ - -Wformat -Wformat-security -Wtype-limits -Wundef -Wconversion \ - -Wsign-compare -Wpointer-arith -Wunused-parameter -Wshadow \ + -Wall -Woverflow -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wswitch \ + -Wsign-compare -Wformat -Wformat-security -Wtype-limits -Wundef -Wconversion \ + -Wpointer-arith -Wunused-parameter -Wshadow \ -pedantic -DPEDANTIC -override CFLAGS +=-Wno-c99-extensions -Wno-language-extension-token -Wno-declaration-after-statement -Wno-expansion-to-defined \ - -Wno-sign-conversion -Wno-shorten-64-to-32 -Wno-shadow # due to libsecutils +override CFLAGS +=-Wno-c99-extensions -Wno-language-extension-token -Wno-declaration-after-statement -Wno-expansion-to-defined ifeq ($(LPATH),) ifndef GENCMP_NO_SECUTILS override CFLAGS += -I$(SECUTILS_DIR)/src/libsecutils/include diff --git a/Makefile_v1 b/Makefile_v1 index cd55d1d5..ef3b2991 100644 --- a/Makefile_v1 +++ b/Makefile_v1 @@ -197,13 +197,13 @@ ifneq ($(filter-out doc start stop doc doc_this doc/cmpClient.md doc/cmpClient.1 # must use ":=" below to avoid error: Recursive variable `OPENSSL_LIB' references itself (eventually) OPENSSL_LIB := $(shell $(GET_LIB) 2>/dev/null) ifeq ($(OPENSSL_LIB),) - $(shell $(GET_LIB)) + $(info $(shell $(GET_LIB))) $(error Error determining OPENSSL_LIB) endif endif LIB_NAME_PATTERN=libcrypto*$(DLL)* ifeq ($(wildcard $(OPENSSL_LIB)/$(LIB_NAME_PATTERN)),) - $(shell $(GET_LIB)) + $(info $(shell $(GET_LIB))) $(error Error: cannot find OpenSSL library $(LIB_NAME_PATTERN) at $(OPENSSL_LIB)/) endif # convert to absolute path @@ -530,7 +530,8 @@ else OCSP_CHECK= # disabled for now: $(OPENSSL) ocsp -url $(EJBCA_OCSP_URL) \ -CAfile $(EJBCA_CMP_TRUSTED) -issuer $(EJBCA_CMP_ISSUER) \ -cert creds/operational.crt - EJBCA_TLS_HOST_FILE=creds/docker/TLS_ROOTCA-docker-cn.txt + EJBCA_TLS_SERVER_CERTS=creds/docker/TLS_server-docker.pem + EJBCA_TLS_HOST_FILE=creds/docker/TLS_server-docker-cn.txt ifeq ($(EJBCA_TLS_HOST),) # workaround for ephemeral TLS server certificate of ejbca-docker: override EXTRA_OPTS += -tls_host `cat $(EJBCA_TLS_HOST_FILE)` BOOTSTRAP_CREDS = -cert creds/manufacturer.crt -key creds/manufacturer.pem @@ -586,9 +587,8 @@ else @echo $(CMPCLIENT) bootstrap -section $(CA_SECTION) -provider default $(EXTRA_OPTS) $(BOOTSTRAP_CREDS) $(GENERATE_OPERATIONAL) - $(OPENSSL) x509 -noout -text -in creds/operational.crt + $(OPENSSL) x509 -noout -text -in creds/operational.crt | sed -E '/^ *([0-9a-f]{2}:).*/d' @echo : - $(OPENSSL) x509 -noout -text -in creds/operational.crt | sed '/^ [0-9a-f].*/d' ifneq ($(CA_SECTION),Insta) # on p10cr, Insta responds with an empty message PKIBody @echo @$(SLEEP) @@ -666,8 +666,8 @@ ifeq ($(EJBCA_CONFIG),) @echo "EJBCA should now be ready to accept requests." ifeq ($(EJBCA_TLS_HOST),) # workaround for ephemeral TLS server certificate of ejbca-docker: @$(OPENSSL) s_client -connect $(EJBCA_HOST):$(EJBCA_HTTPS_PORT) 2>/dev/null \ - -verify_return_error -showcerts >creds/docker/TLS_ROOTCA-docker.pem || true - @echo `grep -E "CN ?= ?" creds/docker/TLS_ROOTCA-docker.pem|head -n 1 | sed -E 's/^.*CN ?= ?//; s/, ?UID ?= ?.*//; s/, O ?= ?.*//;'` >$(EJBCA_TLS_HOST_FILE) + -verify_return_error -showcerts >$(EJBCA_TLS_SERVER_CERTS) || true + @echo `grep -E "CN ?= ?" $(EJBCA_TLS_SERVER_CERTS) | head -n 1 | sed -E 's/^.*CN ?= ?//; s/, ?UID ?= ?.*//; s/, O ?= ?.*//;'` >$(EJBCA_TLS_HOST_FILE) @grep -qE '\w' $(EJBCA_TLS_HOST_FILE) || (echo "cannot determine EJBCA docker TLS host name"; false) endif ifneq ($(EJBCA_STARTED),) diff --git a/OpenSSL_version.mk b/OpenSSL_version.mk index 15e3b245..58e8adc1 100644 --- a/OpenSSL_version.mk +++ b/OpenSSL_version.mk @@ -85,7 +85,7 @@ else override OPENSSL_LIB = $(OPENSSL_DIR) ifeq ($(wildcard $(OPENSSL_LIB)/$(LIB_NAME_PATTERN)),) ifeq ($(OS),Linux) - ifeq ($(shell echo $(OPENSSL_FULL_DIR) | grep -E $(USERS)),) + ifeq ($(shell echo $(OPENSSL_FULL_DIR) | grep -E $(USERS)),) override OPENSSL_LIB = $(wildcard /lib/$(shell uname -i)-linux-*) $(warning Warning: cannot find OpenSSL libraries at $(OPENSSL_DIR), now trying $(OPENSSL_LIB)) endif diff --git a/README.md b/README.md index 34bf5a44..161ed699 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ which is geared towards simple and interoperable industrial certificate manageme @@ -123,7 +123,7 @@ The core library can also be built and used natively under Windows. The following development and network tools are needed or recommended. -* Git (for getting the software, tested versions include 2.7.2, 2.11.0, 2.20, 2.34.1, 2.48.0, 2.53.0) +* Git (for conveniently getting and updating the software, tested versions include 2.7.2, 2.11.0, 2.20, 2.34.1, 2.48.0, 2.53.0) * CMake (for using [`CMakeLists.txt`](CMakeLists.txt), tested versions include 3.18.4, 3.22.1, 3.27.7, 3.31.5) * GNU make (tested versions include 3.81, 4.1, 4.2.1, 4.3) * GNU C compiler (gcc, tested versions include 5.4.0, 7.3.0, 8.3.0, 10.2.1, 11.4.0, 12.2.0) @@ -231,6 +231,10 @@ you can execute in a shell on a Unix-like system: ```bash git clone https://github.com/siemens/gencmpclient.git cd genCMPClient +``` +or using some other way of obtaining the code, then + +```bash make -f OpenSSL_version.mk ``` @@ -273,7 +277,7 @@ or an HTTP proxy set up, for instance: export https_proxy=http://proxy.example.com:8080 ``` -You can clone the git repository and its submodules with +When using `git`, you can clone the git repository and its submodules with ```bash git clone https://github.com/siemens/gencmpclient.git @@ -281,26 +285,29 @@ cd genCMPClient make -f Makefile_v1 get_submodules ``` -This will fetch also the underlying -[CMPforOpenSSL extension to OpenSSL](https://github.com/mpeylo/cmpossl) and -the [Security Utilities (libsecutils)](https://github.com/siemens/libsecutils) -library if needed. - -For using the project as a git submodule, -do for instance the following in the directory where you want to integrate it: +This will fetch also +the [Security Utilities (libsecutils)](https://github.com/siemens/libsecutils) library +and +the underlying [CMPforOpenSSL extension to OpenSSL](https://github.com/mpeylo/cmpossl) +as far as needed. -```bash -git submodule add git@github.com:siemens/gencmpclient.git -``` +When not using `git`, you need to download and unpack the +[genCMPClient source tree](https://github.com/siemens/gencmpclient.git) +by other means, +as well as the sources of any of the two submodules as far as used, +in a state (i.e., git commit ID or version) consistent with the genCMPClient tree. +For instance, place the contents of the +[libsecutils repository](https://github.com/siemens/libsecutils) +in the subdirectory `libsecutils`. When you later want to update your local copy of all relevant repositories -it is sufficient to invoke +and `git` is installed, it is sufficient to invoke ```bash make update ``` -When switching to a certain commit or version, e.g. +When switching to a certain commit or version, e.g., ```bash git checkout v2.2 @@ -310,12 +317,22 @@ then also execute ```bash git submodule update +``` +or update the submodules by other means to a consistent state, then + +```bash make -f Makefile_v1 clean ``` to bring the submodules in a state consistent with that and remove any previous possibly outdated artifacts. +The genCMPClient project itself can be used a git submodule as follows: + +```bash +git submodule add git@github.com:siemens/gencmpclient.git +``` + ## Configuring ### Finding OpenSSL @@ -613,7 +630,7 @@ OPENSSL_TRACE=HTTP ./cmpClient imprint ### Demo use with a local EJBCA -The demo uses by default a Docker instance of the EJBCA, which is included in the repo and launched locally on demo startup. +The demo uses by default a Docker instance of the EJBCA, which is included in the repository and launched locally on demo startup. This variant of the demo can be used explicitly as follows: ```bash @@ -736,4 +753,5 @@ LocalWords: util icvutil NDEBUG DCMAKE ln usr libgencmp CC lssl lcmp md bis LocalWords: cmpClient src DESTDIR ROOTFS cmpclient tarball deb rpath LocalWords: debhelper dh devscripts debuild dpkg ecparam FI cr lgencmp cc cnf LocalWords: genkey insta ref cmd newkey certout noout creds Wl ICV GENCMP +LocalWords: br cmp gencmp dll DGENCMP libSecUtils mkdir PPKI newkeytype --> diff --git a/cmpossl b/cmpossl index 8414f0f7..c10e2fc9 160000 --- a/cmpossl +++ b/cmpossl @@ -1 +1 @@ -Subproject commit 8414f0f7a3bc2f5bd73922b3d189ba359ddc5241 +Subproject commit c10e2fc969c0ab6c743add35ea2767c8d5743b93 diff --git a/config/EJBCA.env b/config/EJBCA.env index fd825ef4..bb6a82e5 100644 --- a/config/EJBCA.env +++ b/config/EJBCA.env @@ -20,9 +20,9 @@ export EJBCA_CDP_URL_POSTFIX= export EJBCA_CDP_URL_POSTFIX_v11= export EJBCA_CMP_CLIENT_CERT=creds/manufacturer.crt export EJBCA_CMP_CLIENT_KEY=creds/manufacturer.pem -export EJBCA_TLS_CLIENT=creds/docker/Docker_Playground_TLS.p12 +export EJBCA_TLS_CLIENT=creds/docker/Docker_Playground_TLS.pem export EJBCA_CMP_TRUSTED=creds/docker/CMP_ROOTCA.pem -export EJBCA_TLS_TRUSTED=creds/docker/TLS_ROOTCA-docker.pem +export EJBCA_TLS_TRUSTED=creds/docker/TLS_ROOTCA.pem,creds/docker/TLS_server-docker.pem #export EJBCA_CMP_UNTRUSTED=creds/docker/CMP_ISSUING_CA.pem export EJBCA_CMP_ISSUER=creds/docker/CUSTOMER_ISSUING_CA.pem export EJBCA_TRUSTED=creds/docker/CUSTOMER_ROOTCA.pem diff --git a/creds/docker/Docker_Playground_CMP.pem b/creds/docker/Docker_Playground_CMP.pem new file mode 100644 index 00000000..150b7949 --- /dev/null +++ b/creds/docker/Docker_Playground_CMP.pem @@ -0,0 +1,54 @@ +Bag Attributes + localKeyID: EF 65 43 CF 4F 35 2E 54 DD 23 80 4A 54 7C FA 25 27 4C 60 9C +subject=CN=Docker_Playground_CMP +issuer=CN=CMP_ISSUING_CA +-----BEGIN CERTIFICATE----- +MIIBnDCCAUGgAwIBAgIUVC3571mWwpFPdnSz0LggFGG5wUYwCgYIKoZIzj0EAwIw +GTEXMBUGA1UEAwwOQ01QX0lTU1VJTkdfQ0EwHhcNMjMwNTA4MDc1NjE2WhcNMjgw +NTA2MDc1NjE1WjAgMR4wHAYDVQQDDBVEb2NrZXJfUGxheWdyb3VuZF9DTVAwWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAATQpHc3WLC0W27WpM2W9y7vfuRRENDsRzNA +nO/1qxsyS41U3ZiHE37fy4h+2jiJaRPq1C1bmM+mEBEhjU748B2Bo2AwXjAMBgNV +HRMBAf8EAjAAMB8GA1UdIwQYMBaAFBe3WkY1OQbB+HoHOyAKrmdp3pOVMB0GA1Ud +DgQWBBQo9f4zIuL+JIF0yOdnEztZFMGdQzAOBgNVHQ8BAf8EBAMCB4AwCgYIKoZI +zj0EAwIDSQAwRgIhALwNgZtLgo4KvhA2dLZlVrBwCblwNrDOjJ1rwaU3eizrAiEA +x6cfHtAWeh6j4s0OY6Sb+vGk5DCQktrxwkxeIOwgXPE= +-----END CERTIFICATE----- +Bag Attributes: +subject=CN=CMP_ROOTCA +issuer=CN=CMP_ROOTCA +-----BEGIN CERTIFICATE----- +MIIBjzCCATWgAwIBAgIUbf73QaxpKix6tj9EDwXsfqvPsPQwCgYIKoZIzj0EAwIw +FTETMBEGA1UEAwwKQ01QX1JPT1RDQTAeFw0yMzAzMjAyMzUzMTJaFw0zODAzMTYy +MzUzMTFaMBUxEzARBgNVBAMMCkNNUF9ST09UQ0EwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAAR0ukviHeyaDmbVCyfw9enYFBCxUDu2r4+dhfz9uJ6TDfR2f9ccoE0Z +EC/8KvNvEM1v5MCkfaOc5PPZmCU7vgNBo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8G +A1UdIwQYMBaAFPj3VMsyBY5x2442sx4yn/fWZ00/MB0GA1UdDgQWBBT491TLMgWO +cduONrMeMp/31mdNPzAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwIDSAAwRQIg +NdlFaGf2E7vhdfCF49ACIq8eo9myKv6f4znLJ1aa8pMCIQD+JHE6i1m8hsHU6jY0 +2ux5Cvt7BzT8+2ebIbSTTT/j5w== +-----END CERTIFICATE----- +Bag Attributes: +subject=CN=CMP_ISSUING_CA +issuer=CN=CMP_ROOTCA +-----BEGIN CERTIFICATE----- +MIIBkzCCATmgAwIBAgIUPgNxHZDaL13Is3RbTJ7joZrzS7swCgYIKoZIzj0EAwIw +FTETMBEGA1UEAwwKQ01QX1JPT1RDQTAeFw0yMzAzMjAyMzU0MDFaFw0zMzAzMTcy +MzU0MDBaMBkxFzAVBgNVBAMMDkNNUF9JU1NVSU5HX0NBMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEf+u8xxjMlp6JD4Hqhn7Wlzse8zsQlWY8PDAFvGOrQsR/4vYC +ITWaV5hZs7fiBo2jH47n8zzSbAEMQcbf3gXtw6NjMGEwDwYDVR0TAQH/BAUwAwEB +/zAfBgNVHSMEGDAWgBT491TLMgWOcduONrMeMp/31mdNPzAdBgNVHQ4EFgQUF7da +RjU5BsH4egc7IAquZ2nek5UwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA0gA +MEUCIQDvA71BlzTasNO9OsIelwV/DwIaR1Ss9kjv99n2q0+boQIgSjLn0IldzuUt +wK/hd2Gz4uNk626jI1EqTZC+goHJNaM= +-----END CERTIFICATE----- +Bag Attributes + localKeyID: EF 65 43 CF 4F 35 2E 54 DD 23 80 4A 54 7C FA 25 27 4C 60 9C +Key Attributes: +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIH0MF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBHXSevPSw+n8K8CE9Z +T6bBAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQ0LGlPDf7cyqpa7mI +Bl0VfgSBkFajoqFxhR4IJYcNUWN9yKN6mFGN+1lSHr+H7xpkb66Ju6r+uBBfdBnQ +y/k9NquDOAZER5LEWD/g7SXnXALyvUZm/hK8/cZOOjHnKot87JD/rLUXyK8xD50b +x0ntYwk+tAWo//mLWs9ACHvjJ/3H3Q1DX5z9F1YQxjGE8jmcSuW9c3ZfjhTEb0Nf +uAE0LYG7WQ== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/creds/docker/Docker_Playground_TLS.pem b/creds/docker/Docker_Playground_TLS.pem new file mode 100644 index 00000000..8a75184c --- /dev/null +++ b/creds/docker/Docker_Playground_TLS.pem @@ -0,0 +1,55 @@ +Bag Attributes + localKeyID: 90 A6 1E 0E 88 E9 EE 5D 61 BC AC B8 B8 41 6A 25 8B A2 94 2A +subject=CN=Docker_Playground_TLS +issuer=CN=TLS_ISSUING_CA +-----BEGIN CERTIFICATE----- +MIIBsDCCAVagAwIBAgIUFnCqv+gqsItFwtJVnwe6xXpYwbUwCgYIKoZIzj0EAwIw +GTEXMBUGA1UEAwwOVExTX0lTU1VJTkdfQ0EwHhcNMjMwNTA4MDc1NjU3WhcNMjgw +NTA2MDc1NjU2WjAgMR4wHAYDVQQDDBVEb2NrZXJfUGxheWdyb3VuZF9UTFMwWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAARXGKeXCT//bKq1OcRrCbX49Y8pPIi+dvT9 +TuTalc2zW22+ZsR34Q2HSCYME6T7upi1g/Xix/VYydGZX/urmaY0o3UwczAMBgNV +HRMBAf8EAjAAMB8GA1UdIwQYMBaAFMXoGtdk6ucyElh9XquMPvKl2sMFMBMGA1Ud +JQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBTJOlyP2jKopRhzMf02B7Hw0HGLjTAO +BgNVHQ8BAf8EBAMCBeAwCgYIKoZIzj0EAwIDSAAwRQIhAOXoTqtur7pj7nGhn3Vr +6v5BFM2nnHltuF3pNsb6YCHQAiBEuV8qopfQPjIkv2ZDwqaVFf2FneTCZVk4dUg9 +XZuKwg== +-----END CERTIFICATE----- +Bag Attributes: +subject=CN=TLS_ROOTCA +issuer=CN=TLS_ROOTCA +-----BEGIN CERTIFICATE----- +MIIBjzCCATWgAwIBAgIUV3mOhOV31ISfC5HwZFI656DFfrwwCgYIKoZIzj0EAwIw +FTETMBEGA1UEAwwKVExTX1JPT1RDQTAeFw0yMzAzMjAyMzU0MzVaFw0zODAzMTYy +MzU0MzRaMBUxEzARBgNVBAMMClRMU19ST09UQ0EwWTATBgcqhkjOPQIBBggqhkjO +PQMBBwNCAATZQ7UcbBgnDMPGF4ErhWxHMXioXjMtc5733ipXRi51/ZfnLl3YIb1z +hEdrnXxcc9UrzvY4A7diwf4GUciCIvNFo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8G +A1UdIwQYMBaAFJnEtCdu4aQyOp5+nifLwEhIddc/MB0GA1UdDgQWBBSZxLQnbuGk +Mjqefp4ny8BISHXXPzAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwIDSAAwRQIh +AJgGpUH4Ra6UrCGht9/lbnAAlZB+N9XhAljfaOiWveLpAiBPeufi17WrQQ1bE/qh +9EGpEmZrCs6urn5Ev/voAIa7nQ== +-----END CERTIFICATE----- +Bag Attributes: +subject=CN=TLS_ISSUING_CA +issuer=CN=TLS_ROOTCA +-----BEGIN CERTIFICATE----- +MIIBkjCCATmgAwIBAgIUDcfEgIEVzvy7TkvJk+ttQOCYfI4wCgYIKoZIzj0EAwIw +FTETMBEGA1UEAwwKVExTX1JPT1RDQTAeFw0yMzAzMjAyMzU1MDdaFw0zMzAzMTcy +MzU1MDZaMBkxFzAVBgNVBAMMDlRMU19JU1NVSU5HX0NBMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEdHKVuCRMGL8GGjeQZFZNuz6e5u5YKvIDpBn29J8dF77a35DO +dt/Kv//3P/HUuJF3BZQRDbsZYRO6bM6y8mR71KNjMGEwDwYDVR0TAQH/BAUwAwEB +/zAfBgNVHSMEGDAWgBSZxLQnbuGkMjqefp4ny8BISHXXPzAdBgNVHQ4EFgQUxega +12Tq5zISWH1eq4w+8qXawwUwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA0cA +MEQCIAjaBQoZoz0s6JAVn9P004OxCosDZ9D8R0YNdd1tfD/nAiBMgXc+C9jtm8nH +I7rwpzaxK5fbOomZDVNebCe/sBn/kg== +-----END CERTIFICATE----- +Bag Attributes + localKeyID: 90 A6 1E 0E 88 E9 EE 5D 61 BC AC B8 B8 41 6A 25 8B A2 94 2A +Key Attributes: +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIH0MF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBCog+CHAJjZjVXN/4GK +kZLsAgIIADAMBggqhkiG9w0CCQUAMB0GCWCGSAFlAwQBKgQQuGlJ+8CiAw9cIQER +y7noVwSBkDwnidGZZLjLC7SwNclTr1xNHDE4jzTW5H/yVhe6eAQeV/6kVTc50ZI/ +/v50kfnDe5849PhtqaJQpz9YqXHfKU6XGNMs7R5TOCy8LCQm21sY7iAyQuHePdwh +K5jpzDqwOlP1QI35vcZr6l4Ldy629BfgUsU63wMFptgG90iunQgMcxFJOgCowaVO +gz6ooYbXzg== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/debian/changelog b/debian/changelog index f2656090..ad24a892 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,7 +7,7 @@ libgencmp (2.2) stable; urgency=medium * Fix various issues and OpenSSL version incompatibilities * Disable demo_Insta because Insta Demo CA is defunct since end of 2025 - -- David von Oheimb Mon Feb 16 16:17:18 2026 +0100 + -- David von Oheimb Mon, 16 Feb 2026 16:17:18 +0100 libgencmp (2.1) stable; urgency=medium diff --git a/doc/Generic_CMP_client_API.odt b/doc/Generic_CMP_client_API.odt index 4516621b..658d0480 100644 Binary files a/doc/Generic_CMP_client_API.odt and b/doc/Generic_CMP_client_API.odt differ diff --git a/doc/Generic_CMP_client_API.pdf b/doc/Generic_CMP_client_API.pdf index 782113b3..87f3be0f 100644 Binary files a/doc/Generic_CMP_client_API.pdf and b/doc/Generic_CMP_client_API.pdf differ diff --git a/doc/OpenSSL_CMP-and-generic_CMP_client_overview.pptx b/doc/OpenSSL_CMP-and-generic_CMP_client_overview.pptx index 9b745821..00d2898c 100644 Binary files a/doc/OpenSSL_CMP-and-generic_CMP_client_overview.pptx and b/doc/OpenSSL_CMP-and-generic_CMP_client_overview.pptx differ diff --git a/doc/cmpClient.pod b/doc/cmpClient.pod index 8b153fd3..c24e54f4 100644 --- a/doc/cmpClient.pod +++ b/doc/cmpClient.pod @@ -50,9 +50,9 @@ Generic message options: Certificate enrollment options: -[B<-newkeytype> EC:I|RSA-I] +[B<-newkeytype> EC:I|RSA-I|ML-DSA-] [B<-centralkeygen>] -[B<-newkey> I] +[B<-newkey> I|I] [B<-newkeypass> I] [B<-subject> I] [B<-issuer> I] @@ -137,7 +137,7 @@ TLS connection options: [B<-tls_keypass> I] [B<-tls_extra> I] [B<-tls_trusted> I] -[B<-tls_host> I
] +[B<-tls_host> I] Debugging options: @@ -360,13 +360,21 @@ Note: any keySpec field contents received are logged as INFO. =item B<-newkeytype> I In case of IR, CR, or KUR, -generate or request a new key of the given type for the requested certificate. -The I may be of the form CI or CI. -The key will be saved in the file specified with the B<-newkey> option. - -This option cannot be used to create a key pair via a provider. -For use with a provider, the key pair must be generated beforehand -and then can be referenced via B<-newkey>. +generate or request a new key pair of the given type for the requested certificate. +The I may be of the form CI, CI, CI, or simply I. +Everything else is considered an ECC curve name if the OpenSSL version is below 3.5, +while for OpenSSL 3.5+, it is taken as an algorithm name, potentially including parameters, +such as C or CI. +For the full list of available algorithms see the output of C. +The RSA key length must be between 1024 and 8192 bits. +The available ECC curves can be shown with the command C. +The new key will be saved in the file specified with the B<-newkey> option, +unless the key is generated on a hardware secure element such as TPM 2.0. + +For key generation via the L provider, use this option in conjunction +with the B<-newkey> option having an argument of the form CI. +The B<-newkeytype> option so far cannot be used to create a key pair via other non-default providers, +so such a key pair must be generated beforehand and then can be referenced via B<-newkey>. =item B<-centralkeygen> @@ -375,15 +383,21 @@ This implies B<-popo> C<-1> = NONE. All other B<-popo> values are not consistent with this option. Default is local key generation. -=item B<-newkey> I +=item B<-newkey> I|I -The file to save the newly generated key +This option is used only when requesting a certificate via IR, CR, or KUR. +When a I or a I in the C scheme is given, +this specifies the file to save the newly generated key in case B<-newkeytype> or B<-centralkeygen> is given. -Otherwise the file to read the private or public key from -for the certificate requested in IR, CR or KUR. -Defaults to the public key in the PKCS#10 CSR given with the B<-csr> option, +Otherwise this gives the location (which may be handled by a provider) +to read the private or public key from for the certificate requested. +The key defaults to the public key in the PKCS#10 CSR given with the B<-csr> option, the public key of the reference certificate, or the current client key. +In conjunction with the B<-newkeytype> option, +if a I of the form CI is given, +this specifies key generation and storage via the `tpm2-openssl` provider. + =item B<-newkeypass> I Pass phrase source for the key file given with the B<-newkey> option. @@ -633,10 +647,16 @@ Reason numbers defined in RFC 5280 are: =item B<-server> I<[http[s]://][userinfo@]host[:port][/path][?query][#fragment]> The I domain name or IP address and optionally I -of the CMP server to connect to using HTTP(S). -IP address may be for v4 or v6, such as C<127.0.0.1> or C<[::1]> for localhost. -If the host string is an IPv6 address, it must be enclosed in C<[> and C<]>. -For TLS connections the host part is taken as fallback for the B<-tls_host> option. +of the CMP server to connect to via HTTP(S). +An IP address may be for v4 or v6, such as C<127.0.0.1> or C<[::1]> for C. +If the I string is an IPv6 address, it must be enclosed in C<[> and C<]>. + +For TLS connections, if I refers to the local host +(e.g., being the IP address C<127.0.0.1>), the server certificate subject is not checked. +Otherwise, the name verified in server certificates is I +unless the B<-tls_host> option is used to specify a different name. +If I is a DNS name, it is also used for +TLS Server Name Indication (SNI) according to RFC 3546 section 3.1. This option is ignored if I<-rspin> is given with enough filename arguments. @@ -1040,7 +1060,7 @@ Specifies name of supported digest to use in RFC 9810's MSG_SIG_ALG and as the one-way function (OWF) in MSG_MAC_ALG. If applicable, this is used for message protection and Proof-of-Possession (POPO) signatures. -To see the list of supported digests, use B. +To see the list of supported digests, use C. Defaults to C. =item B<-mac> I @@ -1119,11 +1139,9 @@ The certificate verification options B<-verify_hostname>, B<-verify_ip>, and B<-verify_email> have no effect on the certificate verification enabled via this option. -=item B<-tls_host> I
+=item B<-tls_host> I -Address to be used for Server Name Indication (SNI) according to RFC 3546 section 3.1 -and to be checked during TLS hostname validation. -This may be a DNS name (for SNI, only this is used) or an IPv4 or IPv6 address. +Hostname or IP address to be checked in the TLS server certificate. If not given it defaults to the host part of the B<-server> option URL argument. =back diff --git a/include/genericCMPClient.h b/include/genericCMPClient.h index 5b7d388c..dd88574a 100644 --- a/include/genericCMPClient.h +++ b/include/genericCMPClient.h @@ -26,8 +26,7 @@ extern "C" { # define OPENSSL_3_2_FEATURES (OPENSSL_VERSION_NUMBER >= 0x30200000L || defined(USE_LIBCMP)) # define OPENSSL_3_3_FEATURES (OPENSSL_VERSION_NUMBER >= 0x30300000L || defined(USE_LIBCMP)) # define OPENSSL_3_4_FEATURES (OPENSSL_VERSION_NUMBER >= 0x30400000L || defined(USE_LIBCMP)) -# define OPENSSL_4_0_FEATURES (OPENSSL_VERSION_NUMBER >= 0x40000000L) -# define OPENSSL_4_1_FEATURES (OPENSSL_VERSION_NUMBER >= 0x40100000L) +# define OPENSSL_4_1_FEATURES (OPENSSL_VERSION_NUMBER >= 0x40100000L || defined(USE_LIBCMP)) # if OPENSSL_VERSION_NUMBER < 0x30000000L || defined(USE_LIBCMP) # include /* if not found, maybe genericCMPClient_config.h is not up to date w.r.t. USE_LIBCMP, or OpenSSL version < 3.0 not correctly detected in CMakeLists.txt or Makefile_v1 */ @@ -270,6 +269,13 @@ void CMPclient_finish(OPTIONAL CMP_CTX *ctx); # include # endif +/* EVP_PKEY helpers */ +EVP_PKEY *KEY_new(const char *spec); /* may be "RSA:","EC:","ML-DSA-" */ +EVP_PKEY *KEY_new_ex(const char *spec, + OPTIONAL const char *location, /* may be "tpm2:handle=0x" */ + OPTIONAL OSSL_LIB_CTX *libctx); +void KEY_free(OPTIONAL EVP_PKEY *pkey); + /* X509_STORE helpers */ EVP_PKEY *KEY_load(OPTIONAL const char *file, OPTIONAL const char *pass, OPTIONAL const char *engine, OPTIONAL const char *desc); diff --git a/include/genericCMPClient_util.h b/include/genericCMPClient_util.h index 107d84c0..38bbe383 100644 --- a/include/genericCMPClient_util.h +++ b/include/genericCMPClient_util.h @@ -30,6 +30,8 @@ typedef struct credentials CREDENTIALS; /* util.h: */ # define OPENSSL_V_3_0_0 0x30000000L # define UTIL_setup_openssl(version, build_name) /* no-op */ +#define HAS_PREFIX(str, pre) (strncmp(str, pre "", sizeof(pre) - 1) == 0) +#define CHECK_AND_SKIP_PREFIX(str, pre) (HAS_PREFIX(str, pre) ? ((str) += sizeof(pre) - 1, 1) : 0) /* log.h: */ extern BIO *bio_err; /* for low-level error output if verbosity >= LOG_DEBUG */ @@ -96,6 +98,15 @@ void CREDENTIALS_free(OPTIONAL CREDENTIALS *creds); static const char *const sec_PASS_STR = "pass:"; /* cert.h: */ +# include /* needed for UTIL_SKIP_SCHEME() */ +/* Advance string pointer s, which must a modifiable lvalue, past scheme according to RFC 3986: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ +#define UTIL_SKIP_SCHEME(s) \ + do { \ + if (isalpha(*(s))) \ + while (*(s) != '\0' && (isalnum(*(s)) || strchr("+-.", *(s)) != NULL)) \ + (s)++; \ + } while (0) +#define UTIL_SCHEME_SUFFIX "://" X509_NAME *UTIL_parse_name(const char *dn, int chtype, bool multirdn); int UTIL_cmp_timeframe(OPTIONAL const X509_VERIFY_PARAM *vpm, OPTIONAL const ASN1_TIME *start, OPTIONAL const ASN1_TIME *end); @@ -120,7 +131,8 @@ X509_STORE *STORE_create(OPTIONAL X509_STORE *store, OPTIONAL const X509 *cert, # ifndef GENCMP_NO_TLS /* conn.h: */ -# define CONN_IS_IP_ADDR(host) ((host) != NULL && ((*(host) >= '0' && *(host) <= '9') || *(host) == '[')) // TODO improve +bool CONN_is_IP_address(OPTIONAL const char *host); +# define CONN_IS_IP_ADDR(host) CONN_is_IP_address(host) /* tls.h: */ # define TLS_init() true /* initialize OpenSSL's SSL lib, no needed at least since 3.0 */ diff --git a/libgencmp.pc b/libgencmp.pc new file mode 100644 index 00000000..d9c259be --- /dev/null +++ b/libgencmp.pc @@ -0,0 +1,18 @@ +# this template is filled-in by CMake `configure_file(... @ONLY)` +# the `@....@` are filled in by CMake configure_file(), +# from variables set in your CMakeLists.txt or by CMake itself +# +# Good tutorial for understanding .pc files: +# https://people.freedesktop.org/~dbn/pkg-config-guide.html + +includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ +libdir=@CMAKE_INSTALL_FULL_LIBDIR@ + +Name: @PROJECT_NAME@ +Description: @CMAKE_PROJECT_DESCRIPTION@ +URL: @CMAKE_PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ +Requires: @pc_req_public@ +Requires.private: @pc_req_private@ +Cflags: -I${includedir} +Libs: -L${libdir} -lsecutils -lgencmp diff --git a/libsecutils b/libsecutils index 3e3d7776..11a64413 160000 --- a/libsecutils +++ b/libsecutils @@ -1 +1 @@ -Subproject commit 3e3d7776784d8b60d043a5ee953488f3749dfe6f +Subproject commit 11a644131360384af5db61650d7a8de77774a60a diff --git a/src/cmpClient.c b/src/cmpClient.c index ec342853..fcba6742 100644 --- a/src/cmpClient.c +++ b/src/cmpClient.c @@ -84,9 +84,7 @@ const char *opt_recipient; const char *opt_expect_sender; bool opt_ignore_keyusage; bool opt_unprotected_errors; -#if OPENSSL_4_1_FEATURES bool opt_nonmatched_error_nonces; -#endif #if OPENSSL_3_3_FEATURES bool opt_no_cache_extracerts; #endif @@ -350,11 +348,9 @@ opt_t cmp_opts[] = { { "unprotected_errors", OPT_BOOL, {.bit = false}, { (const char **) &opt_unprotected_errors }, "Accept missing or invalid protection of regular error messages and negative"}, -#if OPENSSL_4_1_FEATURES { "nonmatched_error_nonces", OPT_BOOL, {.bit = false}, { (const char **) &opt_nonmatched_error_nonces }, "Accept missing or non-matching transactionID or recipNonce in error messages"}, -#endif OPT_MORE("certificate responses (ip/cp/kup), revocation responses (rp), and PKIConf"), #if OPENSSL_3_3_FEATURES { "no_cache_extracerts", OPT_BOOL, {.bit = false}, @@ -438,7 +434,7 @@ opt_t cmp_opts[] = { { "tls_trusted", OPT_TXT, {.txt = NULL}, { &opt_tls_trusted }, "File(s) with certs to trust for TLS server verification (TLS trust anchor)"}, { "tls_host", OPT_TXT, {.txt = NULL}, { &opt_tls_host }, - "Address to be used for SNI and to be checked during TLS hostname validation"}, + "Host name/address (rather than -server) to check in TLS server cert"}, OPT_HEADER("Debugging"), {"reqin", OPT_TXT, {.txt = NULL}, { (const char **) &opt_reqin}, @@ -556,8 +552,6 @@ static SSL_CTX *setup_TLS(STACK_OF(X509) *untrusted_certs) LOG_err("TLS is not enabled in this build"); return NULL; #else - const char *host = opt_tls_host; - char *server_host = NULL; CREDENTIALS *tls_creds = NULL; SSL_CTX *tls = NULL; @@ -606,23 +600,9 @@ static SSL_CTX *setup_TLS(STACK_OF(X509) *untrusted_certs) if (tls == NULL) goto err; - /* - * Enable and parameterize server hostname/IP address check. - * If we did this before checking our own TLS cert in TLS_new(), - * the expected hostname would mislead the check. - */ - if (host == NULL && opt_server != NULL) { - if (!OSSL_HTTP_parse_url(opt_server, NULL, NULL, &server_host, NULL, NULL, - NULL, NULL, NULL)) { - LOG(FL_ERR, "Cannot parse -server URL: %s", opt_server); - goto err; - } - host = server_host; - } - - if (tls_trust != NULL && !STORE_set1_host_ip(tls_trust, host, host)) + if (tls_trust != NULL && opt_tls_host != NULL + && !STORE_set1_host_ip(tls_trust, opt_tls_host, opt_tls_host)) goto err; - OPENSSL_free(server_host); /* If present we append to the list also the certs from opt_tls_extra */ if (opt_tls_extra != NULL) { @@ -670,27 +650,25 @@ static X509_STORE *setup_CMP_truststore(const char *trusted_cert_files) return cmp_truststore; } -static X509_EXTENSIONS *setup_X509_extensions(CMP_CTX *ctx) +/* on success, results in *exts == NULL when there are no extensions */ +static bool setup_X509_extensions_check_policies(CMP_CTX *ctx, X509_EXTENSIONS **exts) { - X509_EXTENSIONS *exts = sk_X509_EXTENSION_new_null(); X509V3_CTX ext_ctx; - if (exts == NULL) - return NULL; if (opt_reqexts != NULL || opt_policies != NULL) { X509V3_set_ctx(&ext_ctx, NULL, NULL, NULL, NULL, 0); X509V3_set_nconf(&ext_ctx, config); } if (opt_reqexts != NULL) { - if (!X509V3_EXT_add_nconf_sk(config, &ext_ctx, opt_reqexts, &exts)) { + if (!X509V3_EXT_add_nconf_sk(config, &ext_ctx, opt_reqexts, exts)) { LOG(FL_ERR, "Cannot load extension section '%s'", opt_reqexts); goto err; } } if (opt_policies != NULL) { - if (!X509V3_EXT_add_nconf_sk(config, &ext_ctx, opt_policies, &exts)) { + if (!X509V3_EXT_add_nconf_sk(config, &ext_ctx, opt_policies, exts)) { LOG(FL_ERR, "Cannot load policy section '%s'", opt_policies); goto err; } @@ -735,11 +713,12 @@ static X509_EXTENSIONS *setup_X509_extensions(CMP_CTX *ctx) opt_policy_oids = next; } - return exts; + return true; err: - EXTENSIONS_free(exts); - return NULL; + EXTENSIONS_free(*exts); + *exts = NULL; + return false; } /* @@ -1080,10 +1059,6 @@ static int setup_ctx(CMP_CTX *ctx) /* set option flags directly via CMP API */ if (!OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS, opt_unprotected_errors ? 1 : 0) -#if OPENSSL_4_1_FEATURES - || !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_NONMATCHED_ERROR_NONCES, - opt_nonmatched_error_nonces ? 1 : 0) -#endif #if OPENSSL_3_3_FEATURES || (opt_no_cache_extracerts && /* TODO remove this condition, which is just a workaround for wrong variant of OSSL_CMP_CTX_set_option() being called */ !OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_NO_CACHE_EXTRACERTS, @@ -1103,6 +1078,19 @@ static int setup_ctx(CMP_CTX *ctx) LOG_err("Failed to set option flags of CMP context"); goto err; } +#if OPENSSL_4_1_FEATURES + if (!OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_NONMATCHED_ERROR_NONCES, + opt_nonmatched_error_nonces ? 1 : 0)) { + LOG_err("Failed to set option flags of CMP context"); + goto err; + } +#else + if (opt_nonmatched_error_nonces) { + LOG_err("-nonmatched_error_nonces option is not supported for OpenSSL < 4.1"); + err = -29; + goto err; + } +#endif if (opt_profile != NULL) { #if OPENSSL_3_3_FEATURES @@ -1392,7 +1380,21 @@ static int setup_transfer(CMP_CTX *ctx) return err; } -/* file (path) name using prefix, subject DN, "_", hash, ".", and suffix */ +static int get_NAME_text_by_NID(const X509_NAME *name, int nid, unsigned char **out) +{ + int i; + + for (i = 0; i < X509_NAME_entry_count(name); i++) { + const X509_NAME_ENTRY *e = X509_NAME_get_entry(name, i); + const ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(e); + + if (OBJ_obj2nid(obj) == nid) + return ASN1_STRING_to_UTF8(out, X509_NAME_ENTRY_get_data(e)); + } + return -2; +} + +/* file (path) name using prefix, subject commonName, "_", hash, ".", and suffix */ static size_t get_cert_filename(const X509 *cert, const char *prefix, const char *suffix, char *buf, size_t buf_len) @@ -1409,13 +1411,20 @@ static size_t get_cert_filename(const X509 *cert, const char *prefix, buf[++len] = '\0'; } - char subject[256], *p; - if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, - subject, sizeof(subject)) <= 0) + unsigned char *subject_cn = NULL; + int cn_len = get_NAME_text_by_NID(X509_get_subject_name(cert), NID_commonName, &subject_cn); + if (cn_len < 0 || + (size_t)cn_len != strlen((char *)subject_cn) /* detects embedded NUL bytes */) { + LOG_err("Error getting subject commonName"); + OPENSSL_free(subject_cn); return 0; - ret = UTIL_safe_string_copy(subject, buf + len, buf_len - len, NULL); + } + ret = UTIL_safe_string_copy((char *)subject_cn, buf + len, buf_len - len, NULL); + OPENSSL_free(subject_cn); if (ret < 0) return 0; + + char *p; for (p = buf + len; *p != '\0'; p++) if (*p == ' ') *p = '_'; @@ -1788,6 +1797,7 @@ static CMP_err check_options(enum use_case use_case) return CMP_OK; } +/* on success, results in *exts == NULL when there are no extensions */ static CMP_err check_set_template_options(CMP_CTX *ctx, EVP_PKEY **new_pkey, X509 **oldcert, X509_REQ **csr, X509_EXTENSIONS **exts, @@ -1815,7 +1825,8 @@ static CMP_err check_set_template_options(CMP_CTX *ctx, EVP_PKEY **new_pkey, } else { if (opt_newkeytype != NULL || opt_centralkeygen) { if (opt_newkey == NULL) { - LOG_err("Missing -newkey option specifying the file to save the new key"); + LOG(FL_ERR, "Missing -newkey option specifying the file to save the new key%s", + opt_centralkeygen ? "" : " (or TPM2 provider handle to use)"); return -40; } if (opt_newkeytype != NULL && *opt_newkeytype != '\0') { @@ -1823,7 +1834,7 @@ static CMP_err check_set_template_options(CMP_CTX *ctx, EVP_PKEY **new_pkey, const char *key_spec = strcmp(opt_newkeytype, "ECC") == 0 ? "EC:secp256r1" : opt_newkeytype; - if ((*new_pkey = KEY_new(key_spec)) == NULL) { + if ((*new_pkey = KEY_new_ex(key_spec, opt_newkey, app_get0_libctx())) == NULL) { LOG(FL_ERR, "Unable to generate new private key according to specification '%s'", key_spec); return CMP_R_GENERATE_KEY; @@ -1862,7 +1873,7 @@ static CMP_err check_set_template_options(CMP_CTX *ctx, EVP_PKEY **new_pkey, if ((err = setup_cert_template(ctx)) != CMP_OK) return err; - if ((*exts = setup_X509_extensions(ctx)) == NULL) { + if (!setup_X509_extensions_check_policies(ctx, exts)) { LOG_err("Unable to set up X509 extensions for CMP client"); return -44; } @@ -2447,7 +2458,7 @@ static int CMPclient(enum use_case use_case, OPTIONAL LOG_cb_t log_fn) goto err; } if ((err = setup_ctx(ctx)) != CMP_OK) { - LOG_err("Failed to prepare CMP client"); + LOG_err("Failed to set up CMP client"); goto err; } if ((err = check_set_template_options(ctx, &new_pkey, &oldcert, &csr, diff --git a/src/credential_loading.c b/src/credential_loading.c index 70f246ec..d6911648 100644 --- a/src/credential_loading.c +++ b/src/credential_loading.c @@ -260,15 +260,16 @@ static const UI_METHOD *get_ui_method(void) /* from OpenSSL/apps/lib/apps.c: */ -static const char *format2string(int format) +static const char *format2string(file_format_t format) { switch (format) { case FORMAT_PEM: return "PEM"; case FORMAT_ASN1: return "DER"; + default: + return NULL; } - return NULL; } static void unbuffer(FILE *fp) @@ -306,8 +307,8 @@ static void unbuffer(FILE *fp) pcrl != NULL ? "CRL" : pcrls != NULL ? "CRLs" : NULL) /* * Load those types of credentials for which the result pointer is not NULL. - * Reads from stdin if 'uri' is NULL and 'maybe_stdin' is nonzero. - * 'format' parameter may be FORMAT_PEM, FORMAT_ASN1, or 0 for no hint. + * Reads from stdin if 'uri' is NULL and 'maybe_stdin' is true. + * 'format' parameter may be FORMAT_PEM, FORMAT_ASN1, or FORMAT_UNDEF (0) for no hint. * desc may contain more detail on the credential(s) to be loaded for error msg * For non-NULL ppkey, pcert, and pcrl the first suitable value found is loaded. * If pcerts is non-NULL and *pcerts == NULL then a new cert list is allocated. @@ -322,7 +323,7 @@ static void unbuffer(FILE *fp) static bool load_key_certs_crls(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, const char *pass, const char *desc, bool quiet, EVP_PKEY **ppkey, EVP_PKEY **ppubkey, EVP_PKEY **pparams, @@ -604,7 +605,7 @@ bool load_key_certs_crls(OSSL_LIB_CTX *libctx, const char *propq, } EVP_PKEY *FILES_load_key_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, const char *source, const char *desc) { char *pass; @@ -620,7 +621,7 @@ EVP_PKEY *FILES_load_key_ex(OSSL_LIB_CTX *libctx, const char *propq, } EVP_PKEY *FILES_load_pubkey_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, const char *source, const char *desc) { char *pass; @@ -636,7 +637,7 @@ EVP_PKEY *FILES_load_pubkey_ex(OSSL_LIB_CTX *libctx, const char *propq, } X509 *FILES_load_cert_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, OPTIONAL const char *source, OPTIONAL const char *desc, int type_CA, OPTIONAL const X509_VERIFY_PARAM *vpm) { @@ -675,7 +676,7 @@ static bool check_cert_chain(const char *src, int type_CA, OPTIONAL const X509_V } bool FILES_load_certs_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *srcs, int format, int timeout, bool maybe_stdin, + const char *srcs, file_format_t format, int timeout, bool maybe_stdin, const char *source, const char *desc, int min_num, int type_CA, OPTIONAL X509_VERIFY_PARAM *vpm, OPTIONAL X509 **cert, OPTIONAL STACK_OF(X509) **certs) @@ -779,7 +780,7 @@ STACK_OF(X509) *load_certs_multifile(const char *files, const char *source, } X509_CRL *FILES_load_crl_ex(OSSL_LIB_CTX *libctx, const char *propq, const char *src, - int format, int maybe_stdin, int timeout, OPTIONAL const char *desc, + file_format_t format, bool maybe_stdin, int timeout, OPTIONAL const char *desc, OPTIONAL const X509_VERIFY_PARAM *vpm) { X509_CRL *crl = NULL; @@ -811,7 +812,7 @@ X509_CRL *FILES_load_crl_ex(OSSL_LIB_CTX *libctx, const char *propq, const char } STACK_OF(X509_CRL) *FILES_load_crls_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *srcs, int format, int timeout, + const char *srcs, file_format_t format, int timeout, OPTIONAL const char *desc, int min_num, OPTIONAL const X509_VERIFY_PARAM *vpm) { diff --git a/src/credential_loading.h b/src/credential_loading.h index f4f49228..f058624f 100644 --- a/src/credential_loading.h +++ b/src/credential_loading.h @@ -30,19 +30,19 @@ int setup_ui_method(void); void destroy_ui_method(void); EVP_PKEY *FILES_load_key_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, const char *source, const char *desc); #define load_key_pwd(uri, format, pass, e, desc) \ FILES_load_key_ex(app_get0_libctx(), app_get0_propq(), uri, format, false, pass, desc) EVP_PKEY *FILES_load_pubkey_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, const char *source, const char *desc); #define load_pubkey_pwd(uri, format, pass, e, desc) \ FILES_load_pubkey_ex(app_get0_libctx(), app_get0_propq(), uri, format, false, pass, desc) X509 *FILES_load_cert_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *uri, int format, bool maybe_stdin, + const char *uri, file_format_t format, bool maybe_stdin, OPTIONAL const char *source, OPTIONAL const char *desc, int type_CA, OPTIONAL const X509_VERIFY_PARAM *vpm); #define load_cert_pwd(uri, source, desc, type_CA, vpm) \ @@ -50,7 +50,7 @@ X509 *FILES_load_cert_ex(OSSL_LIB_CTX *libctx, const char *propq, FILES_get_format(uri), false, source, desc, type_CA, vpm) bool FILES_load_certs_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *srcs, int format, int timeout, bool maybe_stdin, + const char *srcs, file_format_t format, int timeout, bool maybe_stdin, const char *source, const char *desc, int min_num, int type_CA, OPTIONAL X509_VERIFY_PARAM *vpm, OPTIONAL X509 **cert, OPTIONAL STACK_OF(X509) **certs); @@ -59,15 +59,15 @@ STACK_OF(X509) *load_certs_multifile(const char *files, const char *source, OPTIONAL X509_VERIFY_PARAM *vpm); X509_CRL *FILES_load_crl_ex(OSSL_LIB_CTX *libctx, const char *propq, const char *src, - int format, int maybe_stdin, int timeout, OPTIONAL const char *desc, + file_format_t format, bool maybe_stdin, int timeout, OPTIONAL const char *desc, OPTIONAL const X509_VERIFY_PARAM *vpm); #define load_crl(src, format, stdin, timeout, desc, vpm) \ FILES_load_crl_ex(app_get0_libctx(), app_get0_propq(), src, format, stdin, timeout, desc, vpm) STACK_OF(X509_CRL) *FILES_load_crls_ex(OSSL_LIB_CTX *libctx, const char *propq, - const char *files, int format, int timeout, + const char *files, file_format_t format, int timeout, OPTIONAL const char *desc, int min_num, OPTIONAL const X509_VERIFY_PARAM *vpm); -#define load_crls(files, format, timeout, desc, vpm) \ +#define load_crls(files, format, timeout, desc, vpm) \ FILES_load_crls_ex(app_get0_libctx(), app_get0_propq(), files, format, timeout, desc, 0, vpm) bool FILES_load_credentials_ex(OPTIONAL OSSL_LIB_CTX *libctx, const char *propq, diff --git a/src/genericCMPClient.c b/src/genericCMPClient.c index e726a4e6..78eb99ed 100644 --- a/src/genericCMPClient.c +++ b/src/genericCMPClient.c @@ -319,7 +319,6 @@ static char *opt_getprog(void) } typedef struct app_http_tls_info_st { - const char *sni_hostname; const char *server; const char *port; int use_proxy; @@ -378,7 +377,8 @@ static BIO *app_http_tls_cb(BIO *bio, void *arg, int connect, int detail) SSL_set_connect_state(ssl); BIO_set_ssl(sbio, ssl, BIO_CLOSE); - if (!SSL_set_tlsext_host_name(ssl, info->sni_hostname /* may be NULL */)) + if (!CONN_IS_IP_ADDR(info->server) + && !SSL_set_tlsext_host_name(ssl, info->server)) /* set SNI */ goto err; bio = BIO_push(sbio, bio); @@ -413,7 +413,6 @@ static BIO *app_http_tls_cb(BIO *bio, void *arg, int connect, int detail) static void APP_HTTP_TLS_INFO_free(APP_HTTP_TLS_INFO *info) { if (info != NULL) { - OPENSSL_free((char *)info->sni_hostname); OPENSSL_free((char *)info->server); OPENSSL_free((char *)info->port); SSL_CTX_free(info->ssl_ctx); @@ -429,6 +428,10 @@ static int is_localhost(const char *host) } #endif /* ndef GENCMP_NO_TLS */ +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_3_0_0 +# define X509_VERIFY_PARAM_get0_email(vpm) ((void)(vpm), NULL) /* dummy */ +# define X509_VERIFY_PARAM_get1_ip_asc(vpm) ((void)(vpm), NULL) /* dummy */ +#endif /* Will return error when used with OpenSSL compiled with OPENSSL_NO_SOCK. */ CMP_err CMPclient_setup_HTTP(OSSL_CMP_CTX *ctx, const char *server, const char *path, int keep_alive, int timeout, OPTIONAL SSL_CTX *tls, @@ -480,25 +483,31 @@ CMP_err CMPclient_setup_HTTP(OSSL_CMP_CTX *ctx, const char *server, const char * #ifndef GENCMP_NO_TLS if (tls != NULL) { X509_STORE *ts = SSL_CTX_get_cert_store(tls); - X509_VERIFY_PARAM *vpm = ts != NULL ? X509_STORE_get0_param(ts) : NULL; - char *ip; - const char *hostaddr = ts != NULL ? STORE_get0_host(ts) : NULL; - - if (is_localhost(host)) { - hostaddr = NULL; - LOG(FL_WARN, "Skipping host name verification on localhost"); - /* enables self-bootstrapping of local RA using its device cert */ - } else if (hostaddr == NULL) { - hostaddr = host; - /* set expected host in ts, if no name validation has been set there so far */ - if (vpm != NULL && X509_VERIFY_PARAM_get0_email(vpm) == NULL) { - ERR_set_mark(); - ip = X509_VERIFY_PARAM_get1_ip_asc(vpm); - ERR_pop_to_mark(); - OPENSSL_free(ip); - if (ip == NULL && !STORE_set1_host_ip(ts, host, 0)) { - err = CMPOSSL_error(); - goto err; + if (ts != NULL) { + X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts); + const char *custom_tls_host = STORE_get0_host(ts); + if (custom_tls_host == NULL && vpm != NULL) { + custom_tls_host = X509_VERIFY_PARAM_get0_email(vpm); /* theoretical case, just for completeness */ + if (custom_tls_host == NULL) { + ERR_set_mark(); + char *ip = X509_VERIFY_PARAM_get1_ip_asc(vpm); + ERR_pop_to_mark(); + if (ip != NULL) + custom_tls_host = "some IP address"; + OPENSSL_free(ip); + } + } + + if (custom_tls_host == NULL) { + if (is_localhost(host)) { + LOG(FL_WARN, "Skipping TLS server host name verification for %s because it is local", host); + /* enables self-bootstrapping of local RA using its device cert */ + } else { + /* set expected host in ts, if no name validation whatsoever has been set there so far */ + if (!STORE_set1_host_ip(ts, host, host)) { + err = CMPOSSL_error(); + goto err; + } } } } @@ -517,14 +526,6 @@ CMP_err CMPclient_setup_HTTP(OSSL_CMP_CTX *ctx, const char *server, const char * /* info will be freed along with ctx */ OSSL_CMP_CTX_set_transfer_cb_arg(ctx, NULL); /* indicate SSL not used */ - if (!CONN_IS_IP_ADDR(hostaddr)) { - if (hostaddr == NULL) { - info->sni_hostname = NULL; - } else if ((info->sni_hostname = OPENSSL_strdup(hostaddr)) == NULL) { - err = CMPOSSL_error(); - goto err; - } - } info->server = OPENSSL_strdup(host); info->port = OPENSSL_strdup(server_port); info->use_proxy = proxy_host != NULL; diff --git a/src/genericCMPClient_util.c b/src/genericCMPClient_util.c index 80dd452f..77a9798f 100644 --- a/src/genericCMPClient_util.c +++ b/src/genericCMPClient_util.c @@ -577,14 +577,30 @@ X509_STORE *STORE_create(OPTIONAL X509_STORE *store, OPTIONAL const X509 *cert, /* conn.c: */ -static const char *const CONN_scheme_postfix = "://"; +bool CONN_is_IP_address(OPTIONAL const char *host) +{ + if (host == NULL) + return false; + + /* presume IPv6 address literal if host has the form "[]" */ + size_t len = strlen(host); + if (len > 2 && *host == '[' && strchr(host + 1, '[') == NULL + && strchr(host + 1, ']') == host + len - 1) + return true; + + ERR_set_mark(); + ASN1_OCTET_STRING *str = a2i_IPADDRESS(host); + ERR_pop_to_mark(); + ASN1_OCTET_STRING_free(str); + return str != NULL; +} static const char *skip_scheme(const char *str) { - const char *scheme_end = strstr(str, CONN_scheme_postfix); - - if (scheme_end != NULL) - str = scheme_end + strlen(CONN_scheme_postfix); + const char *scheme_end = str; + UTIL_SKIP_SCHEME(scheme_end); + if (scheme_end != str && CHECK_AND_SKIP_PREFIX(scheme_end, UTIL_SCHEME_SUFFIX)) + str = scheme_end; return str; } @@ -629,7 +645,7 @@ bool STORE_set1_host_ip(X509_STORE *ts, OPTIONAL const char *name, OPTIONAL cons !X509_VERIFY_PARAM_set1_host(ts_vpm, 0, 0) || !X509_VERIFY_PARAM_set1_ip(ts_vpm, 0, 0) || !X509_VERIFY_PARAM_set1_email(ts_vpm, 0, 0)) { - LOG_err("Could not clear host name and IP address from store"); + LOG_err("Could not clear host names and IP and email addresses from store"); return false; } @@ -637,13 +653,22 @@ bool STORE_set1_host_ip(X509_STORE *ts, OPTIONAL const char *name, OPTIONAL cons return true; char *name_str = CONN_get_host(name); + char *ip_str = NULL; if (name != NULL && name_str == NULL) return false; - - char *ip_str = CONN_get_host(ip); - if (ip != NULL && ip_str == NULL) { - OPENSSL_free(name_str); - return false; + if (name != NULL && ip != NULL && strcmp(name, ip) == 0) { + if (CONN_IS_IP_ADDR(name)) { + ip_str = name_str; + name = name_str = NULL; + } else { + ip = NULL; + } + } else { + ip_str = CONN_get_host(ip); + if (ip != NULL && ip_str == NULL) { + OPENSSL_free(name_str); + return false; + } } X509_VERIFY_PARAM_set_hostflags(ts_vpm, @@ -652,8 +677,8 @@ bool STORE_set1_host_ip(X509_STORE *ts, OPTIONAL const char *name, OPTIONAL cons bool res = true; if (ip_str != NULL && !X509_VERIFY_PARAM_set1_ip_asc(ts_vpm, ip_str)) res = false; - if (name_str != NULL && (ip_str == NULL || (res && strcmp(name, ip) == 0))) { - res = X509_VERIFY_PARAM_set1_host(ts_vpm, name_str, 0) != 0; + if (name_str != NULL) { + res = res && X509_VERIFY_PARAM_set1_host(ts_vpm, name_str, 0) != 0; # if OPENSSL_VERSION_NUMBER < OPENSSL_V_3_0_0 /* * Before OpenSSL 3.0, there was no API function for retrieving the @@ -661,8 +686,7 @@ bool STORE_set1_host_ip(X509_STORE *ts, OPTIONAL const char *name, OPTIONAL cons * in ex_data for use in CREDENTIALS_print_cert_verify_cb(). * Since OpenSSL 3.0, this is no more needed as X509_VERIFY_PARAM_get0_host() is available. */ - if (res) - res = STORE_set1_host(ts, name_str); + res = res && STORE_set1_host(ts, name_str); # endif } if (!res) @@ -682,7 +706,7 @@ const char *STORE_get0_host(const X509_STORE *store) * We could use ex_data, but do not support this with GENCMP_NO_SECUTILS. */ (void)store; /* prevent compiler warning on unused parameter */ - return false; + return NULL; # else /* first hostname set in store vpm: */ return X509_VERIFY_PARAM_get0_host(X509_STORE_get0_param(store), 0); diff --git a/test/recipes/80-test_cmp_http.t b/test/recipes/80-test_cmp_http.t index 074c5e9f..2ef91c35 100644 --- a/test/recipes/80-test_cmp_http.t +++ b/test/recipes/80-test_cmp_http.t @@ -1,5 +1,5 @@ #! /usr/bin/env perl -# Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 2007-2026 The OpenSSL Project Authors. All Rights Reserved. # Copyright Nokia 2007-2019 # Copyright Siemens AG 2015-2019 # @@ -15,19 +15,28 @@ use warnings; use POSIX; sub data_dir { return "../test/recipes/80-test_cmp_http_data" } sub result_dir { return "." } -use OpenSSL::Test qw/:DEFAULT cmdstr data_file bldtop_dir/; +use OpenSSL::Test qw/:DEFAULT cmdstr data_file srctop_dir bldtop_dir/; use OpenSSL::Test::Utils; BEGIN { setup("test_cmp_http"); } +use lib srctop_dir('Configurations'); +use lib bldtop_dir('.'); + +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; plan skip_all => "These tests are not supported in a no-cmp build" if disabled("cmp"); -plan skip_all => "These tests are not supported in a no-ec build" - if disabled("ec"); +plan skip_all => "These tests are not supported in a no-ecx build" + if disabled("ecx"); # EC and EDDSA test certs, e.g., in Mock/newWithNew.pem plan skip_all => "These tests are not supported in a no-sock build" if disabled("sock"); +plan skip_all => "These tests are not supported in a no-http build" + if disabled("http"); +plan skip_all => "These tests are not supported in a no-cms build" + if disabled("cms"); # central key pair generation plan skip_all => "Tests involving local HTTP server not available on Windows or VMS" if $^O =~ /^(VMS|MSWin32|msys)$/; @@ -50,7 +59,7 @@ my @app = qw(cmpClient); # the server-dependent client configuration consists of: my $ca_dn; # The CA's Distinguished Name my $server_dn; # The server's Distinguished Name -my $server_host;# The server's hostname or IP address +my $server_host;# The server's hostname or IP address, '*' means to be determined from server output my $server_port;# The server's port my $server_tls; # The server's TLS port, if any, or 0 my $server_path;# The server's CMP alias @@ -127,12 +136,13 @@ sub load_config { } close CH; die "Cannot find all server-dependent config values in $test_config section [$section]\n" - if !defined $ca_dn || !defined $server_host + if !defined $ca_dn + || !defined $server_dn || !defined $server_host || !defined $server_port || !defined $server_tls || !defined $server_path || !defined $server_cert - || !defined $kur_port || !defined $pbm_port - || !defined $pbm_ref || !defined $pbm_secret - || !defined $column || !defined $sleep; + || !defined $kur_port || !defined $pbm_port + || !defined $pbm_ref || !defined $pbm_secret + || !defined $column || !defined $sleep; die "Invalid server_port number in $test_config section [$section]: $server_port" unless $server_port =~ m/^\d+$/; $server_dn = $server_dn // $ca_dn; @@ -142,18 +152,19 @@ my @server_configurations = ("Mock"); # ("Mock", "EJBCA", "Insta", "Simple"); @server_configurations = split /\s+/, $ENV{OPENSSL_CMP_SERVER} if $ENV{OPENSSL_CMP_SERVER}; # set env variable, e.g., OPENSSL_CMP_SERVER="Mock Insta" to include further CMP servers -my $mock_openssl_version = `$ENV{OPENSSL} version | perl -pe 's/OpenSSL (\\d\\.\\d).*/\$1/es;'` if grep(/^Mock$/, @server_configurations); +my $openssl = $ENV{OPENSSL}; +my $mock_openssl_version = `$openssl version | perl -pe 's/OpenSSL (\\d\\.\\d).*/\$1/es;'` if grep(/^Mock$/, @server_configurations); my @all_aspects = ("connection", "verification", "credentials", "commands", "enrollment"); push (@all_aspects, "certstatus"); @all_aspects = split /\s+/, $ENV{OPENSSL_CMP_ASPECTS} if $ENV{OPENSSL_CMP_ASPECTS}; # set env variable, e.g., OPENSSL_CMP_ASPECTS="commands enrollment" to select specific aspects +my $Mock_serverlog; my $faillog; -my $file = $ENV{HARNESS_FAILLOG}; # pathname relative to result_dir -if ($file) { - open($faillog, ">", $file) or die "Cannot open '$file' for writing: $!"; -} +my $faillog_file = $ENV{HARNESS_FAILLOG} // "failed_client_invocations.txt"; # pathname relative to result_dir +open($faillog, ">", $faillog_file) or die "Cannot open '$faillog_file' for writing: $!"; +$faillog->autoflush(1); sub test_cmp_http { my $server_name = shift; @@ -163,52 +174,10 @@ sub test_cmp_http { my $title = shift; my $params = shift; my $expected_result = shift; - $params = [ '-server', "127.0.0.1:$server_port", @$params ] + $params = [ '-server', "$server_host:$server_port", @$params ] if ($server_name eq "Mock" && !(grep { $_ eq '-server' } @$params)); my $cmd = app([@app, @$params]); - sleep($sleep) if $server_name eq "Insta"; - sleep($sleep) if $server_name eq "Insta" - && $title eq "path with additional '/'s fine according to RFC 3986" - || $title eq "requesting new signer.crt for Insta" - || $title eq "unknown attribute in expected sender DN skipped" - || $title eq "no -trusted but -srvcert" - || $title eq "ignore key usage" - || $title eq "empty ref but correct cert" - || $title eq "keypass no prefix" - || $title eq "extracerts big file" - || $title eq "extracerts empty file" - || $title eq "default sha256" - || $title eq "--- requesting new signer.crt for Insta ---" - || $title eq "--- get certificate for revocation ----" - || $title eq "rr with revreason AACompromise" - || $title eq "ir + infotype" - || $title eq "geninfo empty str" - || $title eq "missing chain" - || $title eq "newkeypass ignored" - || $title eq "subject organization unit missing" - || $title eq "subject bad syntax: missing '='" - || $title eq "days 1" - || $title eq "reqexts" - || $title eq "sans 2 dns" - || $title eq "san_nodefault" - || $title eq "no out_trusted" - || $title eq "oldcert wrong cert" - || $title eq "kur command explicit options - overwriting oldcert" - || $title eq "crls_timeout infinite" - || $title eq "total_timeout 0" - || $title eq "issuer NULL-DN" - || $title eq "sans 1 dns critical" - || $title eq "reuse last extracerts" - || $title eq "cacertsout given" - || $title eq "subject incorrect data" - || $title eq "cr command" - || $title eq "reqout cr rspout cp" - || $title eq "popo SIGNATURE" - || $title eq "read newkeypass from file" - || $title eq "extracerts wrong chain (some root CA)" - || $title eq "reuse last srvcert"; - unless (is(my $actual_result = run($cmd), $expected_result, $title)) { if ($faillog) { my $quote_spc_empty = sub { $_ eq "" ? '""' : $_ =~ m/ / ? '"'.$_.'"' : $_ }; @@ -220,7 +189,6 @@ sub test_cmp_http { print $faillog "$invocation\n\n"; } sleep($sleep) if $expected_result == 1; - sleep($sleep) if $server_name eq "Insta" && $expected_result == 1; } } @@ -239,6 +207,17 @@ sub test_cmp_http_aspect { # not unlinking test.cert.pem, test.cacerts.pem, and test.extracerts.pem } +sub print_file_prefixed { + my ($file, $desc) = @_; + print "$desc (each line prefixed by \"# \"):\n"; + if (open(my $fh, '<', $file)) { + while (<$fh>) { + print "# $_"; + } + close $fh; + } +} + # The input files for the tests done here dynamically depend on the test server # selected (where the mock server used by default is just one possibility). # On the other hand the main test configuration file test.cnf, which references @@ -251,7 +230,7 @@ sub test_cmp_http_aspect { indir data_dir() => sub { plan tests => 1 + @server_configurations * @all_aspects + 2 - - (grep(/^Mock$/, @server_configurations) # && $mock_openssl_version < 3.x + - (grep(/^Mock$/, @server_configurations) && $mock_openssl_version < 3.0 && grep(/^certstatus$/, @all_aspects)); indir "Mock" => sub { @@ -274,27 +253,38 @@ indir data_dir() => sub { } foreach my $aspect (@all_aspects) { $aspect = chop_dblquot($aspect); - if (# $mock_openssl_version < 3.x && - $server_name eq "Mock" && $aspect eq "certstatus") { + if ($server_name eq "Mock" && $aspect eq "certstatus" && $mock_openssl_version < 3.0) { print "Skipping certstatus check as not supported by $server_name server with OpenSSL version $mock_openssl_version\n"; next; } - if (not($server_name =~ m/Insta/)) { # do not update aspect-specific settings for Insta load_config($server_name, $aspect); # update with any aspect-specific settings - } indir $server_name => sub { my $tests = load_tests($server_name, $aspect); test_cmp_http_aspect($server_name, $aspect, $tests); }; }; - stop_server($server_name, $pid) if $pid; - ok(1, "$server_name server has terminated"); + + if ($server_name eq "Mock") { + stop_server($server_name, $pid) if $pid; + ok(1, "$server_name server has terminated"); + + if (-s $faillog) { + indir "Mock" => sub { + print_file_prefixed($Mock_serverlog, "$server_name server STDERR output is"); + } + } + } } } }; }; close($faillog) if $faillog; +if (-s $faillog_file) { + print "# ------------------------------------------------------------------------------\n"; + print_file_prefixed($faillog_file, "Failed client invocations are"); + print "# ------------------------------------------------------------------------------\n"; +} sub load_tests { my $server_name = shift; @@ -321,16 +311,18 @@ sub load_tests { $line =~ s{_PBM_REF}{$pbm_ref}g; $line =~ s{_PBM_SECRET}{$pbm_secret}g; $line =~ s{_RESULT_DIR}{$result_dir}g; + next LOOP if $server_tls == 0 && $line =~ m/,\s*-tls_used\s*,/; my $noproxy = $no_proxy; + my $server_plain = $server_host =~ m/^\[(.*)\]$/ ? $1 : $server_host; if ($line =~ m/,\s*-no_proxy\s*,(.*?)(,|$)/) { $noproxy = $1; - } elsif ($server_host eq "127.0.0.1") { + } elsif ($server_plain eq "127.0.0.1" || $server_plain eq "::1") { # do connections to localhost (e.g., mock server) without proxy - $line =~ s{-section,,}{-section,,-no_proxy,127.0.0.1,} ; + $line =~ s{-section,,}{-section,,-no_proxy,$server_plain,} ; } if ($line =~ m/,\s*-proxy\s*,/) { - next LOOP if $no_proxy && ($noproxy =~ $server_host); + next LOOP if $no_proxy && ($noproxy =~ /\Q$server_plain\E/); } else { $line =~ s{-section,,}{-section,,-proxy,$proxy,}; } @@ -354,6 +346,7 @@ sub load_tests { # $expected_result = 1 if $server_name eq "Mock" && $title =~ m/- ok for Mock/; next LOOP if (!defined($expected_result) || ($expected_result ne 0 && $expected_result ne 1)); + next LOOP if ($line =~ m/-server,\[.*:.*\]/ && !have_IPv6()); @fields = grep {$_ ne 'BLANK'} @fields[$description + 1 .. @fields - 1]; push @result, [$title, \@fields, $expected_result]; } @@ -364,36 +357,52 @@ sub load_tests { sub start_server { my $server_name = shift; my $args = shift; # optional further CLI arguments - my $cmd = "$ENV{OPENSSL} cmp -config server.cnf $args"; + my $cmd = "$openssl cmp -config server.cnf $args"; print "Current directory is ".getcwd()."\n"; print "Launching $server_name server: $cmd\n"; - my $pid = open($server_fh, "$cmd|"); + $Mock_serverlog = result_dir()."/Mock_server_STDERR.txt"; + my $pid = open($server_fh, "$cmd 2>$Mock_serverlog |"); unless ($pid) { print "Error launching $cmd, cannot obtain $server_name server PID"; return 0; } print "$server_name server PID=$pid\n"; - if ($server_port == 0) { - # Find out the actual server port and possibly different PID - $pid = 0; + if ($server_host eq '*' || $server_port == 0) { + my $server_output = ""; + # Determine the actual server host and port and possibly different PID from server output + my ($host, $port); + my $pid0 = $pid; while (<$server_fh>) { + $server_output .= $_; print "$server_name server output: $_"; - next if m/using section/; + next if m/[Uu]sing section/; s/\R$//; # Better chomp - ($server_port, $pid) = ($1, $2) if /^ACCEPT\s.*:(\d+) PID=(\d+)$/; + ($host, $port, $pid) = ($1, $2, $3) + if /^ACCEPT\s(\[[^\]]+\]|[^:]+):(\d+) PID=(\d+)$/; last; # Do not loop further to prevent hangs on server misbehavior } + if ($server_host eq '*' && defined $host) { + $server_host = $host eq "[::]" ? "[::1]" + : $host eq "0.0.0.0" ? "127.0.0.1" : $host; + } + $server_port = $port if $server_port == 0 && defined $port; + if ($pid0 != $pid) { + # kill the shell process + kill('KILL', $pid0); + waitpid($pid0, 0); + } + if ($server_host eq '*' || $server_port == 0) { + stop_server($server_name, $pid) if $pid; + print "Cannot get server host and port from the $server_name server output: $server_output\n"; + return 0; + } } - unless ($server_port > 0) { - stop_server($server_name, $pid); - print "Cannot get expected output from the $server_name server\n"; - return 0; - } - $kur_port = $server_port; - $pbm_port = $server_port; + $kur_port = $server_port if $kur_port eq "\$server_port"; + $pbm_port = $server_port if $pbm_port eq "\$server_port"; $server_tls = $server_port if $server_tls; return $pid; + } sub stop_server { diff --git a/test/recipes/80-test_cmp_http_data/test.cnf b/test/recipes/80-test_cmp_http_data/test.cnf index 55680822..555ae08c 100644 --- a/test/recipes/80-test_cmp_http_data/test.cnf +++ b/test/recipes/80-test_cmp_http_data/test.cnf @@ -65,8 +65,8 @@ expect_sender = $server_dn subject = "/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=leaf" newkey = signer.key out_trusted = signer_root.crt -kur_port = 0 # will be overwritten to the same value as server_port -pbm_port = 0 # will be overwritten to the same value as server_port +kur_port = $server_port +pbm_port = $server_port pbm_ref = pbm_secret = pass:test cert = signer.crt diff --git a/test/recipes/80-test_cmp_http_data/test_certstatus.csv b/test/recipes/80-test_cmp_http_data/test_certstatus.csv index 0ef6ab39..fe28e175 100644 --- a/test/recipes/80-test_cmp_http_data/test_certstatus.csv +++ b/test/recipes/80-test_cmp_http_data/test_certstatus.csv @@ -1,29 +1,29 @@ Mock,LwCmp,EJBCA,Insta,description, -section,val, -crls,val, -cdps,val, -ocsp,val, -crls_timeout,val, -ocsp_timeout,val, -check_any,val, -check_all,val, -use_cdp,val, -use_aia,val, -ocsp_last,val, -stapling,val, -opt1,arg1, -opt2,arg2 ,,,,,,,,,,,,,,,,,,,,,,,,,,, 1,TBD,1,TBD,default: crls and cdps and ocsp active, -section,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,,,,,,, -1,TBD,1,TBD,check_any, -section,,,,,,,,,,,, -check_any,,BLANK,,,,,,,, -1,TBD,1,TBD,check_all, -section,,,,,,,,,,BLANK,,,, -check_all,,,,,,,, -1,TBD,1,TBD,check_any with crls only, -section,,,, -cdps,"", -ocsp,"",BLANK,,BLANK,, -check_any,,,,,,,,, -1,TBD,1,TBD,check_any with cdps only, -section,, -crls,"",,, -ocsp,"",BLANK,,BLANK,, -check_any,,,,,,,,, -1,TBD,1,TBD,check_any with ocsp only, -section,, -crls,"", -cdps,"",,,BLANK,,BLANK,, -check_any,,,,,,,,, +-,TBD,1,TBD,check_any, -section,,,,,,,,,,,, -check_any,,BLANK,,,,,,,, +-,TBD,1,TBD,check_all, -section,,,,,,,,,,BLANK,,,, -check_all,,,,,,,, +-,TBD,1,TBD,check_any with crls only, -section,,,, -cdps,"", -ocsp,"",BLANK,,BLANK,, -check_any,,,,,,,,, +-,TBD,1,TBD,check_any with cdps only, -section,, -crls,"",,, -ocsp,"",BLANK,,BLANK,, -check_any,,,,,,,,, +-,TBD,1,TBD,check_any with ocsp only, -section,, -crls,"", -cdps,"",,,BLANK,,BLANK,, -check_any,,,,,,,,, 0,0,0,0,check_any without enabled checking, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,, -check_any,,,,,,,,, -1,TBD,1,TBD,check_all with crls only, -section,,,, -cdps,"", -ocsp,"",BLANK,,BLANK,,,, -check_all,,,,,,,,,, -1,TBD,1,TBD,check_all with cdps only, -section,, -crls,"",,, -ocsp,"",BLANK,,BLANK,,,, -check_all,,,,,,,,,, -1,TBD,1,TBD,check_all with ocsp only, -section,, -crls,"", -cdps,"",,,BLANK,,BLANK,,,, -check_all,,,,,,,,,, +-,TBD,1,TBD,check_all with crls only, -section,,,, -cdps,"", -ocsp,"",BLANK,,BLANK,,,, -check_all,,,,,,,,,, +-,TBD,1,TBD,check_all with cdps only, -section,, -crls,"",,, -ocsp,"",BLANK,,BLANK,,,, -check_all,,,,,,,,,, +-,TBD,1,TBD,check_all with ocsp only, -section,, -crls,"", -cdps,"",,,BLANK,,BLANK,,,, -check_all,,,,,,,,,, 0,*,*,*,check_all without any enabled checking, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,,,, -check_all,,,,,,,,,, 0,*,*,*,check_any with parameter, -section,,,,,,,,,,,, -check_any,1,,,,,,,,, 0,*,*,*,check_all with parameter, -section,,,,,,,,,,,,,, -check_all,0,,,,,,,,,, 0,*,*,*,both check_any and check_all, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,, -check_any,, -check_all,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,, -1,TBD,1,TBD,only use_cdp entries in certs, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,,,,,, -use_cdp,,,,,,,, -1,TBD,1,TBD,only use_aia entries in certs, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,,,,,,,, -use_aia,,,,,,, +-,TBD,1,TBD,only use_cdp entries in certs, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,,,,,, -use_cdp,,,,,,,, +-,TBD,1,TBD,only use_aia entries in certs, -section,, -crls,"", -cdps,"", -ocsp,"",BLANK,,BLANK,,,,,,,, -use_aia,,,,,,, 0,*,*,*,use_cdp with parameter, -section,,,,,,,,,,,,,,,, -use_cdp,0,,,,,,,, 0,*,*,*,use_aia with parameter, -section,,,,,,,,,,,,,,,,,, -use_aia,1,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,, -1,TBD,1,TBD,ocsp_last, -section,,,,,,,,,,,,,,,,,,,, -ocsp_last,,,,,,, -1,TBD,1,TBD,ocsp_last without crls, -section,, -crls,"",,,,,,,,,,,,,,,,, -ocsp_last,,,,,,, -1,TBD,1,TBD,ocsp_last without cdps, -section,,,, -cdps,"",,,,,,,,,,,,,,, -ocsp_last,,,,,,, -1,TBD,1,TBD,ocsp_last without crls and cdps, -section,, -crls,"", -cdps,"",,,,,,,,,,,,,,, -ocsp_last,,,,,,, +-,TBD,1,TBD,ocsp_last, -section,,,,,,,,,,,,,,,,,,,, -ocsp_last,,,,,,, +-,TBD,1,TBD,ocsp_last without crls, -section,, -crls,"",,,,,,,,,,,,,,,,, -ocsp_last,,,,,,, +-,TBD,1,TBD,ocsp_last without cdps, -section,,,, -cdps,"",,,,,,,,,,,,,,, -ocsp_last,,,,,,, +-,TBD,1,TBD,ocsp_last without crls and cdps, -section,, -crls,"", -cdps,"",,,,,,,,,,,,,,, -ocsp_last,,,,,,, 0,*,*,*,ocsp_last without ocsp, -section,,,,,, -ocsp,"",,,,,,,,,,,,, -ocsp_last,,,,,,, 0,*,*,*,ocsp_last with parameter, -section,,,,,,,,,,,,,,,,,,,, -ocsp_last,asdf,,,,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/test/recipes/80-test_cmp_http_data/test_enrollment.csv b/test/recipes/80-test_cmp_http_data/test_enrollment.csv index e006219c..5d09f457 100644 --- a/test/recipes/80-test_cmp_http_data/test_enrollment.csv +++ b/test/recipes/80-test_cmp_http_data/test_enrollment.csv @@ -26,6 +26,13 @@ NEED_CACHE_DISABLING,0,0,1,missing chain, -section,, -cmd,ir, -newkey,new.key,, 0,*,*,*,newkeypass invalid, -section,, -cmd,ir, -newkey,new_pass_12345.key,, -newkeypass,fp:4,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,test.cert.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, 1,1,1,1,newkeypass no prefix, -section,, -cmd,ir, -newkey,new_pass_12345.key,, -newkeypass,12345,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,test.cert.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +1,1,1,1,newkeytype RSA:2048, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,RSA:2048 +0,0,0,0,newkeytype RSA:1023, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,RSA:1023 +1,1,1,1,newkeytype EC:secp256r1, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,EC:secp256r1 +0,0,0,0,newkeytype unknown-curve, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,unknown-curve +3.5,3.5,3.5,3.5,newkeytype ML-DSA-65, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,ML-DSA-65 +3.5 0,3.5 0,3.5 0,3.5 0,newkeytype ML-DSA-43, -section,, -cmd,ir, -newkey,_RESULT_DIR/new.key,, -newkeypass,pass:,,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -reqout_only,_RESULT_DIR/t.der,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -newkeytype,ML-DSA-43 +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 0,*,*,*,subject argument missing, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:, -subject,BLANK,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,test.cert.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, TBD,TBD,TBD OpenSSL 3.0 still uses default,0,subject empty string, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:, -subject,"""",BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,test.cert.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,, 0,0,0,Insta gives status 503 and subsequent responses are errors transactionid unmatched,subject NULL-DN, -section,, -cmd,ir, -newkey,new.key,, -newkeypass,pass:, -subject,/,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,,BLANK,, -certout,test.cert.pem,, -out_trusted,root.crt,,BLANK,,BLANK,,,, -unprotected_errors