summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rwxr-xr-xsrc/lib/CMakeLists.txt105
-rw-r--r--src/lib/config.h.in4
-rw-r--r--src/lib/crypto.cpp4
-rw-r--r--src/lib/crypto/backend_version.cpp12
-rw-r--r--src/lib/crypto/bn.h78
-rw-r--r--src/lib/crypto/cipher.hpp5
-rw-r--r--src/lib/crypto/cipher_botan.cpp8
-rw-r--r--src/lib/crypto/dl_ossl.cpp118
-rw-r--r--src/lib/crypto/dsa_ossl.cpp174
-rw-r--r--src/lib/crypto/ec_ossl.cpp181
-rw-r--r--src/lib/crypto/ecdh.cpp13
-rw-r--r--src/lib/crypto/ecdh_ossl.cpp56
-rw-r--r--src/lib/crypto/elgamal_ossl.cpp99
-rw-r--r--src/lib/crypto/rsa.cpp8
-rw-r--r--src/lib/crypto/rsa_ossl.cpp351
-rw-r--r--src/lib/crypto/symmetric.cpp12
-rw-r--r--src/lib/crypto/symmetric_ossl.cpp52
-rw-r--r--src/lib/rnp.cpp23
18 files changed, 983 insertions, 320 deletions
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
index 086ac57..3b4b444 100755
--- a/src/lib/CMakeLists.txt
+++ b/src/lib/CMakeLists.txt
@@ -31,11 +31,15 @@ find_package(ZLIB REQUIRED)
# required packages
find_package(JSON-C 0.11 REQUIRED)
-if (CRYPTO_BACKEND_BOTAN)
- find_package(Botan2 2.14.0 REQUIRED)
+if (CRYPTO_BACKEND_BOTAN3)
+ find_package(Botan 3.0.0 REQUIRED)
+elseif (CRYPTO_BACKEND_BOTAN)
+ find_package(Botan 2.14.0 REQUIRED)
+ if(BOTAN_VERSION VERSION_GREATER_EQUAL 3.0.0)
+ set(CRYPTO_BACKEND_BOTAN3 1)
+ endif()
endif()
if (CRYPTO_BACKEND_OPENSSL)
- include(FindOpenSSL)
find_package(OpenSSL 1.1.1 REQUIRED)
include(FindOpenSSLFeatures)
if("${OPENSSL_VERSION}" VERSION_GREATER_EQUAL "3.0.0")
@@ -43,6 +47,10 @@ if (CRYPTO_BACKEND_OPENSSL)
endif()
endif()
+if(CRYPTO_BACKEND_BOTAN3)
+ set(CMAKE_CXX_STANDARD 20)
+endif()
+
# generate a config.h
include(CheckIncludeFileCXX)
include(CheckCXXSymbolExists)
@@ -75,7 +83,7 @@ function(backend_has_feature FEATURE RESULT_VARNAME)
if (CRYPTO_BACKEND_LOWERCASE STREQUAL "botan")
check_cxx_symbol_exists("BOTAN_HAS_${FEATURE}" botan/build.h ${RESULT_VARNAME})
else()
- message(STATUS "Looking for OpenSSL feature ${FEATURE}")
+ message(STATUS "Looking for OpenSSL feature ${FEATURE}")
OpenSSLHasFeature(${FEATURE} ${RESULT_VARNAME})
if (${RESULT_VARNAME})
message(STATUS "Looking for OpenSSL feature ${FEATURE} - found")
@@ -100,7 +108,7 @@ function(resolve_feature_state RNP_FEATURE BACKEND_FEATURES)
foreach(feature ${BACKEND_FEATURES})
backend_has_feature("${feature}" _has_${feature})
- if (NOT ${_has_${feature}})
+ if (NOT _has_${feature})
set(${RNP_FEATURE} Off CACHE STRING "Autodetected" FORCE)
message(${MESSAGE_TYPE} "${RNP_FEATURE} requires ${CRYPTO_BACKEND} feature which is missing: ${feature}. ${OUTCOME}.")
return()
@@ -129,7 +137,7 @@ endfunction()
if(CRYPTO_BACKEND_BOTAN)
# check botan's enabled features
- set(CMAKE_REQUIRED_INCLUDES "${BOTAN2_INCLUDE_DIRS}")
+ set(CMAKE_REQUIRED_INCLUDES "${BOTAN_INCLUDE_DIRS}")
set(_botan_required_features
# base
BIGINT FFI HEX_CODEC PGP_S2K
@@ -142,12 +150,17 @@ if(CRYPTO_BACKEND_BOTAN)
# hash
CRC24 HASH MD5 SHA1 SHA2_32 SHA2_64 SHA3
# public-key core
- DL_GROUP DL_PUBLIC_KEY_FAMILY ECC_GROUP ECC_PUBLIC_KEY_CRYPTO PUBLIC_KEY_CRYPTO
+ DL_GROUP ECC_GROUP ECC_PUBLIC_KEY_CRYPTO PUBLIC_KEY_CRYPTO # Botan-2: DL_PUBLIC_KEY_FAMILY Botan-3: DL_SCHEME, see switch below
# public-key algs
CURVE_25519 DSA ECDH ECDSA ED25519 ELGAMAL RSA
# public-key operations etc
EME_PKCS1v15 EMSA_PKCS1 EMSA_RAW KDF_BASE RFC3394_KEYWRAP SP800_56A
)
+ if(BOTAN_VERSION VERSION_LESS 3.0.0)
+ set(_botan_required_features ${_botan_required_features} DL_PUBLIC_KEY_FAMILY)
+ else()
+ set(_botan_required_features ${_botan_required_features} DL_SCHEME RAW_HASH_FN)
+ endif()
foreach(feature ${_botan_required_features})
check_cxx_symbol_exists("BOTAN_HAS_${feature}" botan/build.h _botan_has_${feature})
if (NOT _botan_has_${feature})
@@ -181,19 +194,26 @@ if(CRYPTO_BACKEND_OPENSSL)
RSAENCRYPTION DSAENCRYPTION DHKEYAGREEMENT ID-ECPUBLICKEY X25519 ED25519
)
foreach(feature ${_openssl_required_features})
- message(STATUS "Looking for OpenSSL feature ${feature}")
- OpenSSLHasFeature("${feature}" _openssl_has_${feature})
+ backend_has_feature("${feature}" _openssl_has_${feature})
if (NOT _openssl_has_${feature})
message(FATAL_ERROR "A required OpenSSL feature is missing: ${feature}")
endif()
- message(STATUS "Looking for OpenSSL feature ${feature} - found")
endforeach()
+ if (CRYPTO_BACKEND_OPENSSL3)
+ backend_has_feature("LEGACY" CRYPTO_BACKEND_OPENSSL3_LEGACY)
+ endif()
+
resolve_feature_state(ENABLE_BRAINPOOL "BRAINPOOLP256R1;BRAINPOOLP384R1;BRAINPOOLP512R1")
- resolve_feature_state(ENABLE_IDEA "IDEA-ECB;IDEA-CBC")
- resolve_feature_state(ENABLE_BLOWFISH "BF-ECB")
- resolve_feature_state(ENABLE_CAST5 "CAST5-ECB")
- resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD160")
+ # Not all of the OpenSSL installations have legacy crypto provider
+ resolve_feature_state(ENABLE_IDEA "IDEA-ECB;IDEA-CBC;LEGACY")
+ resolve_feature_state(ENABLE_BLOWFISH "BF-ECB;LEGACY")
+ resolve_feature_state(ENABLE_CAST5 "CAST5-ECB;LEGACY")
+ if("${OPENSSL_VERSION}" VERSION_GREATER_EQUAL "3.0.7")
+ resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD160")
+ else()
+ resolve_feature_state(ENABLE_RIPEMD160 "RIPEMD160;LEGACY")
+ endif()
resolve_feature_state(ENABLE_AEAD "AES-128-OCB;AES-192-OCB;AES-256-OCB")
openssl_nope(ENABLE_SM2 "it's on our roadmap, see https://github.com/rnpgp/rnp/issues/1877")
#resolve_feature_state(ENABLE_SM2 "SM2;SM3;SM4-ECB")
@@ -320,15 +340,16 @@ target_include_directories(librnp-obj
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/src"
+ "${SEXPP_INCLUDE_DIRS}"
)
target_link_libraries(librnp-obj PRIVATE JSON-C::JSON-C)
if (CRYPTO_BACKEND_BOTAN)
- target_link_libraries(librnp-obj PRIVATE Botan2::Botan2)
+ target_link_libraries(librnp-obj PRIVATE Botan::Botan)
elseif (CRYPTO_BACKEND_OPENSSL)
target_link_libraries(librnp-obj PRIVATE OpenSSL::Crypto)
endif()
-target_link_libraries(librnp-obj PRIVATE sexp)
+target_link_libraries(librnp-obj PRIVATE sexpp)
set_target_properties(librnp-obj PROPERTIES CXX_VISIBILITY_PRESET hidden)
if (TARGET BZip2::BZip2)
@@ -384,7 +405,7 @@ foreach (prop LINK_LIBRARIES INTERFACE_LINK_LIBRARIES INCLUDE_DIRECTORIES INTERF
get_target_property(val librnp-obj ${prop})
if (BUILD_SHARED_LIBS)
set_property(TARGET librnp-static PROPERTY ${prop} ${val})
- list(REMOVE_ITEM val "$<LINK_ONLY:sexp>")
+ list(REMOVE_ITEM val "$<LINK_ONLY:sexpp>")
set_property(TARGET librnp PROPERTY ${prop} ${val})
else()
set_property(TARGET librnp PROPERTY ${prop} ${val})
@@ -414,15 +435,14 @@ else()
endif()
# add these to the rnp-targets export
-# On Unix like systems we will build/install/pack shared and static libraries librnp.so and librnp.a
-# On Windows we will build/install/pack dynamic, import and static libraries rnp.dll, rnp.lib and rnp-static.lib
+# On Unix like systems we will build/install/pack either shared library librnp.so or static librnp.a
+# On Windows we will build/install/pack either dynamic and import libraries rnp.dll, rnp.lib or static library rnp-static.lib
-# If a client application uses shared rnp library, sexp is statically linked to librnp.so
-# If a client application uses static rnp library, it still needs libsexp.a
+# If a client application uses shared rnp library, sexpp is statically linked to librnp.so and libsexpp.a is not installed
+# If a client application uses static rnp library, it still needs libsexpp.a and it is installed
if (BUILD_SHARED_LIBS)
-# both static and shared libraries
-install(TARGETS librnp
+ install(TARGETS librnp
EXPORT rnp-targets
LIBRARY
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
@@ -433,31 +453,34 @@ install(TARGETS librnp
COMPONENT development
)
- install(TARGETS librnp-static sexp
- EXPORT rnp-targets
- ARCHIVE
- DESTINATION "${CMAKE_INSTALL_LIBDIR}"
- COMPONENT development
- )
+# install dll only for windows
+ if (WIN32)
+ install(TARGETS librnp
+ RUNTIME
+ DESTINATION "${CMAKE_INSTALL_BINDIR}"
+ COMPONENT runtime
+ )
+ endif(WIN32)
else(BUILD_SHARED_LIBS)
-# static libraries only
-install(TARGETS librnp sexp
+# static libraries
+# install libsexpp unless system-installed libsexpp is used
+ if (SYSTEM_LIBSEXPP)
+ install(TARGETS librnp
+ EXPORT rnp-targets
+ ARCHIVE
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ COMPONENT development
+ )
+ else (SYSTEM_LIBSEXPP)
+ install(TARGETS librnp sexpp
EXPORT rnp-targets
ARCHIVE
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
COMPONENT development
-)
+ )
+ endif (SYSTEM_LIBSEXPP)
endif(BUILD_SHARED_LIBS)
-# install dll only for windows
-if (WIN32)
- install(TARGETS librnp
- RUNTIME
- DESTINATION "${CMAKE_INSTALL_BINDIR}"
- COMPONENT runtime
- )
-endif(WIN32)
-
# install headers
install(
FILES
diff --git a/src/lib/config.h.in b/src/lib/config.h.in
index f8880d5..afb2cfe 100644
--- a/src/lib/config.h.in
+++ b/src/lib/config.h.in
@@ -51,8 +51,10 @@
#cmakedefine HAVE__TEMPNAM
#cmakedefine CRYPTO_BACKEND_BOTAN
+#cmakedefine CRYPTO_BACKEND_BOTAN3
#cmakedefine CRYPTO_BACKEND_OPENSSL
#cmakedefine CRYPTO_BACKEND_OPENSSL3
+#cmakedefine CRYPTO_BACKEND_OPENSSL3_LEGACY
#cmakedefine ENABLE_SM2
#cmakedefine ENABLE_AEAD
@@ -67,6 +69,6 @@
* we assume to be bundled with a sane implementation of std::regex. */
#if !defined(__GNUC__) || defined(_GLIBCXX_USE_CXX11_ABI) || \
(defined(WIN32) && !defined(MSYS)) || \
- ((defined(__clang__) && (__clang_major__ >= 4)) )
+ ((defined(__clang__) && (__clang_major__ >= 4)))
#define RNP_USE_STD_REGEX 1
#endif
diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp
index 2634604..da3cba1 100644
--- a/src/lib/crypto.cpp
+++ b/src/lib/crypto.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2017-2023, [Ribose Inc](https://www.ribose.com).
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
@@ -128,7 +128,9 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto,
seckey.material.ec.curve = crypto.ecc.curve;
break;
}
+#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L)
[[fallthrough]];
+#endif
case PGP_PKA_ECDSA:
case PGP_PKA_SM2:
if (!curve_supported(crypto.ecc.curve)) {
diff --git a/src/lib/crypto/backend_version.cpp b/src/lib/crypto/backend_version.cpp
index 859b048..32af839 100644
--- a/src/lib/crypto/backend_version.cpp
+++ b/src/lib/crypto/backend_version.cpp
@@ -72,7 +72,7 @@ backend_version()
if (version[0]) {
return version;
}
- const char *reg = "OpenSSL (([0-9]\\.[0-9]\\.[0-9])[a-z]*(-beta[0-9])*(-dev)*) ";
+ const char *reg = "OpenSSL (([0-9]+\\.[0-9]+\\.[0-9]+)[a-z]*(-[a-z0-9]+)*) ";
#ifndef RNP_USE_STD_REGEX
static regex_t r;
regmatch_t matches[5];
@@ -84,7 +84,9 @@ backend_version()
return "unknown";
}
}
- if (regexec(&r, ver, 5, matches, 0) != 0) {
+ int res = regexec(&r, ver, 5, matches, 0);
+ if (res != 0) {
+ RNP_LOG("regexec() failed on %s: %d", ver, res);
return "unknown";
}
assert(sizeof(version) > matches[1].rm_eo - matches[1].rm_so);
@@ -95,6 +97,7 @@ backend_version()
std::smatch result;
std::string ver = OpenSSL_version(OPENSSL_VERSION);
if (!std::regex_search(ver, result, re)) {
+ RNP_LOG("std::regex_search failed on \"%s\"", ver.c_str());
return "unknown";
}
assert(sizeof(version) > result[1].str().size());
@@ -109,7 +112,10 @@ backend_version()
#if defined(CRYPTO_BACKEND_OPENSSL3)
#if defined(ENABLE_IDEA) || defined(ENABLE_CAST5) || defined(ENABLE_BLOWFISH) || \
- defined(ENABLE_RIPEMD160)
+ (defined(ENABLE_RIPEMD160) && OPENSSL_VERSION_NUMBER < 0x30000070L)
+#if !defined(CRYPTO_BACKEND_OPENSSL3_LEGACY)
+#error "OpenSSL doesn't have legacy provider, however one of the features enables it's load."
+#endif
#define OPENSSL_LOAD_LEGACY
#endif
diff --git a/src/lib/crypto/bn.h b/src/lib/crypto/bn.h
index 26cc547..a4cfa1a 100644
--- a/src/lib/crypto/bn.h
+++ b/src/lib/crypto/bn.h
@@ -61,4 +61,82 @@ bool bn2mpi(const bignum_t *bn, pgp_mpi_t *val);
size_t bn_num_bytes(const bignum_t &a);
+#if defined(CRYPTO_BACKEND_OPENSSL)
+namespace rnp {
+class bn {
+ BIGNUM *_bn;
+
+ public:
+ bn(BIGNUM *val = NULL) : _bn(val)
+ {
+ }
+
+ bn(const pgp_mpi_t &val) : _bn(mpi2bn(&val))
+ {
+ }
+
+ ~bn()
+ {
+ BN_free(_bn);
+ }
+
+ void
+ set(BIGNUM *val = NULL) noexcept
+ {
+ BN_free(_bn);
+ _bn = val;
+ }
+
+ void
+ set(const pgp_mpi_t &val) noexcept
+ {
+ BN_free(_bn);
+ _bn = mpi2bn(&val);
+ }
+
+ BIGNUM **
+ ptr() noexcept
+ {
+ set();
+ return &_bn;
+ }
+
+ BIGNUM *
+ get() noexcept
+ {
+ return _bn;
+ }
+
+ BIGNUM *
+ own() noexcept
+ {
+ auto res = _bn;
+ _bn = NULL;
+ return res;
+ }
+
+ size_t
+ bytes() const noexcept
+ {
+ return BN_num_bytes(_bn);
+ }
+
+ bool
+ bin(uint8_t *b) const noexcept
+ {
+ if (!b) {
+ return false;
+ }
+ return BN_bn2bin(_bn, b) >= 0;
+ }
+
+ bool
+ mpi(pgp_mpi_t &mpi) const noexcept
+ {
+ return bn2mpi(_bn, &mpi);
+ }
+};
+}; // namespace rnp
+#endif
+
#endif
diff --git a/src/lib/crypto/cipher.hpp b/src/lib/crypto/cipher.hpp
index c9edf15..f683b76 100644
--- a/src/lib/crypto/cipher.hpp
+++ b/src/lib/crypto/cipher.hpp
@@ -58,7 +58,10 @@ class Cipher {
const uint8_t *input,
size_t input_length,
size_t * input_consumed) = 0;
- // process final block and perform any padding
+ /**
+ * @brief Finalize cipher. For AEAD mode, depending on backend, may require whole
+ * authentication tag to be present in input.
+ */
virtual bool finish(uint8_t * output,
size_t output_length,
size_t * output_written,
diff --git a/src/lib/crypto/cipher_botan.cpp b/src/lib/crypto/cipher_botan.cpp
index c2c4ab3..6f4a4fc 100644
--- a/src/lib/crypto/cipher_botan.cpp
+++ b/src/lib/crypto/cipher_botan.cpp
@@ -64,8 +64,12 @@ Cipher_Botan::create(pgp_symm_alg_t alg, const std::string &name, bool encrypt)
return nullptr;
}
#endif
- auto cipher = Botan::Cipher_Mode::create(
- name, encrypt ? Botan::Cipher_Dir::ENCRYPTION : Botan::Cipher_Dir::DECRYPTION);
+#if defined(CRYPTO_BACKEND_BOTAN3)
+ auto dir = encrypt ? Botan::Cipher_Dir::Encryption : Botan::Cipher_Dir::Decryption;
+#else
+ auto dir = encrypt ? Botan::Cipher_Dir::ENCRYPTION : Botan::Cipher_Dir::DECRYPTION;
+#endif
+ auto cipher = Botan::Cipher_Mode::create(name, dir);
if (!cipher) {
RNP_LOG("Failed to create cipher '%s'", name.c_str());
return nullptr;
diff --git a/src/lib/crypto/dl_ossl.cpp b/src/lib/crypto/dl_ossl.cpp
index 1e96218..4845baa 100644
--- a/src/lib/crypto/dl_ossl.cpp
+++ b/src/lib/crypto/dl_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021, 2023 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -33,6 +33,34 @@
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#endif
+
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+static OSSL_PARAM *
+dl_build_params(bignum_t *p, bignum_t *q, bignum_t *g, bignum_t *y, bignum_t *x)
+{
+ OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
+ if (!bld) {
+ return NULL; // LCOV_EXCL_LINE
+ }
+ if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
+ (q && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q)) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, y) ||
+ (x && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, x))) {
+ /* LCOV_EXCL_START */
+ OSSL_PARAM_BLD_free(bld);
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ OSSL_PARAM *param = OSSL_PARAM_BLD_to_param(bld);
+ OSSL_PARAM_BLD_free(bld);
+ return param;
+}
+#endif
EVP_PKEY *
dl_load_key(const pgp_mpi_t &mp,
@@ -41,63 +69,89 @@ dl_load_key(const pgp_mpi_t &mp,
const pgp_mpi_t &my,
const pgp_mpi_t *mx)
{
- DH * dh = NULL;
EVP_PKEY *evpkey = NULL;
- bignum_t *p = mpi2bn(&mp);
- bignum_t *q = mq ? mpi2bn(mq) : NULL;
- bignum_t *g = mpi2bn(&mg);
- bignum_t *y = mpi2bn(&my);
- bignum_t *x = mx ? mpi2bn(mx) : NULL;
+ rnp::bn p(mpi2bn(&mp));
+ rnp::bn q(mq ? mpi2bn(mq) : NULL);
+ rnp::bn g(mpi2bn(&mg));
+ rnp::bn y(mpi2bn(&my));
+ rnp::bn x(mx ? mpi2bn(mx) : NULL);
- if (!p || (mq && !q) || !g || !y || (mx && !x)) {
+ if (!p.get() || (mq && !q.get()) || !g.get() || !y.get() || (mx && !x.get())) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- dh = DH_new();
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ OSSL_PARAM *params = dl_build_params(p.get(), q.get(), g.get(), y.get(), x.get());
+ if (!params) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to build dsa params");
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
+ if (!ctx) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to create dl context");
+ OSSL_PARAM_free(params);
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ if ((EVP_PKEY_fromdata_init(ctx) != 1) ||
+ (EVP_PKEY_fromdata(
+ ctx, &evpkey, mx ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1)) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to create key from data");
+ evpkey = NULL;
+ /* LCOV_EXCL_END */
+ }
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+ return evpkey;
+#else
+ DH *dh = DH_new();
if (!dh) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- int res;
/* line below must not fail */
- res = DH_set0_pqg(dh, p, q, g);
+ int res = DH_set0_pqg(dh, p.own(), q.own(), g.own());
assert(res == 1);
if (res < 1) {
goto done;
}
- p = NULL;
- q = NULL;
- g = NULL;
/* line below must not fail */
- res = DH_set0_key(dh, y, x);
+ res = DH_set0_key(dh, y.own(), x.own());
assert(res == 1);
if (res < 1) {
goto done;
}
- y = NULL;
- x = NULL;
evpkey = EVP_PKEY_new();
if (!evpkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("allocation failed");
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_set1_DH(evpkey, dh) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set key: %lu", ERR_peek_last_error());
EVP_PKEY_free(evpkey);
evpkey = NULL;
+ /* LCOV_EXCL_END */
}
done:
DH_free(dh);
- bn_free(p);
- bn_free(q);
- bn_free(g);
- bn_free(y);
- bn_free(x);
return evpkey;
+#endif
}
+#if !defined(CRYPTO_BACKEND_OPENSSL3)
static rnp_result_t
dl_validate_secret_key(EVP_PKEY *dlkey, const pgp_mpi_t &mx)
{
@@ -117,22 +171,28 @@ dl_validate_secret_key(EVP_PKEY *dlkey, const pgp_mpi_t &mx)
bignum_t *cy = bn_new();
if (!x || !cy || !ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed");
goto done;
+ /* LCOV_EXCL_END */
}
if (!q) {
/* if q is NULL then group order is (p - 1) / 2 */
p1 = BN_dup(p);
if (!p1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed");
goto done;
+ /* LCOV_EXCL_END */
}
int res;
res = BN_rshift(p1, p1, 1);
assert(res == 1);
if (res < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("BN_rshift failed.");
goto done;
+ /* LCOV_EXCL_END */
}
q = p1;
}
@@ -154,6 +214,7 @@ done:
bn_free(p1);
return ret;
}
+#endif
rnp_result_t
dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *x)
@@ -161,8 +222,10 @@ dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *x)
rnp_result_t ret = RNP_ERROR_GENERIC;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
int res;
res = EVP_PKEY_param_check(ctx);
@@ -181,6 +244,12 @@ dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *x)
goto done;
}
}
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ res = x ? EVP_PKEY_pairwise_check(ctx) : EVP_PKEY_public_check(ctx);
+ if (res == 1) {
+ ret = RNP_SUCCESS;
+ }
+#else
res = EVP_PKEY_public_check(ctx);
if (res < 0) {
RNP_LOG("Key validation error: %lu", ERR_peek_last_error());
@@ -194,6 +263,7 @@ dl_validate_key(EVP_PKEY *pkey, const pgp_mpi_t *x)
goto done;
}
ret = dl_validate_secret_key(pkey, *x);
+#endif
done:
EVP_PKEY_CTX_free(ctx);
return ret;
diff --git a/src/lib/crypto/dsa_ossl.cpp b/src/lib/crypto/dsa_ossl.cpp
index 1fb75b5..3f91b72 100644
--- a/src/lib/crypto/dsa_ossl.cpp
+++ b/src/lib/crypto/dsa_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021, 2023 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -35,6 +35,10 @@
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#endif
#define DSA_MAX_Q_BITLEN 256
@@ -83,66 +87,118 @@ done:
return res;
}
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+static OSSL_PARAM *
+dsa_build_params(bignum_t *p, bignum_t *q, bignum_t *g, bignum_t *y, bignum_t *x)
+{
+ OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
+ if (!bld) {
+ return NULL; // LCOV_EXCL_LINE
+ }
+ if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, y) ||
+ (x && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, x))) {
+ /* LCOV_EXCL_START */
+ OSSL_PARAM_BLD_free(bld);
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ OSSL_PARAM *param = OSSL_PARAM_BLD_to_param(bld);
+ OSSL_PARAM_BLD_free(bld);
+ return param;
+}
+#endif
+
static EVP_PKEY *
dsa_load_key(const pgp_dsa_key_t *key, bool secret = false)
{
- DSA * dsa = NULL;
EVP_PKEY *evpkey = NULL;
- bignum_t *p = mpi2bn(&key->p);
- bignum_t *q = mpi2bn(&key->q);
- bignum_t *g = mpi2bn(&key->g);
- bignum_t *y = mpi2bn(&key->y);
- bignum_t *x = secret ? mpi2bn(&key->x) : NULL;
+ rnp::bn p(mpi2bn(&key->p));
+ rnp::bn q(mpi2bn(&key->q));
+ rnp::bn g(mpi2bn(&key->g));
+ rnp::bn y(mpi2bn(&key->y));
+ rnp::bn x(secret ? mpi2bn(&key->x) : NULL);
- if (!p || !q || !g || !y || (secret && !x)) {
+ if (!p.get() || !q.get() || !g.get() || !y.get() || (secret && !x.get())) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- dsa = DSA_new();
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ OSSL_PARAM *params = dsa_build_params(p.get(), q.get(), g.get(), y.get(), x.get());
+ if (!params) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to build dsa params");
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
+ if (!ctx) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to create dsa context");
+ OSSL_PARAM_free(params);
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ if ((EVP_PKEY_fromdata_init(ctx) != 1) ||
+ (EVP_PKEY_fromdata(
+ ctx, &evpkey, secret ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1)) {
+ RNP_LOG("failed to create key from data");
+ evpkey = NULL;
+ }
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
+ return evpkey;
+#else
+ DSA *dsa = DSA_new();
if (!dsa) {
+ /* LCOV_EXCL_START */
RNP_LOG("Out of memory");
goto done;
+ /* LCOV_EXCL_END */
}
- if (DSA_set0_pqg(dsa, p, q, g) != 1) {
+ if (DSA_set0_pqg(dsa, p.own(), q.own(), g.own()) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set pqg. Error: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
- p = NULL;
- q = NULL;
- g = NULL;
- if (DSA_set0_key(dsa, y, x) != 1) {
+ if (DSA_set0_key(dsa, y.own(), x.own()) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Secret key load error: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
- y = NULL;
- x = NULL;
evpkey = EVP_PKEY_new();
if (!evpkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("allocation failed");
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_set1_DSA(evpkey, dsa) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set key: %lu", ERR_peek_last_error());
EVP_PKEY_free(evpkey);
evpkey = NULL;
+ /* LCOV_EXCL_END */
}
done:
DSA_free(dsa);
- bn_free(p);
- bn_free(q);
- bn_free(g);
- bn_free(y);
- bn_free(x);
return evpkey;
+#endif
}
rnp_result_t
dsa_validate_key(rnp::RNG *rng, const pgp_dsa_key_t *key, bool secret)
{
/* OpenSSL doesn't implement key checks for the DSA, however we may use DL via DH */
- EVP_PKEY *pkey = dl_load_key(key->p, &key->q, key->g, key->y, NULL);
+ EVP_PKEY *pkey = dl_load_key(key->p, &key->q, key->g, key->y, secret ? &key->x : NULL);
if (!pkey) {
RNP_LOG("Failed to load key");
return RNP_ERROR_BAD_PARAMETERS;
@@ -175,8 +231,10 @@ dsa_sign(rnp::RNG * rng,
/* init context and sign */
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_sign_init(ctx) <= 0) {
RNP_LOG("Failed to initialize signing: %lu", ERR_peek_last_error());
@@ -216,8 +274,10 @@ dsa_verify(const pgp_dsa_signature_t *sig,
/* init context and sign */
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_verify_init(ctx) <= 0) {
RNP_LOG("Failed to initialize verify: %lu", ERR_peek_last_error());
@@ -238,6 +298,43 @@ done:
return ret;
}
+static bool
+dsa_extract_key(EVP_PKEY *pkey, pgp_dsa_key_t &key)
+{
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ rnp::bn p;
+ rnp::bn q;
+ rnp::bn g;
+ rnp::bn y;
+ rnp::bn x;
+
+ bool res = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, p.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_Q, q.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, g.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, y.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, x.ptr());
+ return res && p.mpi(key.p) && q.mpi(key.q) && g.mpi(key.g) && y.mpi(key.y) && x.mpi(key.x);
+#else
+ const DSA *dsa = EVP_PKEY_get0_DSA(pkey);
+ if (!dsa) {
+ RNP_LOG("Failed to retrieve DSA key: %lu", ERR_peek_last_error());
+ return false;
+ }
+
+ const bignum_t *p = DSA_get0_p(dsa);
+ const bignum_t *q = DSA_get0_q(dsa);
+ const bignum_t *g = DSA_get0_g(dsa);
+ const bignum_t *y = DSA_get0_pub_key(dsa);
+ const bignum_t *x = DSA_get0_priv_key(dsa);
+
+ if (!p || !q || !g || !y || !x) {
+ return false;
+ }
+ return bn2mpi(p, &key.p) && bn2mpi(q, &key.q) && bn2mpi(g, &key.g) && bn2mpi(y, &key.y) &&
+ bn2mpi(x, &key.x);
+#endif
+}
+
rnp_result_t
dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits)
{
@@ -246,7 +343,6 @@ dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits)
}
rnp_result_t ret = RNP_ERROR_GENERIC;
- const DSA * dsa = NULL;
EVP_PKEY * pkey = NULL;
EVP_PKEY * parmkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
@@ -254,12 +350,16 @@ dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits)
/* Generate DSA params */
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error());
return ret;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_paramgen_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, keylen) <= 0) {
RNP_LOG("Failed to set key bits: %lu", ERR_peek_last_error());
@@ -293,32 +393,10 @@ dsa_generate(rnp::RNG *rng, pgp_dsa_key_t *key, size_t keylen, size_t qbits)
RNP_LOG("DSA keygen failed: %lu", ERR_peek_last_error());
goto done;
}
- dsa = EVP_PKEY_get0_DSA(pkey);
- if (!dsa) {
- RNP_LOG("Failed to retrieve DSA key: %lu", ERR_peek_last_error());
- goto done;
- }
- const bignum_t *p;
- const bignum_t *q;
- const bignum_t *g;
- const bignum_t *y;
- const bignum_t *x;
- p = DSA_get0_p(dsa);
- q = DSA_get0_q(dsa);
- g = DSA_get0_g(dsa);
- y = DSA_get0_pub_key(dsa);
- x = DSA_get0_priv_key(dsa);
- if (!p || !q || !g || !y || !x) {
- ret = RNP_ERROR_BAD_STATE;
- goto done;
+ if (dsa_extract_key(pkey, *key)) {
+ ret = RNP_SUCCESS;
}
- bn2mpi(p, &key->p);
- bn2mpi(q, &key->q);
- bn2mpi(g, &key->g);
- bn2mpi(y, &key->y);
- bn2mpi(x, &key->x);
- ret = RNP_SUCCESS;
done:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(parmkey);
diff --git a/src/lib/crypto/ec_ossl.cpp b/src/lib/crypto/ec_ossl.cpp
index 6974b4c..46c4677 100644
--- a/src/lib/crypto/ec_ossl.cpp
+++ b/src/lib/crypto/ec_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021, 2023 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -36,6 +36,10 @@
#include <openssl/objects.h>
#include <openssl/err.h>
#include <openssl/ec.h>
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#endif
static bool
ec_is_raw_key(const pgp_curve_t curve)
@@ -61,26 +65,34 @@ ec_generate_pkey(const pgp_pubkey_alg_t alg_id, const pgp_curve_t curve)
}
int nid = OBJ_sn2nid(ec_desc->openssl_name);
if (nid == NID_undef) {
+ /* LCOV_EXCL_START */
RNP_LOG("Unknown SN: %s", ec_desc->openssl_name);
return NULL;
+ /* LCOV_EXCL_END */
}
bool raw = ec_is_raw_key(curve);
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(raw ? nid : EVP_PKEY_EC, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error());
return NULL;
+ /* LCOV_EXCL_END */
}
EVP_PKEY *pkey = NULL;
if (EVP_PKEY_keygen_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (!raw && (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) <= 0)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set curve nid: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
- RNP_LOG("EC keygen failed: %lu", ERR_peek_last_error());
+ RNP_LOG("EC keygen failed: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
}
done:
EVP_PKEY_CTX_free(ctx);
@@ -94,8 +106,10 @@ ec_write_raw_seckey(EVP_PKEY *pkey, pgp_ec_key_t *key)
static_assert(sizeof(key->x.mpi) > 32, "mpi is too small.");
key->x.len = sizeof(key->x.mpi);
if (EVP_PKEY_get_raw_private_key(pkey, key->x.mpi, &key->x.len) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed get raw private key: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
assert(key->x.len == 32);
if (EVP_PKEY_id(pkey) == EVP_PKEY_X25519) {
@@ -107,6 +121,30 @@ ec_write_raw_seckey(EVP_PKEY *pkey, pgp_ec_key_t *key)
return true;
}
+static bool
+ec_write_seckey(EVP_PKEY *pkey, pgp_mpi_t &key)
+{
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ rnp::bn x;
+ return EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, x.ptr()) &&
+ bn2mpi(x.get(), &key);
+#else
+ const bignum_t *x = NULL;
+ const EC_KEY * ec = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("Failed to retrieve EC key: %lu", ERR_peek_last_error());
+ return false;
+ /* LCOV_EXCL_END */
+ }
+ x = EC_KEY_get0_private_key(ec);
+ if (!x) {
+ return false;
+ }
+ return bn2mpi(x, &key);
+#endif
+}
+
rnp_result_t
ec_generate(rnp::RNG * rng,
pgp_ec_key_t * key,
@@ -125,24 +163,19 @@ ec_generate(rnp::RNG * rng,
EVP_PKEY_free(pkey);
return ret;
}
- const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
- if (!ec) {
- RNP_LOG("Failed to retrieve EC key: %lu", ERR_peek_last_error());
- goto done;
- }
if (!ec_write_pubkey(pkey, key->p, curve)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to write pubkey.");
goto done;
+ /* LCOV_EXCL_END */
}
- const bignum_t *x;
- x = EC_KEY_get0_private_key(ec);
- if (!x) {
- ret = RNP_ERROR_BAD_STATE;
+ if (!ec_write_seckey(pkey, key->x)) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("Failed to write seckey.");
goto done;
+ /* LCOV_EXCL_END */
}
- if (bn2mpi(x, &key->x)) {
- ret = RNP_SUCCESS;
- }
+ ret = RNP_SUCCESS;
done:
EVP_PKEY_free(pkey);
return ret;
@@ -161,7 +194,7 @@ ec_load_raw_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, int nid)
EVP_PKEY *evpkey =
EVP_PKEY_new_raw_public_key(nid, NULL, &keyp.mpi[1], mpi_bytes(&keyp) - 1);
if (!evpkey) {
- RNP_LOG("Failed to load public key: %lu", ERR_peek_last_error());
+ RNP_LOG("Failed to load public key: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
}
return evpkey;
}
@@ -189,10 +222,68 @@ ec_load_raw_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, int nid)
evpkey = EVP_PKEY_new_raw_private_key(nid, NULL, prkey.data(), 32);
}
if (!evpkey) {
- RNP_LOG("Failed to load private key: %lu", ERR_peek_last_error());
+ RNP_LOG("Failed to load private key: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
+ }
+ return evpkey;
+}
+
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+static OSSL_PARAM *
+ec_build_params(const pgp_mpi_t &p, bignum_t *x, const char *curve)
+{
+ OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
+ if (!bld) {
+ return NULL;
+ }
+ if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, curve, 0) ||
+ !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, p.mpi, p.len) ||
+ (x && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, x))) {
+ /* LCOV_EXCL_START */
+ OSSL_PARAM_BLD_free(bld);
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ OSSL_PARAM *param = OSSL_PARAM_BLD_to_param(bld);
+ OSSL_PARAM_BLD_free(bld);
+ return param;
+}
+
+static EVP_PKEY *
+ec_load_key_openssl3(const pgp_mpi_t & keyp,
+ const pgp_mpi_t * keyx,
+ const ec_curve_desc_t *curv_desc)
+{
+ rnp::bn x(keyx ? mpi2bn(keyx) : NULL);
+ OSSL_PARAM *params = ec_build_params(keyp, x.get(), curv_desc->openssl_name);
+ if (!params) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to build ec params");
+ return NULL;
+ /* LCOV_EXCL_END */
+ }
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
+ if (!ctx) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to create ec context");
+ OSSL_PARAM_free(params);
+ return NULL;
+ /* LCOV_EXCL_END */
}
+ EVP_PKEY *evpkey = NULL;
+ if ((EVP_PKEY_fromdata_init(ctx) != 1) ||
+ (EVP_PKEY_fromdata(
+ ctx, &evpkey, keyx ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) != 1)) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("failed to create ec key from data");
+ /* Some version of OpenSSL may leave evpkey non-NULL after failure, so let's be safe */
+ evpkey = NULL;
+ /* LCOV_EXCL_END */
+ }
+ OSSL_PARAM_free(params);
+ EVP_PKEY_CTX_free(ctx);
return evpkey;
}
+#endif
EVP_PKEY *
ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve)
@@ -208,20 +299,27 @@ ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve)
}
int nid = OBJ_sn2nid(curv_desc->openssl_name);
if (nid == NID_undef) {
+ /* LCOV_EXCL_START */
RNP_LOG("Unknown SN: %s", curv_desc->openssl_name);
return NULL;
+ /* LCOV_EXCL_END */
}
/* EdDSA and X25519 keys are loaded in a different way */
if (ec_is_raw_key(curve)) {
return ec_load_raw_key(keyp, keyx, nid);
}
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ return ec_load_key_openssl3(keyp, keyx, curv_desc);
+#else
EC_KEY *ec = EC_KEY_new_by_curve_name(nid);
if (!ec) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create EC key with group %d (%s): %s",
nid,
curv_desc->openssl_name,
ERR_reason_error_string(ERR_peek_last_error()));
return NULL;
+ /* LCOV_EXCL_END */
}
bool res = false;
@@ -229,22 +327,30 @@ ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve)
EVP_PKEY *pkey = NULL;
EC_POINT *p = EC_POINT_new(EC_KEY_get0_group(ec));
if (!p) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to allocate point: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EC_POINT_oct2point(EC_KEY_get0_group(ec), p, keyp.mpi, keyp.len, NULL) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to decode point: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EC_KEY_set_public_key(ec, p) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set public key: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
pkey = EVP_PKEY_new();
if (!pkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("EVP_PKEY allocation failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (!keyx) {
res = true;
@@ -253,12 +359,16 @@ ec_load_key(const pgp_mpi_t &keyp, const pgp_mpi_t *keyx, pgp_curve_t curve)
x = mpi2bn(keyx);
if (!x) {
+ /* LCOV_EXCL_START */
RNP_LOG("allocation failed");
goto done;
+ /* LCOV_EXCL_END */
}
if (EC_KEY_set_private_key(ec, x) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set secret key: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
res = true;
done:
@@ -273,6 +383,7 @@ done:
pkey = NULL;
}
return pkey;
+#endif
}
rnp_result_t
@@ -296,14 +407,18 @@ ec_validate_key(const pgp_ec_key_t &key, bool secret)
rnp_result_t ret = RNP_ERROR_GENERIC;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(evpkey, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
int res;
res = secret ? EVP_PKEY_check(ctx) : EVP_PKEY_public_check(ctx);
if (res < 0) {
+ /* LCOV_EXCL_START */
auto err = ERR_peek_last_error();
RNP_LOG("EC key check failed: %lu (%s)", err, ERR_reason_error_string(err));
+ /* LCOV_EXCL_END */
}
if (res > 0) {
ret = RNP_SUCCESS;
@@ -321,29 +436,61 @@ ec_write_pubkey(EVP_PKEY *pkey, pgp_mpi_t &mpi, pgp_curve_t curve)
/* EdDSA and X25519 keys are saved in a different way */
mpi.len = sizeof(mpi.mpi) - 1;
if (EVP_PKEY_get_raw_public_key(pkey, &mpi.mpi[1], &mpi.len) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed get raw public key: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
assert(mpi.len == 32);
mpi.mpi[0] = 0x40;
mpi.len++;
return true;
}
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ const ec_curve_desc_t *ec_desc = get_curve_desc(curve);
+ if (!ec_desc) {
+ return false;
+ }
+ size_t flen = BITS_TO_BYTES(ec_desc->bitlen);
+ rnp::bn qx;
+ rnp::bn qy;
+
+ /* OpenSSL before 3.0.9 by default uses compressed point for OSSL_PKEY_PARAM_PUB_KEY so use
+ * this approach */
+ bool res = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, qx.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, qy.ptr());
+ if (!res) {
+ return false;
+ }
+ /* Compose uncompressed point in mpi */
+ size_t xlen = qx.bytes();
+ size_t ylen = qy.bytes();
+ assert((xlen <= flen) && (ylen <= flen));
+ memset(mpi.mpi, 0, sizeof(mpi.mpi));
+ mpi.mpi[0] = 0x04;
+ mpi.len = 2 * flen + 1;
+ return qx.bin(&mpi.mpi[1 + flen - xlen]) && qy.bin(&mpi.mpi[1 + 2 * flen - ylen]);
+#else
const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
if (!ec) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to retrieve EC key: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
const EC_POINT *p = EC_KEY_get0_public_key(ec);
if (!p) {
+ /* LCOV_EXCL_START */
RNP_LOG("Null point: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
/* call below adds leading zeroes if needed */
mpi.len = EC_POINT_point2oct(
EC_KEY_get0_group(ec), p, POINT_CONVERSION_UNCOMPRESSED, mpi.mpi, sizeof(mpi.mpi), NULL);
if (!mpi.len) {
- RNP_LOG("Failed to encode public key: %lu", ERR_peek_last_error());
+ RNP_LOG("Failed to encode public key: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
}
return mpi.len;
+#endif
}
diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp
index d4411c3..574b3b8 100644
--- a/src/lib/crypto/ecdh.cpp
+++ b/src/lib/crypto/ecdh.cpp
@@ -261,7 +261,13 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng,
}
out->mlen = sizeof(out->m);
+#if defined(CRYPTO_BACKEND_BOTAN3)
+ char name[8];
+ snprintf(name, sizeof(name), "AES-%zu", 8 * kek_len);
+ if (botan_nist_kw_enc(name, 0, m, m_padded_len, kek, kek_len, out->m, &out->mlen)) {
+#else
if (botan_key_wrap3394(m, m_padded_len, kek, kek_len, out->m, &out->mlen)) {
+#endif
goto end;
}
@@ -354,8 +360,15 @@ ecdh_decrypt_pkcs5(uint8_t * out,
goto end;
}
+#if defined(CRYPTO_BACKEND_BOTAN3)
+ char name[8];
+ snprintf(name, sizeof(name), "AES-%zu", 8 * kek_len);
+ if (botan_nist_kw_dec(
+ name, 0, in->m, in->mlen, kek.data(), kek_len, deckey.data(), &deckey_len)) {
+#else
if (botan_key_unwrap3394(
in->m, in->mlen, kek.data(), kek_len, deckey.data(), &deckey_len)) {
+#endif
goto end;
}
diff --git a/src/lib/crypto/ecdh_ossl.cpp b/src/lib/crypto/ecdh_ossl.cpp
index 60b7260..5660318 100644
--- a/src/lib/crypto/ecdh_ossl.cpp
+++ b/src/lib/crypto/ecdh_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2022, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021-2023, [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -70,8 +70,10 @@ ecdh_derive_kek(uint8_t * x,
const size_t hash_len = rnp::Hash::size(key.kdf_hash_alg);
if (!hash_len) {
// must not assert here as kdf/hash algs are not checked during key parsing
+ /* LCOV_EXCL_START */
RNP_LOG("Unsupported key wrap hash algorithm.");
return RNP_ERROR_NOT_SUPPORTED;
+ /* LCOV_EXCL_END */
}
size_t other_len = kdf_other_info_serialize(
other_info, curve_desc, fingerprint, key.kdf_hash_alg, key.key_wrap_alg);
@@ -83,8 +85,10 @@ ecdh_derive_kek(uint8_t * x,
size_t reps = (kek_len + hash_len - 1) / hash_len;
// As we use AES & SHA2 we should not get more then 2 iterations
if (reps > 2) {
+ /* LCOV_EXCL_START */
RNP_LOG("Invalid key wrap/hash alg combination.");
return RNP_ERROR_NOT_SUPPORTED;
+ /* LCOV_EXCL_END */
}
size_t have = 0;
try {
@@ -100,8 +104,10 @@ ecdh_derive_kek(uint8_t * x,
}
return RNP_SUCCESS;
} catch (const std::exception &e) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to derive kek: %s", e.what());
return RNP_ERROR_GENERIC;
+ /* LCOV_EXCL_END */
}
}
@@ -115,27 +121,35 @@ ecdh_rfc3394_wrap_ctx(EVP_CIPHER_CTX **ctx,
const char *cipher_name = NULL;
ARRAY_LOOKUP_BY_ID(ecdh_wrap_alg_map, alg, name, wrap_alg, cipher_name);
if (!cipher_name) {
+ /* LCOV_EXCL_START */
RNP_LOG("Unsupported key wrap algorithm: %d", (int) wrap_alg);
return RNP_ERROR_NOT_SUPPORTED;
+ /* LCOV_EXCL_END */
}
const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_name);
if (!cipher) {
+ /* LCOV_EXCL_START */
RNP_LOG("Cipher %s is not supported by OpenSSL.", cipher_name);
return RNP_ERROR_NOT_SUPPORTED;
+ /* LCOV_EXCL_END */
}
*ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed : %lu", ERR_peek_last_error());
return RNP_ERROR_OUT_OF_MEMORY;
+ /* LCOV_EXCL_END */
}
EVP_CIPHER_CTX_set_flags(*ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
int res = decrypt ? EVP_DecryptInit_ex(*ctx, cipher, NULL, key, NULL) :
EVP_EncryptInit_ex(*ctx, cipher, NULL, key, NULL);
if (res <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to initialize cipher : %lu", ERR_peek_last_error());
EVP_CIPHER_CTX_free(*ctx);
*ctx = NULL;
return RNP_ERROR_GENERIC;
+ /* LCOV_EXCL_END */
}
return RNP_SUCCESS;
}
@@ -151,14 +165,16 @@ ecdh_rfc3394_wrap(uint8_t * out,
EVP_CIPHER_CTX *ctx = NULL;
rnp_result_t ret = ecdh_rfc3394_wrap_ctx(&ctx, wrap_alg, key, false);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Wrap context initialization failed.");
return ret;
+ /* LCOV_EXCL_END */
}
int intlen = *out_len;
/* encrypts in one pass, no final is needed */
int res = EVP_EncryptUpdate(ctx, out, &intlen, in, in_len);
if (res <= 0) {
- RNP_LOG("Failed to encrypt data : %lu", ERR_peek_last_error());
+ RNP_LOG("Failed to encrypt data : %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
} else {
*out_len = intlen;
}
@@ -181,8 +197,10 @@ ecdh_rfc3394_unwrap(uint8_t * out,
EVP_CIPHER_CTX *ctx = NULL;
rnp_result_t ret = ecdh_rfc3394_wrap_ctx(&ctx, wrap_alg, key, true);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Unwrap context initialization failed.");
return ret;
+ /* LCOV_EXCL_END */
}
int intlen = *out_len;
/* decrypts in one pass, no final is needed */
@@ -201,21 +219,29 @@ ecdh_derive_secret(EVP_PKEY *sec, EVP_PKEY *peer, uint8_t *x, size_t *xlen)
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(sec, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
bool res = false;
if (EVP_PKEY_derive_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Key derivation init failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_derive_set_peer(ctx, peer) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Peer setting failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_derive(ctx, x, xlen) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to obtain shared secret size: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
res = true;
done:
@@ -256,14 +282,18 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng,
/* check whether we have valid wrap_alg before doing heavy operations */
size_t keklen = ecdh_kek_len(key->key_wrap_alg);
if (!keklen) {
+ /* LCOV_EXCL_START */
RNP_LOG("Unsupported key wrap algorithm: %d", (int) key->key_wrap_alg);
return RNP_ERROR_NOT_SUPPORTED;
+ /* LCOV_EXCL_END */
}
/* load our public key */
EVP_PKEY *pkey = ec_load_key(key->p, NULL, key->curve);
if (!pkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to load public key.");
return RNP_ERROR_BAD_PARAMETERS;
+ /* LCOV_EXCL_END */
}
rnp::secure_array<uint8_t, MAX_CURVE_BYTELEN + 1> sec;
rnp::secure_array<uint8_t, MAX_AES_KEY_SIZE> kek;
@@ -274,28 +304,36 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng,
/* generate ephemeral key */
EVP_PKEY *ephkey = ec_generate_pkey(PGP_PKA_ECDH, key->curve);
if (!ephkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to generate ephemeral key.");
ret = RNP_ERROR_KEY_GENERATION;
goto done;
+ /* LCOV_EXCL_END */
}
/* do ECDH derivation */
if (!ecdh_derive_secret(ephkey, pkey, sec.data(), &seclen)) {
+ /* LCOV_EXCL_START */
RNP_LOG("ECDH derivation failed.");
goto done;
+ /* LCOV_EXCL_END */
}
/* here we got x value in sec, deriving kek */
ret = ecdh_derive_kek(sec.data(), seclen, *key, fingerprint, kek.data(), keklen);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to derive KEK.");
goto done;
+ /* LCOV_EXCL_END */
}
/* add PKCS#7 padding */
size_t m_padded_len;
m_padded_len = ((in_len / 8) + 1) * 8;
memcpy(mpad.data(), in, in_len);
if (!pad_pkcs7(mpad.data(), m_padded_len, in_len)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to add PKCS #7 padding.");
goto done;
+ /* LCOV_EXCL_END */
}
/* do RFC 3394 AES key wrap */
static_assert(sizeof(out->m) == ECDH_WRAPPED_KEY_SIZE, "Wrong ECDH wrapped key size.");
@@ -303,13 +341,17 @@ ecdh_encrypt_pkcs5(rnp::RNG * rng,
ret = ecdh_rfc3394_wrap(
out->m, &out->mlen, mpad.data(), m_padded_len, kek.data(), key->key_wrap_alg);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to wrap key.");
goto done;
+ /* LCOV_EXCL_END */
}
/* write ephemeral public key */
if (!ec_write_pubkey(ephkey, out->p, key->curve)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to write ec key.");
goto done;
+ /* LCOV_EXCL_END */
}
ret = RNP_SUCCESS;
done:
@@ -351,32 +393,42 @@ ecdh_decrypt_pkcs5(uint8_t * out,
rnp_result_t ret = RNP_ERROR_GENERIC;
EVP_PKEY * pkey = ec_load_key(key->p, &key->x, key->curve);
if (!pkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to load secret key.");
ret = RNP_ERROR_BAD_PARAMETERS;
goto done;
+ /* LCOV_EXCL_END */
}
/* do ECDH derivation */
if (!ecdh_derive_secret(pkey, ephkey, sec.data(), &seclen)) {
+ /* LCOV_EXCL_START */
RNP_LOG("ECDH derivation failed.");
goto done;
+ /* LCOV_EXCL_END */
}
/* here we got x value in sec, deriving kek */
ret = ecdh_derive_kek(sec.data(), seclen, *key, fingerprint, kek.data(), keklen);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to derive KEK.");
goto done;
+ /* LCOV_EXCL_END */
}
/* do RFC 3394 AES key unwrap */
ret = ecdh_rfc3394_unwrap(
mpad.data(), &mpadlen, in->m, in->mlen, kek.data(), key->key_wrap_alg);
if (ret) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to unwrap key.");
goto done;
+ /* LCOV_EXCL_END */
}
/* remove PKCS#7 padding */
if (!unpad_pkcs7(mpad.data(), mpadlen, &mpadlen)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to unpad key.");
goto done;
+ /* LCOV_EXCL_END */
}
assert(mpadlen <= *out_len);
*out_len = mpadlen;
diff --git a/src/lib/crypto/elgamal_ossl.cpp b/src/lib/crypto/elgamal_ossl.cpp
index f3fa381..6049ad2 100644
--- a/src/lib/crypto/elgamal_ossl.cpp
+++ b/src/lib/crypto/elgamal_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021, 2023 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -38,6 +38,10 @@
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#endif
// Max supported key byte size
#define ELGAMAL_MAX_P_BYTELEN BITS_TO_BYTES(PGP_MPINT_BITS)
@@ -47,8 +51,10 @@ elgamal_validate_key(const pgp_eg_key_t *key, bool secret)
{
BN_CTX *ctx = BN_CTX_new();
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed.");
return false;
+ /* LCOV_EXCL_END */
}
BN_CTX_start(ctx);
bool res = false;
@@ -86,8 +92,10 @@ elgamal_validate_key(const pgp_eg_key_t *key, bool secret)
}
for (size_t i = 2; i < (1 << 17); i++) {
if (!BN_mod_mul_reciprocal(r, r, g, rctx, ctx)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Multiplication failed.");
goto done;
+ /* LCOV_EXCL_END */
}
if (BN_cmp(r, BN_value_one()) == 0) {
RNP_LOG("Small subgroup detected. Order %zu", i);
@@ -135,8 +143,10 @@ pkcs1v15_pad(uint8_t *out, size_t out_len, const uint8_t *in, size_t in_len)
while (!out[i] && (cntr--) && (RAND_bytes(&out[i], 1) == 1)) {
}
if (!out[i]) {
+ /* LCOV_EXCL_START */
RNP_LOG("Something is wrong with RNG.");
return false;
+ /* LCOV_EXCL_END */
}
}
memcpy(out + rnd + 3, in, in_len);
@@ -176,14 +186,18 @@ elgamal_encrypt_pkcs1(rnp::RNG * rng,
pgp_mpi_t mm = {};
mm.len = key->p.len;
if (!pkcs1v15_pad(mm.mpi, mm.len, in, in_len)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to add PKCS1 v1.5 padding.");
return RNP_ERROR_BAD_PARAMETERS;
+ /* LCOV_EXCL_END */
}
rnp_result_t ret = RNP_ERROR_GENERIC;
BN_CTX * ctx = BN_CTX_new();
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed.");
return RNP_ERROR_OUT_OF_MEMORY;
+ /* LCOV_EXCL_END */
}
BN_CTX_start(ctx);
BN_MONT_CTX *mctx = BN_MONT_CTX_new();
@@ -195,41 +209,55 @@ elgamal_encrypt_pkcs1(rnp::RNG * rng,
bignum_t * c2 = BN_CTX_get(ctx);
bignum_t * k = BN_secure_new();
if (!mctx || !m || !p || !g || !y || !c1 || !c2 || !k) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed.");
ret = RNP_ERROR_OUT_OF_MEMORY;
goto done;
+ /* LCOV_EXCL_END */
}
/* initialize Montgomery context */
if (BN_MONT_CTX_set(mctx, p, ctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to setup Montgomery context.");
goto done;
+ /* LCOV_EXCL_END */
}
int res;
/* must not fail */
res = BN_rshift1(c1, p);
assert(res == 1);
if (res < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("BN_rshift1 failed.");
goto done;
+ /* LCOV_EXCL_END */
}
/* generate k */
if (BN_rand_range(k, c1) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to generate k.");
goto done;
+ /* LCOV_EXCL_END */
}
/* calculate c1 = g ^ k (mod p) */
if (BN_mod_exp_mont_consttime(c1, g, k, p, ctx, mctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Exponentiation 1 failed");
goto done;
+ /* LCOV_EXCL_END */
}
/* calculate c2 = m * y ^ k (mod p)*/
if (BN_mod_exp_mont_consttime(c2, y, k, p, ctx, mctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Exponentiation 2 failed");
goto done;
+ /* LCOV_EXCL_END */
}
if (BN_mod_mul(c2, c2, m, p, ctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Multiplication failed");
goto done;
+ /* LCOV_EXCL_END */
}
res = bn2mpi(c1, &out->g) && bn2mpi(c2, &out->m);
assert(res == 1);
@@ -258,8 +286,10 @@ elgamal_decrypt_pkcs1(rnp::RNG * rng,
}
BN_CTX *ctx = BN_CTX_new();
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed.");
return RNP_ERROR_OUT_OF_MEMORY;
+ /* LCOV_EXCL_END */
}
pgp_mpi_t mm = {};
size_t padlen = 0;
@@ -274,37 +304,49 @@ elgamal_decrypt_pkcs1(rnp::RNG * rng,
bignum_t * s = BN_CTX_get(ctx);
bignum_t * m = BN_secure_new();
if (!mctx || !p || !g || !x || !c1 || !c2 || !m) {
+ /* LCOV_EXCL_START */
RNP_LOG("Allocation failed.");
ret = RNP_ERROR_OUT_OF_MEMORY;
goto done;
+ /* LCOV_EXCL_END */
}
/* initialize Montgomery context */
if (BN_MONT_CTX_set(mctx, p, ctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to setup Montgomery context.");
goto done;
+ /* LCOV_EXCL_END */
}
/* calculate s = c1 ^ x (mod p) */
if (BN_mod_exp_mont_consttime(s, c1, x, p, ctx, mctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Exponentiation 1 failed");
goto done;
+ /* LCOV_EXCL_END */
}
/* calculate s^-1 (mod p) */
BN_set_flags(s, BN_FLG_CONSTTIME);
if (!BN_mod_inverse(s, s, p, ctx)) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to calculate inverse.");
goto done;
+ /* LCOV_EXCL_END */
}
/* calculate m = c2 * s ^ -1 (mod p)*/
if (BN_mod_mul(m, c2, s, p, ctx) < 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Multiplication failed");
goto done;
+ /* LCOV_EXCL_END */
}
bool res;
res = bn2mpi(m, &mm);
assert(res);
if (!res) {
+ /* LCOV_EXCL_START */
RNP_LOG("bn2mpi failed.");
goto done;
+ /* LCOV_EXCL_END */
}
/* unpad, handling skipped leftmost 0 case */
if (!pkcs1v15_unpad(&padlen, mm.mpi, mm.len, mm.len == key->p.len - 1)) {
@@ -334,8 +376,10 @@ elgamal_generate(rnp::RNG *rng, pgp_eg_key_t *key, size_t keybits)
return RNP_ERROR_BAD_PARAMETERS;
}
- rnp_result_t ret = RNP_ERROR_GENERIC;
- const DH * dh = NULL;
+ rnp_result_t ret = RNP_ERROR_GENERIC;
+#if !defined(CRYPTO_BACKEND_OPENSSL3)
+ const DH *dh = NULL;
+#endif
EVP_PKEY * pkey = NULL;
EVP_PKEY * parmkey = NULL;
EVP_PKEY_CTX *ctx = NULL;
@@ -343,47 +387,93 @@ elgamal_generate(rnp::RNG *rng, pgp_eg_key_t *key, size_t keybits)
/* Generate DH params, which usable for ElGamal as well */
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DH, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error());
return ret;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_paramgen_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, keybits) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set key bits: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
/* OpenSSL correctly handles case with g = 5, making sure that g is primitive root of
* q-group */
if (EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, DH_GENERATOR_5) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set key generator: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_paramgen(ctx, &parmkey) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to generate parameters: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
EVP_PKEY_CTX_free(ctx);
/* Generate DH (ElGamal) key */
start:
ctx = EVP_PKEY_CTX_new(parmkey, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create ctx: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_keygen_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init keygen: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_keygen(ctx, &pkey) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("ElGamal keygen failed: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
+ }
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ {
+ rnp::bn y;
+ if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, y.ptr())) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("Failed to retrieve ElGamal public key: %lu", ERR_peek_last_error());
+ goto done;
+ /* LCOV_EXCL_END */
+ }
+ if (y.bytes() != BITS_TO_BYTES(keybits)) {
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+ EVP_PKEY_free(pkey);
+ pkey = NULL;
+ goto start;
+ }
+
+ rnp::bn p;
+ rnp::bn g;
+ rnp::bn x;
+ bool res = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_P, p.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_FFC_G, g.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, x.ptr());
+ if (res && p.mpi(key->p) && g.mpi(key->g) && y.mpi(key->y) && x.mpi(key->x)) {
+ ret = RNP_SUCCESS;
+ }
}
+#else
dh = EVP_PKEY_get0_DH(pkey);
if (!dh) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to retrieve DH key: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
if (BITS_TO_BYTES(BN_num_bits(DH_get0_pub_key(dh))) != BITS_TO_BYTES(keybits)) {
EVP_PKEY_CTX_free(ctx);
@@ -402,14 +492,17 @@ start:
y = DH_get0_pub_key(dh);
x = DH_get0_priv_key(dh);
if (!p || !g || !y || !x) {
+ /* LCOV_EXCL_START */
ret = RNP_ERROR_BAD_STATE;
goto done;
+ /* LCOV_EXCL_END */
}
bn2mpi(p, &key->p);
bn2mpi(g, &key->g);
bn2mpi(y, &key->y);
bn2mpi(x, &key->x);
ret = RNP_SUCCESS;
+#endif
done:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(parmkey);
diff --git a/src/lib/crypto/rsa.cpp b/src/lib/crypto/rsa.cpp
index f7ddefe..83fa044 100644
--- a/src/lib/crypto/rsa.cpp
+++ b/src/lib/crypto/rsa.cpp
@@ -333,12 +333,16 @@ rsa_decrypt_pkcs1(rnp::RNG * rng,
return RNP_ERROR_OUT_OF_MEMORY;
}
+ size_t skip = 0;
if (botan_pk_op_decrypt_create(&decrypt_op, rsa_key, "PKCS1v15", 0)) {
goto done;
}
-
+ /* Skip trailing zeroes if any as Botan3 doesn't like m.len > e.len */
+ while ((in->m.len - skip > key->e.len) && !in->m.mpi[skip]) {
+ skip++;
+ }
*out_len = PGP_MPINT_SIZE;
- if (botan_pk_op_decrypt(decrypt_op, out, out_len, in->m.mpi, in->m.len)) {
+ if (botan_pk_op_decrypt(decrypt_op, out, out_len, in->m.mpi + skip, in->m.len - skip)) {
goto done;
}
ret = RNP_SUCCESS;
diff --git a/src/lib/crypto/rsa_ossl.cpp b/src/lib/crypto/rsa_ossl.cpp
index 24cff29..445974c 100644
--- a/src/lib/crypto/rsa_ossl.cpp
+++ b/src/lib/crypto/rsa_ossl.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021-2022, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2021-2023, [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -45,30 +45,29 @@
static RSA *
rsa_load_public_key(const pgp_rsa_key_t *key)
{
- RSA * rsa = NULL;
- bignum_t *n = mpi2bn(&key->n);
- bignum_t *e = mpi2bn(&key->e);
+ rnp::bn n(key->n);
+ rnp::bn e(key->e);
- if (!n || !e) {
+ if (!n.get() || !e.get()) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- rsa = RSA_new();
+ RSA *rsa = RSA_new();
if (!rsa) {
+ /* LCOV_EXCL_START */
RNP_LOG("Out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- if (RSA_set0_key(rsa, n, e, NULL) != 1) {
+ /* OpenSSL set0 function transfers ownership of bignums */
+ if (RSA_set0_key(rsa, n.own(), e.own(), NULL) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Public key load error: %lu", ERR_peek_last_error());
RSA_free(rsa);
- rsa = NULL;
- goto done;
- }
-done:
- /* OpenSSL set0 function transfers ownership of bignums */
- if (!rsa) {
- bn_free(n);
- bn_free(e);
+ return NULL;
+ /* LCOV_EXCL_END */
}
return rsa;
}
@@ -76,44 +75,41 @@ done:
static RSA *
rsa_load_secret_key(const pgp_rsa_key_t *key)
{
- RSA * rsa = NULL;
- bignum_t *n = mpi2bn(&key->n);
- bignum_t *e = mpi2bn(&key->e);
- bignum_t *p = mpi2bn(&key->p);
- bignum_t *q = mpi2bn(&key->q);
- bignum_t *d = mpi2bn(&key->d);
+ rnp::bn n(key->n);
+ rnp::bn e(key->e);
+ rnp::bn p(key->p);
+ rnp::bn q(key->q);
+ rnp::bn d(key->d);
- if (!n || !p || !q || !e || !d) {
+ if (!n.get() || !p.get() || !q.get() || !e.get() || !d.get()) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- rsa = RSA_new();
+ RSA *rsa = RSA_new();
if (!rsa) {
+ /* LCOV_EXCL_START */
RNP_LOG("Out of memory");
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
- if (RSA_set0_key(rsa, n, e, d) != 1) {
+ /* OpenSSL set0 function transfers ownership of bignums */
+ if (RSA_set0_key(rsa, n.own(), e.own(), d.own()) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Secret key load error: %lu", ERR_peek_last_error());
RSA_free(rsa);
- rsa = NULL;
- goto done;
+ return NULL;
+ /* LCOV_EXCL_END */
}
/* OpenSSL has p < q, as we do */
- if (RSA_set0_factors(rsa, p, q) != 1) {
+ if (RSA_set0_factors(rsa, p.own(), q.own()) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Factors load error: %lu", ERR_peek_last_error());
RSA_free(rsa);
- rsa = NULL;
- goto done;
- }
-done:
- /* OpenSSL set0 function transfers ownership of bignums */
- if (!rsa) {
- bn_free(n);
- bn_free(p);
- bn_free(q);
- bn_free(e);
- bn_free(d);
+ return NULL;
+ /* LCOV_EXCL_END */
}
return rsa;
}
@@ -123,8 +119,10 @@ rsa_init_context(const pgp_rsa_key_t *key, bool secret)
{
EVP_PKEY *evpkey = EVP_PKEY_new();
if (!evpkey) {
+ /* LCOV_EXCL_START */
RNP_LOG("allocation failed");
return NULL;
+ /* LCOV_EXCL_END */
}
EVP_PKEY_CTX *ctx = NULL;
RSA * rsakey = secret ? rsa_load_secret_key(key) : rsa_load_public_key(key);
@@ -132,12 +130,14 @@ rsa_init_context(const pgp_rsa_key_t *key, bool secret)
goto done;
}
if (EVP_PKEY_set1_RSA(evpkey, rsakey) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set key: %lu", ERR_peek_last_error());
goto done;
+ /* LCOV_EXCL_END */
}
ctx = EVP_PKEY_CTX_new(evpkey, NULL);
if (!ctx) {
- RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error());
+ RNP_LOG("Context allocation failed: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
}
done:
RSA_free(rsakey);
@@ -150,70 +150,72 @@ rsa_bld_params(const pgp_rsa_key_t *key, bool secret)
{
OSSL_PARAM * params = NULL;
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
- bignum_t * n = mpi2bn(&key->n);
- bignum_t * e = mpi2bn(&key->e);
- bignum_t * d = NULL;
- bignum_t * p = NULL;
- bignum_t * q = NULL;
- bignum_t * u = NULL;
+ rnp::bn n(key->n);
+ rnp::bn e(key->e);
+ rnp::bn d;
+ rnp::bn p;
+ rnp::bn q;
+ rnp::bn u;
BN_CTX * bnctx = NULL;
- if (!n || !e || !bld) {
+ if (!n.get() || !e.get() || !bld) {
+ /* LCOV_EXCL_START */
RNP_LOG("Out of memory");
goto done;
+ /* LCOV_EXCL_END */
}
- if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n) ||
- !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e)) {
+ if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, n.get()) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, e.get())) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to push RSA params.");
- goto done;
+ OSSL_PARAM_BLD_free(bld);
+ return NULL;
+ /* LCOV_EXCL_END */
}
if (secret) {
- d = mpi2bn(&key->d);
+ d.set(key->d);
/* As we have u = p^-1 mod q, and qInv = q^-1 mod p, we need to replace one with
* another */
- p = mpi2bn(&key->q);
- q = mpi2bn(&key->p);
- u = mpi2bn(&key->u);
- if (!d || !p || !q || !u) {
+ p.set(key->q);
+ q.set(key->p);
+ u.set(key->u);
+ if (!d.get() || !p.get() || !q.get() || !u.get()) {
goto done;
}
/* We need to calculate exponents manually */
bnctx = BN_CTX_new();
if (!bnctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to allocate BN_CTX.");
goto done;
+ /* LCOV_EXCL_END */
}
bignum_t *p1 = BN_CTX_get(bnctx);
bignum_t *q1 = BN_CTX_get(bnctx);
bignum_t *dp = BN_CTX_get(bnctx);
bignum_t *dq = BN_CTX_get(bnctx);
- if (!BN_copy(p1, p) || !BN_sub_word(p1, 1) || !BN_copy(q1, q) || !BN_sub_word(q1, 1) ||
- !BN_mod(dp, d, p1, bnctx) || !BN_mod(dq, d, q1, bnctx)) {
- RNP_LOG("Failed to calculate dP or dQ.");
+ if (!BN_copy(p1, p.get()) || !BN_sub_word(p1, 1) || !BN_copy(q1, q.get()) ||
+ !BN_sub_word(q1, 1) || !BN_mod(dp, d.get(), p1, bnctx) ||
+ !BN_mod(dq, d.get(), q1, bnctx)) {
+ RNP_LOG("Failed to calculate dP or dQ."); // LCOV_EXCL_LINE
}
/* Push params */
- if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d) ||
- !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p) ||
- !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, q) ||
+ if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, d.get()) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR1, p.get()) ||
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_FACTOR2, q.get()) ||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT1, dp) ||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_EXPONENT2, dq) ||
- !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u)) {
- RNP_LOG("Failed to push RSA secret params.");
+ !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u.get())) {
+ RNP_LOG("Failed to push RSA secret params."); // LCOV_EXCL_LINE
goto done;
}
}
params = OSSL_PARAM_BLD_to_param(bld);
if (!params) {
- RNP_LOG("Failed to build RSA params: %s.", ossl_latest_err());
+ RNP_LOG("Failed to build RSA params: %s.", ossl_latest_err()); // LCOV_EXCL_LINE
}
done:
- bn_free(n);
- bn_free(e);
- bn_free(d);
- bn_free(p);
- bn_free(q);
- bn_free(u);
BN_CTX_free(bnctx);
OSSL_PARAM_BLD_free(bld);
return params;
@@ -231,17 +233,21 @@ rsa_load_key(const pgp_rsa_key_t *key, bool secret)
EVP_PKEY * res = NULL;
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Context allocation failed: %s", ossl_latest_err());
goto done;
+ /* LCOV_EXCL_END */
}
/* Create key */
if (EVP_PKEY_fromdata_init(ctx) <= 0) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to initialize key creation: %s", ossl_latest_err());
goto done;
+ /* LCOV_EXCL_END */
}
if (EVP_PKEY_fromdata(
ctx, &res, secret ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, params) <= 0) {
- RNP_LOG("Failed to create RSA key: %s", ossl_latest_err());
+ RNP_LOG("Failed to create RSA key: %s", ossl_latest_err()); // LCOV_EXCL_LINE
}
done:
EVP_PKEY_CTX_free(ctx);
@@ -258,7 +264,7 @@ rsa_init_context(const pgp_rsa_key_t *key, bool secret)
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx) {
- RNP_LOG("Context allocation failed: %s", ossl_latest_err());
+ RNP_LOG("Context allocation failed: %s", ossl_latest_err()); // LCOV_EXCL_LINE
}
EVP_PKEY_free(pkey);
return ctx;
@@ -271,12 +277,14 @@ rsa_validate_key(rnp::RNG *rng, const pgp_rsa_key_t *key, bool secret)
#ifdef CRYPTO_BACKEND_OPENSSL3
EVP_PKEY_CTX *ctx = rsa_init_context(key, secret);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init context: %s", ossl_latest_err());
return RNP_ERROR_GENERIC;
+ /* LCOV_EXCL_END */
}
int res = secret ? EVP_PKEY_pairwise_check(ctx) : EVP_PKEY_public_check(ctx);
if (res <= 0) {
- RNP_LOG("Key validation error: %s", ossl_latest_err());
+ RNP_LOG("Key validation error: %s", ossl_latest_err()); // LCOV_EXCL_LINE
}
EVP_PKEY_CTX_free(ctx);
return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC;
@@ -284,34 +292,33 @@ rsa_validate_key(rnp::RNG *rng, const pgp_rsa_key_t *key, bool secret)
if (secret) {
EVP_PKEY_CTX *ctx = rsa_init_context(key, secret);
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to init context: %s", ossl_latest_err());
return RNP_ERROR_GENERIC;
+ /* LCOV_EXCL_END */
}
int res = EVP_PKEY_check(ctx);
if (res <= 0) {
- RNP_LOG("Key validation error: %s", ossl_latest_err());
+ RNP_LOG("Key validation error: %s", ossl_latest_err()); // LCOV_EXCL_LINE
}
EVP_PKEY_CTX_free(ctx);
return res > 0 ? RNP_SUCCESS : RNP_ERROR_GENERIC;
}
/* OpenSSL 1.1.1 doesn't have RSA public key check function, so let's do some checks */
- rnp_result_t ret = RNP_ERROR_GENERIC;
- bignum_t * n = mpi2bn(&key->n);
- bignum_t * e = mpi2bn(&key->e);
- if (!n || !e) {
+ rnp::bn n(key->n);
+ rnp::bn e(key->e);
+ if (!n.get() || !e.get()) {
+ /* LCOV_EXCL_START */
RNP_LOG("out of memory");
- ret = RNP_ERROR_OUT_OF_MEMORY;
- goto done;
+ return RNP_ERROR_OUT_OF_MEMORY;
+ /* LCOV_EXCL_END */
}
- if ((BN_num_bits(n) < 512) || !BN_is_odd(n) || (BN_num_bits(e) < 2) || !BN_is_odd(e)) {
- goto done;
+ if ((BN_num_bits(n.get()) < 512) || !BN_is_odd(n.get()) || (BN_num_bits(e.get()) < 2) ||
+ !BN_is_odd(e.get())) {
+ return RNP_ERROR_GENERIC;
}
- ret = RNP_SUCCESS;
-done:
- bn_free(n);
- bn_free(e);
- return ret;
+ return RNP_SUCCESS;
#endif
}
@@ -528,6 +535,97 @@ done:
return ret;
}
+static bool
+rsa_calculate_pqu(const bignum_t *p, const bignum_t *q, const bignum_t *u, pgp_rsa_key_t &key)
+{
+ /* OpenSSL doesn't care whether p < q */
+ if (BN_cmp(p, q) > 0) {
+ /* In this case we have u, as iqmp is inverse of q mod p, and we exchange them */
+ bn2mpi(q, &key.p);
+ bn2mpi(p, &key.q);
+ bn2mpi(u, &key.u);
+ return true;
+ }
+
+ BN_CTX *bnctx = BN_CTX_new();
+ if (!bnctx) {
+ return false;
+ }
+
+ /* we need to calculate u, since we need inverse of p mod q, while OpenSSL has inverse of q
+ * mod p, and doesn't care of p < q */
+ BN_CTX_start(bnctx);
+ bignum_t *nu = BN_CTX_get(bnctx);
+ bignum_t *nq = BN_CTX_get(bnctx);
+ if (!nu || !nq) {
+ BN_CTX_free(bnctx);
+ return false;
+ }
+ BN_with_flags(nq, q, BN_FLG_CONSTTIME);
+ /* calculate inverse of p mod q */
+ if (!BN_mod_inverse(nu, p, nq, bnctx)) {
+ /* LCOV_EXCL_START */
+ RNP_LOG("Failed to calculate u");
+ BN_CTX_free(bnctx);
+ return false;
+ /* LCOV_EXCL_END */
+ }
+ bn2mpi(p, &key.p);
+ bn2mpi(q, &key.q);
+ bn2mpi(nu, &key.u);
+ BN_CTX_free(bnctx);
+ return true;
+}
+
+static bool
+rsa_extract_key(EVP_PKEY *pkey, pgp_rsa_key_t &key)
+{
+#if defined(CRYPTO_BACKEND_OPENSSL3)
+ rnp::bn n;
+ rnp::bn e;
+ rnp::bn d;
+ rnp::bn p;
+ rnp::bn q;
+ rnp::bn u;
+
+ bool res = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, n.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, e.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, d.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q.ptr()) &&
+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, u.ptr()) &&
+ rsa_calculate_pqu(p.get(), q.get(), u.get(), key);
+ return res && n.mpi(key.n) && e.mpi(key.e) && d.mpi(key.d);
+#else
+ const RSA *rsa = EVP_PKEY_get0_RSA(pkey);
+ if (!rsa) {
+ RNP_LOG("Failed to retrieve RSA key: %lu", ERR_peek_last_error());
+ return false;
+ }
+ if (RSA_check_key(rsa) != 1) {
+ RNP_LOG("Key validation error: %lu", ERR_peek_last_error());
+ return false;
+ }
+
+ const bignum_t *n = RSA_get0_n(rsa);
+ const bignum_t *e = RSA_get0_e(rsa);
+ const bignum_t *d = RSA_get0_d(rsa);
+ const bignum_t *p = RSA_get0_p(rsa);
+ const bignum_t *q = RSA_get0_q(rsa);
+ const bignum_t *u = RSA_get0_iqmp(rsa);
+ if (!n || !e || !d || !p || !q || !u) {
+ return false;
+ }
+ if (!rsa_calculate_pqu(p, q, u, key)) {
+ return false;
+ }
+ bn2mpi(n, &key.n);
+ bn2mpi(e, &key.e);
+ bn2mpi(d, &key.d);
+ return true;
+#endif
+}
+
rnp_result_t
rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits)
{
@@ -535,12 +633,9 @@ rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits)
return RNP_ERROR_BAD_PARAMETERS;
}
- rnp_result_t ret = RNP_ERROR_GENERIC;
- const RSA * rsa = NULL;
- EVP_PKEY * pkey = NULL;
- EVP_PKEY_CTX * ctx = NULL;
- const bignum_t *u = NULL;
- BN_CTX * bnctx = NULL;
+ rnp_result_t ret = RNP_ERROR_GENERIC;
+ EVP_PKEY * pkey = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
if (!ctx) {
@@ -559,71 +654,11 @@ rsa_generate(rnp::RNG *rng, pgp_rsa_key_t *key, size_t numbits)
RNP_LOG("RSA keygen failed: %lu", ERR_peek_last_error());
goto done;
}
- rsa = EVP_PKEY_get0_RSA(pkey);
- if (!rsa) {
- RNP_LOG("Failed to retrieve RSA key: %lu", ERR_peek_last_error());
- goto done;
- }
- if (RSA_check_key(rsa) != 1) {
- RNP_LOG("Key validation error: %lu", ERR_peek_last_error());
- goto done;
- }
-
- const bignum_t *n;
- const bignum_t *e;
- const bignum_t *p;
- const bignum_t *q;
- const bignum_t *d;
- n = RSA_get0_n(rsa);
- e = RSA_get0_e(rsa);
- d = RSA_get0_d(rsa);
- p = RSA_get0_p(rsa);
- q = RSA_get0_q(rsa);
- if (!n || !e || !d || !p || !q) {
- ret = RNP_ERROR_OUT_OF_MEMORY;
- goto done;
+ if (rsa_extract_key(pkey, *key)) {
+ ret = RNP_SUCCESS;
}
- /* OpenSSL doesn't care whether p < q */
- if (BN_cmp(p, q) > 0) {
- /* In this case we have u, as iqmp is inverse of q mod p, and we exchange them */
- const bignum_t *tmp = p;
- p = q;
- q = tmp;
- u = RSA_get0_iqmp(rsa);
- } else {
- /* we need to calculate u, since we need inverse of p mod q, while OpenSSL has inverse
- * of q mod p, and doesn't care of p < q */
- bnctx = BN_CTX_new();
- if (!bnctx) {
- ret = RNP_ERROR_OUT_OF_MEMORY;
- goto done;
- }
- BN_CTX_start(bnctx);
- bignum_t *nu = BN_CTX_get(bnctx);
- bignum_t *nq = BN_CTX_get(bnctx);
- if (!nu || !nq) {
- ret = RNP_ERROR_OUT_OF_MEMORY;
- goto done;
- }
- BN_with_flags(nq, q, BN_FLG_CONSTTIME);
- /* calculate inverse of p mod q */
- if (!BN_mod_inverse(nu, p, nq, bnctx)) {
- RNP_LOG("Failed to calculate u");
- ret = RNP_ERROR_BAD_STATE;
- goto done;
- }
- u = nu;
- }
- bn2mpi(n, &key->n);
- bn2mpi(e, &key->e);
- bn2mpi(p, &key->p);
- bn2mpi(q, &key->q);
- bn2mpi(d, &key->d);
- bn2mpi(u, &key->u);
- ret = RNP_SUCCESS;
done:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
- BN_CTX_free(bnctx);
return ret;
}
diff --git a/src/lib/crypto/symmetric.cpp b/src/lib/crypto/symmetric.cpp
index aeed784..0f7b259 100644
--- a/src/lib/crypto/symmetric.cpp
+++ b/src/lib/crypto/symmetric.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2017-2023, [Ribose Inc](https://www.ribose.com).
* Copyright (c) 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
@@ -57,6 +57,7 @@
#include <stdlib.h>
#include <assert.h>
#include <botan/ffi.h>
+#include <botan/build.h>
#include "utils.h"
static const char *
@@ -224,7 +225,7 @@ pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
uint64_t buf64[512]; // 4KB - page size
uint64_t iv64[2];
size_t blocks, blockb;
- unsigned blsize = crypt->blocksize;
+ size_t blsize = crypt->blocksize;
/* encrypting till the block boundary */
while (bytes && crypt->cfb.remaining) {
@@ -306,7 +307,7 @@ pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
uint64_t outbuf64[512];
uint64_t iv64[2];
size_t blocks, blockb;
- unsigned blsize = crypt->blocksize;
+ size_t blsize = crypt->blocksize;
/* decrypting till the block boundary */
while (bytes && crypt->cfb.remaining) {
@@ -613,7 +614,10 @@ pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
void
pgp_cipher_aead_destroy(pgp_crypt_t *crypt)
{
- botan_cipher_destroy(crypt->aead.obj);
+ if (crypt->aead.obj) {
+ botan_cipher_destroy(crypt->aead.obj);
+ }
+ memset(crypt, 0x0, sizeof(*crypt));
}
size_t
diff --git a/src/lib/crypto/symmetric_ossl.cpp b/src/lib/crypto/symmetric_ossl.cpp
index 98e90ed..ff19362 100644
--- a/src/lib/crypto/symmetric_ossl.cpp
+++ b/src/lib/crypto/symmetric_ossl.cpp
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2021 Ribose Inc.
+ * Copyright (c) 2021-2023 Ribose Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,8 +94,10 @@ pgp_cipher_cfb_start(pgp_crypt_t * crypt,
const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_name);
if (!cipher) {
+ /* LCOV_EXCL_START */
RNP_LOG("Cipher %s is not supported by OpenSSL.", cipher_name);
return false;
+ /* LCOV_EXCL_END */
}
crypt->alg = alg;
@@ -104,9 +106,11 @@ pgp_cipher_cfb_start(pgp_crypt_t * crypt,
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int res = EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv);
if (res != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to initialize cipher.");
EVP_CIPHER_CTX_free(ctx);
return false;
+ /* LCOV_EXCL_END */
}
crypt->cfb.obj = ctx;
@@ -131,7 +135,7 @@ int
pgp_cipher_cfb_finish(pgp_crypt_t *crypt)
{
if (!crypt) {
- return 0;
+ return 0; // LCOV_EXCL_LINE
}
if (crypt->cfb.obj) {
EVP_CIPHER_CTX_free(crypt->cfb.obj);
@@ -149,7 +153,7 @@ pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
uint64_t buf64[512]; // 4KB - page size
uint64_t iv64[2];
size_t blocks, blockb;
- unsigned blsize = crypt->blocksize;
+ size_t blsize = crypt->blocksize;
/* encrypting till the block boundary */
while (bytes && crypt->cfb.remaining) {
@@ -182,7 +186,7 @@ pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
EVP_EncryptUpdate(
crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 16);
if (outlen != 16) {
- RNP_LOG("Bad outlen: must be 16");
+ RNP_LOG("Bad outlen: must be 16"); // LCOV_EXCL_LINE
}
*in64 ^= iv64[0];
iv64[0] = *in64++;
@@ -196,7 +200,7 @@ pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
EVP_EncryptUpdate(
crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 8);
if (outlen != 8) {
- RNP_LOG("Bad outlen: must be 8");
+ RNP_LOG("Bad outlen: must be 8"); // LCOV_EXCL_LINE
}
*in64 ^= iv64[0];
iv64[0] = *in64++;
@@ -218,7 +222,7 @@ pgp_cipher_cfb_encrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
int outlen = blsize;
EVP_EncryptUpdate(crypt->cfb.obj, crypt->cfb.iv, &outlen, crypt->cfb.iv, (int) blsize);
if (outlen != (int) blsize) {
- RNP_LOG("Bad outlen: must be %u", blsize);
+ RNP_LOG("Bad outlen: must be %zu", blsize); // LCOV_EXCL_LINE
}
crypt->cfb.remaining = blsize;
@@ -243,7 +247,7 @@ pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
uint64_t outbuf64[512];
uint64_t iv64[2];
size_t blocks, blockb;
- unsigned blsize = crypt->blocksize;
+ size_t blsize = crypt->blocksize;
/* decrypting till the block boundary */
while (bytes && crypt->cfb.remaining) {
@@ -279,7 +283,7 @@ pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
EVP_EncryptUpdate(
crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 16);
if (outlen != 16) {
- RNP_LOG("Bad outlen: must be 16");
+ RNP_LOG("Bad outlen: must be 16"); // LCOV_EXCL_LINE
}
*out64++ = *in64 ^ iv64[0];
iv64[0] = *in64++;
@@ -293,7 +297,7 @@ pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
EVP_EncryptUpdate(
crypt->cfb.obj, (uint8_t *) iv64, &outlen, (uint8_t *) iv64, 8);
if (outlen != 8) {
- RNP_LOG("Bad outlen: must be 8");
+ RNP_LOG("Bad outlen: must be 8"); // LCOV_EXCL_LINE
}
*out64++ = *in64 ^ iv64[0];
iv64[0] = *in64++;
@@ -315,7 +319,7 @@ pgp_cipher_cfb_decrypt(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
int outlen = blsize;
EVP_EncryptUpdate(crypt->cfb.obj, crypt->cfb.iv, &outlen, crypt->cfb.iv, (int) blsize);
if (outlen != (int) blsize) {
- RNP_LOG("Bad outlen: must be %u", blsize);
+ RNP_LOG("Bad outlen: must be %zu", blsize); // LCOV_EXCL_LINE
}
crypt->cfb.remaining = blsize;
@@ -435,14 +439,18 @@ pgp_cipher_aead_init(pgp_crypt_t * crypt,
}
auto cipher = EVP_get_cipherbyname(algname);
if (!cipher) {
+ /* LCOV_EXCL_START */
RNP_LOG("Cipher %s is not supported.", algname);
return false;
+ /* LCOV_EXCL_END */
}
/* Create and setup context */
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to create cipher context: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
crypt->aead.key = new rnp::secure_vector<uint8_t>(key, key + pgp_key_size(ealg));
@@ -510,21 +518,29 @@ pgp_cipher_aead_start(pgp_crypt_t *crypt, const uint8_t *nonce, size_t len)
assert(len == aead.n_len);
EVP_CIPHER_CTX_reset(ctx);
if (EVP_CipherInit_ex(ctx, aead.cipher, NULL, NULL, NULL, enc) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to initialize cipher: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, aead.n_len, NULL) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set nonce length: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
if (EVP_CipherInit_ex(ctx, NULL, NULL, aead.key->data(), nonce, enc) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to start cipher: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
int adlen = 0;
if (EVP_CipherUpdate(ctx, NULL, &adlen, aead.ad, aead.ad_len) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set AD: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
return true;
}
@@ -538,7 +554,7 @@ pgp_cipher_aead_update(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
int out_len = 0;
bool res = EVP_CipherUpdate(crypt->aead.obj, out, &out_len, in, len) == 1;
if (!res) {
- RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error());
+ RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error()); // LCOV_EXCL_LINE
}
assert(out_len == (int) len);
return res;
@@ -558,26 +574,34 @@ pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
if (aead.decrypt) {
assert(len >= aead.taglen);
if (len < aead.taglen) {
+ /* LCOV_EXCL_START */
RNP_LOG("Invalid state: too few input bytes.");
return false;
+ /* LCOV_EXCL_END */
}
size_t data_len = len - aead.taglen;
int out_len = 0;
if (EVP_CipherUpdate(ctx, out, &out_len, in, data_len) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
uint8_t tag[PGP_AEAD_MAX_TAG_LEN] = {0};
memcpy(tag, in + data_len, aead.taglen);
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, aead.taglen, tag) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to set tag: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
int out_len2 = 0;
if (EVP_CipherFinal_ex(ctx, out + out_len, &out_len2) != 1) {
/* Zero value if auth tag is incorrect */
if (ERR_peek_last_error()) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to finish AEAD decryption: %lu", ERR_peek_last_error());
+ /* LCOV_EXCL_END */
}
return false;
}
@@ -585,18 +609,24 @@ pgp_cipher_aead_finish(pgp_crypt_t *crypt, uint8_t *out, const uint8_t *in, size
} else {
int out_len = 0;
if (EVP_CipherUpdate(ctx, out, &out_len, in, len) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to update cipher: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
int out_len2 = 0;
if (EVP_CipherFinal_ex(ctx, out + out_len, &out_len2) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to finish AEAD encryption: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
assert(out_len + out_len2 == (int) len);
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, aead.taglen, out + len) != 1) {
+ /* LCOV_EXCL_START */
RNP_LOG("Failed to get tag: %lu", ERR_peek_last_error());
return false;
+ /* LCOV_EXCL_END */
}
}
return true;
diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp
index 24c46f9..9e92aaf 100644
--- a/src/lib/rnp.cpp
+++ b/src/lib/rnp.cpp
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2017-2021, Ribose Inc.
+ * Copyright (c) 2017-2023, Ribose Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -6197,6 +6197,20 @@ try {
FFI_GUARD
rnp_result_t
+rnp_signature_get_features(rnp_signature_handle_t handle, uint32_t *features)
+try {
+ if (!handle || !features) {
+ return RNP_ERROR_NULL_POINTER;
+ }
+ if (!handle->sig) {
+ return RNP_ERROR_BAD_PARAMETERS;
+ }
+ *features = handle->sig->sig.key_get_features();
+ return RNP_SUCCESS;
+}
+FFI_GUARD
+
+rnp_result_t
rnp_signature_get_keyid(rnp_signature_handle_t handle, char **result)
try {
if (!handle || !result) {
@@ -7750,7 +7764,10 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags)
}
json_object_object_add(jso, "key wrap cipher", jsocipher);
}
+
+#if (!defined(_MSVC_LANG) || _MSVC_LANG >= 201703L)
[[fallthrough]];
+#endif
case PGP_PKA_ECDSA:
case PGP_PKA_EDDSA:
case PGP_PKA_SM2: {
@@ -8313,7 +8330,9 @@ try {
}
pgp_armored_msg_t msgtype = PGP_ARMORED_UNKNOWN;
- if (is_armored_source(&input->src)) {
+ if (is_cleartext_source(&input->src)) {
+ msgtype = PGP_ARMORED_CLEARTEXT;
+ } else if (is_armored_source(&input->src)) {
msgtype = rnp_armored_get_type(&input->src);
} else {
msgtype = rnp_armor_guess_type(&input->src);