--- a/third_party/README.rnp
+++ b/third_party/README.rnp
@@ -1,12 +1,12 @@
Directory ./rnp contains a copy of rnp which has been obtained from:
https://github.com/rnpgp/rnp
-[commit 49a675e374e6e298e432cffa171d2cd9378b6706]
+[commit a2c5ecd3a84a33450f5d8cda09cf5549410b5e70]
For licensing information, please refer to the included documentation.
To update this copy, run "update_rnp.sh" in this directory from this directory
within a complete build tree (including mozilla-central) as "mach python" is
used.
update_rnp.sh will generate rnp/src/lib/version.h from rnp/src/lib/version.h.in
--- a/third_party/rnp/include/rekey/rnp_key_store.h
+++ b/third_party/rnp/include/rekey/rnp_key_store.h
@@ -127,17 +127,16 @@ typedef enum pgp_sig_import_status_t {
typedef std::unordered_map<pgp_fingerprint_t, std::list<pgp_key_t>::iterator> pgp_key_fp_map_t;
typedef struct rnp_key_store_t {
std::string path;
pgp_key_store_format_t format;
bool disable_validation =
false; /* do not automatically validate keys, added to this key store */
- bool skip_parsing_errors = false; /* do not fail on parsing errors */
std::list<pgp_key_t> keys;
pgp_key_fp_map_t keybyfp;
list blobs = NULL; // list of kbx_blob_t
~rnp_key_store_t();
rnp_key_store_t() : path(""), format(PGP_KEY_STORE_UNKNOWN){};
--- a/third_party/rnp/include/repgp/repgp_def.h
+++ b/third_party/rnp/include/repgp/repgp_def.h
@@ -413,16 +413,22 @@ typedef enum {
PGP_KF_AUTH = 0x20, /* This key may be used for authentication. */
PGP_KF_SHARED = 0x80, /* The private component of this key may be in the
possession of more than one person. */
/* pseudo flags */
PGP_KF_NONE = 0x00,
PGP_KF_ENCRYPT = PGP_KF_ENCRYPT_COMMS | PGP_KF_ENCRYPT_STORAGE,
} pgp_key_flags_t;
+typedef enum {
+ PGP_KEY_FEATURE_MDC = 0x01,
+ PGP_KEY_FEATURE_AEAD = 0x02,
+ PGP_KEY_FEATURE_V5 = 0x04
+} pgp_key_feature_t;
+
/** Types of Compression */
typedef enum {
PGP_C_NONE = 0,
PGP_C_ZIP = 1,
PGP_C_ZLIB = 2,
PGP_C_BZIP2 = 3,
PGP_C_UNKNOWN = 255
} pgp_compression_type_t;
--- a/third_party/rnp/include/rnp/rnp.h
+++ b/third_party/rnp/include/rnp/rnp.h
@@ -72,16 +72,17 @@ typedef uint32_t rnp_result_t;
#define RNP_DUMP_GRIP (1U << 2)
/**
* Flags for the key loading/saving functions.
*/
#define RNP_LOAD_SAVE_PUBLIC_KEYS (1U << 0)
#define RNP_LOAD_SAVE_SECRET_KEYS (1U << 1)
#define RNP_LOAD_SAVE_PERMISSIVE (1U << 8)
+#define RNP_LOAD_SAVE_SINGLE (1U << 9)
/**
* Flags for output structure creation.
*/
#define RNP_OUTPUT_FILE_OVERWRITE (1U << 0)
#define RNP_OUTPUT_FILE_RANDOM (1U << 1)
/**
@@ -423,20 +424,27 @@ RNP_API rnp_result_t rnp_unload_keys(rnp
/** import keys to the keyring and receive JSON list of the new/updated keys.
* Note: this will work only with keys in OpenPGP format, use rnp_load_keys for other formats.
* @param ffi
* @param input source to read from. Cannot be NULL.
* @param flags see RNP_LOAD_SAVE_* constants. If RNP_LOAD_SAVE_PERMISSIVE is specified
* then import process will skip unrecognized or bad keys/signatures instead of
* failing the whole operation.
+ * If flag RNP_LOAD_SAVE_SINGLE is set, then only first key will be loaded (subkey
+ * or primary key with it's subkeys). In case RNP_LOAD_SAVE_PERMISSIVE and
+ * erroneous first key on the stream RNP_SUCCESS will be returned, but results
+ * will include an empty array. Also RNP_ERROR_EOF will be returned if the last
+ * key was read.
* @param results if not NULL then after the successfull execution will contain JSON with
* information about new and updated keys. You must free it using the
* rnp_buffer_destroy() function.
- * @return RNP_SUCCESS on success, or any other value on error.
+ * @return RNP_SUCCESS on success
+ * RNP_ERROR_EOF if last key was read (if RNP_LOAD_SAVE_SINGLE was used)
+ * any other value on error.
*/
RNP_API rnp_result_t rnp_import_keys(rnp_ffi_t ffi,
rnp_input_t input,
uint32_t flags,
char ** results);
/** import standalone signatures to the keyring and receive JSON list of the updated keys.
*
@@ -1361,16 +1369,18 @@ RNP_API rnp_result_t rnp_key_is_locked(r
* - "Encrypted" : secret key data is encrypted, using just CRC as integrity
* protection.
* - "Encrypted-Hashed" : secret key data is encrypted, using the SHA1 hash as
* an integrity protection.
* - "GPG-None" : secret key data is not available at all (this would happen if
* secret key is exported from GnuPG via --export-secret-subkeys)
* - "GPG-Smartcard" : secret key data is stored on smartcard by GnuPG, so is not
* available
+ * - "Unknown" : key protection type is unknown, so secret key data is not
+ * available
* @return RNP_SUCCESS on success, or any other value on error
*/
RNP_API rnp_result_t rnp_key_get_protection_type(rnp_key_handle_t key, char **type);
/**
* @brief Get mode in which secret key data is encrypted.
*
* @param key key handle, cannot be NULL and should have secret part (see function
--- a/third_party/rnp/src/common/file-utils.cpp
+++ b/third_party/rnp/src/common/file-utils.cpp
@@ -23,24 +23,31 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** File utilities
* @file
*/
#include "file-utils.h"
-
-extern "C" {
+#include "config.h"
#ifdef _MSC_VER
+#include <stdlib.h>
+#include <stdio.h>
#include "uniwin.h"
+#include <errno.h>
+#include <locale>
+#include <codecvt>
+#include <random>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
#else
#include <sys/stat.h>
-#endif
-}
+#endif // _MSC_VER
bool
rnp_file_exists(const char *path)
{
struct stat st;
return stat(path, &st) == 0 && S_ISREG(st.st_mode);
}
@@ -51,8 +58,67 @@ rnp_filemtime(const char *path)
struct stat st;
if (stat(path, &st) != 0) {
return 0;
} else {
return st.st_mtime;
}
}
+
+#ifdef _MSC_VER
+static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/** @private
+ * generate a temporary file name based on TMPL.
+ *
+ * @param tmpl filename template in UTF-8 ending in XXXXXX
+ * @return file descriptor of newly created and opened file, or -1 on error
+ **/
+int
+rnp_mkstemp(char *tmpl)
+{
+ int save_errno = errno;
+ const int mask_length = 6;
+ int len = strlen(tmpl);
+ if (len < mask_length || strcmp(&tmpl[len - mask_length], "XXXXXX")) {
+ errno = EINVAL;
+ return -1;
+ }
+ std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8conv;
+ std::wstring tmpl_w = utf8conv.from_bytes(tmpl, tmpl + len - mask_length);
+
+ /* This is where the Xs start. */
+ char *XXXXXX = &tmpl[len - mask_length];
+
+ std::random_device rd;
+ std::mt19937_64 rng(rd());
+
+ for (unsigned int countdown = TMP_MAX; --countdown;) {
+ unsigned long long v = rng();
+
+ XXXXXX[0] = letters[v % 36];
+ v /= 36;
+ XXXXXX[1] = letters[v % 36];
+ v /= 36;
+ XXXXXX[2] = letters[v % 36];
+ v /= 36;
+ XXXXXX[3] = letters[v % 36];
+ v /= 36;
+ XXXXXX[4] = letters[v % 36];
+ v /= 36;
+ XXXXXX[5] = letters[v % 36];
+
+ int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
+ int fd =
+ _wopen((tmpl_w + utf8conv.from_bytes(XXXXXX)).c_str(), flags, _S_IREAD | _S_IWRITE);
+ if (fd != -1) {
+ errno = save_errno;
+ return fd;
+ } else if (errno != EEXIST)
+ return -1;
+ }
+
+ // We got out of the loop because we ran out of combinations to try.
+ errno = EEXIST;
+ return -1;
+}
+#endif // _MSC_VER
--- a/third_party/rnp/src/common/file-utils.h
+++ b/third_party/rnp/src/common/file-utils.h
@@ -27,9 +27,20 @@
#ifndef RNP_FILE_UTILS_H_
#define RNP_FILE_UTILS_H_
#include <stdint.h>
bool rnp_file_exists(const char *path);
int64_t rnp_filemtime(const char *path);
+/** @private
+ * generate a temporary file name based on TMPL. TMPL must match the
+ * rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ * does not exist at the time of the call to mkstemp. TMPL is
+ * overwritten with the result.get the list item at specified index
+ *
+ * @param tmpl filename template
+ * @return file descriptor of newly created and opened file, or -1 on error
+ **/
+int rnp_mkstemp(char *tmpl);
+
#endif
--- a/third_party/rnp/src/fuzzing/CMakeLists.txt
+++ b/third_party/rnp/src/fuzzing/CMakeLists.txt
@@ -55,16 +55,42 @@ target_include_directories(fuzz_keyring
"${PROJECT_SOURCE_DIR}/src/lib"
)
target_link_libraries(fuzz_keyring
PRIVATE
librnp
)
+add_executable(fuzz_keyimport keyimport.c)
+
+target_include_directories(fuzz_keyimport
+ PRIVATE
+ "${PROJECT_SOURCE_DIR}/src"
+ "${PROJECT_SOURCE_DIR}/src/lib"
+)
+
+target_link_libraries(fuzz_keyimport
+ PRIVATE
+ librnp
+)
+
+add_executable(fuzz_sigimport sigimport.c)
+
+target_include_directories(fuzz_sigimport
+ PRIVATE
+ "${PROJECT_SOURCE_DIR}/src"
+ "${PROJECT_SOURCE_DIR}/src/lib"
+)
+
+target_link_libraries(fuzz_sigimport
+ PRIVATE
+ librnp
+)
+
add_executable(fuzz_verify verify.c)
target_include_directories(fuzz_verify
PRIVATE
"${PROJECT_SOURCE_DIR}/src"
"${PROJECT_SOURCE_DIR}/src/lib"
)
@@ -108,12 +134,12 @@ target_include_directories(fuzz_keyring_
)
target_link_libraries(fuzz_keyring_g10
PRIVATE
librnp-static
)
if (ENABLE_SANITIZERS)
- foreach(tgt fuzz_dump fuzz_keyring fuzz_verify fuzz_verify_detached fuzz_keyring_kbx fuzz_keyring_g10)
+ foreach(tgt fuzz_dump fuzz_keyring fuzz_keyimport fuzz_sigimport fuzz_verify fuzz_verify_detached fuzz_keyring_kbx fuzz_keyring_g10)
set_target_properties(${tgt} PROPERTIES LINKER_LANGUAGE CXX)
endforeach()
endif()
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/fuzzing/keyimport.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rnp/rnp.h>
+#include <rnp/rnp_err.h>
+
+#ifdef RNP_RUN_TESTS
+int keyimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+int
+keyimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+#else
+int
+LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+#endif
+{
+ rnp_input_t input = NULL;
+ rnp_result_t ret = 0;
+ rnp_ffi_t ffi = NULL;
+
+ /* try non-permissive import */
+ ret = rnp_input_from_memory(&input, data, size, false);
+ ret = rnp_ffi_create(&ffi, "GPG", "GPG");
+ char *results = NULL;
+ ret = rnp_import_keys(
+ ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS, &results);
+ rnp_buffer_destroy(results);
+ rnp_input_destroy(input);
+ rnp_ffi_destroy(ffi);
+
+ /* try permissive import */
+ ret = rnp_input_from_memory(&input, data, size, false);
+ ret = rnp_ffi_create(&ffi, "GPG", "GPG");
+ results = NULL;
+ ret = rnp_import_keys(ffi,
+ input,
+ RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS |
+ RNP_LOAD_SAVE_PERMISSIVE,
+ &results);
+ rnp_buffer_destroy(results);
+ rnp_input_destroy(input);
+ rnp_ffi_destroy(ffi);
+
+ /* try non-permissive iterative import */
+ ret = rnp_input_from_memory(&input, data, size, false);
+ ret = rnp_ffi_create(&ffi, "GPG", "GPG");
+ do {
+ results = NULL;
+ ret = rnp_import_keys(ffi,
+ input,
+ RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS |
+ RNP_LOAD_SAVE_SINGLE,
+ &results);
+ rnp_buffer_destroy(results);
+ } while (!ret);
+ rnp_input_destroy(input);
+ rnp_ffi_destroy(ffi);
+
+ /* try permissive iterative import */
+ ret = rnp_input_from_memory(&input, data, size, false);
+ ret = rnp_ffi_create(&ffi, "GPG", "GPG");
+ do {
+ results = NULL;
+ ret = rnp_import_keys(ffi,
+ input,
+ RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS |
+ RNP_LOAD_SAVE_PERMISSIVE | RNP_LOAD_SAVE_SINGLE,
+ &results);
+ rnp_buffer_destroy(results);
+ } while (!ret);
+ rnp_input_destroy(input);
+ rnp_ffi_destroy(ffi);
+
+ return 0;
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/fuzzing/sigimport.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020, [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rnp/rnp.h>
+
+#ifdef RNP_RUN_TESTS
+int sigimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+int
+sigimport_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+#else
+int
+LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+#endif
+{
+ rnp_input_t input = NULL;
+ rnp_result_t ret = 0;
+ rnp_ffi_t ffi = NULL;
+
+ ret = rnp_input_from_memory(&input, data, size, false);
+ ret = rnp_ffi_create(&ffi, "GPG", "GPG");
+ char *results = NULL;
+ ret = rnp_import_signatures(ffi, input, 0, &results);
+ rnp_buffer_destroy(results);
+ rnp_input_destroy(input);
+ rnp_ffi_destroy(ffi);
+
+ return 0;
+}
--- a/third_party/rnp/src/lib/CMakeLists.txt
+++ b/third_party/rnp/src/lib/CMakeLists.txt
@@ -42,20 +42,20 @@ check_include_file_cxx(limits.h HAVE_LIM
check_include_file_cxx(stdint.h HAVE_STDINT_H)
check_include_file_cxx(string.h HAVE_STRING_H)
check_include_file_cxx(sys/cdefs.h HAVE_SYS_CDEFS_H)
check_include_file_cxx(sys/cdefs.h HAVE_SYS_MMAN_H)
check_include_file_cxx(sys/resource.h HAVE_SYS_RESOURCE_H)
check_include_file_cxx(sys/stat.h HAVE_SYS_STAT_H)
check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
check_include_file_cxx(sys/param.h HAVE_SYS_PARAM_H)
-check_include_file_cxx(sys/time.h HAVE_SYS_TIME_H)
check_include_file_cxx(unistd.h HAVE_UNISTD_H)
check_include_file_cxx(sys/wait.h HAVE_SYS_WAIT_H)
check_cxx_symbol_exists(mkdtemp "stdlib.h;unistd.h" HAVE_MKDTEMP)
+check_cxx_symbol_exists(mkstemp "stdlib.h;unistd.h" HAVE_MKSTEMP)
check_cxx_symbol_exists(realpath stdlib.h HAVE_REALPATH)
check_cxx_symbol_exists(O_BINARY fcntl.h HAVE_O_BINARY)
check_cxx_symbol_exists(_O_BINARY fcntl.h HAVE__O_BINARY)
check_cxx_symbol_exists(_tempnam stdio.h HAVE__TEMPNAM)
set(HAVE_ZLIB_H "${ZLIB_FOUND}")
set(HAVE_BZLIB_H "${BZIP2_FOUND}")
configure_file(config.h.in config.h)
# generate a version.h
--- a/third_party/rnp/src/lib/config.h.in
+++ b/third_party/rnp/src/lib/config.h.in
@@ -19,17 +19,17 @@
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#define PACKAGE_STRING "rnp 0.13.1+git20200913.49a675e3.MZLA"
+#define PACKAGE_STRING "rnp 0.13.1+git20201030.a2c5ecd3.MZLA"
#define PACKAGE_BUGREPORT "https://bugzilla.mozilla.org/enter_bug.cgi?product=Thunderbird"
#undef HAVE_BZLIB_H
#undef HAVE_ZLIB_H
#undef HAVE_FCNTL_H
#undef HAVE_INTTYPES_H
#undef HAVE_LIMITS_H
@@ -37,19 +37,19 @@
#undef HAVE_STRING_H
#undef HAVE_SYS_CDEFS_H
#undef HAVE_SYS_MMAN_H
#undef HAVE_SYS_RESOURCE_H
#undef HAVE_SYS_STAT_H
#undef HAVE_SYS_TYPES_H
#undef HAVE_UNISTD_H
#undef HAVE_SYS_WAIT_H
-#undef HAVE_SYS_TIME_H
#undef HAVE_SYS_PARAM_H
#undef HAVE_MKDTEMP
+#undef HAVE_MKSTEMP
#undef HAVE_REALPATH
#undef HAVE_O_BINARY
#undef HAVE__O_BINARY
#undef HAVE__TEMPNAM
/* Macro _GLIBCXX_USE_CXX11_ABI was first introduced with GCC 5.0, which
* we assume to be bundled with a sane implementation of std::regex. */
#if !defined(__GNUC__) || defined(_GLIBCXX_USE_CXX11_ABI) || defined(MSVC)
--- a/third_party/rnp/src/lib/crypto.cpp
+++ b/third_party/rnp/src/lib/crypto.cpp
@@ -193,16 +193,20 @@ key_material_equal(const pgp_key_materia
RNP_LOG("unknown public key algorithm: %d", (int) key1->alg);
return false;
}
}
rnp_result_t
validate_pgp_key_material(const pgp_key_material_t *material, rng_t *rng)
{
+#ifdef FUZZERS_ENABLED
+ /* do not timeout on large keys during fuzzing */
+ return RNP_SUCCESS;
+#else
switch (material->alg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
case PGP_PKA_RSA_SIGN_ONLY:
return rsa_validate_key(rng, &material->rsa, material->secret);
case PGP_PKA_DSA:
return dsa_validate_key(rng, &material->dsa, material->secret);
case PGP_PKA_EDDSA:
@@ -216,16 +220,17 @@ validate_pgp_key_material(const pgp_key_
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
return elgamal_validate_key(rng, &material->eg, material->secret);
default:
RNP_LOG("unknown public key algorithm: %d", (int) material->alg);
}
return RNP_ERROR_BAD_PARAMETERS;
+#endif
}
size_t
key_bitlength(const pgp_key_material_t *key)
{
switch (key->alg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
--- a/third_party/rnp/src/lib/crypto/s2k.cpp
+++ b/third_party/rnp/src/lib/crypto/s2k.cpp
@@ -26,17 +26,17 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <botan/ffi.h>
#include <stdio.h>
#include "config.h"
-#ifdef HAVE_SYS_TIME_H
+#ifndef _MSC_VER
#include <sys/time.h>
#else
#include "uniwin.h"
#endif
#include "crypto/s2k.h"
#include "defaults.h"
#include "rnp.h"
@@ -148,17 +148,17 @@ pgp_s2k_encode_iterations(size_t iterati
}
return 255;
}
/// Should this function be elsewhere?
static uint64_t
get_timestamp_usec()
{
-#ifdef HAVE_SYS_TIME_H
+#ifndef _MSC_VER
// TODO: Consider clock_gettime
struct timeval tv;
::gettimeofday(&tv, NULL);
return (static_cast<uint64_t>(tv.tv_sec) * 1000000) + static_cast<uint64_t>(tv.tv_usec);
#else
return GetTickCount64() * 1000;
#endif
}
--- a/third_party/rnp/src/lib/ffi-priv-types.h
+++ b/third_party/rnp/src/lib/ffi-priv-types.h
@@ -23,16 +23,17 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <rnp/rnp.h>
#include <json.h>
#include "utils.h"
+#include <list>
struct rnp_key_handle_st {
rnp_ffi_t ffi;
pgp_key_search_t locator;
pgp_key_t * pub;
pgp_key_t * sec;
};
@@ -92,88 +93,94 @@ struct rnp_output_st {
char * dst_directory;
rnp_output_writer_t *writer;
rnp_output_closer_t *closer;
void * app_ctx;
bool keep;
};
struct rnp_op_generate_st {
- rnp_ffi_t ffi;
- bool primary;
- pgp_key_t *primary_sec;
- pgp_key_t *primary_pub;
- pgp_key_t *gen_sec;
- pgp_key_t *gen_pub;
+ rnp_ffi_t ffi{};
+ bool primary{};
+ pgp_key_t *primary_sec{};
+ pgp_key_t *primary_pub{};
+ pgp_key_t *gen_sec{};
+ pgp_key_t *gen_pub{};
/* password used to encrypt the key, if specified */
- char *password;
+ char *password{};
/* request password for key encryption via ffi's password provider */
- bool request_password;
+ bool request_password{};
/* we don't use top-level keygen action here for easier fields access */
- rnp_keygen_crypto_params_t crypto;
- rnp_key_protection_params_t protection;
- rnp_selfsig_cert_info_t cert;
- rnp_selfsig_binding_info_t binding;
-};
+ rnp_keygen_crypto_params_t crypto{};
+ rnp_key_protection_params_t protection{};
+ rnp_selfsig_cert_info_t cert{};
+ rnp_selfsig_binding_info_t binding{};
-struct rnp_op_sign_st {
- rnp_ffi_t ffi;
- rnp_input_t input;
- rnp_output_t output;
- rnp_ctx_t rnpctx;
- list signatures;
+ ~rnp_op_generate_st();
};
struct rnp_op_sign_signature_st {
- rnp_ffi_t ffi;
- rnp_signer_info_t signer;
+ rnp_ffi_t ffi{};
+ rnp_signer_info_t signer{};
bool expiry_set : 1;
bool create_set : 1;
bool hash_set : 1;
};
+typedef std::list<rnp_op_sign_signature_st> rnp_op_sign_signatures_t;
+
+struct rnp_op_sign_st {
+ rnp_ffi_t ffi{};
+ rnp_input_t input{};
+ rnp_output_t output{};
+ rnp_ctx_t rnpctx{};
+ rnp_op_sign_signatures_t signatures{};
+};
+
struct rnp_op_verify_signature_st {
rnp_ffi_t ffi;
rnp_result_t verify_status;
pgp_signature_t sig_pkt;
};
struct rnp_op_verify_st {
- rnp_ffi_t ffi;
- rnp_input_t input;
- rnp_input_t detached_input; /* for detached signature will be source file/data */
- rnp_output_t output;
- rnp_ctx_t rnpctx;
+ rnp_ffi_t ffi{};
+ rnp_input_t input{};
+ rnp_input_t detached_input{}; /* for detached signature will be source file/data */
+ rnp_output_t output{};
+ rnp_ctx_t rnpctx{};
/* these fields are filled after operation execution */
- rnp_op_verify_signature_t signatures;
- size_t signature_count;
- char * filename;
- uint32_t file_mtime;
+ rnp_op_verify_signature_t signatures{};
+ size_t signature_count{};
+ char * filename{};
+ uint32_t file_mtime{};
/* encryption information */
- bool encrypted;
- bool mdc;
- bool validated;
- pgp_aead_alg_t aead;
- pgp_symm_alg_t salg;
+ bool encrypted{};
+ bool mdc{};
+ bool validated{};
+ pgp_aead_alg_t aead{};
+ pgp_symm_alg_t salg{};
/* recipient/symenc information */
- rnp_recipient_handle_t recipients;
- size_t recipient_count;
- rnp_recipient_handle_t used_recipient;
- rnp_symenc_handle_t symencs;
- size_t symenc_count;
- rnp_symenc_handle_t used_symenc;
- size_t encrypted_layers;
+ rnp_recipient_handle_t recipients{};
+ size_t recipient_count{};
+ rnp_recipient_handle_t used_recipient{};
+ rnp_symenc_handle_t symencs{};
+ size_t symenc_count{};
+ rnp_symenc_handle_t used_symenc{};
+ size_t encrypted_layers{};
+
+ ~rnp_op_verify_st();
};
struct rnp_op_encrypt_st {
- rnp_ffi_t ffi;
- rnp_input_t input;
- rnp_output_t output;
- rnp_ctx_t rnpctx;
- list signatures;
+ rnp_ffi_t ffi{};
+ rnp_input_t input{};
+ rnp_output_t output{};
+ rnp_ctx_t rnpctx{};
+ rnp_op_sign_signatures_t signatures{};
};
struct rnp_identifier_iterator_st {
rnp_ffi_t ffi;
pgp_key_search_type_t type;
rnp_key_store_t * store;
std::list<pgp_key_t>::iterator *keyp;
unsigned uididx;
--- a/third_party/rnp/src/lib/generate-key.cpp
+++ b/third_party/rnp/src/lib/generate-key.cpp
@@ -153,79 +153,79 @@ pk_alg_default_flags(pgp_pubkey_alg_t al
{
// just use the full capabilities as the ultimate fallback
return pgp_pk_alg_capabilities(alg);
}
// TODO: Similar as pgp_pick_hash_alg but different enough to
// keep another version. This will be changed when refactoring crypto
static void
-adjust_hash_alg(rnp_keygen_crypto_params_t *crypto)
+adjust_hash_alg(rnp_keygen_crypto_params_t &crypto)
{
- if (!crypto->hash_alg) {
- crypto->hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0];
+ if (!crypto.hash_alg) {
+ crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0];
}
- if ((crypto->key_alg != PGP_PKA_DSA) && (crypto->key_alg != PGP_PKA_ECDSA)) {
+ if ((crypto.key_alg != PGP_PKA_DSA) && (crypto.key_alg != PGP_PKA_ECDSA)) {
return;
}
- pgp_hash_alg_t min_hash = (crypto->key_alg == PGP_PKA_ECDSA) ?
- ecdsa_get_min_hash(crypto->ecc.curve) :
- dsa_get_min_hash(crypto->dsa.q_bitlen);
+ pgp_hash_alg_t min_hash = (crypto.key_alg == PGP_PKA_ECDSA) ?
+ ecdsa_get_min_hash(crypto.ecc.curve) :
+ dsa_get_min_hash(crypto.dsa.q_bitlen);
- if (pgp_digest_length(crypto->hash_alg) < pgp_digest_length(min_hash)) {
- crypto->hash_alg = min_hash;
+ if (pgp_digest_length(crypto.hash_alg) < pgp_digest_length(min_hash)) {
+ crypto.hash_alg = min_hash;
}
}
static void
-keygen_merge_crypto_defaults(rnp_keygen_crypto_params_t *crypto)
+keygen_merge_crypto_defaults(rnp_keygen_crypto_params_t &crypto)
{
// default to RSA
- if (!crypto->key_alg) {
- crypto->key_alg = PGP_PKA_RSA;
+ if (!crypto.key_alg) {
+ crypto.key_alg = PGP_PKA_RSA;
}
- switch (crypto->key_alg) {
+ switch (crypto.key_alg) {
case PGP_PKA_RSA:
- if (!crypto->rsa.modulus_bit_len) {
- crypto->rsa.modulus_bit_len = DEFAULT_RSA_NUMBITS;
+ if (!crypto.rsa.modulus_bit_len) {
+ crypto.rsa.modulus_bit_len = DEFAULT_RSA_NUMBITS;
}
break;
case PGP_PKA_SM2:
- if (!crypto->hash_alg) {
- crypto->hash_alg = PGP_HASH_SM3;
+ if (!crypto.hash_alg) {
+ crypto.hash_alg = PGP_HASH_SM3;
}
- if (!crypto->ecc.curve) {
- crypto->ecc.curve = PGP_CURVE_SM2_P_256;
+ if (!crypto.ecc.curve) {
+ crypto.ecc.curve = PGP_CURVE_SM2_P_256;
}
break;
case PGP_PKA_ECDH:
case PGP_PKA_ECDSA: {
- if (!crypto->hash_alg) {
- crypto->hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0];
+ if (!crypto.hash_alg) {
+ crypto.hash_alg = (pgp_hash_alg_t) DEFAULT_HASH_ALGS[0];
}
break;
}
case PGP_PKA_EDDSA:
- if (!crypto->ecc.curve) {
- crypto->ecc.curve = PGP_CURVE_ED25519;
+ if (!crypto.ecc.curve) {
+ crypto.ecc.curve = PGP_CURVE_ED25519;
}
break;
case PGP_PKA_DSA: {
- if (!crypto->dsa.p_bitlen) {
- crypto->dsa.p_bitlen = DSA_DEFAULT_P_BITLEN;
+ if (!crypto.dsa.p_bitlen) {
+ crypto.dsa.p_bitlen = DSA_DEFAULT_P_BITLEN;
}
- if (!crypto->dsa.q_bitlen) {
- crypto->dsa.q_bitlen = dsa_choose_qsize_by_psize(crypto->dsa.p_bitlen);
+ if (!crypto.dsa.q_bitlen) {
+ crypto.dsa.q_bitlen = dsa_choose_qsize_by_psize(crypto.dsa.p_bitlen);
}
break;
}
default:
break;
}
adjust_hash_alg(crypto);
@@ -285,58 +285,56 @@ get_numbits(const rnp_keygen_crypto_para
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
return crypto->elgamal.key_bitlen;
default:
return 0;
}
}
-static bool
-set_default_user_prefs(pgp_user_prefs_t *prefs)
+static void
+set_default_user_prefs(pgp_user_prefs_t &prefs)
{
- if (!prefs->symm_algs &&
- !pgp_user_prefs_set_symm_algs(
- prefs, &DEFAULT_SYMMETRIC_ALGS[0], ARRAY_SIZE(DEFAULT_SYMMETRIC_ALGS))) {
- return false;
+ if (prefs.symm_algs.empty()) {
+ prefs.set_symm_algs(
+ std::vector<uint8_t>(DEFAULT_SYMMETRIC_ALGS,
+ DEFAULT_SYMMETRIC_ALGS + ARRAY_SIZE(DEFAULT_SYMMETRIC_ALGS)));
}
- if (!prefs->hash_algs && !pgp_user_prefs_set_hash_algs(
- prefs, &DEFAULT_HASH_ALGS[0], ARRAY_SIZE(DEFAULT_HASH_ALGS))) {
- return false;
+ if (prefs.hash_algs.empty()) {
+ prefs.set_hash_algs(std::vector<uint8_t>(
+ DEFAULT_HASH_ALGS, DEFAULT_HASH_ALGS + ARRAY_SIZE(DEFAULT_HASH_ALGS)));
}
- if (!prefs->z_algs && !pgp_user_prefs_set_z_algs(prefs,
- &DEFAULT_COMPRESS_ALGS[0],
- ARRAY_SIZE(DEFAULT_COMPRESS_ALGS))) {
- return false;
+ if (prefs.z_algs.empty()) {
+ prefs.set_z_algs(std::vector<uint8_t>(
+ DEFAULT_COMPRESS_ALGS, DEFAULT_COMPRESS_ALGS + ARRAY_SIZE(DEFAULT_COMPRESS_ALGS)));
}
- return true;
}
static const char *
pgp_show_pka(pgp_pubkey_alg_t pka)
{
return pgp_str_from_map(pka, pubkey_alg_map);
}
static void
-keygen_primary_merge_defaults(rnp_keygen_primary_desc_t *desc)
+keygen_primary_merge_defaults(rnp_keygen_primary_desc_t &desc)
{
- keygen_merge_crypto_defaults(&desc->crypto);
- set_default_user_prefs(&desc->cert.prefs);
+ keygen_merge_crypto_defaults(desc.crypto);
+ set_default_user_prefs(desc.cert.prefs);
- if (!desc->cert.key_flags) {
+ if (!desc.cert.key_flags) {
// set some default key flags if none are provided
- desc->cert.key_flags = pk_alg_default_flags(desc->crypto.key_alg);
+ desc.cert.key_flags = pk_alg_default_flags(desc.crypto.key_alg);
}
- if (desc->cert.userid[0] == '\0') {
- snprintf((char *) desc->cert.userid,
- sizeof(desc->cert.userid),
+ if (desc.cert.userid[0] == '\0') {
+ snprintf((char *) desc.cert.userid,
+ sizeof(desc.cert.userid),
"%s %d-bit key <%s@localhost>",
- pgp_show_pka(desc->crypto.key_alg),
- get_numbits(&desc->crypto),
+ pgp_show_pka(desc.crypto.key_alg),
+ get_numbits(&desc.crypto),
getenv_logname());
}
}
static void
pgp_key_mark_valid(pgp_key_t *key)
{
key->valid = true;
@@ -350,96 +348,94 @@ pgp_key_mark_valid(pgp_key_t *key)
bool
pgp_generate_primary_key(rnp_keygen_primary_desc_t *desc,
bool merge_defaults,
pgp_key_t * primary_sec,
pgp_key_t * primary_pub,
pgp_key_store_format_t secformat)
{
- bool ok = false;
- pgp_transferable_key_t tkeysec;
- pgp_transferable_key_t tkeypub;
- pgp_transferable_userid_t *uid = NULL;
-
// validate args
if (!desc || !primary_pub || !primary_sec) {
- goto end;
+ return false;
}
if (pgp_key_get_type(primary_sec) || pgp_key_get_type(primary_pub)) {
RNP_LOG("invalid parameters (should be zeroed)");
- goto end;
+ return false;
}
// merge some defaults in, if requested
if (merge_defaults) {
- keygen_primary_merge_defaults(desc);
+ try {
+ keygen_primary_merge_defaults(*desc);
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
+ return false;
+ }
}
// now validate the keygen fields
if (!validate_keygen_primary(desc)) {
- goto end;
+ return false;
}
// generate the raw key and fill tag/secret fields
+ pgp_transferable_key_t tkeysec;
if (!pgp_generate_seckey(&desc->crypto, &tkeysec.key, true)) {
- goto end;
+ return false;
}
- uid = transferable_key_add_userid(tkeysec, (char *) desc->cert.userid);
+ pgp_transferable_userid_t *uid =
+ transferable_key_add_userid(tkeysec, (char *) desc->cert.userid);
if (!uid) {
RNP_LOG("failed to add userid");
- goto end;
+ return false;
}
if (!transferable_userid_certify(
tkeysec.key, *uid, tkeysec.key, desc->crypto.hash_alg, desc->cert)) {
RNP_LOG("failed to certify key");
- goto end;
+ return false;
}
+ pgp_transferable_key_t tkeypub;
try {
tkeypub = pgp_transferable_key_t(tkeysec, true);
} catch (const std::exception &e) {
RNP_LOG("failed to copy public key part: %s", e.what());
- goto end;
+ return false;
}
if (!rnp_key_from_transferable_key(primary_pub, &tkeypub)) {
- goto end;
+ return false;
}
switch (secformat) {
case PGP_KEY_STORE_GPG:
case PGP_KEY_STORE_KBX:
if (!rnp_key_from_transferable_key(primary_sec, &tkeysec)) {
- goto end;
+ return false;
}
break;
case PGP_KEY_STORE_G10:
if (!load_generated_g10_key(primary_sec, &tkeysec.key, NULL, primary_pub)) {
RNP_LOG("failed to load generated key");
- goto end;
+ return false;
}
break;
default:
RNP_LOG("invalid format");
- goto end;
- break;
+ return false;
}
/* mark it as valid */
pgp_key_mark_valid(primary_pub);
pgp_key_mark_valid(primary_sec);
/* refresh key's data */
- ok = pgp_key_refresh_data(primary_pub) && pgp_key_refresh_data(primary_sec);
-end:
- // free any user preferences
- pgp_free_user_prefs(&desc->cert.prefs);
- return ok;
+ return pgp_key_refresh_data(primary_pub) && pgp_key_refresh_data(primary_sec);
}
static bool
validate_keygen_subkey(rnp_keygen_subkey_desc_t *desc)
{
if (!desc->binding.key_flags) {
RNP_LOG("key flags are required");
return false;
@@ -447,22 +443,22 @@ validate_keygen_subkey(rnp_keygen_subkey
// check the flags against the alg capabilities
RNP_LOG("usage not permitted for pk algorithm");
return false;
}
return true;
}
static void
-keygen_subkey_merge_defaults(rnp_keygen_subkey_desc_t *desc)
+keygen_subkey_merge_defaults(rnp_keygen_subkey_desc_t &desc)
{
- keygen_merge_crypto_defaults(&desc->crypto);
- if (!desc->binding.key_flags) {
+ keygen_merge_crypto_defaults(desc.crypto);
+ if (!desc.binding.key_flags) {
// set some default key flags if none are provided
- desc->binding.key_flags = pk_alg_default_flags(desc->crypto.key_alg);
+ desc.binding.key_flags = pk_alg_default_flags(desc.crypto.key_alg);
}
}
bool
pgp_generate_subkey(rnp_keygen_subkey_desc_t * desc,
bool merge_defaults,
pgp_key_t * primary_sec,
pgp_key_t * primary_pub,
@@ -490,17 +486,17 @@ pgp_generate_subkey(rnp_keygen_subkey_de
}
if (pgp_key_get_type(subkey_sec) || pgp_key_get_type(subkey_pub)) {
RNP_LOG("invalid parameters (should be zeroed)");
goto end;
}
// merge some defaults in, if requested
if (merge_defaults) {
- keygen_subkey_merge_defaults(desc);
+ keygen_subkey_merge_defaults(*desc);
}
// now validate the keygen fields
if (!validate_keygen_subkey(desc)) {
goto end;
}
ctx = {.op = PGP_OP_ADD_SUBKEY, .key = primary_sec};
--- a/third_party/rnp/src/lib/pgp-key.cpp
+++ b/third_party/rnp/src/lib/pgp-key.cpp
@@ -68,115 +68,16 @@
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <algorithm>
#include <stdexcept>
#include "defaults.h"
static bool
-pgp_user_prefs_set_arr(uint8_t **arr, size_t *arrlen, const uint8_t *val, size_t len)
-{
- uint8_t *newarr = (uint8_t *) malloc(len);
-
- if (len && !newarr) {
- return false;
- }
-
- free(*arr);
- memcpy(newarr, val, len);
- *arrlen = len;
- *arr = newarr;
- return true;
-}
-
-static bool
-pgp_user_prefs_add_val(uint8_t **arr, size_t *arrlen, uint8_t val)
-{
- /* do not add duplicate values */
- for (size_t i = 0; i < *arrlen; i++) {
- if ((*arr)[i] == val) {
- return true;
- }
- }
-
- uint8_t *newarr = (uint8_t *) realloc(*arr, *arrlen + 1);
-
- if (!newarr) {
- return false;
- }
-
- newarr[(*arrlen)++] = val;
- *arr = newarr;
- return true;
-}
-
-bool
-pgp_user_prefs_set_symm_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len)
-{
- return pgp_user_prefs_set_arr(&prefs->symm_algs, &prefs->symm_alg_count, algs, len);
-}
-
-bool
-pgp_user_prefs_set_hash_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len)
-{
- return pgp_user_prefs_set_arr(&prefs->hash_algs, &prefs->hash_alg_count, algs, len);
-}
-
-bool
-pgp_user_prefs_set_z_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len)
-{
- return pgp_user_prefs_set_arr(&prefs->z_algs, &prefs->z_alg_count, algs, len);
-}
-
-bool
-pgp_user_prefs_set_ks_prefs(pgp_user_prefs_t *prefs, const uint8_t *vals, size_t len)
-{
- return pgp_user_prefs_set_arr(&prefs->ks_prefs, &prefs->ks_pref_count, vals, len);
-}
-
-bool
-pgp_user_prefs_add_symm_alg(pgp_user_prefs_t *prefs, pgp_symm_alg_t alg)
-{
- return pgp_user_prefs_add_val(&prefs->symm_algs, &prefs->symm_alg_count, alg);
-}
-
-bool
-pgp_user_prefs_add_hash_alg(pgp_user_prefs_t *prefs, pgp_hash_alg_t alg)
-{
- return pgp_user_prefs_add_val(&prefs->hash_algs, &prefs->hash_alg_count, alg);
-}
-
-bool
-pgp_user_prefs_add_z_alg(pgp_user_prefs_t *prefs, pgp_compression_type_t alg)
-{
- return pgp_user_prefs_add_val(&prefs->z_algs, &prefs->z_alg_count, alg);
-}
-
-bool
-pgp_user_prefs_add_ks_pref(pgp_user_prefs_t *prefs, pgp_key_server_prefs_t val)
-{
- return pgp_user_prefs_add_val(&prefs->ks_prefs, &prefs->ks_pref_count, val);
-}
-
-void
-pgp_free_user_prefs(pgp_user_prefs_t *prefs)
-{
- if (!prefs) {
- return;
- }
- free(prefs->symm_algs);
- free(prefs->hash_algs);
- free(prefs->z_algs);
- free(prefs->ks_prefs);
- free(prefs->key_server);
- memset(prefs, 0, sizeof(*prefs));
-}
-
-static bool
pgp_key_init_with_pkt(pgp_key_t *key, const pgp_key_pkt_t *pkt)
{
assert(!key->pkt.version);
assert(is_key_pkt(pkt->tag));
assert(pkt->material.alg);
if (pgp_keyid(key->keyid, pkt) || pgp_fingerprint(key->fingerprint, pkt) ||
!rnp_key_store_get_key_grip(&pkt->material, key->grip)) {
return false;
@@ -221,56 +122,16 @@ pgp_key_from_pkt(pgp_key_t *key, const p
static void
pgp_key_clear_revokes(pgp_key_t *key)
{
key->revoked = false;
key->revokes.clear();
key->revocation = {};
}
-static rnp_result_t
-pgp_userprefs_copy(pgp_user_prefs_t *dst, const pgp_user_prefs_t *src)
-{
- rnp_result_t ret = RNP_ERROR_OUT_OF_MEMORY;
-
- memset(dst, 0, sizeof(*dst));
- if (src->symm_alg_count &&
- !pgp_user_prefs_set_symm_algs(dst, src->symm_algs, src->symm_alg_count)) {
- return ret;
- }
-
- if (src->hash_alg_count &&
- !pgp_user_prefs_set_hash_algs(dst, src->hash_algs, src->hash_alg_count)) {
- goto error;
- }
-
- if (src->z_alg_count && !pgp_user_prefs_set_z_algs(dst, src->z_algs, src->z_alg_count)) {
- goto error;
- }
-
- if (src->ks_pref_count &&
- !pgp_user_prefs_set_ks_prefs(dst, src->ks_prefs, src->ks_pref_count)) {
- goto error;
- }
-
- if (src->key_server) {
- size_t len = strlen((char *) src->key_server) + 1;
- dst->key_server = (uint8_t *) malloc(len);
- if (!dst->key_server) {
- goto error;
- }
- memcpy(dst->key_server, src->key_server, len);
- }
-
- return RNP_SUCCESS;
-error:
- pgp_free_user_prefs(dst);
- return ret;
-}
-
/**
\ingroup HighLevel_KeyGeneral
\brief Returns the public key in the given key.
\param key
\return Pointer to public key
@@ -649,66 +510,50 @@ pgp_key_get_subsig(const pgp_key_t *key,
pgp_subsig_t *
pgp_key_get_subsig(pgp_key_t *key, size_t idx)
{
return (idx < key->subsigs.size()) ? &key->subsigs[idx] : NULL;
}
bool
-pgp_subsig_from_signature(pgp_subsig_t *dst, const pgp_signature_t *sig)
+pgp_subsig_from_signature(pgp_subsig_t &dst, const pgp_signature_t &sig)
{
pgp_subsig_t subsig = {};
- subsig.sig = *sig;
- if (signature_has_trust(&subsig.sig)) {
- signature_get_trust(&subsig.sig, &subsig.trustlevel, &subsig.trustamount);
- }
- uint8_t *algs = NULL;
- size_t count = 0;
- if (signature_get_preferred_symm_algs(&subsig.sig, &algs, &count) &&
- !pgp_user_prefs_set_symm_algs(&subsig.prefs, algs, count)) {
- RNP_LOG("failed to alloc symm algs");
- return false;
- }
- if (signature_get_preferred_hash_algs(&subsig.sig, &algs, &count) &&
- !pgp_user_prefs_set_hash_algs(&subsig.prefs, algs, count)) {
- RNP_LOG("failed to alloc hash algs");
- return false;
+ subsig.sig = sig;
+ if (subsig.sig.has_subpkt(PGP_SIG_SUBPKT_TRUST)) {
+ subsig.trustlevel = subsig.sig.trust_level();
+ subsig.trustamount = subsig.sig.trust_amount();
}
- if (signature_get_preferred_z_algs(&subsig.sig, &algs, &count) &&
- !pgp_user_prefs_set_z_algs(&subsig.prefs, algs, count)) {
- RNP_LOG("failed to alloc z algs");
+ try {
+ subsig.prefs.set_symm_algs(subsig.sig.preferred_symm_algs());
+ subsig.prefs.set_hash_algs(subsig.sig.preferred_hash_algs());
+ subsig.prefs.set_z_algs(subsig.sig.preferred_z_algs());
+
+ if (subsig.sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) {
+ subsig.key_flags = subsig.sig.key_flags();
+ }
+ if (subsig.sig.has_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS)) {
+ subsig.prefs.set_ks_prefs({subsig.sig.key_server_prefs()});
+ }
+ if (subsig.sig.has_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV)) {
+ subsig.prefs.key_server = subsig.sig.key_server();
+ }
+ } catch (const std::exception &e) {
+ RNP_LOG("Failed to copy preferences: %s", e.what());
return false;
}
- if (signature_has_key_flags(&subsig.sig)) {
- subsig.key_flags = signature_get_key_flags(&subsig.sig);
- }
- if (signature_has_key_server_prefs(&subsig.sig)) {
- uint8_t ks_pref = signature_get_key_server_prefs(&subsig.sig);
- if (!pgp_user_prefs_set_ks_prefs(&subsig.prefs, &ks_pref, 1)) {
- RNP_LOG("failed to alloc ks prefs");
- return false;
- }
- }
- if (signature_has_key_server(&subsig.sig)) {
- subsig.prefs.key_server = (uint8_t *) signature_get_key_server(&subsig.sig);
- if (!subsig.prefs.key_server) {
- RNP_LOG("failed to alloc ks");
- return false;
- }
- }
/* add signature rawpacket */
try {
- subsig.rawpkt = pgp_rawpacket_t(*sig);
+ subsig.rawpkt = pgp_rawpacket_t(sig);
} catch (const std::exception &e) {
RNP_LOG("failed to build sig rawpacket: %s", e.what());
return false;
}
-
- *dst = std::move(subsig);
+ dst = std::move(subsig);
return true;
}
bool
pgp_key_has_signature(const pgp_key_t *key, const pgp_signature_t *sig)
{
for (size_t i = 0; i < pgp_key_get_subsig_count(key); i++) {
const pgp_subsig_t *subsig = pgp_key_get_subsig(key, i);
@@ -742,17 +587,17 @@ pgp_key_replace_signature(pgp_key_t *key
newraw = *newsig;
} catch (const std::exception &e) {
RNP_LOG("failed to create rawpacket: %s", e.what());
return NULL;
}
/* fill new subsig */
pgp_subsig_t newsubsig = {};
- if (!pgp_subsig_from_signature(&newsubsig, newsig)) {
+ if (!pgp_subsig_from_signature(newsubsig, *newsig)) {
RNP_LOG("failed to fill subsig");
return NULL;
}
newsubsig.uid = subsig->uid;
/* replace rawpacket */
try {
newsubsig.rawpkt = pgp_rawpacket_t(*newsig);
} catch (const std::exception &e) {
@@ -762,83 +607,76 @@ pgp_key_replace_signature(pgp_key_t *key
*subsig = std::move(newsubsig);
return subsig;
}
static bool
pgp_sig_is_certification(const pgp_subsig_t *sig)
{
- pgp_sig_type_t type = signature_get_type(&sig->sig);
+ pgp_sig_type_t type = sig->sig.type();
return (type == PGP_CERT_CASUAL) || (type == PGP_CERT_GENERIC) ||
(type == PGP_CERT_PERSONA) || (type == PGP_CERT_POSITIVE);
}
static bool
pgp_sig_self_signed(const pgp_key_t *key, const pgp_subsig_t *sig)
{
/* if we have fingerprint let's check it */
- if (signature_has_keyfp(&sig->sig)) {
- pgp_fingerprint_t sigfp = {};
- if (signature_get_keyfp(&sig->sig, sigfp)) {
- return pgp_key_get_fp(key) == sigfp;
- }
+ if (sig->sig.has_keyfp()) {
+ return sig->sig.keyfp() == pgp_key_get_fp(key);
}
- if (!signature_has_keyid(&sig->sig)) {
+ if (!sig->sig.has_keyid()) {
return false;
}
- pgp_key_id_t sigid = {};
- if (!signature_get_keyid(&sig->sig, sigid)) {
- return false;
- }
- return pgp_key_get_keyid(key) == sigid;
+ return pgp_key_get_keyid(key) == sig->sig.keyid();
}
static bool
pgp_sig_is_self_signature(const pgp_key_t *key, const pgp_subsig_t *sig)
{
if (!pgp_key_is_primary_key(key) || !pgp_sig_is_certification(sig)) {
return false;
}
return pgp_sig_self_signed(key, sig);
}
static bool
pgp_sig_is_direct_self_signature(const pgp_key_t *key, const pgp_subsig_t *sig)
{
- if (!pgp_key_is_primary_key(key) || (signature_get_type(&sig->sig) != PGP_SIG_DIRECT)) {
+ if (!pgp_key_is_primary_key(key) || (sig->sig.type() != PGP_SIG_DIRECT)) {
return false;
}
return pgp_sig_self_signed(key, sig);
}
static bool
pgp_sig_is_key_revocation(const pgp_key_t *key, const pgp_subsig_t *sig)
{
- return pgp_key_is_primary_key(key) && (signature_get_type(&sig->sig) == PGP_SIG_REV_KEY);
+ return pgp_key_is_primary_key(key) && (sig->sig.type() == PGP_SIG_REV_KEY);
}
static bool
pgp_sig_is_userid_revocation(const pgp_key_t *key, const pgp_subsig_t *sig)
{
- return pgp_key_is_primary_key(key) && (signature_get_type(&sig->sig) == PGP_SIG_REV_CERT);
+ return pgp_key_is_primary_key(key) && (sig->sig.type() == PGP_SIG_REV_CERT);
}
static bool
pgp_sig_is_subkey_binding(const pgp_key_t *key, const pgp_subsig_t *sig)
{
- return pgp_key_is_subkey(key) && (signature_get_type(&sig->sig) == PGP_SIG_SUBKEY);
+ return pgp_key_is_subkey(key) && (sig->sig.type() == PGP_SIG_SUBKEY);
}
static bool
pgp_sig_is_subkey_revocation(const pgp_key_t *key, const pgp_subsig_t *sig)
{
- return pgp_key_is_subkey(key) && (signature_get_type(&sig->sig) == PGP_SIG_REV_SUBKEY);
+ return pgp_key_is_subkey(key) && (sig->sig.type() == PGP_SIG_REV_SUBKEY);
}
pgp_subsig_t *
pgp_key_latest_selfsig(pgp_key_t *key, pgp_sig_subpacket_type_t subpkt)
{
uint32_t latest = 0;
pgp_subsig_t *res = NULL;
@@ -847,21 +685,21 @@ pgp_key_latest_selfsig(pgp_key_t *key, p
if (!sig->valid) {
continue;
}
if (!pgp_sig_is_self_signature(key, sig) &&
!pgp_sig_is_direct_self_signature(key, sig)) {
continue;
}
- if (subpkt && !signature_get_subpkt(&sig->sig, subpkt)) {
+ if (subpkt && !sig->sig.get_subpkt(subpkt)) {
continue;
}
- uint32_t creation = signature_get_creation(&sig->sig);
+ uint32_t creation = sig->sig.creation();
if (creation >= latest) {
latest = creation;
res = sig;
}
}
return res;
}
@@ -875,17 +713,17 @@ pgp_key_latest_uid_selfcert(pgp_key_t *k
pgp_subsig_t *sig = pgp_key_get_subsig(key, i);
if (!sig->valid || (sig->uid != uid)) {
continue;
}
if (!pgp_sig_is_self_signature(key, sig)) {
continue;
}
- uint32_t creation = signature_get_creation(&sig->sig);
+ uint32_t creation = sig->sig.creation();
if (creation >= latest) {
latest = creation;
res = sig;
}
}
return res;
}
@@ -899,17 +737,17 @@ pgp_key_latest_binding(pgp_key_t *subkey
pgp_subsig_t *sig = pgp_key_get_subsig(subkey, i);
if (validated && !sig->valid) {
continue;
}
if (!pgp_sig_is_subkey_binding(subkey, sig)) {
continue;
}
- uint32_t creation = signature_get_creation(&sig->sig);
+ uint32_t creation = sig->sig.creation();
if (creation >= latest) {
latest = creation;
res = sig;
}
}
return res;
}
@@ -934,17 +772,17 @@ pgp_key_validate_signature(pgp_key_t *
pgp_signature_info_t sinfo = {};
sinfo.sig = &sig->sig;
sinfo.signer = signer;
sinfo.signer_valid = true;
if (pgp_sig_is_self_signature(key, sig) || pgp_sig_is_subkey_binding(key, sig)) {
sinfo.ignore_expiry = true;
}
- pgp_sig_type_t stype = signature_get_type(&sig->sig);
+ pgp_sig_type_t stype = sig->sig.type();
switch (stype) {
case PGP_SIG_BINARY:
case PGP_SIG_TEXT:
case PGP_SIG_STANDALONE:
case PGP_SIG_PRIMARY:
RNP_LOG("Invalid key signature type: %d", (int) stype);
return;
case PGP_CERT_GENERIC:
@@ -1031,48 +869,46 @@ bool
pgp_subkey_refresh_data(pgp_key_t *sub, pgp_key_t *key)
{
/* validate self-signatures if not done yet */
if (key) {
pgp_subkey_validate_self_signatures(sub, key);
}
pgp_subsig_t *sig = pgp_key_latest_binding(sub, key);
/* subkey expiration */
- sub->expiration = sig ? signature_get_key_expiration(&sig->sig) : 0;
+ sub->expiration = sig ? sig->sig.key_expiration() : 0;
/* subkey flags */
- if (sig && signature_has_key_flags(&sig->sig)) {
+ if (sig && sig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) {
sub->key_flags = sig->key_flags;
} else {
sub->key_flags = pgp_pk_alg_capabilities(pgp_key_get_alg(sub));
}
/* revocation */
pgp_key_clear_revokes(sub);
for (size_t i = 0; i < pgp_key_get_subsig_count(sub); i++) {
sig = pgp_key_get_subsig(sub, i);
if (!sig->valid || !pgp_sig_is_subkey_revocation(sub, sig)) {
continue;
}
sub->revoked = true;
- char *reason = NULL;
- if (!signature_has_revocation_reason(&sig->sig)) {
- RNP_LOG("Warning: no revocation reason in subkey revocation");
- sub->revocation.code = PGP_REVOCATION_NO_REASON;
- } else if (!signature_get_revocation_reason(
- &sig->sig, &sub->revocation.code, &reason)) {
- return false;
- }
+ try {
+ if (!sig->sig.has_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON)) {
+ RNP_LOG("Warning: no revocation reason in subkey revocation");
+ sub->revocation.code = PGP_REVOCATION_NO_REASON;
+ } else {
+ sub->revocation.code = sig->sig.revocation_code();
+ sub->revocation.reason = sig->sig.revocation_reason();
+ }
- try {
- sub->revocation.reason = (reason && strlen(reason)) ?
- reason :
- pgp_str_from_map(sub->revocation.code, ss_rr_code_map);
- free(reason);
+ if (sub->revocation.reason.empty()) {
+ sub->revocation.reason =
+ pgp_str_from_map(sub->revocation.code, ss_rr_code_map);
+ }
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
- free(reason);
return false;
}
break;
}
return true;
}
bool
@@ -1081,31 +917,31 @@ pgp_key_refresh_data(pgp_key_t *key)
if (!pgp_key_is_primary_key(key)) {
RNP_LOG("key must be primary");
return false;
}
/* validate self-signatures if not done yet */
pgp_key_validate_self_signatures(key);
/* key expiration */
pgp_subsig_t *sig = pgp_key_latest_selfsig(key, PGP_SIG_SUBPKT_UNKNOWN);
- key->expiration = sig ? signature_get_key_expiration(&sig->sig) : 0;
+ key->expiration = sig ? sig->sig.key_expiration() : 0;
/* key flags */
- if (sig && signature_has_key_flags(&sig->sig)) {
+ if (sig && sig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS)) {
key->key_flags = sig->key_flags;
} else {
key->key_flags = pgp_pk_alg_capabilities(pgp_key_get_alg(key));
}
/* primary userid */
key->uid0_set = false;
for (size_t i = 0; i < pgp_key_get_subsig_count(key); i++) {
sig = pgp_key_get_subsig(key, i);
if (!sig->valid || !pgp_sig_is_self_signature(key, sig)) {
continue;
}
- if (signature_get_primary_uid(&sig->sig)) {
+ if (sig->sig.primary_uid()) {
key->uid0 = sig->uid;
key->uid0_set = true;
break;
}
}
/* revocation(s) */
pgp_key_clear_revokes(key);
for (size_t i = 0; i < pgp_key_get_subsig_count(key); i++) {
@@ -1128,32 +964,29 @@ pgp_key_refresh_data(pgp_key_t *key)
}
revocation->uid = sig->uid;
}
if (!revocation) {
continue;
}
- char *reason = NULL;
- if (!signature_has_revocation_reason(&sig->sig)) {
- RNP_LOG("Warning: no revocation reason in key/userid revocation");
- revocation->code = PGP_REVOCATION_NO_REASON;
- } else if (!signature_get_revocation_reason(&sig->sig, &revocation->code, &reason)) {
- return false;
- }
-
try {
- revocation->reason = (reason && strlen(reason)) ?
- reason :
- pgp_str_from_map(revocation->code, ss_rr_code_map);
- free(reason);
+ if (!sig->sig.has_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON)) {
+ RNP_LOG("Warning: no revocation reason in key/userid revocation");
+ revocation->code = PGP_REVOCATION_NO_REASON;
+ } else {
+ revocation->code = sig->sig.revocation_code();
+ revocation->reason = sig->sig.revocation_reason();
+ }
+ if (revocation->reason.empty()) {
+ revocation->reason = pgp_str_from_map(revocation->code, ss_rr_code_map);
+ }
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
- free(reason);
return false;
}
}
return true;
}
size_t
@@ -1602,28 +1435,27 @@ pgp_key_add_userid_certified(pgp_key_t *
return rnp_key_add_transferable_userid(key, &uid) && pgp_key_refresh_data(key);
}
static bool
update_sig_expiration(pgp_signature_t *dst, const pgp_signature_t *src, uint32_t expiry)
{
try {
*dst = *src;
+ if (!expiry) {
+ dst->remove_subpkt(dst->get_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY));
+ } else {
+ dst->set_key_expiration(expiry);
+ }
+ dst->set_creation(time(NULL));
+ return true;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
- if (!expiry) {
- pgp_sig_subpkt_t *subpkt = signature_get_subpkt(dst, PGP_SIG_SUBPKT_KEY_EXPIRY);
- signature_remove_subpkt(dst, subpkt);
- } else {
- signature_set_key_expiration(dst, expiry);
- }
- signature_set_creation(dst, time(NULL));
- return true;
}
bool
pgp_key_set_expiration(pgp_key_t * key,
pgp_key_t * seckey,
uint32_t expiry,
const pgp_password_provider_t *prov)
{
@@ -1635,17 +1467,17 @@ pgp_key_set_expiration(pgp_key_t *
/* locate the latest valid certification */
pgp_subsig_t *subsig = pgp_key_latest_selfsig(key, PGP_SIG_SUBPKT_UNKNOWN);
if (!subsig) {
RNP_LOG("No valid self-signature");
return false;
}
/* update signature and re-sign it */
- if (!expiry && !signature_has_key_expiration(&subsig->sig)) {
+ if (!expiry && !subsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) {
return true;
}
bool locked = pgp_key_is_locked(seckey);
if (locked && !pgp_key_unlock(seckey, prov)) {
RNP_LOG("Failed to unlock secret key");
return false;
}
@@ -1701,17 +1533,17 @@ pgp_subkey_set_expiration(pgp_key_t *
}
/* find the latest valid subkey binding */
pgp_subsig_t *subsig = pgp_key_latest_binding(sub, true);
if (!subsig) {
RNP_LOG("No valid subkey binding");
return false;
}
- if (!expiry && !signature_has_key_expiration(&subsig->sig)) {
+ if (!expiry && !subsig->sig.has_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY)) {
return true;
}
bool res = false;
bool subsign = pgp_key_get_flags(secsub) & PGP_KF_SIGN;
bool locked = pgp_key_is_locked(primsec);
if (locked && !pgp_key_unlock(primsec, prov)) {
RNP_LOG("Failed to unlock primary key");
@@ -1883,24 +1715,28 @@ find_suitable_key(pgp_op_t op
return NULL;
}
if (pgp_key_get_flags(key) & desired_usage) {
return key;
}
pgp_key_request_ctx_t ctx{.op = op, .secret = pgp_key_is_secret(key)};
ctx.search.type = PGP_KEY_SEARCH_FINGERPRINT;
+ pgp_key_t *subkey = NULL;
for (auto &fp : key->subkey_fps) {
ctx.search.by.fingerprint = fp;
- pgp_key_t *subkey = pgp_request_key(key_provider, &ctx);
- if (subkey && (pgp_key_get_flags(subkey) & desired_usage)) {
- return subkey;
+ pgp_key_t *cur = pgp_request_key(key_provider, &ctx);
+ if (!cur || !(pgp_key_get_flags(cur) & desired_usage) || !cur->valid) {
+ continue;
+ }
+ if (!subkey || (pgp_key_get_creation(cur) > pgp_key_get_creation(subkey))) {
+ subkey = cur;
}
}
- return NULL;
+ return subkey;
}
pgp_hash_alg_t
pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey)
{
if ((pubkey->alg != PGP_PKA_DSA) && (pubkey->alg != PGP_PKA_ECDSA)) {
return hash;
}
@@ -1917,17 +1753,17 @@ pgp_hash_adjust_alg_to_key(pgp_hash_alg_
}
return hash;
}
static bool
is_key_expired(const pgp_key_t &key, const pgp_subsig_t &sig)
{
/* key expiration: absense of subpkt or 0 means it never expires */
- uint32_t expiration = signature_get_key_expiration(&sig.sig);
+ uint32_t expiration = sig.sig.key_expiration();
if (!expiration) {
return false;
}
return pgp_key_get_creation(&key) + expiration < time(NULL);
}
static void
pgp_key_validate_primary(pgp_key_t *key, rnp_key_store_t *keyring)
@@ -2071,16 +1907,72 @@ mem_dest_to_vector(pgp_dest_t *dst, std:
dst_close(dst, true);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
dst_close(dst, true);
throw;
}
}
+static void
+bytevec_append_uniq(std::vector<uint8_t> &vec, uint8_t val)
+{
+ if (std::find(vec.begin(), vec.end(), val) == vec.end()) {
+ vec.push_back(val);
+ }
+}
+
+void
+pgp_user_prefs_t::set_symm_algs(const std::vector<uint8_t> &algs)
+{
+ symm_algs = algs;
+}
+
+void
+pgp_user_prefs_t::add_symm_alg(pgp_symm_alg_t alg)
+{
+ bytevec_append_uniq(symm_algs, alg);
+}
+
+void
+pgp_user_prefs_t::set_hash_algs(const std::vector<uint8_t> &algs)
+{
+ hash_algs = algs;
+}
+
+void
+pgp_user_prefs_t::add_hash_alg(pgp_hash_alg_t alg)
+{
+ bytevec_append_uniq(hash_algs, alg);
+}
+
+void
+pgp_user_prefs_t::set_z_algs(const std::vector<uint8_t> &algs)
+{
+ z_algs = algs;
+}
+
+void
+pgp_user_prefs_t::add_z_alg(pgp_compression_type_t alg)
+{
+ bytevec_append_uniq(z_algs, alg);
+}
+
+void
+pgp_user_prefs_t::set_ks_prefs(const std::vector<uint8_t> &prefs)
+{
+ ks_prefs = prefs;
+}
+
+void
+pgp_user_prefs_t::add_ks_pref(pgp_key_server_prefs_t pref)
+{
+ bytevec_append_uniq(ks_prefs, pref);
+}
+
pgp_rawpacket_t::pgp_rawpacket_t(const pgp_signature_t &sig)
{
pgp_dest_t dst = {};
if (init_mem_dest(&dst, NULL, 0)) {
throw std::bad_alloc();
}
@@ -2122,93 +2014,16 @@ pgp_rawpacket_t::pgp_rawpacket_t(const p
dst_close(&dst, true);
throw std::bad_alloc();
}
mem_dest_to_vector(&dst, raw);
tag = uid.tag;
}
-pgp_subsig_t::pgp_subsig_t(const pgp_subsig_t &src)
-{
- uid = src.uid;
- sig = src.sig;
- rawpkt = src.rawpkt;
- trustlevel = src.trustlevel;
- trustamount = src.trustamount;
- key_flags = src.key_flags;
- if (pgp_userprefs_copy(&prefs, &src.prefs)) {
- throw std::bad_alloc();
- }
- validated = src.validated;
- valid = src.valid;
-}
-
-pgp_subsig_t::pgp_subsig_t(pgp_subsig_t &&src)
-{
- uid = src.uid;
- sig = std::move(src.sig);
- rawpkt = std::move(src.rawpkt);
- trustlevel = src.trustlevel;
- trustamount = src.trustamount;
- key_flags = src.key_flags;
- prefs = src.prefs;
- src.prefs = {};
- validated = src.validated;
- valid = src.valid;
-}
-
-pgp_subsig_t &
-pgp_subsig_t::operator=(pgp_subsig_t &&src)
-{
- if (&src == this) {
- return *this;
- }
-
- pgp_free_user_prefs(&prefs);
- uid = src.uid;
- sig = std::move(src.sig);
- rawpkt = std::move(src.rawpkt);
- trustlevel = src.trustlevel;
- trustamount = src.trustamount;
- key_flags = src.key_flags;
- prefs = src.prefs;
- src.prefs = {};
- validated = src.validated;
- valid = src.valid;
- return *this;
-}
-
-pgp_subsig_t &
-pgp_subsig_t::operator=(const pgp_subsig_t &src)
-{
- if (&src == this) {
- return *this;
- }
-
- pgp_free_user_prefs(&prefs);
- uid = src.uid;
- sig = src.sig;
- rawpkt = src.rawpkt;
- trustlevel = src.trustlevel;
- trustamount = src.trustamount;
- key_flags = src.key_flags;
- if (pgp_userprefs_copy(&prefs, &src.prefs)) {
- throw std::bad_alloc();
- }
- validated = src.validated;
- valid = src.valid;
- return *this;
-}
-
-pgp_subsig_t::~pgp_subsig_t()
-{
- pgp_free_user_prefs(&prefs);
-}
-
pgp_key_t::pgp_key_t(const pgp_key_t &src, bool pubonly)
{
/* Do some checks for g10 keys */
if (src.format == PGP_KEY_STORE_G10) {
if (pubonly) {
RNP_LOG("attempt to copy public part from g10 key");
throw std::invalid_argument("pubonly");
}
--- a/third_party/rnp/src/lib/pgp-key.h
+++ b/third_party/rnp/src/lib/pgp-key.h
@@ -98,34 +98,16 @@ typedef struct rnp_key_store_t rnp_key_s
* @brief Create pgp_key_t object from the OpenPGP key packet.
*
* @param key pointer to the key object, cannot be NULL.
* @param pkt pointer to the key packet, cannot be NULL.
* @return true if operation succeeded or false otherwise.
*/
bool pgp_key_from_pkt(pgp_key_t *key, const pgp_key_pkt_t *pkt);
-void pgp_free_user_prefs(pgp_user_prefs_t *prefs);
-
-bool pgp_user_prefs_set_symm_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len);
-
-bool pgp_user_prefs_add_symm_alg(pgp_user_prefs_t *prefs, pgp_symm_alg_t alg);
-
-bool pgp_user_prefs_set_hash_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len);
-
-bool pgp_user_prefs_add_hash_alg(pgp_user_prefs_t *prefs, pgp_hash_alg_t alg);
-
-bool pgp_user_prefs_set_z_algs(pgp_user_prefs_t *prefs, const uint8_t *algs, size_t len);
-
-bool pgp_user_prefs_add_z_alg(pgp_user_prefs_t *prefs, pgp_compression_type_t alg);
-
-bool pgp_user_prefs_set_ks_prefs(pgp_user_prefs_t *prefs, const uint8_t *vals, size_t len);
-
-bool pgp_user_prefs_add_ks_pref(pgp_user_prefs_t *prefs, pgp_key_server_prefs_t val);
-
const pgp_key_pkt_t *pgp_key_get_pkt(const pgp_key_t *);
const pgp_key_material_t *pgp_key_get_material(const pgp_key_t *key);
pgp_pubkey_alg_t pgp_key_get_alg(const pgp_key_t *key);
size_t pgp_key_get_dsa_qbits(const pgp_key_t *key);
@@ -248,17 +230,17 @@ pgp_revoke_t *pgp_key_get_revoke(pgp_key
pgp_subsig_t *pgp_key_add_subsig(pgp_key_t *);
size_t pgp_key_get_subsig_count(const pgp_key_t *);
const pgp_subsig_t *pgp_key_get_subsig(const pgp_key_t *, size_t);
pgp_subsig_t * pgp_key_get_subsig(pgp_key_t *, size_t);
-bool pgp_subsig_from_signature(pgp_subsig_t *subsig, const pgp_signature_t *sig);
+bool pgp_subsig_from_signature(pgp_subsig_t &subsig, const pgp_signature_t &sig);
bool pgp_key_has_signature(const pgp_key_t *key, const pgp_signature_t *sig);
pgp_subsig_t *pgp_key_replace_signature(pgp_key_t * key,
pgp_signature_t *oldsig,
pgp_signature_t *newsig);
/**
--- a/third_party/rnp/src/lib/rnp.cpp
+++ b/third_party/rnp/src/lib/rnp.cpp
@@ -22,22 +22,22 @@
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "crypto.h"
#include "crypto/common.h"
-#include "list.h"
#include "pgp-key.h"
#include "defaults.h"
#include <assert.h>
#include <json_object.h>
#include <json.h>
+#include <librekey/key_store_pgp.h>
#include <librepgp/stream-ctx.h>
#include <librepgp/stream-common.h>
#include <librepgp/stream-armor.h>
#include <librepgp/stream-parse.h>
#include <librepgp/stream-write.h>
#include <librepgp/stream-sig.h>
#include <librepgp/stream-packet.h>
#include <librepgp/stream-key.h>
@@ -127,21 +127,20 @@ find_key(rnp_ffi_t ffi,
static pgp_key_t *
ffi_key_provider(const pgp_key_request_ctx_t *ctx, void *userdata)
{
rnp_ffi_t ffi = (rnp_ffi_t) userdata;
return find_key(ffi, &ctx->search, ctx->secret ? KEY_TYPE_SECRET : KEY_TYPE_PUBLIC, true);
}
static void
-rnp_ctx_init_ffi(rnp_ctx_t *ctx, rnp_ffi_t ffi)
+rnp_ctx_init_ffi(rnp_ctx_t &ctx, rnp_ffi_t ffi)
{
- memset(ctx, 0, sizeof(*ctx));
- ctx->rng = &ffi->rng;
- ctx->ealg = DEFAULT_PGP_SYMM_ALG;
+ ctx.rng = &ffi->rng;
+ ctx.ealg = DEFAULT_PGP_SYMM_ALG;
}
static const pgp_map_t sig_type_map[] = {{PGP_SIG_BINARY, "binary"},
{PGP_SIG_TEXT, "text"},
{PGP_SIG_STANDALONE, "standalone"},
{PGP_CERT_GENERIC, "certification (generic)"},
{PGP_CERT_PERSONA, "certification (persona)"},
{PGP_CERT_CASUAL, "certification (casual)"},
@@ -439,16 +438,20 @@ ffi_exception(FILE *fp, const char *func
if (rnp_log_switch()) {
fprintf(
fp, "[%s()] Error 0x%08X (%s): %s\n", func, ret, rnp_result_to_string(ret), msg);
}
return ret;
}
#define FFI_GUARD_FP(fp) \
+ catch (rnp::rnp_exception & e) \
+ { \
+ return ffi_exception((fp), __func__, e.what(), e.code()); \
+ } \
catch (std::bad_alloc &) \
{ \
return ffi_exception((fp), __func__, "bad_alloc", RNP_ERROR_OUT_OF_MEMORY); \
} \
catch (std::exception & e) \
{ \
return ffi_exception((fp), __func__, e.what()); \
} \
@@ -1298,16 +1301,66 @@ try {
if (flags & RNP_KEY_UNLOAD_SECRET) {
rnp_key_store_clear(ffi->secring);
}
return RNP_SUCCESS;
}
FFI_GUARD
+static rnp_result_t
+rnp_input_dearmor_if_needed(rnp_input_t input)
+{
+ if (!input) {
+ return RNP_ERROR_NULL_POINTER;
+ }
+ if (input->src_directory) {
+ return RNP_ERROR_BAD_PARAMETERS;
+ }
+ bool require_armor = false;
+ /* check whether we already have armored stream */
+ if (input->src.type == PGP_STREAM_ARMORED) {
+ if (!src_eof(&input->src)) {
+ return RNP_SUCCESS;
+ }
+ /* eof - probably next we have another armored message */
+ src_close(&input->src);
+ void *app_ctx = input->app_ctx;
+ *input = *(rnp_input_t) app_ctx;
+ free(app_ctx);
+ /* we should not mix armored data with binary */
+ require_armor = true;
+ }
+ if (src_eof(&input->src)) {
+ return RNP_ERROR_EOF;
+ }
+ if (!is_armored_source(&input->src)) {
+ return require_armor ? RNP_ERROR_BAD_FORMAT : RNP_SUCCESS;
+ }
+
+ rnp_input_t app_ctx = (rnp_input_t) calloc(1, sizeof(*input));
+ if (!app_ctx) {
+ return RNP_ERROR_OUT_OF_MEMORY;
+ }
+ *app_ctx = *input;
+
+ pgp_source_t armored;
+ rnp_result_t ret = init_armored_src(&armored, &app_ctx->src);
+ if (ret) {
+ /* original src may be changed during init_armored_src call, so copy it back */
+ input->src = app_ctx->src;
+ free(app_ctx);
+ return ret;
+ }
+
+ input->src = armored;
+ input->app_ctx = app_ctx;
+ return RNP_SUCCESS;
+}
+
static const char *
key_status_to_str(pgp_key_import_status_t status)
{
if (status == PGP_KEY_IMPORT_STATUS_UNKNOWN) {
return "none";
}
const char *str = "none";
ARRAY_LOOKUP_BY_ID(key_import_status_map, type, string, status, str);
@@ -1360,16 +1413,21 @@ try {
FFI_LOG(ffi, "bad flags: need to specify public and/or secret keys");
return RNP_ERROR_BAD_PARAMETERS;
}
bool skipbad = false;
if (flags & RNP_LOAD_SAVE_PERMISSIVE) {
skipbad = true;
flags &= ~RNP_LOAD_SAVE_PERMISSIVE;
}
+ bool single = false;
+ if (flags & RNP_LOAD_SAVE_SINGLE) {
+ single = true;
+ flags &= ~RNP_LOAD_SAVE_SINGLE;
+ }
if (flags) {
FFI_LOG(ffi, "unexpected flags remaining: 0x%X", flags);
return RNP_ERROR_BAD_PARAMETERS;
}
rnp_result_t ret = RNP_ERROR_GENERIC;
rnp_key_store_t *tmp_store = NULL;
rnp_result_t tmpret;
@@ -1379,20 +1437,36 @@ try {
// load keys to temporary keystore.
try {
tmp_store = new rnp_key_store_t(PGP_KEY_STORE_GPG, "");
} catch (const std::exception &e) {
FFI_LOG(ffi, "Failed to create key store: %s.", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
- tmp_store->skip_parsing_errors = skipbad;
- if (!rnp_key_store_load_from_src(tmp_store, &input->src, NULL)) {
- ret = RNP_ERROR_BAD_FORMAT;
- goto done;
+ if (single) {
+ /* we need to init and handle dearmor on this layer since it may be used for the next
+ * keys import */
+ ret = rnp_input_dearmor_if_needed(input);
+ if (ret == RNP_ERROR_EOF) {
+ goto done;
+ }
+ if (ret) {
+ FFI_LOG(ffi, "Failed to init/check dearmor.");
+ goto done;
+ }
+ ret = rnp_key_store_pgp_read_key_from_src(*tmp_store, input->src, skipbad);
+ if (ret) {
+ goto done;
+ }
+ } else {
+ ret = rnp_key_store_pgp_read_from_src(tmp_store, &input->src, skipbad);
+ if (ret) {
+ goto done;
+ }
}
jsores = json_object_new_object();
if (!jsores) {
ret = RNP_ERROR_OUT_OF_MEMORY;
goto done;
}
jsokeys = json_object_new_array();
if (!obj_add_field_json(jsores, "keys", jsokeys)) {
@@ -1755,16 +1829,19 @@ try {
free(*input);
*input = NULL;
return RNP_ERROR_OUT_OF_MEMORY;
}
memcpy(data, buf, buf_len);
}
rnp_result_t ret = init_mem_src(&(*input)->src, data, buf_len, do_copy);
if (ret) {
+ if (do_copy) {
+ free(data);
+ }
free(*input);
*input = NULL;
return ret;
}
return RNP_SUCCESS;
}
FFI_GUARD
@@ -1819,17 +1896,21 @@ try {
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_input_destroy(rnp_input_t input)
try {
if (input) {
+ bool armored = input->src.type == PGP_STREAM_ARMORED;
src_close(&input->src);
+ if (armored) {
+ rnp_input_destroy((rnp_input_t) input->app_ctx);
+ }
free(input->src_directory);
free(input);
}
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
@@ -2096,168 +2177,136 @@ try {
free(output->dst_directory);
free(output);
}
return RNP_SUCCESS;
}
FFI_GUARD
static rnp_result_t
-rnp_op_add_signature(rnp_ffi_t ffi,
- list * signatures,
- rnp_key_handle_t key,
- rnp_ctx_t * ctx,
- rnp_op_sign_signature_t *sig)
+rnp_op_add_signature(rnp_ffi_t ffi,
+ rnp_op_sign_signatures_t &signatures,
+ rnp_key_handle_t key,
+ rnp_ctx_t & ctx,
+ rnp_op_sign_signature_t * sig)
{
- rnp_op_sign_signature_t newsig = NULL;
-
- if (!signatures || !key) {
- return RNP_ERROR_NULL_POINTER;
- }
-
- newsig = (rnp_op_sign_signature_t) list_append(signatures, NULL, sizeof(*newsig));
- if (!newsig) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
- newsig->signer.key = find_suitable_key(
+ if (!key) {
+ return RNP_ERROR_NULL_POINTER;
+ }
+
+ pgp_key_t *signkey = find_suitable_key(
PGP_OP_SIGN, get_key_prefer_public(key), &key->ffi->key_provider, PGP_KF_SIGN);
- if (newsig->signer.key && !pgp_key_is_secret(newsig->signer.key)) {
+ if (signkey && !pgp_key_is_secret(signkey)) {
pgp_key_request_ctx_t ctx = {.op = PGP_OP_SIGN, .secret = true};
ctx.search.type = PGP_KEY_SEARCH_GRIP;
- ctx.search.by.grip = pgp_key_get_grip(newsig->signer.key);
- newsig->signer.key = pgp_request_key(&key->ffi->key_provider, &ctx);
- }
- if (!newsig->signer.key) {
- list_remove((list_item *) newsig);
+ ctx.search.by.grip = pgp_key_get_grip(signkey);
+ signkey = pgp_request_key(&key->ffi->key_provider, &ctx);
+ }
+ if (!signkey) {
return RNP_ERROR_NO_SUITABLE_KEY;
}
+ try {
+ signatures.emplace_back();
+ } catch (const std::exception &e) {
+ FFI_LOG(ffi, "%s", e.what());
+ return RNP_ERROR_BAD_PARAMETERS;
+ }
+ rnp_op_sign_signature_t newsig = &signatures.back();
+ newsig->signer.key = signkey;
/* set default create/expire times */
- newsig->signer.sigcreate = ctx->sigcreate;
- newsig->signer.sigexpire = ctx->sigexpire;
+ newsig->signer.sigcreate = ctx.sigcreate;
+ newsig->signer.sigexpire = ctx.sigexpire;
newsig->ffi = ffi;
if (sig) {
*sig = newsig;
}
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_armor(rnp_ctx_t *ctx, bool armored)
+rnp_op_set_armor(rnp_ctx_t &ctx, bool armored)
{
- if (!ctx) {
- return RNP_ERROR_NULL_POINTER;
- }
- ctx->armor = armored;
+ ctx.armor = armored;
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_compression(rnp_ffi_t ffi, rnp_ctx_t *ctx, const char *compression, int level)
+rnp_op_set_compression(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *compression, int level)
{
- if (!ctx || !compression) {
+ if (!compression) {
return RNP_ERROR_NULL_POINTER;
}
pgp_compression_type_t zalg = PGP_C_UNKNOWN;
if (!str_to_compression_alg(compression, &zalg)) {
FFI_LOG(ffi, "Invalid compression: %s", compression);
return RNP_ERROR_BAD_PARAMETERS;
}
- ctx->zalg = (int) zalg;
- ctx->zlevel = level;
+ ctx.zalg = (int) zalg;
+ ctx.zlevel = level;
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_hash(rnp_ffi_t ffi, rnp_ctx_t *ctx, const char *hash)
+rnp_op_set_hash(rnp_ffi_t ffi, rnp_ctx_t &ctx, const char *hash)
{
- if (!ctx || !hash) {
- return RNP_ERROR_NULL_POINTER;
- }
-
- if (!str_to_hash_alg(hash, &ctx->halg)) {
+ if (!hash) {
+ return RNP_ERROR_NULL_POINTER;
+ }
+
+ if (!str_to_hash_alg(hash, &ctx.halg)) {
FFI_LOG(ffi, "Invalid hash: %s", hash);
return RNP_ERROR_BAD_PARAMETERS;
}
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_creation_time(rnp_ctx_t *ctx, uint32_t create)
+rnp_op_set_creation_time(rnp_ctx_t &ctx, uint32_t create)
{
- if (!ctx) {
- return RNP_ERROR_NULL_POINTER;
- }
- ctx->sigcreate = create;
- return RNP_SUCCESS;
-}
-
-static rnp_result_t
-rnp_op_set_expiration_time(rnp_ctx_t *ctx, uint32_t expire)
-{
- if (!ctx) {
- return RNP_ERROR_NULL_POINTER;
- }
- ctx->sigexpire = expire;
+ ctx.sigcreate = create;
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_file_name(rnp_ctx_t *ctx, const char *filename)
+rnp_op_set_expiration_time(rnp_ctx_t &ctx, uint32_t expire)
{
- if (!ctx) {
- return RNP_ERROR_NULL_POINTER;
- }
- free(ctx->filename);
- if (!filename) {
- ctx->filename = NULL;
- return RNP_SUCCESS;
- }
- ctx->filename = strdup(filename);
- if (!ctx->filename) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
+ ctx.sigexpire = expire;
return RNP_SUCCESS;
}
static rnp_result_t
-rnp_op_set_file_mtime(rnp_ctx_t *ctx, uint32_t mtime)
+rnp_op_set_file_name(rnp_ctx_t &ctx, const char *filename)
{
- if (!ctx) {
- return RNP_ERROR_NULL_POINTER;
- }
- ctx->filemtime = mtime;
- return RNP_SUCCESS;
-}
-
-static void
-rnp_op_signatures_destroy(list *signatures)
+ ctx.filename = filename ? filename : "";
+ return RNP_SUCCESS;
+}
+
+static rnp_result_t
+rnp_op_set_file_mtime(rnp_ctx_t &ctx, uint32_t mtime)
{
- list_destroy(signatures);
+ ctx.filemtime = mtime;
+ return RNP_SUCCESS;
}
rnp_result_t
rnp_op_encrypt_create(rnp_op_encrypt_t *op,
rnp_ffi_t ffi,
rnp_input_t input,
rnp_output_t output)
try {
// checks
if (!op || !ffi || !input || !output) {
return RNP_ERROR_NULL_POINTER;
}
- *op = (rnp_op_encrypt_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
- rnp_ctx_init_ffi(&(*op)->rnpctx, ffi);
+ *op = new rnp_op_encrypt_st();
+ rnp_ctx_init_ffi((*op)->rnpctx, ffi);
(*op)->ffi = ffi;
(*op)->input = input;
(*op)->output = output;
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
@@ -2267,62 +2316,60 @@ try {
if (!op || !handle) {
return RNP_ERROR_NULL_POINTER;
}
pgp_key_t *key = find_suitable_key(PGP_OP_ENCRYPT,
get_key_prefer_public(handle),
&handle->ffi->key_provider,
PGP_KF_ENCRYPT);
- if (!list_append(&op->rnpctx.recipients, &key, sizeof(key))) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
+ op->rnpctx.recipients.push_back(key);
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_add_signature(rnp_op_encrypt_t op,
rnp_key_handle_t key,
rnp_op_sign_signature_t *sig)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_add_signature(op->ffi, &op->signatures, key, &op->rnpctx, sig);
+ return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_hash(rnp_op_encrypt_t op, const char *hash)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_hash(op->ffi, &op->rnpctx, hash);
+ return rnp_op_set_hash(op->ffi, op->rnpctx, hash);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_creation_time(rnp_op_encrypt_t op, uint32_t create)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_creation_time(&op->rnpctx, create);
+ return rnp_op_set_creation_time(op->rnpctx, create);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_expiration_time(rnp_op_encrypt_t op, uint32_t expire)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_expiration_time(&op->rnpctx, expire);
+ return rnp_op_set_expiration_time(op->rnpctx, expire);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_add_password(rnp_op_encrypt_t op,
const char * password,
const char * s2k_hash,
size_t iterations,
@@ -2362,32 +2409,32 @@ try {
pgp_password_ctx_t pswdctx = {.op = PGP_OP_ENCRYPT_SYM, .key = NULL};
if (!pgp_request_password(
&op->ffi->pass_provider, &pswdctx, &ask_pass[0], ask_pass.size())) {
return RNP_ERROR_BAD_PASSWORD;
}
password = ask_pass.data();
}
return rnp_ctx_add_encryption_password(
- &op->rnpctx, password, hash_alg, symm_alg, iterations);
+ op->rnpctx, password, hash_alg, symm_alg, iterations);
} catch (const std::exception &e) {
FFI_LOG(op->ffi, "%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_armor(rnp_op_encrypt_t op, bool armored)
try {
// checks
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_armor(&op->rnpctx, armored);
+ return rnp_op_set_armor(op->rnpctx, armored);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_cipher(rnp_op_encrypt_t op, const char *cipher)
try {
// checks
if (!op) {
@@ -2432,37 +2479,37 @@ FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_compression(rnp_op_encrypt_t op, const char *compression, int level)
try {
// checks
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_compression(op->ffi, &op->rnpctx, compression, level);
+ return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_file_name(rnp_op_encrypt_t op, const char *filename)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_file_name(&op->rnpctx, filename);
+ return rnp_op_set_file_name(op->rnpctx, filename);
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_set_file_mtime(rnp_op_encrypt_t op, uint32_t mtime)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_file_mtime(&op->rnpctx, mtime);
+ return rnp_op_set_file_mtime(op->rnpctx, mtime);
}
FFI_GUARD
static pgp_write_handler_t
pgp_write_handler(pgp_password_provider_t *pass_provider,
rnp_ctx_t * rnpctx,
void * param,
pgp_key_provider_t * key_provider)
@@ -2472,42 +2519,35 @@ pgp_write_handler(pgp_password_provider_
handler.password_provider = pass_provider;
handler.ctx = rnpctx;
handler.param = param;
handler.key_provider = key_provider;
return handler;
}
static rnp_result_t
-rnp_op_add_signatures(list opsigs, rnp_ctx_t *ctx)
+rnp_op_add_signatures(rnp_op_sign_signatures_t &opsigs, rnp_ctx_t &ctx)
{
- for (list_item *sig = list_front(opsigs); sig; sig = list_next(sig)) {
- rnp_signer_info_t sinfo = {};
- rnp_op_sign_signature_t osig = (rnp_op_sign_signature_t) sig;
-
- if (!osig->signer.key) {
+ for (auto &sig : opsigs) {
+ if (!sig.signer.key) {
return RNP_ERROR_NO_SUITABLE_KEY;
}
- sinfo = osig->signer;
- if (!osig->hash_set) {
- sinfo.halg = ctx->halg;
- }
- if (!osig->expiry_set) {
- sinfo.sigexpire = ctx->sigexpire;
- }
- if (!osig->create_set) {
- sinfo.sigcreate = ctx->sigcreate;
- }
-
- if (!list_append(&ctx->signers, &sinfo, sizeof(sinfo))) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
- }
-
+ rnp_signer_info_t sinfo = sig.signer;
+ if (!sig.hash_set) {
+ sinfo.halg = ctx.halg;
+ }
+ if (!sig.expiry_set) {
+ sinfo.sigexpire = ctx.sigexpire;
+ }
+ if (!sig.create_set) {
+ sinfo.sigcreate = ctx.sigcreate;
+ }
+ ctx.signers.push_back(sinfo);
+ }
return RNP_SUCCESS;
}
rnp_result_t
rnp_op_encrypt_execute(rnp_op_encrypt_t op)
try {
// checks
if (!op || !op->input || !op->output) {
@@ -2517,18 +2557,18 @@ try {
// set the default hash alg if none was specified
if (!op->rnpctx.halg) {
op->rnpctx.halg = DEFAULT_PGP_HASH_ALG;
}
pgp_write_handler_t handler =
pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider);
rnp_result_t ret;
- if (list_length(op->signatures)) {
- if ((ret = rnp_op_add_signatures(op->signatures, &op->rnpctx))) {
+ if (!op->signatures.empty()) {
+ if ((ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) {
return ret;
}
ret = rnp_encrypt_sign_src(&handler, &op->input->src, &op->output->dst);
} else {
ret = rnp_encrypt_src(&handler, &op->input->src, &op->output->dst);
}
dst_flush(&op->output->dst);
@@ -2537,39 +2577,31 @@ try {
op->output = NULL;
return ret;
}
FFI_GUARD
rnp_result_t
rnp_op_encrypt_destroy(rnp_op_encrypt_t op)
try {
- if (op) {
- rnp_ctx_free(&op->rnpctx);
- rnp_op_signatures_destroy(&op->signatures);
- free(op);
- }
+ delete op;
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_sign_create(rnp_op_sign_t *op, rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output)
try {
// checks
if (!op || !ffi || !input || !output) {
return RNP_ERROR_NULL_POINTER;
}
- *op = (rnp_op_sign_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
- rnp_ctx_init_ffi(&(*op)->rnpctx, ffi);
+ *op = new rnp_op_sign_st();
+ rnp_ctx_init_ffi((*op)->rnpctx, ffi);
(*op)->ffi = ffi;
(*op)->input = input;
(*op)->output = output;
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
@@ -2601,17 +2633,17 @@ try {
FFI_GUARD
rnp_result_t
rnp_op_sign_add_signature(rnp_op_sign_t op, rnp_key_handle_t key, rnp_op_sign_signature_t *sig)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_add_signature(op->ffi, &op->signatures, key, &op->rnpctx, sig);
+ return rnp_op_add_signature(op->ffi, op->signatures, key, op->rnpctx, sig);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_signature_set_hash(rnp_op_sign_signature_t sig, const char *hash)
try {
if (!sig) {
return RNP_ERROR_NULL_POINTER;
@@ -2650,77 +2682,77 @@ try {
FFI_GUARD
rnp_result_t
rnp_op_sign_set_armor(rnp_op_sign_t op, bool armored)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_armor(&op->rnpctx, armored);
+ return rnp_op_set_armor(op->rnpctx, armored);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_compression(rnp_op_sign_t op, const char *compression, int level)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_compression(op->ffi, &op->rnpctx, compression, level);
+ return rnp_op_set_compression(op->ffi, op->rnpctx, compression, level);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_hash(rnp_op_sign_t op, const char *hash)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_hash(op->ffi, &op->rnpctx, hash);
+ return rnp_op_set_hash(op->ffi, op->rnpctx, hash);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_creation_time(rnp_op_sign_t op, uint32_t create)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_creation_time(&op->rnpctx, create);
+ return rnp_op_set_creation_time(op->rnpctx, create);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_expiration_time(rnp_op_sign_t op, uint32_t expire)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_expiration_time(&op->rnpctx, expire);
+ return rnp_op_set_expiration_time(op->rnpctx, expire);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_file_name(rnp_op_sign_t op, const char *filename)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_file_name(&op->rnpctx, filename);
+ return rnp_op_set_file_name(op->rnpctx, filename);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_set_file_mtime(rnp_op_sign_t op, uint32_t mtime)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
- return rnp_op_set_file_mtime(&op->rnpctx, mtime);
+ return rnp_op_set_file_mtime(op->rnpctx, mtime);
}
FFI_GUARD
rnp_result_t
rnp_op_sign_execute(rnp_op_sign_t op)
try {
// checks
if (!op || !op->input || !op->output) {
@@ -2730,37 +2762,33 @@ try {
// set the default hash alg if none was specified
if (!op->rnpctx.halg) {
op->rnpctx.halg = DEFAULT_PGP_HASH_ALG;
}
pgp_write_handler_t handler =
pgp_write_handler(&op->ffi->pass_provider, &op->rnpctx, NULL, &op->ffi->key_provider);
rnp_result_t ret;
- if ((ret = rnp_op_add_signatures(op->signatures, &op->rnpctx))) {
+ if ((ret = rnp_op_add_signatures(op->signatures, op->rnpctx))) {
return ret;
}
ret = rnp_sign_src(&handler, &op->input->src, &op->output->dst);
dst_flush(&op->output->dst);
op->output->keep = ret == RNP_SUCCESS;
op->input = NULL;
op->output = NULL;
return ret;
}
FFI_GUARD
rnp_result_t
rnp_op_sign_destroy(rnp_op_sign_t op)
try {
- if (op) {
- rnp_ctx_free(&op->rnpctx);
- rnp_op_signatures_destroy(&op->signatures);
- free(op);
- }
+ delete op;
return RNP_SUCCESS;
}
FFI_GUARD
static void
rnp_op_verify_on_signatures(const std::vector<pgp_signature_info_t> &sigs, void *param)
{
rnp_op_verify_t op = (rnp_op_verify_t) param;
@@ -2945,22 +2973,18 @@ rnp_op_verify_create(rnp_op_verify_t *op
rnp_ffi_t ffi,
rnp_input_t input,
rnp_output_t output)
try {
if (!op || !ffi || !input || !output) {
return RNP_ERROR_NULL_POINTER;
}
- *op = (rnp_op_verify_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
- rnp_ctx_init_ffi(&(*op)->rnpctx, ffi);
+ *op = new rnp_op_verify_st();
+ rnp_ctx_init_ffi((*op)->rnpctx, ffi);
(*op)->ffi = ffi;
(*op)->input = input;
(*op)->output = output;
return RNP_SUCCESS;
}
FFI_GUARD
@@ -2969,22 +2993,18 @@ rnp_op_verify_detached_create(rnp_op_ver
rnp_ffi_t ffi,
rnp_input_t input,
rnp_input_t signature)
try {
if (!op || !ffi || !input || !signature) {
return RNP_ERROR_NULL_POINTER;
}
- *op = (rnp_op_verify_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
- rnp_ctx_init_ffi(&(*op)->rnpctx, ffi);
+ *op = new rnp_op_verify_st();
+ rnp_ctx_init_ffi((*op)->rnpctx, ffi);
(*op)->rnpctx.detached = true;
(*op)->ffi = ffi;
(*op)->input = signature;
(*op)->detached_input = input;
return RNP_SUCCESS;
}
FFI_GUARD
@@ -3267,29 +3287,30 @@ try {
*iterations = symenc->iterations;
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_verify_destroy(rnp_op_verify_t op)
try {
- if (op) {
- rnp_ctx_free(&op->rnpctx);
- delete[] op->signatures;
- free(op->filename);
- free(op->recipients);
- free(op->used_recipient);
- free(op->symencs);
- free(op->used_symenc);
- free(op);
- }
- return RNP_SUCCESS;
-}
-FFI_GUARD
+ delete op;
+ return RNP_SUCCESS;
+}
+FFI_GUARD
+
+rnp_op_verify_st::~rnp_op_verify_st()
+{
+ delete[] signatures;
+ free(filename);
+ free(recipients);
+ free(used_recipient);
+ free(symencs);
+ free(used_symenc);
+}
rnp_result_t
rnp_op_verify_signature_get_status(rnp_op_verify_signature_t sig)
try {
if (!sig) {
return RNP_ERROR_NULL_POINTER;
}
return sig->verify_status;
@@ -3338,19 +3359,20 @@ try {
FFI_GUARD
rnp_result_t
rnp_op_verify_signature_get_key(rnp_op_verify_signature_t sig, rnp_key_handle_t *key)
try {
rnp_ffi_t ffi = sig->ffi;
pgp_key_search_t search = {};
- if (!signature_get_keyid(&sig->sig_pkt, search.by.keyid)) {
- return RNP_ERROR_BAD_PARAMETERS;
- }
+ if (!sig->sig_pkt.has_keyid()) {
+ return RNP_ERROR_BAD_PARAMETERS;
+ }
+ search.by.keyid = sig->sig_pkt.keyid();
// create a search (since we'll use this later anyways)
search.type = PGP_KEY_SEARCH_KEYID;
// search the stores
pgp_key_t *pub = rnp_key_store_search(ffi->pubring, &search, NULL);
pgp_key_t *sec = rnp_key_store_search(ffi->secring, &search, NULL);
if (!pub && !sec) {
return RNP_ERROR_KEY_NOT_FOUND;
@@ -3370,20 +3392,20 @@ try {
FFI_GUARD
rnp_result_t
rnp_op_verify_signature_get_times(rnp_op_verify_signature_t sig,
uint32_t * create,
uint32_t * expires)
try {
if (create) {
- *create = signature_get_creation(&sig->sig_pkt);
+ *create = sig->sig_pkt.creation();
}
if (expires) {
- *expires = signature_get_expiration(&sig->sig_pkt);
+ *expires = sig->sig_pkt.expiration();
}
return RNP_SUCCESS;
}
FFI_GUARD
static bool
rnp_decrypt_dest_provider(pgp_parse_handler_t *handler,
@@ -3394,24 +3416,23 @@ rnp_decrypt_dest_provider(pgp_parse_hand
*dst = &((rnp_output_t) handler->param)->dst;
*closedst = false;
return true;
}
rnp_result_t
rnp_decrypt(rnp_ffi_t ffi, rnp_input_t input, rnp_output_t output)
try {
- rnp_ctx_t rnpctx;
-
// checks
if (!ffi || !input || !output) {
return RNP_ERROR_NULL_POINTER;
}
- rnp_ctx_init_ffi(&rnpctx, ffi);
+ rnp_ctx_t rnpctx;
+ rnp_ctx_init_ffi(rnpctx, ffi);
pgp_parse_handler_t handler;
memset(&handler, 0, sizeof(handler));
handler.password_provider = &ffi->pass_provider;
handler.key_provider = &ffi->key_provider;
handler.dest_provider = rnp_decrypt_dest_provider;
handler.param = output;
handler.ctx = &rnpctx;
@@ -3968,17 +3989,17 @@ pk_alg_allows_custom_curve(pgp_pubkey_al
case PGP_PKA_SM2:
return true;
default:
return false;
}
}
static bool
-parse_preferences(json_object *jso, pgp_user_prefs_t *prefs)
+parse_preferences(json_object *jso, pgp_user_prefs_t &prefs)
{
static const struct {
const char * key;
enum json_type type;
} properties[] = {{"hashes", json_type_array},
{"ciphers", json_type_array},
{"compression", json_type_array},
{"key server", json_type_string}};
@@ -3989,66 +4010,62 @@ parse_preferences(json_object *jso, pgp_
if (!json_object_object_get_ex(jso, key, &value)) {
continue;
}
if (!json_object_is_type(value, properties[iprop].type)) {
return false;
}
- if (!rnp_strcasecmp(key, "hashes")) {
- int length = json_object_array_length(value);
- for (int i = 0; i < length; i++) {
- json_object *item = json_object_array_get_idx(value, i);
- if (!json_object_is_type(item, json_type_string)) {
- return false;
- }
- pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
- if (!str_to_hash_alg(json_object_get_string(item), &hash_alg)) {
- return false;
- }
- if (!pgp_user_prefs_add_hash_alg(prefs, hash_alg)) {
- return false;
- }
- }
- } else if (!rnp_strcasecmp(key, "ciphers")) {
- int length = json_object_array_length(value);
- for (int i = 0; i < length; i++) {
- json_object *item = json_object_array_get_idx(value, i);
- if (!json_object_is_type(item, json_type_string)) {
- return false;
+ try {
+ if (!rnp_strcasecmp(key, "hashes")) {
+ int length = json_object_array_length(value);
+ for (int i = 0; i < length; i++) {
+ json_object *item = json_object_array_get_idx(value, i);
+ if (!json_object_is_type(item, json_type_string)) {
+ return false;
+ }
+ pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
+ if (!str_to_hash_alg(json_object_get_string(item), &hash_alg)) {
+ return false;
+ }
+ prefs.add_hash_alg(hash_alg);
}
- pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
- if (!str_to_cipher(json_object_get_string(item), &symm_alg)) {
- return false;
+ } else if (!rnp_strcasecmp(key, "ciphers")) {
+ int length = json_object_array_length(value);
+ for (int i = 0; i < length; i++) {
+ json_object *item = json_object_array_get_idx(value, i);
+ if (!json_object_is_type(item, json_type_string)) {
+ return false;
+ }
+ pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
+ if (!str_to_cipher(json_object_get_string(item), &symm_alg)) {
+ return false;
+ }
+ prefs.add_symm_alg(symm_alg);
}
- if (!pgp_user_prefs_add_symm_alg(prefs, symm_alg)) {
- return false;
+ } else if (!rnp_strcasecmp(key, "compression")) {
+ int length = json_object_array_length(value);
+ for (int i = 0; i < length; i++) {
+ json_object *item = json_object_array_get_idx(value, i);
+ if (!json_object_is_type(item, json_type_string)) {
+ return false;
+ }
+ pgp_compression_type_t z_alg = PGP_C_UNKNOWN;
+ if (!str_to_compression_alg(json_object_get_string(item), &z_alg)) {
+ return false;
+ }
+ prefs.add_z_alg(z_alg);
}
+ } else if (!rnp_strcasecmp(key, "key server")) {
+ prefs.key_server = json_object_get_string(value);
}
- } else if (!rnp_strcasecmp(key, "compression")) {
- int length = json_object_array_length(value);
- for (int i = 0; i < length; i++) {
- json_object *item = json_object_array_get_idx(value, i);
- if (!json_object_is_type(item, json_type_string)) {
- return false;
- }
- pgp_compression_type_t z_alg = PGP_C_UNKNOWN;
- if (!str_to_compression_alg(json_object_get_string(item), &z_alg)) {
- return false;
- }
- if (!pgp_user_prefs_add_z_alg(prefs, z_alg)) {
- return false;
- }
- }
- } else if (!rnp_strcasecmp(key, "key server")) {
- prefs->key_server = (uint8_t *) strdup(json_object_get_string(value));
- if (!prefs->key_server) {
- return false;
- }
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
+ return false;
}
// delete this field since it has been handled
json_object_object_del(jso, key);
}
return true;
}
static bool
@@ -4220,17 +4237,17 @@ parse_keygen_primary(json_object *jso, r
if (!json_object_is_type(value, json_type_int)) {
return false;
}
cert->key_expiration = json_object_get_int(value);
} else if (!rnp_strcasecmp(key, "preferences")) {
if (!json_object_is_type(value, json_type_object)) {
return false;
}
- if (!parse_preferences(value, &cert->prefs)) {
+ if (!parse_preferences(value, cert->prefs)) {
return false;
}
if (json_object_object_length(value) != 0) {
return false;
}
} else if (!rnp_strcasecmp(key, "protection")) {
if (!json_object_is_type(value, json_type_object)) {
return false;
@@ -4611,17 +4628,16 @@ try {
goto done;
}
ret = RNP_SUCCESS;
done:
json_object_put(jso);
free(identifier_type);
free(identifier);
- pgp_free_user_prefs(&keygen_desc.primary.keygen.cert.prefs);
return ret;
}
FFI_GUARD
rnp_result_t
rnp_generate_key_ex(rnp_ffi_t ffi,
const char * key_alg,
const char * sub_alg,
@@ -4832,21 +4848,17 @@ try {
if (!str_to_pubkey_alg(alg, &key_alg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
if (!(pgp_pk_alg_capabilities(key_alg) & PGP_KF_SIGN)) {
return RNP_ERROR_BAD_PARAMETERS;
}
- *op = (rnp_op_generate_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
+ *op = new rnp_op_generate_st();
(*op)->ffi = ffi;
(*op)->primary = true;
(*op)->crypto.key_alg = key_alg;
(*op)->crypto.rng = &ffi->rng;
(*op)->cert.key_flags = default_key_flags(key_alg, false);
return RNP_SUCCESS;
}
@@ -4880,21 +4892,17 @@ try {
return RNP_ERROR_BAD_PARAMETERS;
}
pgp_pubkey_alg_t key_alg = PGP_PKA_NOTHING;
if (!str_to_pubkey_alg(alg, &key_alg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
- *op = (rnp_op_generate_t) calloc(1, sizeof(**op));
- if (!*op) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
-
+ *op = new rnp_op_generate_st();
(*op)->ffi = ffi;
(*op)->primary = false;
(*op)->crypto.key_alg = key_alg;
(*op)->crypto.rng = &ffi->rng;
(*op)->binding.key_flags = default_key_flags(key_alg, true);
(*op)->primary_sec = primary->sec;
(*op)->primary_pub = primary->pub;
@@ -5123,19 +5131,17 @@ rnp_result_t
rnp_op_generate_clear_pref_hashes(rnp_op_generate_t op)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_set_hash_algs(&op->cert.prefs, NULL, 0)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.set_hash_algs({});
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_add_pref_hash(rnp_op_generate_t op, const char *hash)
try {
if (!op || !hash) {
@@ -5143,35 +5149,31 @@ try {
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
if (!str_to_hash_alg(hash, &hash_alg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_add_hash_alg(&op->cert.prefs, hash_alg)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.add_hash_alg(hash_alg);
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_clear_pref_compression(rnp_op_generate_t op)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_set_z_algs(&op->cert.prefs, NULL, 0)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.set_z_algs({});
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_add_pref_compression(rnp_op_generate_t op, const char *compression)
try {
if (!op || !compression) {
@@ -5179,35 +5181,31 @@ try {
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
pgp_compression_type_t z_alg = PGP_C_UNKNOWN;
if (!str_to_compression_alg(compression, &z_alg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_add_z_alg(&op->cert.prefs, z_alg)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.add_z_alg(z_alg);
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_clear_pref_ciphers(rnp_op_generate_t op)
try {
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_set_symm_algs(&op->cert.prefs, NULL, 0)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.set_symm_algs({});
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_add_pref_cipher(rnp_op_generate_t op, const char *cipher)
try {
if (!op || !cipher) {
@@ -5215,41 +5213,31 @@ try {
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
pgp_symm_alg_t symm_alg = PGP_SA_UNKNOWN;
if (!str_to_cipher(cipher, &symm_alg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (!pgp_user_prefs_add_symm_alg(&op->cert.prefs, symm_alg)) {
- return RNP_ERROR_BAD_STATE;
- }
+ op->cert.prefs.add_symm_alg(symm_alg);
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_set_pref_keyserver(rnp_op_generate_t op, const char *keyserver)
try {
- uint8_t *_keyserver = NULL;
if (!op) {
return RNP_ERROR_NULL_POINTER;
}
if (!op->primary) {
return RNP_ERROR_BAD_PARAMETERS;
}
- if (keyserver) {
- _keyserver = (uint8_t *) strdup(keyserver);
- if (!_keyserver) {
- return RNP_ERROR_OUT_OF_MEMORY;
- }
- }
- free(op->cert.prefs.key_server);
- op->cert.prefs.key_server = _keyserver;
+ op->cert.prefs.key_server = keyserver ? keyserver : "";
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_execute(rnp_op_generate_t op)
try {
if (!op || !op->ffi) {
@@ -5349,28 +5337,29 @@ try {
(*handle)->sec = op->gen_sec;
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_op_generate_destroy(rnp_op_generate_t op)
try {
- if (op) {
- pgp_free_user_prefs(&op->cert.prefs);
- if (op->password) {
- pgp_forget(op->password, strlen(op->password) + 1);
- free(op->password);
- op->password = NULL;
- }
- free(op);
- }
- return RNP_SUCCESS;
-}
-FFI_GUARD
+ delete op;
+ return RNP_SUCCESS;
+}
+FFI_GUARD
+
+rnp_op_generate_st::~rnp_op_generate_st()
+{
+ if (password) {
+ pgp_forget(password, strlen(password) + 1);
+ free(password);
+ password = NULL;
+ }
+}
rnp_result_t
rnp_key_handle_destroy(rnp_key_handle_t key)
try {
// This does not free key->key which is owned by the keyring
free(key);
return RNP_SUCCESS;
}
@@ -5463,17 +5452,17 @@ rnp_result_t
rnp_key_add_uid(rnp_key_handle_t handle,
const char * uid,
const char * hash,
uint32_t expiration,
uint8_t key_flags,
bool primary)
try {
rnp_result_t ret = RNP_ERROR_GENERIC;
- rnp_selfsig_cert_info_t info = {{0}};
+ rnp_selfsig_cert_info_t info = {};
pgp_hash_alg_t hash_alg = PGP_HASH_UNKNOWN;
pgp_key_t * public_key = NULL;
pgp_key_t * secret_key = NULL;
pgp_key_pkt_t * seckey = NULL;
pgp_key_pkt_t * decrypted_seckey = NULL;
if (!handle || !uid || !hash) {
return RNP_ERROR_NULL_POINTER;
@@ -5713,35 +5702,35 @@ rnp_result_t
rnp_signature_get_creation(rnp_signature_handle_t handle, uint32_t *create)
try {
if (!handle || !create) {
return RNP_ERROR_NULL_POINTER;
}
if (!handle->sig) {
return RNP_ERROR_BAD_PARAMETERS;
}
- *create = signature_get_creation(&handle->sig->sig);
+ *create = handle->sig->sig.creation();
return RNP_SUCCESS;
}
FFI_GUARD
rnp_result_t
rnp_signature_get_keyid(rnp_signature_handle_t handle, char **result)
try {
if (!handle || !result) {
return RNP_ERROR_NULL_POINTER;
}
if (!handle->sig) {
return RNP_ERROR_BAD_PARAMETERS;
}
- pgp_key_id_t keyid = {};
- if (!signature_get_keyid(&handle->sig->sig, keyid)) {
+ if (!handle->sig->sig.has_keyid()) {
*result = NULL;
return RNP_SUCCESS;
}
+ pgp_key_id_t keyid = handle->sig->sig.keyid();
return hex_encode_value(keyid.data(), keyid.size(), result, RNP_HEX_UPPERCASE);
}
FFI_GUARD
rnp_result_t
rnp_signature_get_signer(rnp_signature_handle_t sig, rnp_key_handle_t *key)
try {
char * keyid = NULL;
@@ -6198,17 +6187,17 @@ try {
if (!key || !type) {
return RNP_ERROR_NULL_POINTER;
}
if (!key->sec) {
return RNP_ERROR_BAD_PARAMETERS;
}
pgp_s2k_t & s2k = key->sec->pkt.sec_protection.s2k;
- const char *res = NULL;
+ const char *res = "Unknown";
if (s2k.usage == PGP_S2KU_NONE) {
res = "None";
}
if ((s2k.usage == PGP_S2KU_ENCRYPTED) && (s2k.specifier != PGP_S2KS_EXPERIMENTAL)) {
res = "Encrypted";
}
if ((s2k.usage == PGP_S2KU_ENCRYPTED_AND_HASHED) &&
(s2k.specifier != PGP_S2KS_EXPERIMENTAL)) {
@@ -6540,16 +6529,19 @@ key_to_bytes(pgp_key_t *key, uint8_t **b
if (!pgp_key_write_packets(key, &memdst)) {
dst_close(&memdst, true);
return RNP_ERROR_OUT_OF_MEMORY;
}
*buf_len = memdst.writeb;
*buf = (uint8_t *) mem_dest_own_memory(&memdst);
dst_close(&memdst, true);
+ if (*buf_len && !*buf) {
+ return RNP_ERROR_OUT_OF_MEMORY;
+ }
return RNP_SUCCESS;
}
rnp_result_t
rnp_get_public_key_data(rnp_key_handle_t handle, uint8_t **buf, size_t *buf_len)
try {
// checks
if (!handle || !buf || !buf_len) {
@@ -6761,86 +6753,82 @@ add_json_sig_mpis(json_object *jso, cons
default:
// TODO: we could use info->unknown and add a hex string of raw data here
return RNP_ERROR_NOT_SUPPORTED;
}
return RNP_SUCCESS;
}
static bool
-add_json_user_prefs(json_object *jso, const pgp_user_prefs_t *prefs)
+add_json_user_prefs(json_object *jso, const pgp_user_prefs_t &prefs)
{
// TODO: instead of using a string "Unknown" as a fallback for these,
// we could add a string of hex/dec (or even an int)
- if (prefs->symm_alg_count) {
+ if (!prefs.symm_algs.empty()) {
json_object *jsoarr = json_object_new_array();
if (!jsoarr) {
return false;
}
json_object_object_add(jso, "ciphers", jsoarr);
- for (unsigned i = 0; i < prefs->symm_alg_count; i++) {
- const char * name = "Unknown";
- pgp_symm_alg_t alg = (pgp_symm_alg_t) prefs->symm_algs[i];
+ for (auto alg : prefs.symm_algs) {
+ const char *name = "Unknown";
ARRAY_LOOKUP_BY_ID(symm_alg_map, type, string, alg, name);
json_object *jsoname = json_object_new_string(name);
if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
return false;
}
}
}
- if (prefs->hash_alg_count) {
+ if (!prefs.hash_algs.empty()) {
json_object *jsoarr = json_object_new_array();
if (!jsoarr) {
return false;
}
json_object_object_add(jso, "hashes", jsoarr);
- for (unsigned i = 0; i < prefs->hash_alg_count; i++) {
- const char * name = "Unknown";
- pgp_hash_alg_t alg = (pgp_hash_alg_t) prefs->hash_algs[i];
+ for (auto alg : prefs.hash_algs) {
+ const char *name = "Unknown";
ARRAY_LOOKUP_BY_ID(hash_alg_map, type, string, alg, name);
json_object *jsoname = json_object_new_string(name);
if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
return false;
}
}
}
- if (prefs->z_alg_count) {
+ if (!prefs.z_algs.empty()) {
json_object *jsoarr = json_object_new_array();
if (!jsoarr) {
return false;
}
json_object_object_add(jso, "compression", jsoarr);
- for (unsigned i = 0; i < prefs->z_alg_count; i++) {
- const char * name = "Unknown";
- pgp_compression_type_t alg = (pgp_compression_type_t) prefs->z_algs[i];
+ for (auto alg : prefs.z_algs) {
+ const char *name = "Unknown";
ARRAY_LOOKUP_BY_ID(compress_alg_map, type, string, alg, name);
json_object *jsoname = json_object_new_string(name);
if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
return false;
}
}
}
- if (prefs->ks_pref_count) {
+ if (!prefs.ks_prefs.empty()) {
json_object *jsoarr = json_object_new_array();
if (!jsoarr) {
return false;
}
json_object_object_add(jso, "key server preferences", jsoarr);
- for (unsigned i = 0; i < prefs->ks_pref_count; i++) {
- const char * name = "Unknown";
- pgp_key_server_prefs_t flag = (pgp_key_server_prefs_t) prefs->ks_prefs[i];
+ for (auto flag : prefs.ks_prefs) {
+ const char *name = "Unknown";
ARRAY_LOOKUP_BY_ID(key_server_prefs_map, type, string, flag, name);
json_object *jsoname = json_object_new_string(name);
if (!jsoname || json_object_array_add(jsoarr, jsoname)) {
return false;
}
}
}
- if (prefs->key_server) {
- if (!add_json_string_field(jso, "key server", (const char *) prefs->key_server)) {
+ if (!prefs.key_server.empty()) {
+ if (!add_json_string_field(jso, "key server", prefs.key_server.c_str())) {
return false;
}
}
return true;
}
static rnp_result_t
add_json_subsig(json_object *jso, bool is_sub, uint32_t flags, const pgp_subsig_t *subsig)
@@ -6875,19 +6863,19 @@ add_json_subsig(json_object *jso, bool i
if (!add_json_key_usage(jso, subsig->key_flags)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
// key flags (other)
if (!add_json_key_flags(jso, subsig->key_flags)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
// preferences
- const pgp_user_prefs_t *prefs = &subsig->prefs;
- if (prefs->symm_alg_count || prefs->hash_alg_count || prefs->z_alg_count ||
- prefs->ks_pref_count || prefs->key_server) {
+ const pgp_user_prefs_t &prefs = subsig->prefs;
+ if (!prefs.symm_algs.empty() || !prefs.hash_algs.empty() || !prefs.z_algs.empty() ||
+ !prefs.ks_prefs.empty() || !prefs.key_server.empty()) {
json_object *jsoprefs = json_object_new_object();
if (!jsoprefs) {
return RNP_ERROR_OUT_OF_MEMORY;
}
json_object_object_add(jso, "preferences", jsoprefs);
if (!add_json_user_prefs(jsoprefs, prefs)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
@@ -6896,56 +6884,55 @@ add_json_subsig(json_object *jso, bool i
// version
json_object *jsoversion = json_object_new_int(sig->version);
if (!jsoversion) {
return RNP_ERROR_OUT_OF_MEMORY;
}
json_object_object_add(jso, "version", jsoversion);
// signature type
const char *type = "unknown";
- ARRAY_LOOKUP_BY_ID(sig_type_map, type, string, sig->type, type);
+ ARRAY_LOOKUP_BY_ID(sig_type_map, type, string, sig->type(), type);
if (!add_json_string_field(jso, "type", type)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
// signer key type
const char *key_type = "unknown";
ARRAY_LOOKUP_BY_ID(pubkey_alg_map, type, string, sig->palg, key_type);
if (!add_json_string_field(jso, "key type", key_type)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
// hash
const char *hash = "unknown";
ARRAY_LOOKUP_BY_ID(hash_alg_map, type, string, sig->halg, hash);
if (!add_json_string_field(jso, "hash", hash)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
// creation time
- json_object *jsocreation_time = json_object_new_int64(signature_get_creation(sig));
+ json_object *jsocreation_time = json_object_new_int64(sig->creation());
if (!jsocreation_time) {
return RNP_ERROR_OUT_OF_MEMORY;
}
json_object_object_add(jso, "creation time", jsocreation_time);
// expiration (seconds)
- json_object *jsoexpiration = json_object_new_int64(signature_get_expiration(sig));
+ json_object *jsoexpiration = json_object_new_int64(sig->expiration());
if (!jsoexpiration) {
return RNP_ERROR_OUT_OF_MEMORY;
}
json_object_object_add(jso, "expiration", jsoexpiration);
// signer
json_object *jsosigner = NULL;
// TODO: add signer fingerprint as well (no support internally yet)
- if (signature_has_keyid(sig)) {
+ if (sig->has_keyid()) {
jsosigner = json_object_new_object();
if (!jsosigner) {
return RNP_ERROR_OUT_OF_MEMORY;
}
char keyid[PGP_KEY_ID_SIZE * 2 + 1];
- pgp_key_id_t signer = {};
- if (!signature_get_keyid(sig, signer) ||
- !rnp_hex_encode(
+ pgp_key_id_t signer = sig->keyid();
+ if (!rnp_hex_encode(
signer.data(), signer.size(), keyid, sizeof(keyid), RNP_HEX_UPPERCASE)) {
return RNP_ERROR_GENERIC;
}
if (!add_json_string_field(jsosigner, "keyid", keyid)) {
json_object_put(jsosigner);
return RNP_ERROR_OUT_OF_MEMORY;
}
}
--- a/third_party/rnp/src/lib/types.h
+++ b/third_party/rnp/src/lib/types.h
@@ -107,16 +107,35 @@ template <> struct hash<pgp_fingerprint_
}
};
} // namespace std
typedef std::array<uint8_t, PGP_KEY_GRIP_SIZE> pgp_key_grip_t;
typedef std::array<uint8_t, PGP_KEY_ID_SIZE> pgp_key_id_t;
+namespace rnp {
+class rnp_exception : public std::exception {
+ rnp_result_t code_;
+
+ public:
+ rnp_exception(rnp_result_t code = RNP_ERROR_GENERIC) : code_(code){};
+ virtual const char *
+ what() const throw()
+ {
+ return "rnp_exception";
+ };
+ rnp_result_t
+ code()
+ {
+ return code_;
+ };
+};
+} // namespace rnp
+
/**
* Type to keep public/secret key mpis without any openpgp-dependent data.
*/
typedef struct pgp_key_material_t {
pgp_pubkey_alg_t alg; /* algorithm of the key */
bool secret; /* secret part of the key material is populated */
union {
@@ -147,34 +166,35 @@ typedef struct pgp_encrypted_material_t
pgp_rsa_encrypted_t rsa;
pgp_eg_encrypted_t eg;
pgp_sm2_encrypted_t sm2;
pgp_ecdh_encrypted_t ecdh;
};
} pgp_encrypted_material_t;
typedef struct pgp_s2k_t {
- pgp_s2k_usage_t usage;
+ pgp_s2k_usage_t usage{};
/* below fields may not all be valid, depending on the usage field above */
- pgp_s2k_specifier_t specifier;
- pgp_hash_alg_t hash_alg;
+ pgp_s2k_specifier_t specifier{};
+ pgp_hash_alg_t hash_alg{};
uint8_t salt[PGP_SALT_SIZE];
- unsigned iterations;
-
+ unsigned iterations{};
/* GnuPG custom s2k data */
- pgp_s2k_gpg_extension_t gpg_ext_num;
- uint8_t gpg_serial_len;
+ pgp_s2k_gpg_extension_t gpg_ext_num{};
+ uint8_t gpg_serial_len{};
uint8_t gpg_serial[16];
+ /* Experimental s2k data */
+ std::vector<uint8_t> experimental{};
} pgp_s2k_t;
typedef struct pgp_key_protection_t {
- pgp_s2k_t s2k; /* string-to-key kdf params */
- pgp_symm_alg_t symm_alg; /* symmetric alg */
- pgp_cipher_mode_t cipher_mode; /* block cipher mode */
+ pgp_s2k_t s2k{}; /* string-to-key kdf params */
+ pgp_symm_alg_t symm_alg{}; /* symmetric alg */
+ pgp_cipher_mode_t cipher_mode{}; /* block cipher mode */
uint8_t iv[PGP_MAX_BLOCK_SIZE];
} pgp_key_protection_t;
/** Struct to hold a key packet. May contain public or private key/subkey */
typedef struct pgp_key_pkt_t {
pgp_pkt_type_t tag; /* packet tag: public key/subkey or private key/subkey */
pgp_version_t version; /* Key packet version */
uint32_t creation_time; /* Key creation time */
@@ -282,21 +302,17 @@ typedef struct pgp_sig_subpkt_t {
const char *uid;
unsigned len;
} signer; /* 5.2.3.22. Signer's User ID */
struct {
pgp_revocation_type_t code;
const char * str;
unsigned len;
} revocation_reason; /* 5.2.3.23. Reason for Revocation */
- struct {
- bool mdc;
- bool aead;
- bool key_v5;
- } features; /* 5.2.3.24. Features */
+ uint8_t features; /* 5.2.3.24. Features */
struct {
pgp_pubkey_alg_t pkalg;
pgp_hash_alg_t halg;
uint8_t * hash;
unsigned hlen;
} sig_target; /* 5.2.3.25. Signature Target */
pgp_signature_t *sig; /* 5.2.3.27. Embedded Signature */
struct {
@@ -311,46 +327,296 @@ typedef struct pgp_sig_subpkt_t {
parsed(false), fields({}){};
pgp_sig_subpkt_t(const pgp_sig_subpkt_t &src);
pgp_sig_subpkt_t(pgp_sig_subpkt_t &&src);
pgp_sig_subpkt_t &operator=(pgp_sig_subpkt_t &&src);
pgp_sig_subpkt_t &operator=(const pgp_sig_subpkt_t &src);
~pgp_sig_subpkt_t();
} pgp_sig_subpkt_t;
+typedef struct pgp_one_pass_sig_t pgp_one_pass_sig_t;
+
typedef struct pgp_signature_t {
+ private:
+ pgp_sig_type_t type_;
+ std::vector<uint8_t> preferred(pgp_sig_subpacket_type_t type) const;
+ void set_preferred(const std::vector<uint8_t> &data, pgp_sig_subpacket_type_t type);
+
+ public:
pgp_version_t version;
/* common v3 and v4 fields */
- pgp_sig_type_t type;
pgp_pubkey_alg_t palg;
pgp_hash_alg_t halg;
uint8_t lbits[2];
uint8_t * hashed_data;
size_t hashed_len;
uint8_t * material_buf; /* raw signature material */
size_t material_len; /* raw signature material length */
/* v3 - only fields */
uint32_t creation_time;
pgp_key_id_t signer;
/* v4 - only fields */
std::vector<pgp_sig_subpkt_t> subpkts;
pgp_signature_t()
- : version(PGP_VUNKNOWN), type(PGP_SIG_BINARY), palg(PGP_PKA_NOTHING),
+ : type_(PGP_SIG_BINARY), version(PGP_VUNKNOWN), palg(PGP_PKA_NOTHING),
halg(PGP_HASH_UNKNOWN), hashed_data(NULL), hashed_len(0), material_buf(NULL),
material_len(0), creation_time(0){};
pgp_signature_t(const pgp_signature_t &src);
pgp_signature_t(pgp_signature_t &&src);
pgp_signature_t &operator=(pgp_signature_t &&src);
pgp_signature_t &operator=(const pgp_signature_t &src);
bool operator==(const pgp_signature_t &src) const;
bool operator!=(const pgp_signature_t &src) const;
~pgp_signature_t();
+
+ /* @brief Get signature's type */
+ pgp_sig_type_t
+ type() const
+ {
+ return type_;
+ };
+ void
+ set_type(pgp_sig_type_t atype)
+ {
+ type_ = atype;
+ };
+
+ /**
+ * @brief Get v4 signature's subpacket of the specified type and hashedness.
+ * @param stype subpacket type.
+ * @param hashed If true (default), then will search for subpacket only in hashed (i.e.
+ * covered by signature) area, otherwise will search in both hashed and non-hashed areas.
+ * @return pointer to the subpacket, or NULL if subpacket was not found.
+ */
+ pgp_sig_subpkt_t * get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true);
+ const pgp_sig_subpkt_t *get_subpkt(pgp_sig_subpacket_type_t stype,
+ bool hashed = true) const;
+ /* @brief Check whether v4 signature has subpacket of the specified type/hashedness */
+ bool has_subpkt(pgp_sig_subpacket_type_t stype, bool hashed = true) const;
+ /* @brief Check whether signature has signing key id (via v3 field, or v4 key id/key fp
+ * subpacket) */
+ bool has_keyid() const;
+ /**
+ * @brief Get signer's key id if available. Availability may be checked via has_keyid().
+ * @return signer's key id if available, or throws an exception otherwise.
+ */
+ pgp_key_id_t keyid() const;
+ /** @brief Set the signer's key id for the signature being populated. Version should be set
+ * prior of setting key id. */
+ void set_keyid(const pgp_key_id_t &id);
+ /**
+ * @brief Check whether signature has valid issuer fingerprint subpacket.
+ * @return true if there is one, and it can be safely returned via keyfp() method or false
+ * otherwise.
+ */
+ bool has_keyfp() const;
+ /**
+ * @brief Get signing key's fingerprint if it is available. Availability may be checked via
+ * has_keyfp() method.
+ * @return fingerprint or throws an error if it is unavailable.
+ */
+ pgp_fingerprint_t keyfp() const;
+
+ /** @brief Set signing key's fingerprint. Works only for signatures with version 4 and up,
+ * so version should be set prior to fingerprint. */
+ void set_keyfp(const pgp_fingerprint_t &fp);
+
+ /**
+ * @brief Get signature's creation time
+ * @return time in seconds since the Jan 1, 1970 UTC. 0 is the default value and returned
+ * even if creation time is not available
+ */
+ uint32_t creation() const;
+
+ /**
+ * @brief Set signature's creation time
+ * @param ctime creation time in seconds since the Jan 1, 1970 UTC.
+ */
+ void set_creation(uint32_t ctime);
+
+ /**
+ * @brief Get the signature's expiration time
+ * @return expiration time in seconds since the creation time. 0 if signature never
+ * expires.
+ */
+ uint32_t expiration() const;
+
+ /**
+ * @brief Set the signature's expiration time
+ * @param etime expiration time
+ */
+ void set_expiration(uint32_t etime);
+
+ /**
+ * @brief Get the key expiration time
+ * @return expiration time in seconds since the creation time. 0 if key never expires.
+ */
+ uint32_t key_expiration() const;
+
+ /**
+ * @brief Set the key expiration time
+ * @param etime expiration time
+ */
+ void set_key_expiration(uint32_t etime);
+
+ /**
+ * @brief Get the key flags
+ * @return byte of key flags. If there is no corresponding subpackets then 0 is returned.
+ */
+ uint8_t key_flags() const;
+
+ /**
+ * @brief Set the key flags
+ * @param flags byte of key flags
+ */
+ void set_key_flags(uint8_t flags);
+
+ /**
+ * @brief Get the primary user id flag
+ * @return true if user id is marked as primary or false otherwise
+ */
+ bool primary_uid() const;
+
+ /**
+ * @brief Set the primary user id flag
+ * @param primary true if user id should be marked as primary
+ */
+ void set_primary_uid(bool primary);
+
+ /** @brief Get preferred symmetric algorithms if any. If there are no ones then empty
+ * vector is returned. */
+ std::vector<uint8_t> preferred_symm_algs() const;
+
+ /** @brief Set the preferred symmetric algorithms. If empty vector is passed then
+ * corresponding subpacket is deleted. */
+ void set_preferred_symm_algs(const std::vector<uint8_t> &algs);
+
+ /** @brief Get preferred hash algorithms if any. If there are no ones then empty vector is
+ * returned.*/
+ std::vector<uint8_t> preferred_hash_algs() const;
+
+ /** @brief Set the preferred hash algorithms. If empty vector is passed then corresponding
+ * subpacket is deleted. */
+ void set_preferred_hash_algs(const std::vector<uint8_t> &algs);
+
+ /** @brief Get preferred compression algorithms if any. If there are no ones then empty
+ * vector is returned.*/
+ std::vector<uint8_t> preferred_z_algs() const;
+
+ /** @brief Set the preferred compression algorithms. If empty vector is passed then
+ * corresponding subpacket is deleted. */
+ void set_preferred_z_algs(const std::vector<uint8_t> &algs);
+
+ /** @brief Get key server preferences flags. If subpacket is not available then 0 is
+ * returned. */
+ uint8_t key_server_prefs() const;
+
+ /** @brief Set key server preferences flags. */
+ void set_key_server_prefs(uint8_t prefs);
+
+ /** @brief Get preferred key server URI, if available. Otherwise empty string is returned.
+ */
+ std::string key_server() const;
+
+ /** @brief Set preferred key server URI. If it is empty string then subpacket is deleted if
+ * it is available. */
+ void set_key_server(const std::string &uri);
+
+ /** @brief Get trust level, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14.
+ * for the detailed information on trust level and amount.
+ */
+ uint8_t trust_level() const;
+
+ /** @brief Get trust amount, if available. Otherwise will return 0. See RFC 4880, 5.2.3.14.
+ * for the detailed information on trust level and amount.
+ */
+ uint8_t trust_amount() const;
+
+ /** @brief Set the trust level and amount. See RFC 4880, 5.2.3.14.
+ * for the detailed information on trust level and amount.
+ */
+ void set_trust(uint8_t level, uint8_t amount);
+
+ /** @brief check whether signature is revocable. True by default.
+ */
+ bool revocable() const;
+
+ /** @brief Set the signature's revocability status.
+ */
+ void set_revocable(bool status);
+
+ /** @brief Get the key/subkey revocation reason in humand-readable form. If there is no
+ * revocation reason subpacket, then empty string will be returned.
+ */
+ std::string revocation_reason() const;
+
+ /** @brief Get the key/subkey revocation code. If there is no revocation reason subpacket,
+ * then PGP_REVOCATION_NO_REASON will be rerturned. See the RFC 4880, 5.2.3.24 for
+ * the detailed explanation.
+ */
+ pgp_revocation_type_t revocation_code() const;
+
+ /** @brief Set the revocation reason and code for key/subkey revocation signature. See the
+ * RFC 4880, 5.2.3.24 for the detailed explanation.
+ */
+ void set_revocation_reason(pgp_revocation_type_t code, const std::string &reason);
+
+ /**
+ * @brief Check whether signer's key supports certain feature(s). Makes sense only for
+ * self-signature, for more details see the RFC 4880bis, 5.2.3.25. If there is no
+ * corresponding subpacket then false will be returned.
+ * @param flags one or more flags, combined via bitwise OR operation.
+ * @return true if key is claimed to support all of the features listed in flags, or false
+ * otherwise
+ */
+ bool key_has_features(pgp_key_feature_t flags) const;
+
+ /**
+ * @brief Set the features supported by the signer's key, makes sense only for
+ * self-signature. For more details see the RFC 4880bis, 5.2.3.25.
+ * @param flags one or more flags, combined via bitwise OR operation.
+ */
+ void set_key_features(pgp_key_feature_t flags);
+
+ /** @brief Get signer's user id, if available. Otherwise empty string is returned. See the
+ * RFC 4880bis, 5.2.3.23 for details.
+ */
+ std::string signer_uid() const;
+
+ /**
+ * @brief Set the signer's uid, responcible for the signature creation. See the RFC
+ * 4880bis, 5.2.3.23 for details.
+ */
+ void set_signer_uid(const std::string &uid);
+
+ /**
+ * @brief Add subpacket of the specified type to v4 signature
+ * @param type type of the subpacket
+ * @param datalen length of the subpacket body
+ * @param reuse replace already existing subpacket of the specified type if any
+ * @return reference to the subpacket structure or throws an exception
+ */
+ pgp_sig_subpkt_t &add_subpkt(pgp_sig_subpacket_type_t type, size_t datalen, bool reuse);
+
+ /**
+ * @brief Remove signature's subpacket
+ * @param subpkt subpacket to remove. If not in the subpackets list then no action is
+ * taken.
+ */
+ void remove_subpkt(pgp_sig_subpkt_t *subpkt);
+
+ /**
+ * @brief Check whether signature packet matches one-pass signature packet.
+ * @param onepass reference to the read one-pass signature packet
+ * @return true if sig corresponds to onepass or false otherwise
+ */
+ bool matches_onepass(const pgp_one_pass_sig_t &onepass) const;
} pgp_signature_t;
/** pgp_rawpacket_t */
typedef struct pgp_rawpacket_t {
pgp_pkt_type_t tag;
std::vector<uint8_t> raw;
pgp_rawpacket_t() = default;
@@ -399,78 +665,76 @@ typedef enum {
PGP_LDT_TEXT = 't',
PGP_LDT_UTF8 = 'u',
PGP_LDT_LOCAL = 'l',
PGP_LDT_LOCAL2 = '1'
} pgp_litdata_enum;
/** public-key encrypted session key packet */
typedef struct pgp_pk_sesskey_t {
- unsigned version;
- pgp_key_id_t key_id;
- pgp_pubkey_alg_t alg;
+ unsigned version{};
+ pgp_key_id_t key_id{};
+ pgp_pubkey_alg_t alg{};
- pgp_encrypted_material_t material;
+ pgp_encrypted_material_t material{};
} pgp_pk_sesskey_t;
/** pkp_sk_sesskey_t */
-typedef struct {
- unsigned version;
- pgp_symm_alg_t alg;
- pgp_s2k_t s2k;
- uint8_t enckey[PGP_MAX_KEY_SIZE + PGP_AEAD_MAX_TAG_LEN + 1];
- unsigned enckeylen;
+typedef struct pgp_sk_sesskey_t {
+ unsigned version{};
+ pgp_symm_alg_t alg{};
+ pgp_s2k_t s2k{};
+ uint8_t enckey[PGP_MAX_KEY_SIZE + PGP_AEAD_MAX_TAG_LEN + 1]{};
+ unsigned enckeylen{};
/* v5 specific fields */
- pgp_aead_alg_t aalg;
- uint8_t iv[PGP_MAX_BLOCK_SIZE];
- unsigned ivlen;
+ pgp_aead_alg_t aalg{};
+ uint8_t iv[PGP_MAX_BLOCK_SIZE]{};
+ unsigned ivlen{};
} pgp_sk_sesskey_t;
/* user revocation info */
typedef struct pgp_revoke_t {
uint32_t uid; /* index in uid array */
pgp_revocation_type_t code; /* revocation code */
std::string reason; /* revocation reason */
} pgp_revoke_t;
typedef struct pgp_user_prefs_t {
// preferred symmetric algs (pgp_symm_alg_t)
- uint8_t *symm_algs;
- size_t symm_alg_count;
+ std::vector<uint8_t> symm_algs{};
// preferred hash algs (pgp_hash_alg_t)
- uint8_t *hash_algs;
- size_t hash_alg_count;
+ std::vector<uint8_t> hash_algs{};
// preferred compression algs (pgp_compression_type_t)
- uint8_t *z_algs;
- size_t z_alg_count;
+ std::vector<uint8_t> z_algs{};
// key server preferences (pgp_key_server_prefs_t)
- uint8_t *ks_prefs;
- size_t ks_pref_count;
+ std::vector<uint8_t> ks_prefs{};
// preferred key server
- uint8_t *key_server;
+ std::string key_server{};
+
+ void set_symm_algs(const std::vector<uint8_t> &algs);
+ void add_symm_alg(pgp_symm_alg_t alg);
+ void set_hash_algs(const std::vector<uint8_t> &algs);
+ void add_hash_alg(pgp_hash_alg_t alg);
+ void set_z_algs(const std::vector<uint8_t> &algs);
+ void add_z_alg(pgp_compression_type_t alg);
+ void set_ks_prefs(const std::vector<uint8_t> &prefs);
+ void add_ks_pref(pgp_key_server_prefs_t pref);
} pgp_user_prefs_t;
/** information about the signature */
typedef struct pgp_subsig_t {
uint32_t uid; /* index in userid array in key for certification sig */
pgp_signature_t sig; /* signature packet */
pgp_rawpacket_t rawpkt; /* signature's rawpacket */
uint8_t trustlevel; /* level of trust */
uint8_t trustamount; /* amount of trust */
uint8_t key_flags; /* key flags for certification/direct key sig */
pgp_user_prefs_t prefs; /* user preferences for certification sig */
bool validated; /* signature was validated */
bool valid; /* signature was validated and is valid */
-
- pgp_subsig_t() = default;
- pgp_subsig_t(const pgp_subsig_t &src);
- pgp_subsig_t(pgp_subsig_t &&src);
- pgp_subsig_t &operator=(pgp_subsig_t &&src);
- pgp_subsig_t &operator=(const pgp_subsig_t &src);
- ~pgp_subsig_t();
} pgp_subsig_t;
typedef struct pgp_userid_t {
pgp_userid_pkt_t pkt; /* User ID or User Attribute packet as it was loaded */
pgp_rawpacket_t rawpkt; /* Raw packet contents */
std::string str; /* Human-readable representation of the userid */
} pgp_userid_t;
@@ -503,31 +767,31 @@ typedef struct rnp_keygen_crypto_params_
struct rnp_keygen_ecc_params_t ecc;
struct rnp_keygen_rsa_params_t rsa;
struct rnp_keygen_dsa_params_t dsa;
struct rnp_keygen_elgamal_params_t elgamal;
};
} rnp_keygen_crypto_params_t;
typedef struct rnp_selfsig_cert_info_t {
- uint8_t userid[MAX_ID_LENGTH]; /* userid, required */
- uint8_t key_flags; /* key flags */
- uint32_t key_expiration; /* key expiration time (sec), 0 = no expiration */
- pgp_user_prefs_t prefs; /* user preferences, optional */
- unsigned primary : 1; /* mark this as the primary user id */
+ uint8_t userid[MAX_ID_LENGTH]{}; /* userid, required */
+ uint8_t key_flags{}; /* key flags */
+ uint32_t key_expiration{}; /* key expiration time (sec), 0 = no expiration */
+ pgp_user_prefs_t prefs{}; /* user preferences, optional */
+ bool primary : 1; /* mark this as the primary user id */
} rnp_selfsig_cert_info_t;
typedef struct rnp_selfsig_binding_info_t {
uint8_t key_flags;
uint32_t key_expiration;
} rnp_selfsig_binding_info_t;
typedef struct rnp_keygen_primary_desc_t {
- rnp_keygen_crypto_params_t crypto;
- rnp_selfsig_cert_info_t cert;
+ rnp_keygen_crypto_params_t crypto{};
+ rnp_selfsig_cert_info_t cert{};
} rnp_keygen_primary_desc_t;
typedef struct rnp_keygen_subkey_desc_t {
rnp_keygen_crypto_params_t crypto;
rnp_selfsig_binding_info_t binding;
} rnp_keygen_subkey_desc_t;
typedef struct rnp_key_protection_params_t {
--- a/third_party/rnp/src/lib/version.h
+++ b/third_party/rnp/src/lib/version.h
@@ -23,19 +23,19 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#define RNP_VERSION_MAJOR 0
#define RNP_VERSION_MINOR 13
#define RNP_VERSION_PATCH 1
#define RNP_VERSION_STRING "0.13.1"
-#define RNP_VERSION_STRING_FULL "0.13.1+git20200913.49a675e3.MZLA"
+#define RNP_VERSION_STRING_FULL "0.13.1+git20201030.a2c5ecd3.MZLA"
-#define RNP_VERSION_COMMIT_TIMESTAMP 1600015711
+#define RNP_VERSION_COMMIT_TIMESTAMP 1604058640
// using a 32-bit version with 10 bits per component
#define RNP_VERSION_COMPONENT_MASK 0x3ff
#define RNP_VERSION_MAJOR_SHIFT 20
#define RNP_VERSION_MINOR_SHIFT 10
#define RNP_VERSION_PATCH_SHIFT 0
#define RNP_VERSION_CODE_FOR(major, minor, patch) \
(((major & RNP_VERSION_COMPONENT_MASK) << RNP_VERSION_MAJOR_SHIFT) | \
--- a/third_party/rnp/src/librekey/key_store_g10.cpp
+++ b/third_party/rnp/src/librekey/key_store_g10.cpp
@@ -42,35 +42,16 @@
#define G10_CBC_IV_SIZE 16
#define G10_OCB_NONCE_SIZE 12
#define G10_SHA1_HASH_SIZE 20
#define G10_PROTECTED_AT_SIZE 15
-typedef struct {
- size_t len;
- uint8_t *bytes;
-} s_exp_block_t;
-
-typedef struct sub_element_t sub_element_t;
-
-typedef struct {
- list sub_elements; // list of sub_element_t
-} s_exp_t;
-
-struct sub_element_t {
- bool is_block;
- union {
- s_exp_t s_exp;
- s_exp_block_t block;
- };
-};
-
typedef struct format_info {
pgp_symm_alg_t cipher;
pgp_cipher_mode_t cipher_mode;
pgp_hash_alg_t hash_alg;
const char * botan_cipher_name;
size_t cipher_block_size;
const char * g10_type;
size_t iv_size;
@@ -169,17 +150,17 @@ parse_format(const char *format, size_t
if (strlen(formats[i].g10_type) == format_len &&
!strncmp(formats[i].g10_type, format, format_len)) {
return &formats[i];
}
}
return NULL;
}
-static void
+void
destroy_s_exp(s_exp_t *s_exp)
{
if (s_exp == NULL) {
return;
}
for (list_item *li = list_front(s_exp->sub_elements); li; li = list_next(li)) {
sub_element_t *sub_el = (sub_element_t *) li;
@@ -257,29 +238,34 @@ add_sub_sexp_to_sexp(s_exp_t *s_exp, s_e
* Supported format: (1:a2:ab(3:asd1:a))
* It should be parsed to:
* - a
* - ab
* + - asd
* - a
*
*/
-static bool
-parse_sexp(s_exp_t *s_exp, const char **r_bytes, size_t *r_length)
+bool
+parse_sexp(s_exp_t *s_exp, const char **r_bytes, size_t *r_length, size_t depth)
{
size_t length = *r_length;
const char *bytes = *r_bytes;
s_exp_t new_s_exp = {0};
if (!bytes || !length) {
RNP_LOG("empty s-exp");
return true;
}
+ if (depth > SXP_MAX_DEPTH) {
+ RNP_LOG("sxp maximum recursion depth exceeded");
+ return false;
+ }
+
if (*bytes != '(') { // doesn't start from (
return false;
}
bytes++;
length--;
do {
@@ -291,17 +277,17 @@ parse_sexp(s_exp_t *s_exp, const char **
if (*bytes == '(') {
s_exp_t *new_sub_s_exp;
if (!add_sub_sexp_to_sexp(&new_s_exp, &new_sub_s_exp)) {
return false;
}
- if (!parse_sexp(new_sub_s_exp, &bytes, &length)) {
+ if (!parse_sexp(new_sub_s_exp, &bytes, &length, depth + 1)) {
destroy_s_exp(&new_s_exp);
return false;
}
if (!length) {
RNP_LOG("No space for closing ) left.");
destroy_s_exp(&new_s_exp);
return false;
--- a/third_party/rnp/src/librekey/key_store_g10.h
+++ b/third_party/rnp/src/librekey/key_store_g10.h
@@ -25,17 +25,40 @@
*/
#ifndef RNP_KEY_STORE_G10_H
#define RNP_KEY_STORE_G10_H
#include <rekey/rnp_key_store.h>
#include <librepgp/stream-common.h>
+#define SXP_MAX_DEPTH 30
+
+typedef struct {
+ size_t len;
+ uint8_t *bytes;
+} s_exp_block_t;
+
+typedef struct sub_element_t sub_element_t;
+
+typedef struct {
+ list sub_elements; // list of sub_element_t
+} s_exp_t;
+
+struct sub_element_t {
+ bool is_block;
+ union {
+ s_exp_t s_exp;
+ s_exp_block_t block;
+ };
+};
+
bool rnp_key_store_g10_from_src(rnp_key_store_t *, pgp_source_t *, const pgp_key_provider_t *);
bool rnp_key_store_g10_key_to_dst(pgp_key_t *, pgp_dest_t *);
bool g10_write_seckey(pgp_dest_t *dst, pgp_key_pkt_t *seckey, const char *password);
pgp_key_pkt_t *g10_decrypt_seckey(const uint8_t * data,
size_t data_len,
const pgp_key_pkt_t *pubkey,
const char * password);
+bool parse_sexp(s_exp_t *s_exp, const char **r_bytes, size_t *r_length, size_t depth = 1);
+void destroy_s_exp(s_exp_t *s_exp);
#endif // RNP_KEY_STORE_G10_H
--- a/third_party/rnp/src/librekey/key_store_kbx.cpp
+++ b/third_party/rnp/src/librekey/key_store_kbx.cpp
@@ -589,17 +589,17 @@ rnp_key_store_kbx_write_pgp(rnp_key_stor
if (!pbuf(&memdst, pgp_key_get_fp(subkey).fingerprint, PGP_FINGERPRINT_SIZE) ||
!pu32(&memdst, memdst.writeb - 8) || // offset to keyid (part of fpr for V4)
!pu16(&memdst, 0) || // flags, not used by GnuPG
!pu16(&memdst, 0)) { // RFU
goto finish;
}
// load signature expirations while we're at it
for (i = 0; i < pgp_key_get_subsig_count(subkey); i++) {
- expiration = signature_get_key_expiration(&pgp_key_get_subsig(subkey, i)->sig);
+ expiration = pgp_key_get_subsig(subkey, i)->sig.key_expiration();
if (list_append(&subkey_sig_expirations, &expiration, sizeof(expiration)) ==
NULL) {
goto finish;
};
}
}
if (!pu16(&memdst, 0)) { // Zero size of serial number
@@ -630,17 +630,17 @@ rnp_key_store_kbx_write_pgp(rnp_key_stor
}
if (!pu16(&memdst, pgp_key_get_subsig_count(key) + list_length(subkey_sig_expirations)) ||
!pu16(&memdst, 4)) {
goto finish;
}
for (i = 0; i < pgp_key_get_subsig_count(key); i++) {
- if (!pu32(&memdst, signature_get_key_expiration(&pgp_key_get_subsig(key, i)->sig))) {
+ if (!pu32(&memdst, pgp_key_get_subsig(key, i)->sig.key_expiration())) {
goto finish;
}
}
for (list_item *expiration_entry = list_front(subkey_sig_expirations); expiration_entry;
expiration_entry = list_next(expiration_entry)) {
expiration = *(uint32_t *) expiration_entry;
if (!pu32(&memdst, expiration)) {
goto finish;
--- a/third_party/rnp/src/librekey/key_store_pgp.cpp
+++ b/third_party/rnp/src/librekey/key_store_pgp.cpp
@@ -71,17 +71,17 @@ bool
rnp_key_add_signature(pgp_key_t *key, const pgp_signature_t *sig)
{
pgp_subsig_t *subsig = pgp_key_add_subsig(key);
if (!subsig) {
RNP_LOG("Failed to add subsig");
return false;
}
/* setup subsig and key from signature */
- if (!pgp_subsig_from_signature(subsig, sig)) {
+ if (!pgp_subsig_from_signature(*subsig, *sig)) {
return false;
}
subsig->uid = pgp_key_get_userid_count(key) - 1;
return true;
}
static bool
rnp_key_add_signatures(pgp_key_t *key, pgp_signature_list_t &signatures)
@@ -235,35 +235,63 @@ rnp_key_from_transferable_subkey(pgp_key
if (primary && !pgp_key_link_subkey_fp(primary, subkey)) {
return false;
}
return true;
}
rnp_result_t
-rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring, pgp_source_t *src)
+rnp_key_store_pgp_read_key_from_src(rnp_key_store_t &keyring,
+ pgp_source_t & src,
+ bool skiperrors)
+{
+ pgp_transferable_key_t key;
+ rnp_result_t ret = process_pgp_key_auto(src, key, true, skiperrors);
+
+ if (ret && (!skiperrors || (ret != RNP_ERROR_BAD_FORMAT))) {
+ return ret;
+ }
+
+ /* check whether we have primary key */
+ if (key.key.tag != PGP_PKT_RESERVED) {
+ return rnp_key_store_add_transferable_key(&keyring, &key) ? RNP_SUCCESS :
+ RNP_ERROR_BAD_STATE;
+ }
+
+ /* we just skipped some unexpected packets and read nothing */
+ if (key.subkeys.empty()) {
+ return RNP_SUCCESS;
+ }
+
+ return rnp_key_store_add_transferable_subkey(&keyring, &key.subkeys.front(), NULL) ?
+ RNP_SUCCESS :
+ RNP_ERROR_BAD_STATE;
+}
+
+rnp_result_t
+rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring, pgp_source_t *src, bool skiperrors)
{
rnp_result_t ret = RNP_ERROR_GENERIC;
/* check whether we have transferable subkey in source */
if (is_subkey_pkt(stream_pkt_type(src))) {
pgp_transferable_subkey_t tskey;
- ret = process_pgp_subkey(*src, tskey, keyring->skip_parsing_errors);
+ ret = process_pgp_subkey(*src, tskey, skiperrors);
if (ret) {
return ret;
}
return rnp_key_store_add_transferable_subkey(keyring, &tskey, NULL) ?
RNP_SUCCESS :
RNP_ERROR_BAD_STATE;
}
/* process armored or raw transferable key packets sequence(s) */
pgp_key_sequence_t keys;
- if ((ret = process_pgp_keys(src, keys, keyring->skip_parsing_errors))) {
+ if ((ret = process_pgp_keys(src, keys, skiperrors))) {
return ret;
}
for (auto &key : keys.keys) {
if (!rnp_key_store_add_transferable_key(keyring, &key)) {
return RNP_ERROR_BAD_STATE;
}
}
--- a/third_party/rnp/src/librekey/key_store_pgp.h
+++ b/third_party/rnp/src/librekey/key_store_pgp.h
@@ -54,17 +54,25 @@
#ifndef KEY_STORE_PGP_H_
#define KEY_STORE_PGP_H_
#include <rekey/rnp_key_store.h>
#include <librepgp/stream-common.h>
#include <librepgp/stream-key.h>
-rnp_result_t rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring, pgp_source_t *src);
+/* Read the whole keyring from the src, processing all available keys or subkeys */
+rnp_result_t rnp_key_store_pgp_read_from_src(rnp_key_store_t *keyring,
+ pgp_source_t * src,
+ bool skiperrors = false);
+
+/* Read the first key or subkey from the src */
+rnp_result_t rnp_key_store_pgp_read_key_from_src(rnp_key_store_t &keyring,
+ pgp_source_t & src,
+ bool skiperrors = false);
bool rnp_key_store_pgp_write_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst);
bool rnp_key_store_add_transferable_subkey(rnp_key_store_t * keyring,
pgp_transferable_subkey_t *tskey,
pgp_key_t * pkey);
bool rnp_key_store_add_transferable_key(rnp_key_store_t * keyring,
--- a/third_party/rnp/src/librekey/rnp_key_store.cpp
+++ b/third_party/rnp/src/librekey/rnp_key_store.cpp
@@ -364,46 +364,40 @@ rnp_key_store_merge_key(pgp_key_t *dst,
*dst = std::move(tmpkey);
return true;
}
static bool
rnp_key_store_refresh_subkey_grips(rnp_key_store_t *keyring, pgp_key_t *key)
{
- pgp_key_id_t keyid = {};
- pgp_fingerprint_t keyfp = {};
-
if (pgp_key_is_subkey(key)) {
RNP_LOG("wrong argument");
return false;
}
for (auto &skey : keyring->keys) {
bool found = false;
/* if we have primary_grip then we also added to subkey_grips */
if (!pgp_key_is_subkey(&skey) || pgp_key_has_primary_fp(&skey)) {
continue;
}
for (unsigned i = 0; i < pgp_key_get_subsig_count(&skey); i++) {
const pgp_subsig_t *subsig = pgp_key_get_subsig(&skey, i);
- if (subsig->sig.type != PGP_SIG_SUBKEY) {
+ if (subsig->sig.type() != PGP_SIG_SUBKEY) {
continue;
}
-
- if (signature_get_keyfp(&subsig->sig, keyfp) && (pgp_key_get_fp(key) == keyfp)) {
+ if (subsig->sig.has_keyfp() && (pgp_key_get_fp(key) == subsig->sig.keyfp())) {
found = true;
break;
}
-
- if (signature_get_keyid(&subsig->sig, keyid) &&
- (pgp_key_get_keyid(key) != keyid)) {
+ if (subsig->sig.has_keyid() && (pgp_key_get_keyid(key) == subsig->sig.keyid())) {
found = true;
break;
}
}
if (found && !pgp_key_link_subkey_fp(key, &skey)) {
return false;
}
@@ -503,27 +497,27 @@ rnp_key_store_add_key(rnp_key_store_t *k
added_key = &keyring->keys.back();
keyring->keybyfp[pgp_key_get_fp(srckey)] = std::prev(keyring->keys.end());
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return NULL;
}
try {
*added_key = pgp_key_t(*srckey);
+ /* primary key may be added after subkeys, so let's handle this case correctly */
+ if (!rnp_key_store_refresh_subkey_grips(keyring, added_key)) {
+ RNP_LOG_KEY("failed to refresh subkey grips for %s", added_key);
+ }
} catch (const std::exception &e) {
RNP_LOG_KEY("key %s copying failed", srckey);
RNP_LOG("%s", e.what());
keyring->keys.pop_back();
keyring->keybyfp.erase(pgp_key_get_fp(srckey));
return NULL;
}
- /* primary key may be added after subkeys, so let's handle this case correctly */
- if (!rnp_key_store_refresh_subkey_grips(keyring, added_key)) {
- RNP_LOG_KEY("failed to refresh subkey grips for %s", added_key);
- }
}
RNP_DLOG("keyc %lu", (long unsigned) rnp_key_store_get_key_count(keyring));
/* validate all added keys if not disabled or already validated */
if (!keyring->disable_validation && !added_key->validated) {
pgp_key_revalidate_updated(added_key, keyring);
} else if (!pgp_key_refresh_data(added_key)) {
RNP_LOG_KEY("Failed to refresh key %s data", srckey);
@@ -568,35 +562,35 @@ rnp_key_store_import_key(rnp_key_store_t
return exkey;
}
pgp_key_t *
rnp_key_store_get_signer_key(rnp_key_store_t *store, const pgp_signature_t *sig)
{
pgp_key_search_t search = {};
// prefer using the issuer fingerprint when available
- if (signature_has_keyfp(sig) && signature_get_keyfp(sig, search.by.fingerprint)) {
+ if (sig->has_keyfp()) {
+ search.by.fingerprint = sig->keyfp();
search.type = PGP_KEY_SEARCH_FINGERPRINT;
return rnp_key_store_search(store, &search, NULL);
}
// fall back to key id search
- if (signature_get_keyid(sig, search.by.keyid)) {
- search.type = PGP_KEY_SEARCH_KEYID;
+ if (sig->has_keyid()) {
+ search.by.keyid = sig->keyid();
return rnp_key_store_search(store, &search, NULL);
}
return NULL;
}
static pgp_sig_import_status_t
rnp_key_store_import_subkey_signature(rnp_key_store_t * keyring,
pgp_key_t * key,
const pgp_signature_t *sig)
{
- pgp_sig_type_t sigtype = signature_get_type(sig);
- if ((sigtype != PGP_SIG_SUBKEY) && (sigtype != PGP_SIG_REV_SUBKEY)) {
+ if ((sig->type() != PGP_SIG_SUBKEY) && (sig->type() != PGP_SIG_REV_SUBKEY)) {
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
pgp_key_t *primary = rnp_key_store_get_signer_key(keyring, sig);
if (!primary || !pgp_key_has_primary_fp(key)) {
RNP_LOG("No primary grip or primary key");
return PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
}
if (pgp_key_get_fp(primary) != pgp_key_get_primary_fp(key)) {
@@ -624,19 +618,18 @@ rnp_key_store_import_subkey_signature(rn
pgp_sig_import_status_t
rnp_key_store_import_key_signature(rnp_key_store_t * keyring,
pgp_key_t * key,
const pgp_signature_t *sig)
{
if (pgp_key_is_subkey(key)) {
return rnp_key_store_import_subkey_signature(keyring, key, sig);
}
- pgp_sig_type_t sigtype = signature_get_type(sig);
- if ((sigtype != PGP_SIG_DIRECT) && (sigtype != PGP_SIG_REV_KEY)) {
- RNP_LOG("Wrong signature type: %d", (int) sigtype);
+ if ((sig->type() != PGP_SIG_DIRECT) && (sig->type() != PGP_SIG_REV_KEY)) {
+ RNP_LOG("Wrong signature type: %d", (int) sig->type());
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
pgp_key_t tmpkey;
if (!pgp_key_from_pkt(&tmpkey, &key->pkt) || !rnp_key_add_signature(&tmpkey, sig) ||
!pgp_key_refresh_data(&tmpkey)) {
RNP_LOG("Failed to add signature to the key.");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
@@ -658,19 +651,18 @@ rnp_key_store_import_signature(rnp_key_s
pgp_sig_import_status_t *status)
{
pgp_sig_import_status_t tmp_status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
if (!status) {
status = &tmp_status;
}
*status = PGP_SIG_IMPORT_STATUS_UNKNOWN;
- pgp_sig_type_t sigtype = signature_get_type(sig);
/* we support only direct-key and key revocation signatures here */
- if ((sigtype != PGP_SIG_DIRECT) && (sigtype != PGP_SIG_REV_KEY)) {
+ if ((sig->type() != PGP_SIG_DIRECT) && (sig->type() != PGP_SIG_REV_KEY)) {
return NULL;
}
pgp_key_t *res_key = rnp_key_store_get_signer_key(keyring, sig);
if (!res_key || !pgp_key_is_primary_key(res_key)) {
*status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
return NULL;
}
@@ -796,39 +788,36 @@ rnp_key_store_get_key_by_fpr(rnp_key_sto
return NULL;
}
return &*it->second;
}
pgp_key_t *
rnp_key_store_get_primary_key(rnp_key_store_t *keyring, const pgp_key_t *subkey)
{
- pgp_key_id_t keyid = {};
- pgp_fingerprint_t keyfp = {};
-
if (!pgp_key_is_subkey(subkey)) {
return NULL;
}
if (pgp_key_has_primary_fp(subkey)) {
return rnp_key_store_get_key_by_fpr(keyring, pgp_key_get_primary_fp(subkey));
}
for (unsigned i = 0; i < pgp_key_get_subsig_count(subkey); i++) {
const pgp_subsig_t *subsig = pgp_key_get_subsig(subkey, i);
- if (subsig->sig.type != PGP_SIG_SUBKEY) {
+ if (subsig->sig.type() != PGP_SIG_SUBKEY) {
continue;
}
- if (signature_get_keyfp(&subsig->sig, keyfp)) {
- return rnp_key_store_get_key_by_fpr(keyring, keyfp);
+ if (subsig->sig.has_keyfp()) {
+ return rnp_key_store_get_key_by_fpr(keyring, subsig->sig.keyfp());
}
- if (signature_get_keyid(&subsig->sig, keyid)) {
- return rnp_key_store_get_key_by_id(keyring, keyid, NULL);
+ if (subsig->sig.has_keyid()) {
+ return rnp_key_store_get_key_by_id(keyring, subsig->sig.keyid(), NULL);
}
}
return NULL;
}
static bool
grip_hash_mpi(pgp_hash_t *hash, const pgp_mpi_t *val, const char name, bool lzero)
--- a/third_party/rnp/src/librepgp/stream-armor.cpp
+++ b/third_party/rnp/src/librepgp/stream-armor.cpp
@@ -519,19 +519,54 @@ rnp_armor_guess_type(pgp_source_t *src)
return PGP_ARMORED_SECRET_KEY;
case PGP_PKT_SIGNATURE:
return PGP_ARMORED_SIGNATURE;
default:
return PGP_ARMORED_UNKNOWN;
}
}
+static pgp_armored_msg_t
+rnp_armored_guess_type_by_readahead(pgp_source_t *src)
+{
+ if (!src->cache) {
+ return PGP_ARMORED_UNKNOWN;
+ }
+
+ pgp_source_t armorsrc = {0};
+ pgp_source_t memsrc = {0};
+ size_t read;
+ // peek as much as the cache can take
+ bool cache_res = src_peek(src, NULL, sizeof(src->cache->buf), &read);
+ if (!cache_res || !read ||
+ init_mem_src(&memsrc,
+ src->cache->buf + src->cache->pos,
+ src->cache->len - src->cache->pos,
+ false)) {
+ return PGP_ARMORED_UNKNOWN;
+ }
+ rnp_result_t res = init_armored_src(&armorsrc, &memsrc);
+ if (res) {
+ RNP_LOG("failed to parse armored data");
+ return PGP_ARMORED_UNKNOWN;
+ }
+ pgp_armored_msg_t guessed = rnp_armor_guess_type(&armorsrc);
+ src_close(&armorsrc);
+ src_close(&memsrc);
+ return guessed;
+}
+
pgp_armored_msg_t
rnp_armored_get_type(pgp_source_t *src)
{
+ pgp_armored_msg_t guessed = rnp_armored_guess_type_by_readahead(src);
+ if (guessed != PGP_ARMORED_UNKNOWN) {
+ return guessed;
+ }
+
char hdr[128];
const char *armhdr;
size_t armhdrlen;
size_t read;
if (!src_peek(src, hdr, sizeof(hdr), &read) || (read < 20)) {
return PGP_ARMORED_UNKNOWN;
}
--- a/third_party/rnp/src/librepgp/stream-common.cpp
+++ b/third_party/rnp/src/librepgp/stream-common.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2017, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
@@ -37,16 +37,19 @@
#include <stdarg.h>
#include <errno.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
+#ifndef HAVE_MKSTEMP
+#include "file-utils.h"
+#endif
#include <rnp/rnp_def.h>
#include "rnp.h"
#include "stream-common.h"
#include "types.h"
#include <algorithm>
bool
src_read(pgp_source_t *src, void *buf, size_t len, size_t *readres)
@@ -340,32 +343,32 @@ src_peek_line(pgp_source_t *src, char *b
} while (scan_pos < len);
return false;
}
bool
init_src_common(pgp_source_t *src, size_t paramsize)
{
memset(src, 0, sizeof(*src));
-
- if ((src->cache = (pgp_source_cache_t *) calloc(1, sizeof(pgp_source_cache_t))) == NULL) {
+ src->cache = (pgp_source_cache_t *) calloc(1, sizeof(*src->cache));
+ if (!src->cache) {
RNP_LOG("cache allocation failed");
return false;
}
src->cache->readahead = true;
-
- if (paramsize > 0) {
- if ((src->param = calloc(1, paramsize)) == NULL) {
- RNP_LOG("param allocation failed");
- free(src->cache);
- src->cache = NULL;
- return false;
- }
+ if (!paramsize) {
+ return true;
}
-
+ src->param = calloc(1, paramsize);
+ if (!src->param) {
+ RNP_LOG("param allocation failed");
+ free(src->cache);
+ src->cache = NULL;
+ return false;
+ }
return true;
}
typedef struct pgp_source_file_param_t {
int fd;
} pgp_source_file_param_t;
static bool
@@ -507,24 +510,25 @@ mem_src_close(pgp_source_t *src)
free(src->param);
src->param = NULL;
}
}
rnp_result_t
init_mem_src(pgp_source_t *src, const void *mem, size_t len, bool free)
{
- pgp_source_mem_param_t *param;
-
+ if (!mem && len) {
+ return RNP_ERROR_NULL_POINTER;
+ }
/* this is actually double buffering, but then src_peek will fail */
if (!init_src_common(src, sizeof(pgp_source_mem_param_t))) {
return RNP_ERROR_OUT_OF_MEMORY;
}
- param = (pgp_source_mem_param_t *) src->param;
+ pgp_source_mem_param_t *param = (pgp_source_mem_param_t *) src->param;
param->memory = mem;
param->len = len;
param->pos = 0;
param->free = free;
src->read = mem_src_read;
src->close = mem_src_close;
src->finish = NULL;
src->size = len;
@@ -607,26 +611,24 @@ mem_src_get_memory(pgp_source_t *src)
param = (pgp_source_mem_param_t *) src->param;
return param->memory;
}
bool
init_dst_common(pgp_dest_t *dst, size_t paramsize)
{
memset(dst, 0, sizeof(*dst));
-
- if (paramsize > 0) {
- if ((dst->param = calloc(1, paramsize)) == NULL) {
+ if (paramsize) {
+ dst->param = calloc(1, paramsize);
+ if (!dst->param) {
RNP_LOG("allocation failed");
return false;
}
}
-
dst->werr = RNP_SUCCESS;
-
return true;
}
void
dst_write(pgp_dest_t *dst, const void *buf, size_t len)
{
/* we call write function only if all previous calls succeeded */
if ((len > 0) && (dst->write) && (dst->werr == RNP_SUCCESS)) {
@@ -758,16 +760,39 @@ file_dst_close(pgp_dest_t *dst, bool dis
unlink(param->path);
}
}
free(param);
dst->param = NULL;
}
+static rnp_result_t
+init_fd_dest(pgp_dest_t *dst, int fd, const char *path)
+{
+ pgp_dest_file_param_t *param;
+ size_t path_len = strlen(path);
+ if (path_len >= sizeof(param->path)) {
+ RNP_LOG("path too long");
+ return RNP_ERROR_BAD_PARAMETERS;
+ }
+ if (!init_dst_common(dst, sizeof(*param))) {
+ return RNP_ERROR_OUT_OF_MEMORY;
+ }
+
+ param = (pgp_dest_file_param_t *) dst->param;
+ param->fd = fd;
+ memcpy(param->path, path, path_len + 1);
+ dst->write = file_dst_write;
+ dst->close = file_dst_close;
+ dst->type = PGP_STREAM_FILE;
+
+ return RNP_SUCCESS;
+}
+
rnp_result_t
init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite)
{
int fd;
int flags;
struct stat st;
pgp_dest_file_param_t *param;
@@ -797,35 +822,27 @@ init_file_dest(pgp_dest_t *dst, const ch
flags |= overwrite ? O_TRUNC : O_EXCL;
#ifdef HAVE_O_BINARY
flags |= O_BINARY;
#else
#ifdef HAVE__O_BINARY
flags |= _O_BINARY;
#endif
#endif
- fd = open(path, flags, 0600);
+ fd = open(path, flags, S_IRUSR | S_IWUSR);
if (fd < 0) {
RNP_LOG("failed to create file '%s'. Error %d.", path, errno);
return RNP_ERROR_WRITE;
}
- if (!init_dst_common(dst, sizeof(*param))) {
+ rnp_result_t res = init_fd_dest(dst, fd, path);
+ if (res) {
close(fd);
- return RNP_ERROR_OUT_OF_MEMORY;
}
-
- param = (pgp_dest_file_param_t *) dst->param;
- param->fd = fd;
- memcpy(param->path, path, path_len + 1);
- dst->write = file_dst_write;
- dst->close = file_dst_close;
- dst->type = PGP_STREAM_FILE;
-
- return RNP_SUCCESS;
+ return res;
}
#define TMPDST_SUFFIX ".rnp-tmp.XXXXXX"
static rnp_result_t
file_tmpdst_finish(pgp_dest_t *dst)
{
pgp_dest_file_param_t *param = (pgp_dest_file_param_t *) dst->param;
@@ -841,17 +858,17 @@ file_tmpdst_finish(pgp_dest_t *dst)
plen = strnlen(param->path, sizeof(param->path));
if (plen < strlen(TMPDST_SUFFIX)) {
return RNP_ERROR_BAD_PARAMETERS;
}
strncpy(origpath, param->path, plen - strlen(TMPDST_SUFFIX));
/* rename the temporary file */
close(param->fd);
- param->fd = 0;
+ param->fd = -1;
/* check if file already exists */
if (!stat(origpath, &st)) {
if (!param->overwrite) {
RNP_LOG("target path already exists");
return RNP_ERROR_BAD_STATE;
}
#ifdef _WIN32
@@ -905,19 +922,27 @@ init_tmpfile_dest(pgp_dest_t *dst, const
rnp_result_t res = RNP_ERROR_GENERIC;
int ires = 0;
ires = snprintf(tmp, sizeof(tmp), "%s%s", path, TMPDST_SUFFIX);
if ((ires < 0) || ((size_t) ires >= sizeof(tmp))) {
RNP_LOG("failed to build file path");
return RNP_ERROR_BAD_PARAMETERS;
}
- mktemp(tmp);
-
- if ((res = init_file_dest(dst, tmp, overwrite))) {
+#ifdef HAVE_MKSTEMP
+ int fd = mkstemp(tmp);
+#else
+ int fd = rnp_mkstemp(tmp);
+#endif
+ if (fd < 0) {
+ RNP_LOG("failed to create temporary file with tempate '%s'. Error %d.", tmp, errno);
+ return RNP_ERROR_WRITE;
+ }
+ if ((res = init_fd_dest(dst, fd, tmp))) {
+ close(fd);
return res;
}
/* now let's change some parameters to handle temporary file correctly */
param = (pgp_dest_file_param_t *) dst->param;
param->overwrite = overwrite;
dst->finish = file_tmpdst_finish;
dst->close = file_tmpdst_close;
@@ -1068,18 +1093,27 @@ mem_dest_own_memory(pgp_dest_t *dst)
if (!param) {
RNP_LOG("null param");
return NULL;
}
dst_finish(dst);
if (param->free) {
- /* it may be larger then required */
- param->memory = realloc(param->memory, dst->writeb);
+ if (!dst->writeb) {
+ free(param->memory);
+ param->memory = NULL;
+ return param->memory;
+ }
+ /* it may be larger then required - let's truncate */
+ void *newalloc = realloc(param->memory, dst->writeb);
+ if (!newalloc) {
+ return NULL;
+ }
+ param->memory = newalloc;
param->allocated = dst->writeb;
param->free = false;
return param->memory;
}
/* in this case we should copy the memory */
void *res = malloc(dst->writeb);
if (res) {
--- a/third_party/rnp/src/librepgp/stream-common.h
+++ b/third_party/rnp/src/librepgp/stream-common.h
@@ -338,17 +338,19 @@ void mem_dest_discard_overflow(pgp_dest_
* @param dst pre-allocated and initialized memory dest
* @return pointer to the memory area or NULL if memory was not allocated
**/
void *mem_dest_get_memory(pgp_dest_t *dst);
/** @brief get ownership on the memory dest's contents. This must be called only before
* closing the dest
* @param dst pre-allocated and initialized memory dest
- * @return pointer to the memory area or NULL if memory was not allocated
+ * @return pointer to the memory area or NULL if memory was not allocated (i.e. nothing was
+ * written to the destination). Also NULL will be returned on possible (re-)allocation
+ * failure, this case can be identified by non-zero dst->writeb.
**/
void *mem_dest_own_memory(pgp_dest_t *dst);
/** @brief init null destination which silently discards all the output
* @param dst pre-allocated dest structure
* @return RNP_SUCCESS or error code
**/
rnp_result_t init_null_dest(pgp_dest_t *dst);
--- a/third_party/rnp/src/librepgp/stream-ctx.cpp
+++ b/third_party/rnp/src/librepgp/stream-ctx.cpp
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2019, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2019-2020, [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
@@ -22,39 +22,40 @@
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <assert.h>
#include "defaults.h"
+#include "utils.h"
#include "stream-ctx.h"
rng_t *
rnp_ctx_rng_handle(const rnp_ctx_t *ctx)
{
assert(ctx->rng);
return ctx->rng;
}
rnp_result_t
-rnp_ctx_add_encryption_password(rnp_ctx_t * ctx,
+rnp_ctx_add_encryption_password(rnp_ctx_t & ctx,
const char * password,
pgp_hash_alg_t halg,
pgp_symm_alg_t ealg,
int iterations)
{
rnp_symmetric_pass_info_t info = {};
info.s2k.usage = PGP_S2KU_ENCRYPTED_AND_HASHED;
info.s2k.specifier = PGP_S2KS_ITERATED_AND_SALTED;
info.s2k.hash_alg = halg;
- if (!rng_get_data(ctx->rng, info.s2k.salt, sizeof(info.s2k.salt))) {
+ if (!rng_get_data(ctx.rng, info.s2k.salt, sizeof(info.s2k.salt))) {
return RNP_ERROR_GENERIC;
}
if (iterations == 0) {
iterations = pgp_s2k_compute_iters(halg, DEFAULT_S2K_MSEC, DEFAULT_S2K_TUNE_MSEC);
}
if (!iterations) {
return RNP_ERROR_BAD_PARAMETERS;
}
@@ -69,24 +70,21 @@ rnp_ctx_add_encryption_password(rnp_ctx_
* end up being used with until later.
*
* An alternative would be to keep a list of actual passwords and s2k params,
* and save the key derivation for later.
*/
if (!pgp_s2k_derive_key(&info.s2k, password, info.key, sizeof(info.key))) {
return RNP_ERROR_GENERIC;
}
- if (!list_append(&ctx->passwords, &info, sizeof(info))) {
- pgp_forget(&info, sizeof(info));
+ try {
+ ctx.passwords.push_back(info);
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
return RNP_SUCCESS;
}
-/* free operation context */
-void
-rnp_ctx_free(rnp_ctx_t *ctx)
+rnp_symmetric_pass_info_t::~rnp_symmetric_pass_info_t()
{
- free(ctx->filename);
- list_destroy(&ctx->recipients);
- list_destroy(&ctx->signers);
- list_destroy(&ctx->passwords);
+ pgp_forget(key, sizeof(key));
}
--- a/third_party/rnp/src/librepgp/stream-ctx.h
+++ b/third_party/rnp/src/librepgp/stream-ctx.h
@@ -1,10 +1,10 @@
/*
- * Copyright (c) 2019, [Ribose Inc](https://www.ribose.com).
+ * Copyright (c) 2019-2020, [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
@@ -26,32 +26,42 @@
#ifndef STREAM_CTX_H_
#define STREAM_CTX_H_
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include "types.h"
+#include <string>
+#include <list>
typedef enum rnp_operation_t {
RNP_OP_UNKNOWN = 0,
RNP_OP_DECRYPT_VERIFY = 1,
RNP_OP_ENCRYPT_SIGN = 2,
RNP_OP_ARMOR = 3
} rnp_operation_t;
/* signature info structure */
typedef struct rnp_signer_info_t {
- pgp_key_t * key;
- pgp_hash_alg_t halg;
- int64_t sigcreate;
- uint64_t sigexpire;
+ pgp_key_t * key{};
+ pgp_hash_alg_t halg{};
+ int64_t sigcreate{};
+ uint64_t sigexpire{};
} rnp_signer_info_t;
+typedef struct rnp_symmetric_pass_info_t {
+ pgp_s2k_t s2k{};
+ pgp_symm_alg_t s2k_cipher{};
+ uint8_t key[PGP_MAX_KEY_SIZE]{};
+
+ ~rnp_symmetric_pass_info_t();
+} rnp_symmetric_pass_info_t;
+
/** rnp operation context : contains configuration data about the currently ongoing operation.
*
* Common fields which make sense for every operation:
* - overwrite : silently overwrite output file if exists
* - armor : except cleartext signing, which outputs text in clear and always armor signature,
* this controls whether output is armored (base64-encoded). For armor/dearmor operation it
* controls the direction of the conversion (true means enarmor, false - dearmor),
* - rng : random number generator
@@ -77,47 +87,46 @@ typedef struct rnp_signer_info_t {
* - filename, filemtime, zalg, zlevel : only for attached signatures, see previous
*
* For data decryption and/or verification there is not much of fields:
* - discard: dicard the output data (i.e. just decrypt and/or verify signatures)
*
*/
typedef struct rnp_ctx_t {
- char * filename; /* name of the input file to store in literal data packet */
- int64_t filemtime; /* file modification time to store in literal data packet */
- int64_t sigcreate; /* signature creation time */
- uint64_t sigexpire; /* signature expiration time */
- bool clearsign; /* cleartext signature */
- bool detached; /* detached signature */
- pgp_hash_alg_t halg; /* hash algorithm */
- pgp_symm_alg_t ealg; /* encryption algorithm */
- int zalg; /* compression algorithm used */
- int zlevel; /* compression level */
- pgp_aead_alg_t aalg; /* non-zero to use AEAD */
- int abits; /* AEAD chunk bits */
- bool overwrite; /* allow to overwrite output file if exists */
- bool armor; /* whether to use ASCII armor on output */
- list recipients; /* recipients of the encrypted message */
- list passwords; /* list of rnp_symmetric_pass_info_t */
- list signers; /* list of rnp_signer_info_t structures */
- bool discard; /* discard the output */
- rng_t * rng; /* pointer to rng_t */
- rnp_operation_t operation; /* current operation type */
+ std::string filename{}; /* name of the input file to store in literal data packet */
+ int64_t filemtime{}; /* file modification time to store in literal data packet */
+ int64_t sigcreate{}; /* signature creation time */
+ uint64_t sigexpire{}; /* signature expiration time */
+ bool clearsign{}; /* cleartext signature */
+ bool detached{}; /* detached signature */
+ pgp_hash_alg_t halg{}; /* hash algorithm */
+ pgp_symm_alg_t ealg{}; /* encryption algorithm */
+ int zalg{}; /* compression algorithm used */
+ int zlevel{}; /* compression level */
+ pgp_aead_alg_t aalg{}; /* non-zero to use AEAD */
+ int abits{}; /* AEAD chunk bits */
+ bool overwrite{}; /* allow to overwrite output file if exists */
+ bool armor{}; /* whether to use ASCII armor on output */
+ std::list<pgp_key_t *> recipients{}; /* recipients of the encrypted message */
+ std::list<rnp_symmetric_pass_info_t> passwords{}; /* passwords to encrypt message */
+ std::list<rnp_signer_info_t> signers{}; /* keys to which sign message */
+ bool discard{}; /* discard the output */
+ rng_t * rng{}; /* pointer to rng_t */
+ rnp_operation_t operation{}; /* current operation type */
+
+ rnp_ctx_t() = default;
+ rnp_ctx_t(const rnp_ctx_t &) = delete;
+ rnp_ctx_t(rnp_ctx_t &&) = delete;
+
+ rnp_ctx_t &operator=(const rnp_ctx_t &) = delete;
+ rnp_ctx_t &operator=(rnp_ctx_t &&) = delete;
} rnp_ctx_t;
-typedef struct rnp_symmetric_pass_info_t {
- pgp_s2k_t s2k;
- pgp_symm_alg_t s2k_cipher;
- uint8_t key[PGP_MAX_KEY_SIZE];
-} rnp_symmetric_pass_info_t;
-
-/* free rnp operation context */
-void rnp_ctx_free(rnp_ctx_t *);
struct rng_st_t *rnp_ctx_rng_handle(const rnp_ctx_t *ctx);
-rnp_result_t rnp_ctx_add_encryption_password(rnp_ctx_t * ctx,
+rnp_result_t rnp_ctx_add_encryption_password(rnp_ctx_t & ctx,
const char * password,
pgp_hash_alg_t halg,
pgp_symm_alg_t ealg,
int iterations);
#endif
\ No newline at end of file
--- a/third_party/rnp/src/librepgp/stream-dump.cpp
+++ b/third_party/rnp/src/librepgp/stream-dump.cpp
@@ -442,16 +442,24 @@ dst_print_s2k(pgp_dest_t *dst, pgp_s2k_t
dst_printf(dst, "GPG extension num: %d\n", (int) s2k->gpg_ext_num);
if (s2k->gpg_ext_num == PGP_S2K_GPG_SMARTCARD) {
static_assert(sizeof(s2k->gpg_serial) == 16, "invalid s2k->gpg_serial size");
size_t slen = s2k->gpg_serial_len > 16 ? 16 : s2k->gpg_serial_len;
dst_print_hex(dst, "card serial number", s2k->gpg_serial, slen, true);
}
return;
}
+ if (s2k->specifier == PGP_S2KS_EXPERIMENTAL) {
+ dst_print_hex(dst,
+ "Unknown experimental s2k",
+ s2k->experimental.data(),
+ s2k->experimental.size(),
+ true);
+ return;
+ }
dst_print_halg(dst, "s2k hash algorithm", s2k->hash_alg);
if ((s2k->specifier == PGP_S2KS_SALTED) ||
(s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED)) {
dst_print_hex(dst, "s2k salt", s2k->salt, PGP_SALT_SIZE, false);
}
if (s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED) {
size_t real_iter = pgp_s2k_decode_iterations(s2k->iterations);
dst_printf(dst, "s2k iterations: %zu (encoded as %u)\n", real_iter, s2k->iterations);
@@ -623,19 +631,19 @@ signature_dump_subpacket(rnp_dump_ctx_t
dst_print_raw(dst,
"message",
subpkt.fields.revocation_reason.str,
subpkt.fields.revocation_reason.len);
break;
}
case PGP_SIG_SUBPKT_FEATURES:
dst_printf(dst, "%s: 0x%02x ( ", sname, subpkt.data[0]);
- dst_printf(dst, "%s", subpkt.fields.features.mdc ? "mdc " : "");
- dst_printf(dst, "%s", subpkt.fields.features.aead ? "aead " : "");
- dst_printf(dst, "%s", subpkt.fields.features.key_v5 ? "v5 keys " : "");
+ dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_MDC ? "mdc " : "");
+ dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_AEAD ? "aead " : "");
+ dst_printf(dst, "%s", subpkt.fields.features & PGP_KEY_FEATURE_V5 ? "v5 keys " : "");
dst_printf(dst, ")\n");
break;
case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE:
dst_printf(dst, "%s:\n", sname);
stream_dump_signature_pkt(ctx, subpkt.fields.sig, dst);
break;
case PGP_SIG_SUBPKT_ISSUER_FPR:
dst_print_hex(
@@ -687,17 +695,17 @@ signature_dump_subpackets(rnp_dump_ctx_t
}
static void
stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t *dst)
{
indent_dest_increase(dst);
dst_printf(dst, "version: %d\n", (int) sig->version);
- dst_print_sig_type(dst, "type", sig->type);
+ dst_print_sig_type(dst, "type", sig->type());
if (sig->version < PGP_V4) {
dst_print_time(dst, "creation time", sig->creation_time);
dst_print_keyid(dst, "signing key id", sig->signer);
}
dst_print_palg(dst, NULL, sig->palg);
dst_print_halg(dst, NULL, sig->halg);
if (sig->version >= PGP_V4) {
@@ -1447,16 +1455,20 @@ obj_add_s2k_json(json_object *obj, pgp_s
}
if (s2k->gpg_ext_num == PGP_S2K_GPG_SMARTCARD) {
size_t slen = s2k->gpg_serial_len > 16 ? 16 : s2k->gpg_serial_len;
if (!obj_add_hex_json(s2k_obj, "card serial number", s2k->gpg_serial, slen)) {
return false;
}
}
}
+ if (s2k->specifier == PGP_S2KS_EXPERIMENTAL) {
+ return obj_add_hex_json(
+ s2k_obj, "unknown experimental", s2k->experimental.data(), s2k->experimental.size());
+ }
if (!obj_add_intstr_json(s2k_obj, "hash algorithm", s2k->hash_alg, hash_alg_map)) {
return false;
}
if (((s2k->specifier == PGP_S2KS_SALTED) ||
(s2k->specifier == PGP_S2KS_ITERATED_AND_SALTED)) &&
!obj_add_hex_json(s2k_obj, "salt", s2k->salt, PGP_SALT_SIZE)) {
return false;
}
@@ -1605,21 +1617,27 @@ signature_dump_subpacket_json(rnp_dump_c
return obj_add_field_json(
obj,
"message",
json_object_new_string_len(subpkt.fields.revocation_reason.str,
subpkt.fields.revocation_reason.len));
}
case PGP_SIG_SUBPKT_FEATURES:
return obj_add_field_json(
- obj, "mdc", json_object_new_boolean(subpkt.fields.features.mdc)) &&
+ obj,
+ "mdc",
+ json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_MDC)) &&
obj_add_field_json(
- obj, "aead", json_object_new_boolean(subpkt.fields.features.aead)) &&
+ obj,
+ "aead",
+ json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_AEAD)) &&
obj_add_field_json(
- obj, "v5 keys", json_object_new_boolean(subpkt.fields.features.key_v5));
+ obj,
+ "v5 keys",
+ json_object_new_boolean(subpkt.fields.features & PGP_KEY_FEATURE_V5));
case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE: {
json_object *sig = json_object_new_object();
if (!sig || !obj_add_field_json(obj, "signature", sig)) {
return false;
}
return !stream_dump_signature_pkt_json(ctx, subpkt.fields.sig, sig);
}
case PGP_SIG_SUBPKT_ISSUER_FPR:
@@ -1685,17 +1703,17 @@ stream_dump_signature_pkt_json(rnp_dump_
{
json_object * material = NULL;
pgp_signature_material_t sigmaterial = {};
rnp_result_t ret = RNP_ERROR_OUT_OF_MEMORY;
if (!obj_add_field_json(pkt, "version", json_object_new_int(sig->version))) {
goto done;
}
- if (!obj_add_intstr_json(pkt, "type", sig->type, sig_type_map)) {
+ if (!obj_add_intstr_json(pkt, "type", sig->type(), sig_type_map)) {
goto done;
}
if (sig->version < PGP_V4) {
if (!obj_add_field_json(
pkt, "creation time", json_object_new_int(sig->creation_time))) {
goto done;
}
--- a/third_party/rnp/src/librepgp/stream-key.cpp
+++ b/third_party/rnp/src/librepgp/stream-key.cpp
@@ -296,68 +296,48 @@ transferable_userid_certify(const pgp_ke
if (pgp_fingerprint(keyfp, &signer)) {
RNP_LOG("failed to calculate keyfp");
return NULL;
}
sig.version = PGP_V4;
sig.halg = pgp_hash_adjust_alg_to_key(hash_alg, &signer);
sig.palg = signer.alg;
- sig.type = PGP_CERT_POSITIVE;
+ sig.set_type(PGP_CERT_POSITIVE);
- if (!signature_set_keyfp(&sig, keyfp)) {
- RNP_LOG("failed to set issuer fingerprint");
- return NULL;
- }
- if (!signature_set_creation(&sig, time(NULL))) {
- RNP_LOG("failed to set creation time");
- return NULL;
- }
- if (cert.key_expiration && !signature_set_key_expiration(&sig, cert.key_expiration)) {
- RNP_LOG("failed to set key expiration time");
- return NULL;
- }
- if (cert.key_flags && !signature_set_key_flags(&sig, cert.key_flags)) {
- RNP_LOG("failed to set key flags");
- return NULL;
- }
- if (cert.primary && !signature_set_primary_uid(&sig, true)) {
- RNP_LOG("failed to set primary userid");
- return NULL;
- }
- const pgp_user_prefs_t *prefs = &cert.prefs;
- if (prefs->symm_alg_count &&
- !signature_set_preferred_symm_algs(
- &sig, (uint8_t *) prefs->symm_algs, prefs->symm_alg_count)) {
- RNP_LOG("failed to set symm alg prefs");
- return NULL;
- }
- if (prefs->hash_alg_count &&
- !signature_set_preferred_hash_algs(
- &sig, (uint8_t *) prefs->hash_algs, prefs->hash_alg_count)) {
- RNP_LOG("failed to set hash alg prefs");
- return NULL;
- }
- if (prefs->z_alg_count &&
- !signature_set_preferred_z_algs(&sig, (uint8_t *) prefs->z_algs, prefs->z_alg_count)) {
- RNP_LOG("failed to set compress alg prefs");
- return NULL;
- }
- if (prefs->ks_pref_count &&
- !signature_set_key_server_prefs(&sig, (uint8_t) prefs->ks_prefs[0])) {
- RNP_LOG("failed to set key server prefs");
- return NULL;
- }
- if (prefs->key_server &&
- !signature_set_preferred_key_server(&sig, (char *) prefs->key_server)) {
- RNP_LOG("failed to set preferred key server");
- return NULL;
- }
- if (!signature_set_keyid(&sig, keyid)) {
- RNP_LOG("failed to set issuer key id");
+ try {
+ sig.set_keyfp(keyfp);
+ sig.set_creation(time(NULL));
+ if (cert.key_expiration) {
+ sig.set_key_expiration(cert.key_expiration);
+ }
+ if (cert.key_flags) {
+ sig.set_key_flags(cert.key_flags);
+ }
+ if (cert.primary) {
+ sig.set_primary_uid(true);
+ }
+ if (!cert.prefs.symm_algs.empty()) {
+ sig.set_preferred_symm_algs(cert.prefs.symm_algs);
+ }
+ if (!cert.prefs.hash_algs.empty()) {
+ sig.set_preferred_hash_algs(cert.prefs.hash_algs);
+ }
+ if (!cert.prefs.z_algs.empty()) {
+ sig.set_preferred_z_algs(cert.prefs.z_algs);
+ }
+ if (!cert.prefs.ks_prefs.empty()) {
+ sig.set_key_server_prefs(cert.prefs.ks_prefs[0]);
+ }
+ if (!cert.prefs.key_server.empty()) {
+ sig.set_key_server(cert.prefs.key_server);
+ }
+ sig.set_keyid(keyid);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to setup signature: %s", e.what());
return NULL;
}
if (!signature_calculate_certification(&key, &userid.uid, &sig, &signer)) {
RNP_LOG("failed to calculate signature");
return NULL;
}
try {
@@ -378,28 +358,27 @@ signature_calculate_primary_binding(cons
{
pgp_key_id_t keyid = {};
pgp_hash_t hash = {};
bool res = false;
sig->version = PGP_V4;
sig->halg = pgp_hash_adjust_alg_to_key(halg, subkey);
sig->palg = subkey->alg;
- sig->type = PGP_SIG_PRIMARY;
+ sig->set_type(PGP_SIG_PRIMARY);
if (pgp_keyid(keyid, subkey)) {
RNP_LOG("failed to calculate keyid");
return false;
}
- if (!signature_set_creation(sig, time(NULL))) {
- RNP_LOG("failed to set embedded sig creation time");
- return false;
- }
- if (!signature_set_keyid(sig, keyid)) {
- RNP_LOG("failed to set issuer key id");
+ try {
+ sig->set_creation(time(NULL));
+ sig->set_keyid(keyid);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to setup embedded signature: %s", e.what());
return false;
}
if (!signature_hash_binding(sig, key, subkey, &hash)) {
RNP_LOG("failed to hash key and subkey");
goto end;
}
if (!signature_fill_hashed_data(sig)) {
RNP_LOG("failed to hash signature");
@@ -458,18 +437,20 @@ signature_calculate_binding(const pgp_ke
}
if (!signature_set_embedded_sig(sig, &embsig)) {
RNP_LOG("failed to add primary key binding signature");
goto end;
}
}
/* add keyid since it should (probably) be after the primary key binding if any */
- if (!signature_set_keyid(sig, keyid)) {
- RNP_LOG("failed to set issuer key id");
+ try {
+ sig->set_keyid(keyid);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to set issuer key id: %s", e.what());
goto end;
}
res = true;
end:
rng_destroy(&rng);
return res;
}
@@ -486,33 +467,29 @@ transferable_subkey_bind(const pgp_key_p
}
pgp_signature_t sig;
pgp_key_flags_t realkf = (pgp_key_flags_t) 0;
sig.version = PGP_V4;
sig.halg = pgp_hash_adjust_alg_to_key(hash_alg, &key);
sig.palg = key.alg;
- sig.type = PGP_SIG_SUBKEY;
+ sig.set_type(PGP_SIG_SUBKEY);
- if (!signature_set_keyfp(&sig, keyfp)) {
- RNP_LOG("failed to set issuer fingerprint");
- return NULL;
- }
- if (!signature_set_creation(&sig, time(NULL))) {
- RNP_LOG("failed to set creation time");
- return NULL;
- }
- if (binding.key_expiration &&
- !signature_set_key_expiration(&sig, binding.key_expiration)) {
- RNP_LOG("failed to set key expiration time");
- return NULL;
- }
- if (binding.key_flags && !signature_set_key_flags(&sig, binding.key_flags)) {
- RNP_LOG("failed to set key flags");
+ try {
+ sig.set_keyfp(keyfp);
+ sig.set_creation(time(NULL));
+ if (binding.key_expiration) {
+ sig.set_key_expiration(binding.key_expiration);
+ }
+ if (binding.key_flags) {
+ sig.set_key_flags(binding.key_flags);
+ }
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to setup signature: %s", e.what());
return NULL;
}
realkf = (pgp_key_flags_t) binding.key_flags;
if (!realkf) {
realkf = pgp_pk_alg_capabilities(subkey.subkey.alg);
}
@@ -546,32 +523,25 @@ transferable_key_revoke(const pgp_key_pk
if (pgp_fingerprint(keyfp, &signer)) {
RNP_LOG("failed to calculate keyfp");
return NULL;
}
sig.version = PGP_V4;
sig.halg = pgp_hash_adjust_alg_to_key(hash_alg, &signer);
sig.palg = signer.alg;
- sig.type = is_primary_key_pkt(key.tag) ? PGP_SIG_REV_KEY : PGP_SIG_REV_SUBKEY;
+ sig.set_type(is_primary_key_pkt(key.tag) ? PGP_SIG_REV_KEY : PGP_SIG_REV_SUBKEY);
- if (!signature_set_keyfp(&sig, keyfp)) {
- RNP_LOG("failed to set issuer fingerprint");
- return NULL;
- }
- if (!signature_set_creation(&sig, time(NULL))) {
- RNP_LOG("failed to set creation time");
- return NULL;
- }
- if (!signature_set_revocation_reason(&sig, revoke.code, revoke.reason.c_str())) {
- RNP_LOG("failed to set revocation reason");
- return NULL;
- }
- if (!signature_set_keyid(&sig, keyid)) {
- RNP_LOG("failed to set issuer key id");
+ try {
+ sig.set_keyfp(keyfp);
+ sig.set_creation(time(NULL));
+ sig.set_revocation_reason(revoke.code, revoke.reason);
+ sig.set_keyid(keyid);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to setup signature: %s", e.what());
return NULL;
}
if (is_primary_key_pkt(key.tag)) {
res = signature_calculate_direct(&key, &sig, &signer);
} else {
res = signature_calculate_binding(&signer, &key, &sig, false);
}
@@ -588,19 +558,22 @@ transferable_key_revoke(const pgp_key_pk
}
}
static bool
skip_pgp_packets(pgp_source_t *src, const std::set<pgp_pkt_type_t> &pkts)
{
do {
int pkt = stream_pkt_type(src);
- if (pkt <= 0) {
+ if (!pkt) {
break;
}
+ if (pkt < 0) {
+ return false;
+ }
if (pkts.find((pgp_pkt_type_t) pkt) == pkts.end()) {
return true;
}
uint64_t ppos = src->readb;
if (stream_skip_packet(src)) {
RNP_LOG("failed to skip packet at %" PRIu64, ppos);
return false;
}
@@ -676,71 +649,109 @@ process_pgp_subkey(pgp_source_t &src, pg
}
ret = process_pgp_key_signatures(&src, subkey.signatures, skiperrors);
done:
return ret;
}
rnp_result_t
+process_pgp_key_auto(pgp_source_t & src,
+ pgp_transferable_key_t &key,
+ bool allowsub,
+ bool skiperrors)
+{
+ key = {};
+ uint64_t srcpos = src.readb;
+ int ptag = stream_pkt_type(&src);
+ if (is_subkey_pkt(ptag) && allowsub) {
+ pgp_transferable_subkey_t subkey;
+ rnp_result_t ret = process_pgp_subkey(src, subkey, skiperrors);
+ if (subkey.subkey.tag != PGP_PKT_RESERVED) {
+ try {
+ key.subkeys.push_back(std::move(subkey));
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
+ ret = RNP_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ /* change error code if we didn't process anything at all */
+ if (srcpos == src.readb) {
+ ret = RNP_ERROR_BAD_STATE;
+ }
+ return ret;
+ }
+
+ rnp_result_t ret = RNP_ERROR_BAD_FORMAT;
+ if (!is_primary_key_pkt(ptag)) {
+ RNP_LOG("wrong key tag: %d at pos %" PRIu64, ptag, src.readb);
+ } else {
+ ret = process_pgp_key(&src, key, skiperrors);
+ }
+ if (skiperrors && (ret == RNP_ERROR_BAD_FORMAT) &&
+ !skip_pgp_packets(&src,
+ {PGP_PKT_TRUST,
+ PGP_PKT_SIGNATURE,
+ PGP_PKT_USER_ID,
+ PGP_PKT_USER_ATTR,
+ PGP_PKT_PUBLIC_SUBKEY,
+ PGP_PKT_SECRET_SUBKEY})) {
+ ret = RNP_ERROR_READ;
+ }
+ /* change error code if we didn't process anything at all */
+ if (srcpos == src.readb) {
+ ret = RNP_ERROR_BAD_STATE;
+ }
+ return ret;
+}
+
+rnp_result_t
process_pgp_keys(pgp_source_t *src, pgp_key_sequence_t &keys, bool skiperrors)
{
bool armored = false;
pgp_source_t armorsrc = {0};
pgp_source_t *origsrc = src;
bool has_secret = false;
bool has_public = false;
rnp_result_t ret = RNP_ERROR_GENERIC;
keys.keys.clear();
/* check whether keys are armored */
armoredpass:
- if (is_armored_source(src)) {
- if ((ret = init_armored_src(&armorsrc, src))) {
+ if ((src->type != PGP_STREAM_ARMORED) && is_armored_source(src)) {
+ if (init_armored_src(&armorsrc, src)) {
RNP_LOG("failed to parse armored data");
+ ret = RNP_ERROR_READ;
goto finish;
}
armored = true;
src = &armorsrc;
}
/* read sequence of transferable OpenPGP keys as described in RFC 4880, 11.1 - 11.2 */
while (!src_eof(src) && !src_error(src)) {
pgp_transferable_key_t curkey;
- int ptag = stream_pkt_type(src);
- if (!is_primary_key_pkt(ptag)) {
- RNP_LOG("wrong key tag: %d at pos %" PRIu64, ptag, src->readb);
- ret = RNP_ERROR_BAD_FORMAT;
+ ret = process_pgp_key_auto(*src, curkey, false, skiperrors);
+ if (ret && (!skiperrors || (ret != RNP_ERROR_BAD_FORMAT))) {
goto finish;
}
-
- ret = process_pgp_key(src, curkey, skiperrors);
- if ((ret == RNP_ERROR_BAD_FORMAT) && skiperrors &&
- skip_pgp_packets(src,
- {PGP_PKT_TRUST,
- PGP_PKT_SIGNATURE,
- PGP_PKT_USER_ID,
- PGP_PKT_USER_ATTR,
- PGP_PKT_PUBLIC_SUBKEY,
- PGP_PKT_SECRET_SUBKEY})) {
+ /* check whether we actually read any key or just skipped erroneous packets */
+ if (curkey.key.tag == PGP_PKT_RESERVED) {
continue;
}
- if (ret) {
- goto finish;
- }
+ has_secret |= (curkey.key.tag == PGP_PKT_SECRET_KEY);
+ has_public |= (curkey.key.tag == PGP_PKT_PUBLIC_KEY);
+
try {
keys.keys.emplace_back(std::move(curkey));
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_OUT_OF_MEMORY;
goto finish;
}
-
- has_secret |= (ptag == PGP_PKT_SECRET_KEY);
- has_public |= (ptag == PGP_PKT_PUBLIC_KEY);
}
/* file may have multiple armored keys */
if (armored && !src_eof(origsrc) && is_armored_source(origsrc)) {
src_close(&armorsrc);
armored = false;
src = origsrc;
goto armoredpass;
@@ -766,20 +777,20 @@ process_pgp_key(pgp_source_t *src, pgp_t
{
pgp_source_t armorsrc = {0};
bool armored = false;
int ptag;
rnp_result_t ret = RNP_ERROR_GENERIC;
key = pgp_transferable_key_t();
/* check whether keys are armored */
- if (is_armored_source(src)) {
- if ((ret = init_armored_src(&armorsrc, src))) {
+ if ((src->type != PGP_STREAM_ARMORED) && is_armored_source(src)) {
+ if (init_armored_src(&armorsrc, src)) {
RNP_LOG("failed to parse armored data");
- return ret;
+ return RNP_ERROR_READ;
}
armored = true;
src = &armorsrc;
}
/* main key packet */
uint64_t keypos = src->readb;
ptag = stream_pkt_type(src);
--- a/third_party/rnp/src/librepgp/stream-key.h
+++ b/third_party/rnp/src/librepgp/stream-key.h
@@ -92,16 +92,27 @@ pgp_signature_t *transferable_subkey_bin
pgp_hash_alg_t hash_alg,
const rnp_selfsig_binding_info_t &binding);
pgp_signature_t *transferable_key_revoke(const pgp_key_pkt_t &key,
const pgp_key_pkt_t &signer,
pgp_hash_alg_t hash_alg,
const pgp_revoke_t & revoke);
+/* Process single primary key or subkey, skipping all key-related packets on error.
+ If key.key.tag is zero, then (on success) result is subkey and it is stored in
+ key.subkeys[0].
+ If returns RNP_ERROR_BAD_FORMAT then some packets failed parsing, but still key may contain
+ successfully read key or subkey.
+*/
+rnp_result_t process_pgp_key_auto(pgp_source_t & src,
+ pgp_transferable_key_t &key,
+ bool allowsub,
+ bool skiperrors);
+
rnp_result_t process_pgp_keys(pgp_source_t *src, pgp_key_sequence_t &keys, bool skiperrors);
rnp_result_t process_pgp_key(pgp_source_t *src, pgp_transferable_key_t &key, bool skiperrors);
rnp_result_t process_pgp_subkey(pgp_source_t & src,
pgp_transferable_subkey_t &subkey,
bool skiperrors);
--- a/third_party/rnp/src/librepgp/stream-packet.cpp
+++ b/third_party/rnp/src/librepgp/stream-packet.cpp
@@ -401,17 +401,17 @@ add_packet_body_s2k(pgp_packet_body_t *b
}
return add_packet_body(body, s2k->salt, PGP_SALT_SIZE) &&
add_packet_body_byte(body, iter);
}
case PGP_S2KS_EXPERIMENTAL: {
if ((s2k->gpg_ext_num != PGP_S2K_GPG_NO_SECRET) &&
(s2k->gpg_ext_num != PGP_S2K_GPG_SMARTCARD)) {
RNP_LOG("Unknown experimental s2k.");
- return false;
+ return add_packet_body(body, s2k->experimental.data(), s2k->experimental.size());
}
if (!add_packet_body(body, "GNU", 3) ||
!add_packet_body_byte(body, s2k->gpg_ext_num)) {
return false;
}
if (s2k->gpg_ext_num == PGP_S2K_GPG_SMARTCARD) {
static_assert(sizeof(s2k->gpg_serial) == 16, "invalid gpg serial length");
size_t slen = s2k->gpg_serial_len > 16 ? 16 : s2k->gpg_serial_len;
@@ -571,75 +571,84 @@ get_packet_body_key_curve(pgp_packet_bod
return false;
}
*val = res;
return true;
}
static bool
-get_packet_body_s2k(pgp_packet_body_t *body, pgp_s2k_t *s2k)
+get_packet_body_s2k(pgp_packet_body_t &body, pgp_s2k_t &s2k)
{
uint8_t spec = 0, halg = 0;
- if (!get_packet_body_byte(body, &spec) || !get_packet_body_byte(body, &halg)) {
+ if (!get_packet_body_byte(&body, &spec) || !get_packet_body_byte(&body, &halg)) {
return false;
}
- s2k->specifier = (pgp_s2k_specifier_t) spec;
- s2k->hash_alg = (pgp_hash_alg_t) halg;
+ s2k.specifier = (pgp_s2k_specifier_t) spec;
+ s2k.hash_alg = (pgp_hash_alg_t) halg;
- switch (s2k->specifier) {
+ switch (s2k.specifier) {
case PGP_S2KS_SIMPLE:
return true;
case PGP_S2KS_SALTED:
- return get_packet_body_buf(body, s2k->salt, PGP_SALT_SIZE);
+ return get_packet_body_buf(&body, s2k.salt, PGP_SALT_SIZE);
case PGP_S2KS_ITERATED_AND_SALTED: {
uint8_t iter;
- if (!get_packet_body_buf(body, s2k->salt, PGP_SALT_SIZE) ||
- !get_packet_body_byte(body, &iter)) {
+ if (!get_packet_body_buf(&body, s2k.salt, PGP_SALT_SIZE) ||
+ !get_packet_body_byte(&body, &iter)) {
return false;
}
- s2k->iterations = iter;
+ s2k.iterations = iter;
return true;
}
case PGP_S2KS_EXPERIMENTAL: {
+ try {
+ s2k.experimental = {body.data + body.pos, body.data + body.len};
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
+ return false;
+ }
uint8_t gnu[3] = {0};
- if (!get_packet_body_buf(body, gnu, 3) || memcmp(gnu, "GNU", 3)) {
+ if (!get_packet_body_buf(&body, gnu, 3) || memcmp(gnu, "GNU", 3)) {
RNP_LOG("Unknown experimental s2k. Skipping.");
- body->pos = body->len;
- s2k->gpg_ext_num = PGP_S2K_GPG_NONE;
+ body.pos = body.len;
+ s2k.gpg_ext_num = PGP_S2K_GPG_NONE;
return true;
}
uint8_t ext_num = 0;
- if (!get_packet_body_byte(body, &ext_num)) {
+ if (!get_packet_body_byte(&body, &ext_num)) {
return false;
}
if ((ext_num != PGP_S2K_GPG_NO_SECRET) && (ext_num != PGP_S2K_GPG_SMARTCARD)) {
- RNP_LOG("Unsupported gpg extension num: %" PRIu8, ext_num);
- }
- s2k->gpg_ext_num = (pgp_s2k_gpg_extension_t) ext_num;
- if (s2k->gpg_ext_num == PGP_S2K_GPG_NO_SECRET) {
+ RNP_LOG("Unsupported gpg extension num: %" PRIu8 ", skipping", ext_num);
+ body.pos = body.len;
+ s2k.gpg_ext_num = PGP_S2K_GPG_NONE;
return true;
}
- if (!get_packet_body_byte(body, &s2k->gpg_serial_len)) {
+ s2k.gpg_ext_num = (pgp_s2k_gpg_extension_t) ext_num;
+ if (s2k.gpg_ext_num == PGP_S2K_GPG_NO_SECRET) {
+ return true;
+ }
+ if (!get_packet_body_byte(&body, &s2k.gpg_serial_len)) {
RNP_LOG("Failed to get GPG serial len");
return false;
}
- size_t len = s2k->gpg_serial_len;
- if (s2k->gpg_serial_len > 16) {
+ size_t len = s2k.gpg_serial_len;
+ if (s2k.gpg_serial_len > 16) {
RNP_LOG("Warning: gpg_serial_len is %d", (int) len);
len = 16;
}
- if (!get_packet_body_buf(body, s2k->gpg_serial, len)) {
+ if (!get_packet_body_buf(&body, s2k.gpg_serial, len)) {
RNP_LOG("Failed to get GPG serial");
return false;
}
return true;
}
default:
- RNP_LOG("unknown s2k specifier: %d", (int) s2k->specifier);
+ RNP_LOG("unknown s2k specifier: %d", (int) s2k.specifier);
return false;
}
}
void
free_packet_body(pgp_packet_body_t *body)
{
free(body->data);
@@ -1106,17 +1115,17 @@ stream_parse_sk_sesskey(pgp_source_t *sr
RNP_LOG("wrong sk ptag: %d", ptag);
return RNP_ERROR_BAD_FORMAT;
}
if ((res = stream_read_packet_body(src, &pkt))) {
return res;
}
- memset(skey, 0, sizeof(*skey));
+ *skey = {};
res = RNP_ERROR_BAD_FORMAT;
/* version */
if (!get_packet_body_byte(&pkt, &bt) || ((bt != PGP_SKSK_V4) && (bt != PGP_SKSK_V5))) {
RNP_LOG("wrong packet version");
goto finish;
}
skey->version = bt;
@@ -1138,17 +1147,17 @@ stream_parse_sk_sesskey(pgp_source_t *sr
if ((skey->aalg != PGP_AEAD_EAX) && (skey->aalg != PGP_AEAD_OCB)) {
RNP_LOG("unsupported AEAD algorithm : %d", (int) skey->aalg);
res = RNP_ERROR_BAD_PARAMETERS;
goto finish;
}
}
/* s2k */
- if (!get_packet_body_s2k(&pkt, &skey->s2k)) {
+ if (!get_packet_body_s2k(pkt, skey->s2k)) {
RNP_LOG("failed to parse s2k");
goto finish;
}
if (skey->version == PGP_SKSK_V5) {
/* v5: iv + esk + tag. For both EAX and OCB ivlen and taglen are 16 octets */
size_t ivlen = pgp_cipher_aead_nonce_len(skey->aalg);
size_t taglen = pgp_cipher_aead_tag_len(skey->aalg);
@@ -1211,17 +1220,17 @@ stream_parse_pk_sesskey(pgp_source_t *sr
RNP_LOG("wrong pk ptag: %d", ptag);
return RNP_ERROR_BAD_FORMAT;
}
if ((res = stream_read_packet_body(src, &pkt))) {
return res;
}
- memset(pkey, 0, sizeof(*pkey));
+ *pkey = {};
res = RNP_ERROR_BAD_FORMAT;
/* version */
if (!get_packet_body_byte(&pkt, &bt) || (bt != PGP_PKSK_V3)) {
RNP_LOG("wrong packet version");
goto finish;
}
pkey->version = bt;
@@ -1366,17 +1375,17 @@ signature_read_v3(pgp_packet_body_t *pkt
if ((sig->hashed_data = (uint8_t *) malloc(5)) == NULL) {
RNP_LOG("allocation failed");
return RNP_ERROR_OUT_OF_MEMORY;
}
memcpy(sig->hashed_data, &buf[1], 5);
sig->hashed_len = 5;
/* signature type */
- sig->type = (pgp_sig_type_t) buf[1];
+ sig->set_type((pgp_sig_type_t) buf[1]);
/* creation time */
sig->creation_time = read_uint32(&buf[2]);
/* signer's key id */
static_assert(std::tuple_size<decltype(sig->signer)>::value == PGP_KEY_ID_SIZE,
"v3 signer field size mismatch");
memcpy(sig->signer.data(), &buf[6], PGP_KEY_ID_SIZE);
@@ -1498,19 +1507,17 @@ signature_parse_subpacket(pgp_sig_subpkt
if ((oklen = subpkt.len >= 1)) {
subpkt.fields.revocation_reason.code = (pgp_revocation_type_t) subpkt.data[0];
subpkt.fields.revocation_reason.str = (const char *) &subpkt.data[1];
subpkt.fields.revocation_reason.len = subpkt.len - 1;
}
break;
case PGP_SIG_SUBPKT_FEATURES:
if ((oklen = subpkt.len >= 1)) {
- subpkt.fields.features.mdc = subpkt.data[0] & 0x01;
- subpkt.fields.features.aead = subpkt.data[0] & 0x02;
- subpkt.fields.features.key_v5 = subpkt.data[0] & 0x04;
+ subpkt.fields.features = subpkt.data[0];
}
break;
case PGP_SIG_SUBPKT_SIGNATURE_TARGET:
if ((oklen = subpkt.len >= 18)) {
subpkt.fields.sig_target.pkalg = (pgp_pubkey_alg_t) subpkt.data[0];
subpkt.fields.sig_target.halg = (pgp_hash_alg_t) subpkt.data[1];
subpkt.fields.sig_target.hash = &subpkt.data[2];
subpkt.fields.sig_target.hlen = subpkt.len - 2;
@@ -1661,17 +1668,17 @@ signature_read_v4(pgp_packet_body_t *pkt
rnp_result_t res = RNP_ERROR_BAD_FORMAT;
if (!get_packet_body_buf(pkt, buf, 5)) {
RNP_LOG("cannot get first 5 bytes");
return RNP_ERROR_BAD_FORMAT;
}
/* signature type */
- sig->type = (pgp_sig_type_t) buf[0];
+ sig->set_type((pgp_sig_type_t) buf[0]);
/* public key algorithm */
sig->palg = (pgp_pubkey_alg_t) buf[1];
/* hash algorithm */
sig->halg = (pgp_hash_alg_t) buf[2];
/* hashed subpackets length */
@@ -2094,17 +2101,17 @@ stream_parse_key(pgp_source_t *src, pgp_
}
/* Read the packet into memory */
if ((res = stream_read_packet_body(src, &pkt))) {
return res;
}
res = RNP_ERROR_BAD_FORMAT;
- memset(key, 0, sizeof(*key));
+ *key = {};
/* key type, i.e. tag */
key->tag = pkt.tag;
/* version */
if (!get_packet_body_byte(&pkt, &ver) || (ver < PGP_V2) || (ver > PGP_V4)) {
RNP_LOG("wrong key packet version");
goto finish;
@@ -2216,17 +2223,17 @@ stream_parse_key(pgp_source_t *src, pgp_
switch (key->sec_protection.s2k.usage) {
case PGP_S2KU_NONE:
break;
case PGP_S2KU_ENCRYPTED:
case PGP_S2KU_ENCRYPTED_AND_HASHED: {
/* we have s2k */
uint8_t salg = 0;
if (!get_packet_body_byte(&pkt, &salg) ||
- !get_packet_body_s2k(&pkt, &key->sec_protection.s2k)) {
+ !get_packet_body_s2k(pkt, key->sec_protection.s2k)) {
RNP_LOG("failed to read key protection");
goto finish;
}
key->sec_protection.symm_alg = (pgp_symm_alg_t) salg;
break;
}
default:
/* old-style: usage is symmetric algorithm identifier */
--- a/third_party/rnp/src/librepgp/stream-parse.cpp
+++ b/third_party/rnp/src/librepgp/stream-parse.cpp
@@ -751,17 +751,17 @@ add_hash_for_sig(pgp_source_signed_param
}
return pgp_hash_list_add(param->hashes, halg);
}
static const pgp_hash_t *
get_hash_for_sig(pgp_source_signed_param_t *param, pgp_signature_info_t *sinfo)
{
/* Cleartext always uses param->hashes instead of param->txt_hashes */
- if (!param->cleartext && (sinfo->sig->type == PGP_SIG_TEXT)) {
+ if (!param->cleartext && (sinfo->sig->type() == PGP_SIG_TEXT)) {
return pgp_hash_list_get(param->txt_hashes, sinfo->sig->halg);
}
return pgp_hash_list_get(param->hashes, sinfo->sig->halg);
}
static void
signed_validate_signature(pgp_source_signed_param_t *param, pgp_signature_info_t *sinfo)
{
@@ -938,17 +938,17 @@ signed_read_signatures(pgp_source_t *src
pgp_source_signed_param_t *param = (pgp_source_signed_param_t *) src->param;
/* reading signatures */
for (auto op = param->onepasses.rbegin(); op != param->onepasses.rend(); op++) {
if ((ret = signed_read_single_signature(param, src, &sig)) != RNP_SUCCESS) {
return ret;
}
- if (!signature_matches_onepass(sig, &*op)) {
+ if (!sig || !sig->matches_onepass(*op)) {
RNP_LOG("signature doesn't match one-pass");
return RNP_ERROR_BAD_FORMAT;
}
}
return RNP_SUCCESS;
}
@@ -982,21 +982,22 @@ signed_src_finish(pgp_source_t *src)
if (!sinfo.sig) {
continue;
}
/* we need public key, however may fallback to secret later on */
keyctx.secret = false;
/* Get the key id */
- if (!signature_get_keyid(sinfo.sig, keyctx.search.by.keyid)) {
+ if (!sinfo.sig->has_keyid()) {
RNP_LOG("cannot get signer's key id from signature");
sinfo.unknown = true;
continue;
}
+ keyctx.search.by.keyid = sinfo.sig->keyid();
/* Get the public key */
if (!(key = pgp_request_key(param->handler->key_provider, &keyctx))) {
// fallback to secret key
keyctx.secret = true;
if (!(key = pgp_request_key(param->handler->key_provider, &keyctx))) {
RNP_LOG("signer's key not found");
sinfo.no_signer = true;
@@ -1818,18 +1819,18 @@ get_aead_src_hdr(pgp_source_t *src, pgp_
static rnp_result_t
encrypted_read_packet_data(pgp_source_encrypted_param_t *param)
{
rnp_result_t errcode = RNP_ERROR_GENERIC;
uint8_t ptag;
uint8_t mdcver;
uint8_t hdr[4];
int ptype;
- pgp_sk_sesskey_t skey = {0};
- pgp_pk_sesskey_t pkey = {0};
+ pgp_sk_sesskey_t skey;
+ pgp_pk_sesskey_t pkey;
/* Reading pk/sk encrypted session key(s) */
while (true) {
if (!src_peek_eq(param->pkt.readsrc, &ptag, 1)) {
RNP_LOG("failed to read packet header");
return RNP_ERROR_READ;
}
ptype = get_packet_type(ptag);
@@ -2193,19 +2194,19 @@ init_signed_src(pgp_parse_handler_t *han
if (onepass.nested) {
/* despite the name non-zero value means that it is the last one-pass */
break;
}
} else if (ptype == PGP_PKT_SIGNATURE) {
/* no need to check the error here - we already know tag */
signed_read_single_signature(param, readsrc, &sig);
/* adding hash context */
- if (sig && !add_hash_for_sig(param, sig->type, sig->halg)) {
+ if (sig && !add_hash_for_sig(param, sig->type(), sig->halg)) {
RNP_LOG(
- "Failed to create hash %d for sig %d.", (int) sig->halg, (int) sig->type);
+ "Failed to create hash %d for sig %d.", (int) sig->halg, (int) sig->type());
errcode = RNP_ERROR_BAD_PARAMETERS;
goto finish;
}
} else {
break;
}
/* check if we are not it endless loop */
--- a/third_party/rnp/src/librepgp/stream-sig.cpp
+++ b/third_party/rnp/src/librepgp/stream-sig.cpp
@@ -29,645 +29,28 @@
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#include "uniwin.h"
#endif
#include <string.h>
#include <type_traits>
+#include <stdexcept>
#include <rnp/rnp_def.h>
#include "types.h"
#include "stream-sig.h"
#include "stream-packet.h"
#include "stream-armor.h"
#include "pgp-key.h"
#include "crypto/signatures.h"
#include <time.h>
bool
-signature_matches_onepass(pgp_signature_t *sig, pgp_one_pass_sig_t *onepass)
-{
- if (!sig || !onepass) {
- return false;
- }
-
- pgp_key_id_t keyid = {};
- if (!signature_get_keyid(sig, keyid)) {
- return false;
- }
-
- return (keyid == onepass->keyid) && (sig->halg == onepass->halg) &&
- (sig->palg == onepass->palg) && (sig->type == onepass->type);
-}
-
-pgp_sig_subpkt_t *
-signature_get_subpkt(pgp_signature_t *sig, pgp_sig_subpacket_type_t type)
-{
- if (!sig || (sig->version < PGP_V4)) {
- return NULL;
- }
- for (auto &subpkt : sig->subpkts) {
- if (subpkt.type == type) {
- return &subpkt;
- }
- }
- return NULL;
-}
-
-const pgp_sig_subpkt_t *
-signature_get_subpkt(const pgp_signature_t *sig, pgp_sig_subpacket_type_t type)
-{
- if (!sig || (sig->version < PGP_V4)) {
- return NULL;
- }
- for (auto &subpkt : sig->subpkts) {
- if (subpkt.type == type) {
- return &subpkt;
- }
- }
- return NULL;
-}
-
-pgp_sig_subpkt_t *
-signature_add_subpkt(pgp_signature_t * sig,
- pgp_sig_subpacket_type_t type,
- size_t datalen,
- bool reuse)
-{
- pgp_sig_subpkt_t *subpkt = NULL;
- if (!sig) {
- return NULL;
- }
- if (sig->version < PGP_V4) {
- RNP_LOG("wrong signature version");
- return NULL;
- }
-
- uint8_t *newdata = (uint8_t *) calloc(1, datalen);
- if (!newdata) {
- RNP_LOG("Allocation failed");
- return NULL;
- }
-
- if (reuse && (subpkt = signature_get_subpkt(sig, type))) {
- *subpkt = {};
- } else {
- try {
- sig->subpkts.push_back({});
- subpkt = &sig->subpkts.back();
- } catch (const std::exception &e) {
- RNP_LOG("%s", e.what());
- free(newdata);
- return NULL;
- }
- }
-
- subpkt->data = newdata;
- subpkt->type = type;
- subpkt->len = datalen;
- return subpkt;
-}
-
-void
-signature_remove_subpkt(pgp_signature_t *sig, pgp_sig_subpkt_t *subpkt)
-{
- for (auto it = sig->subpkts.begin(); it < sig->subpkts.end(); it++) {
- if (&*it == subpkt) {
- sig->subpkts.erase(it);
- return;
- }
- }
-}
-
-pgp_sig_type_t
-signature_get_type(const pgp_signature_t *sig)
-{
- return sig->type;
-}
-
-bool
-signature_has_keyfp(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_FPR);
-}
-
-bool
-signature_get_keyfp(const pgp_signature_t *sig, pgp_fingerprint_t &fp)
-{
- if (!sig || (sig->version < PGP_V4)) {
- return false;
- }
-
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_FPR);
- if (!subpkt) {
- return false;
- }
- fp.length = subpkt->fields.issuer_fp.len;
- if (subpkt->fields.issuer_fp.len <= sizeof(fp.fingerprint)) {
- memcpy(fp.fingerprint, subpkt->fields.issuer_fp.fp, subpkt->fields.issuer_fp.len);
- return true;
- }
- return false;
-}
-
-bool
-signature_set_keyfp(pgp_signature_t *sig, const pgp_fingerprint_t &fp)
-{
- pgp_sig_subpkt_t *subpkt = NULL;
-
- if (!sig) {
- return false;
- }
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_FPR, 1 + fp.length, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = 4;
- memcpy(subpkt->data + 1, fp.fingerprint, fp.length);
- subpkt->fields.issuer_fp.len = fp.length;
- subpkt->fields.issuer_fp.version = subpkt->data[0];
- subpkt->fields.issuer_fp.fp = subpkt->data + 1;
- return true;
-}
-
-bool
-signature_has_keyid(const pgp_signature_t *sig)
-{
- if (!sig) {
- return false;
- }
-
- return (sig->version < PGP_V4) ||
- signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_KEY_ID) ||
- signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_FPR);
-}
-
-bool
-signature_get_keyid(const pgp_signature_t *sig, pgp_key_id_t &id)
-{
- if (!sig) {
- return false;
- }
-
- /* version 3 uses signature field */
- if (sig->version < PGP_V4) {
- id = sig->signer;
- return true;
- }
-
- /* version 4 and up use subpackets */
- const pgp_sig_subpkt_t *subpkt;
- static_assert(std::tuple_size<std::remove_reference<decltype(id)>::type>::value ==
- PGP_KEY_ID_SIZE,
- "pgp_key_id_t size mismatch");
- if ((subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_KEY_ID))) {
- memcpy(id.data(), subpkt->fields.issuer, PGP_KEY_ID_SIZE);
- return true;
- }
- if ((subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_FPR))) {
- memcpy(id.data(),
- subpkt->fields.issuer_fp.fp + subpkt->fields.issuer_fp.len - PGP_KEY_ID_SIZE,
- PGP_KEY_ID_SIZE);
- return true;
- }
- return false;
-}
-
-bool
-signature_set_keyid(pgp_signature_t *sig, const pgp_key_id_t &id)
-{
- if (!sig) {
- return false;
- }
-
- if (sig->version < PGP_V4) {
- sig->signer = id;
- return true;
- }
-
- static_assert(std::tuple_size<std::remove_reference<decltype(id)>::type>::value ==
- PGP_KEY_ID_SIZE,
- "pgp_key_id_t size mismatch");
- pgp_sig_subpkt_t *subpkt =
- signature_add_subpkt(sig, PGP_SIG_SUBPKT_ISSUER_KEY_ID, PGP_KEY_ID_SIZE, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 0;
- memcpy(subpkt->data, id.data(), PGP_KEY_ID_SIZE);
- subpkt->fields.issuer = subpkt->data;
- return true;
-}
-
-uint32_t
-signature_get_creation(const pgp_signature_t *sig)
-{
- if (!sig) {
- return 0;
- }
- if (sig->version < PGP_V4) {
- return sig->creation_time;
- }
- const pgp_sig_subpkt_t *subpkt;
- if ((subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_CREATION_TIME))) {
- return subpkt->fields.create;
- }
-
- return 0;
-}
-
-bool
-signature_set_creation(pgp_signature_t *sig, uint32_t ctime)
-{
- pgp_sig_subpkt_t *subpkt;
-
- if (!sig) {
- return false;
- }
- if (sig->version < PGP_V4) {
- sig->creation_time = ctime;
- return true;
- }
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_CREATION_TIME, 4, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- STORE32BE(subpkt->data, ctime);
- subpkt->fields.create = ctime;
- return true;
-}
-
-uint32_t
-signature_get_expiration(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_EXPIRATION_TIME);
- return subpkt ? subpkt->fields.expiry : 0;
-}
-
-bool
-signature_set_expiration(pgp_signature_t *sig, uint32_t etime)
-{
- pgp_sig_subpkt_t *subpkt;
-
- if (!sig || (sig->version < PGP_V4)) {
- return false;
- }
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_EXPIRATION_TIME, 4, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- STORE32BE(subpkt->data, etime);
- subpkt->fields.expiry = etime;
- return true;
-}
-
-bool
-signature_has_key_expiration(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEY_EXPIRY);
-}
-
-uint32_t
-signature_get_key_expiration(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEY_EXPIRY);
- return subpkt ? subpkt->fields.expiry : 0;
-}
-
-bool
-signature_set_key_expiration(pgp_signature_t *sig, uint32_t etime)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_KEY_EXPIRY, 4, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- STORE32BE(subpkt->data, etime);
- subpkt->fields.expiry = etime;
- return true;
-}
-
-bool
-signature_has_key_flags(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEY_FLAGS);
-}
-
-uint8_t
-signature_get_key_flags(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEY_FLAGS);
- return subpkt ? subpkt->fields.key_flags : 0;
-}
-
-bool
-signature_set_key_flags(pgp_signature_t *sig, uint8_t flags)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_KEY_FLAGS, 1, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = flags;
- subpkt->fields.key_flags = flags;
- return true;
-}
-
-bool
-signature_get_primary_uid(pgp_signature_t *sig)
-{
- pgp_sig_subpkt_t *subpkt;
-
- if ((subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_PRIMARY_USER_ID))) {
- return subpkt->fields.primary_uid;
- }
-
- return false;
-}
-
-bool
-signature_set_primary_uid(pgp_signature_t *sig, bool primary)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_PRIMARY_USER_ID, 1, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = primary;
- subpkt->fields.primary_uid = primary;
- return true;
-}
-
-static bool
-signature_set_preferred_algs(pgp_signature_t * sig,
- uint8_t algs[],
- size_t len,
- pgp_sig_subpacket_type_t type)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, type, len, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- memcpy(subpkt->data, algs, len);
- subpkt->fields.preferred.arr = subpkt->data;
- subpkt->fields.preferred.len = len;
- return true;
-}
-
-static bool
-signature_get_preferred_algs(const pgp_signature_t * sig,
- uint8_t ** algs,
- size_t * len,
- pgp_sig_subpacket_type_t type)
-{
- if (!algs || !len) {
- return false;
- }
-
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, type);
- if (subpkt) {
- *algs = subpkt->fields.preferred.arr;
- *len = subpkt->fields.preferred.len;
- return true;
- }
- return false;
-}
-
-bool
-signature_has_preferred_symm_algs(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_PREFERRED_SKA);
-}
-
-bool
-signature_get_preferred_symm_algs(const pgp_signature_t *sig, uint8_t **algs, size_t *count)
-{
- return signature_get_preferred_algs(sig, algs, count, PGP_SIG_SUBPKT_PREFERRED_SKA);
-}
-
-bool
-signature_set_preferred_symm_algs(pgp_signature_t *sig, uint8_t algs[], size_t len)
-{
- return signature_set_preferred_algs(sig, algs, len, PGP_SIG_SUBPKT_PREFERRED_SKA);
-}
-
-bool
-signature_has_preferred_hash_algs(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_PREFERRED_HASH);
-}
-
-bool
-signature_get_preferred_hash_algs(const pgp_signature_t *sig, uint8_t **algs, size_t *count)
-{
- return signature_get_preferred_algs(sig, algs, count, PGP_SIG_SUBPKT_PREFERRED_HASH);
-}
-
-bool
-signature_set_preferred_hash_algs(pgp_signature_t *sig, uint8_t algs[], size_t len)
-{
- return signature_set_preferred_algs(sig, algs, len, PGP_SIG_SUBPKT_PREFERRED_HASH);
-}
-
-bool
-signature_has_preferred_z_algs(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_PREF_COMPRESS);
-}
-
-bool
-signature_get_preferred_z_algs(const pgp_signature_t *sig, uint8_t **algs, size_t *count)
-{
- return signature_get_preferred_algs(sig, algs, count, PGP_SIG_SUBPKT_PREF_COMPRESS);
-}
-
-bool
-signature_set_preferred_z_algs(pgp_signature_t *sig, uint8_t algs[], size_t len)
-{
- return signature_set_preferred_algs(sig, algs, len, PGP_SIG_SUBPKT_PREF_COMPRESS);
-}
-
-bool
-signature_has_key_server_prefs(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEYSERV_PREFS);
-}
-
-uint8_t
-signature_get_key_server_prefs(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_KEYSERV_PREFS);
- return subpkt ? subpkt->data[0] : 0;
-}
-
-bool
-signature_set_key_server_prefs(pgp_signature_t *sig, uint8_t prefs)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_KEYSERV_PREFS, 1, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = prefs;
- subpkt->fields.ks_prefs.no_modify = prefs & 0x80;
- return true;
-}
-
-bool
-signature_set_preferred_key_server(pgp_signature_t *sig, const char *uri)
-{
- pgp_sig_subpkt_t *subpkt;
- size_t len = strlen(uri);
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_PREF_KEYSERV, len, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- memcpy(subpkt->data, uri, len);
- subpkt->fields.preferred_ks.uri = (char *) subpkt->data;
- subpkt->fields.preferred_ks.len = len;
- return true;
-}
-
-bool
-signature_has_trust(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_TRUST);
-}
-
-bool
-signature_get_trust(const pgp_signature_t *sig, uint8_t *level, uint8_t *amount)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_TRUST);
- if (subpkt) {
- if (level) {
- *level = subpkt->fields.trust.level;
- }
- if (amount) {
- *amount = subpkt->fields.trust.amount;
- }
- return true;
- }
- return false;
-}
-
-bool
-signature_set_trust(pgp_signature_t *sig, uint8_t level, uint8_t amount)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_TRUST, 2, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = level;
- subpkt->data[1] = amount;
- subpkt->fields.trust.level = level;
- subpkt->fields.trust.amount = amount;
- return true;
-}
-
-bool
-signature_get_revocable(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_REVOCABLE);
- return subpkt ? subpkt->fields.revocable : true;
-}
-
-bool
-signature_set_revocable(pgp_signature_t *sig, bool revocable)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_REVOCABLE, 1, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->parsed = 1;
- subpkt->hashed = 1;
- subpkt->data[0] = revocable;
- subpkt->fields.revocable = revocable;
- return true;
-}
-
-bool
-signature_set_features(pgp_signature_t *sig, uint8_t features)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_FEATURES, 1, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->hashed = 1;
- subpkt->data[0] = features;
- return signature_parse_subpacket(*subpkt);
-}
-
-bool
-signature_set_signer_uid(pgp_signature_t *sig, uint8_t *uid, size_t len)
-{
- pgp_sig_subpkt_t *subpkt;
-
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_SIGNERS_USER_ID, len, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->hashed = 1;
- memcpy(subpkt->data, uid, len);
- return signature_parse_subpacket(*subpkt);
-}
-
-bool
signature_set_embedded_sig(pgp_signature_t *sig, pgp_signature_t *esig)
{
pgp_sig_subpkt_t *subpkt = NULL;
pgp_dest_t memdst = {};
pgp_source_t memsrc = {};
size_t len = 0;
bool res = false;
@@ -683,149 +66,69 @@ signature_set_embedded_sig(pgp_signature
RNP_LOG("failed to init mem src");
goto finish;
}
if (!stream_read_pkt_len(&memsrc, &len)) {
RNP_LOG("wrong pkt len");
goto finish;
}
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, len, true);
- if (!subpkt) {
- RNP_LOG("failed to add subpkt");
- goto finish;
- }
-
- subpkt->hashed = 0;
- if (!src_read_eq(&memsrc, subpkt->data, len)) {
- RNP_LOG("failed to read back signature");
- goto finish;
- }
try {
+ subpkt = &sig->add_subpkt(PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, len, true);
+ subpkt->hashed = false;
+ if (!src_read_eq(&memsrc, subpkt->data, len)) {
+ RNP_LOG("failed to read back signature");
+ goto finish;
+ }
subpkt->fields.sig = new pgp_signature_t(*esig);
+ subpkt->parsed = true;
+ res = true;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
- goto finish;
}
- subpkt->parsed = 1;
- res = true;
finish:
if (!res && subpkt) {
- signature_remove_subpkt(sig, subpkt);
+ sig->remove_subpkt(subpkt);
}
src_close(&memsrc);
dst_close(&memdst, true);
return res;
}
bool
signature_add_notation_data(pgp_signature_t *sig,
bool readable,
const char * name,
const char * value)
{
- pgp_sig_subpkt_t *subpkt;
- size_t nlen, vlen;
-
- nlen = strlen(name);
- vlen = strlen(value);
+ size_t nlen = strlen(name);
+ size_t vlen = strlen(value);
if ((nlen > 0xffff) || (vlen > 0xffff)) {
RNP_LOG("wrong length");
return false;
}
- subpkt = signature_add_subpkt(sig, PGP_SIG_SUBPKT_NOTATION_DATA, 8 + nlen + vlen, false);
- if (!subpkt) {
+ try {
+ pgp_sig_subpkt_t &subpkt =
+ sig->add_subpkt(PGP_SIG_SUBPKT_NOTATION_DATA, 8 + nlen + vlen, false);
+ subpkt.hashed = true;
+ if (readable) {
+ subpkt.data[0] = 0x80;
+ subpkt.fields.notation.flags[0] = 0x80;
+ }
+ write_uint16(subpkt.data + 4, nlen);
+ memcpy(subpkt.data + 6, name, nlen);
+ write_uint16(subpkt.data + 6 + nlen, vlen);
+ memcpy(subpkt.data + 8 + nlen, value, vlen);
+ return signature_parse_subpacket(subpkt);
+ } catch (const std::exception &e) {
+ RNP_LOG("%s", e.what());
return false;
}
-
- subpkt->hashed = 1;
- if (readable) {
- subpkt->data[0] = 0x80;
- subpkt->fields.notation.flags[0] = 0x80;
- }
- write_uint16(subpkt->data + 4, nlen);
- memcpy(subpkt->data + 6, name, nlen);
- write_uint16(subpkt->data + 6 + nlen, vlen);
- memcpy(subpkt->data + 8 + nlen, value, vlen);
- return signature_parse_subpacket(*subpkt);
-}
-
-bool
-signature_has_key_server(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_PREF_KEYSERV);
-}
-
-char *
-signature_get_key_server(const pgp_signature_t *sig)
-{
- const pgp_sig_subpkt_t *subpkt = signature_get_subpkt(sig, PGP_SIG_SUBPKT_PREF_KEYSERV);
- if (subpkt) {
- char *res = (char *) malloc(subpkt->len + 1);
- if (res) {
- memcpy(res, subpkt->data, subpkt->len);
- res[subpkt->len] = '\0';
- }
- return res;
- }
- return NULL;
-}
-
-bool
-signature_has_revocation_reason(const pgp_signature_t *sig)
-{
- return signature_get_subpkt(sig, PGP_SIG_SUBPKT_REVOCATION_REASON);
-}
-
-bool
-signature_get_revocation_reason(const pgp_signature_t *sig,
- pgp_revocation_type_t *code,
- char ** reason)
-{
- const pgp_sig_subpkt_t *subpkt =
- signature_get_subpkt(sig, PGP_SIG_SUBPKT_REVOCATION_REASON);
- if (subpkt) {
- if (code) {
- *code = subpkt->fields.revocation_reason.code;
- }
- if (reason) {
- size_t len = subpkt->fields.revocation_reason.len;
- *reason = (char *) malloc(len + 1);
- if (!*reason) {
- RNP_LOG("alloc failed");
- return false;
- }
- memcpy(*reason, subpkt->fields.revocation_reason.str, len);
- (*reason)[len] = '\0';
- }
- return true;
- }
- return false;
-}
-
-bool
-signature_set_revocation_reason(pgp_signature_t * sig,
- pgp_revocation_type_t code,
- const char * reason)
-{
- size_t datalen = 1 + (reason ? strlen(reason) : 0);
- pgp_sig_subpkt_t *subpkt =
- signature_add_subpkt(sig, PGP_SIG_SUBPKT_REVOCATION_REASON, datalen, true);
- if (!subpkt) {
- return false;
- }
-
- subpkt->hashed = 1;
- subpkt->data[0] = code;
- if (reason) {
- memcpy(subpkt->data + 1, reason, strlen(reason));
- }
- return signature_parse_subpacket(*subpkt);
}
bool
signature_fill_hashed_data(pgp_signature_t *sig)
{
pgp_packet_body_t hbody;
bool res;
@@ -840,21 +143,21 @@ signature_fill_hashed_data(pgp_signature
}
if (!init_packet_body(&hbody, PGP_PKT_RESERVED)) {
RNP_LOG("allocation failed");
return false;
}
if (sig->version < PGP_V4) {
- res = add_packet_body_byte(&hbody, sig->type) &&
+ res = add_packet_body_byte(&hbody, sig->type()) &&
add_packet_body_uint32(&hbody, sig->creation_time);
} else {
res = add_packet_body_byte(&hbody, sig->version) &&
- add_packet_body_byte(&hbody, sig->type) &&
+ add_packet_body_byte(&hbody, sig->type()) &&
add_packet_body_byte(&hbody, sig->palg) &&
add_packet_body_byte(&hbody, sig->halg) &&
add_packet_body_subpackets(&hbody, sig, true);
}
if (res) {
free(sig->hashed_data);
/* get ownership on body data */
@@ -1000,20 +303,19 @@ signature_hash_direct(const pgp_signatur
}
return res;
}
rnp_result_t
signature_check(pgp_signature_info_t *sinfo, pgp_hash_t *hash)
{
- time_t now;
- uint32_t create, expiry, kcreate;
- pgp_fingerprint_t fp = {};
- rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID;
+ time_t now;
+ uint32_t create, expiry, kcreate;
+ rnp_result_t ret = RNP_ERROR_SIGNATURE_INVALID;
sinfo->no_signer = !sinfo->signer;
sinfo->valid = false;
sinfo->expired = false;
if (!sinfo->sig) {
ret = RNP_ERROR_NULL_POINTER;
goto finish;
@@ -1030,18 +332,18 @@ signature_check(pgp_signature_info_t *si
!signature_validate(sinfo->sig, pgp_key_get_material(sinfo->signer), hash);
} else {
sinfo->valid = false;
RNP_LOG("invalid or untrusted key");
}
/* Check signature's expiration time */
now = time(NULL);
- create = signature_get_creation(sinfo->sig);
- expiry = signature_get_expiration(sinfo->sig);
+ create = sinfo->sig->creation();
+ expiry = sinfo->sig->expiration();
if (create > now) {
/* signature created later then now */
RNP_LOG("signature created %d seconds in future", (int) (create - now));
sinfo->expired = true;
}
if (create && expiry && (create + expiry < now)) {
/* signature expired */
RNP_LOG("signature expired");
@@ -1058,17 +360,17 @@ signature_check(pgp_signature_info_t *si
/* check whether key was not expired when sig created */
if (!sinfo->ignore_expiry && pgp_key_get_expiration(sinfo->signer) &&
(kcreate + pgp_key_get_expiration(sinfo->signer) < create)) {
RNP_LOG("signature made after key expiration");
sinfo->valid = false;
}
/* Check signer's fingerprint */
- if (signature_get_keyfp(sinfo->sig, fp) && (fp != pgp_key_get_fp(sinfo->signer))) {
+ if (sinfo->sig->has_keyfp() && (sinfo->sig->keyfp() != pgp_key_get_fp(sinfo->signer))) {
RNP_LOG("issuer fingerprint doesn't match signer's one");
sinfo->valid = false;
}
if (sinfo->expired && sinfo->valid) {
ret = RNP_ERROR_SIGNATURE_EXPIRED;
} else {
ret = sinfo->valid ? RNP_SUCCESS : RNP_ERROR_SIGNATURE_INVALID;
@@ -1100,34 +402,34 @@ signature_check_binding(pgp_signature_in
pgp_hash_t hash = {};
rnp_result_t res = RNP_ERROR_SIGNATURE_INVALID;
if (!signature_hash_binding(sinfo->sig, key, pgp_key_get_pkt(subkey), &hash)) {
return RNP_ERROR_BAD_FORMAT;
}
res = signature_check(sinfo, &hash);
- if (res || !(signature_get_key_flags(sinfo->sig) & PGP_KF_SIGN)) {
+ if (res || !(sinfo->sig->key_flags() & PGP_KF_SIGN)) {
return res;
}
/* check primary key binding signature if any */
res = RNP_ERROR_SIGNATURE_INVALID;
sinfo->valid = false;
pgp_sig_subpkt_t *subpkt =
- signature_get_subpkt(sinfo->sig, PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE);
+ sinfo->sig->get_subpkt(PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE, false);
if (!subpkt) {
RNP_LOG("error! no primary key binding signature");
return res;
}
if (!subpkt->parsed) {
RNP_LOG("invalid embedded signature subpacket");
return res;
}
- if (subpkt->fields.sig->type != PGP_SIG_PRIMARY) {
+ if (subpkt->fields.sig->type() != PGP_SIG_PRIMARY) {
RNP_LOG("invalid primary key binding signature");
return res;
}
if (subpkt->fields.sig->version < PGP_V4) {
RNP_LOG("invalid primary key binding signature version");
return res;
}
@@ -1314,17 +616,17 @@ pgp_sig_subpkt_t::~pgp_sig_subpkt_t()
delete fields.sig;
}
free(data);
}
pgp_signature_t::pgp_signature_t(const pgp_signature_t &src)
{
version = src.version;
- type = src.type;
+ type_ = src.type_;
palg = src.palg;
halg = src.halg;
memcpy(lbits, src.lbits, sizeof(src.lbits));
creation_time = src.creation_time;
signer = src.signer;
hashed_len = src.hashed_len;
hashed_data = NULL;
@@ -1343,17 +645,17 @@ pgp_signature_t::pgp_signature_t(const p
memcpy(material_buf, src.material_buf, material_len);
}
subpkts = src.subpkts;
}
pgp_signature_t::pgp_signature_t(pgp_signature_t &&src)
{
version = src.version;
- type = src.type;
+ type_ = src.type_;
palg = src.palg;
halg = src.halg;
memcpy(lbits, src.lbits, sizeof(src.lbits));
creation_time = src.creation_time;
signer = src.signer;
hashed_len = src.hashed_len;
hashed_data = src.hashed_data;
src.hashed_data = NULL;
@@ -1366,17 +668,17 @@ pgp_signature_t::pgp_signature_t(pgp_sig
pgp_signature_t &
pgp_signature_t::operator=(pgp_signature_t &&src)
{
if (this == &src) {
return *this;
}
version = src.version;
- type = src.type;
+ type_ = src.type_;
palg = src.palg;
halg = src.halg;
memcpy(lbits, src.lbits, sizeof(src.lbits));
creation_time = src.creation_time;
signer = src.signer;
hashed_len = src.hashed_len;
free(hashed_data);
hashed_data = src.hashed_data;
@@ -1393,17 +695,17 @@ pgp_signature_t::operator=(pgp_signature
pgp_signature_t &
pgp_signature_t::operator=(const pgp_signature_t &src)
{
if (this == &src) {
return *this;
}
version = src.version;
- type = src.type;
+ type_ = src.type_;
palg = src.palg;
halg = src.halg;
memcpy(lbits, src.lbits, sizeof(src.lbits));
creation_time = src.creation_time;
signer = src.signer;
hashed_len = src.hashed_len;
free(hashed_data);
@@ -1447,8 +749,525 @@ pgp_signature_t::operator!=(const pgp_si
return !(*this == src);
}
pgp_signature_t::~pgp_signature_t()
{
free(hashed_data);
free(material_buf);
}
+
+pgp_sig_subpkt_t *
+pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed)
+{
+ if (version < PGP_V4) {
+ return NULL;
+ }
+ for (auto &subpkt : subpkts) {
+ /* if hashed is false then accept any hashed/not hashed subpacket */
+ if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) {
+ return &subpkt;
+ }
+ }
+ return NULL;
+}
+
+const pgp_sig_subpkt_t *
+pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) const
+{
+ if (version < PGP_V4) {
+ return NULL;
+ }
+ for (auto &subpkt : subpkts) {
+ /* if hashed is false then accept any hashed/not hashed subpacket */
+ if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) {
+ return &subpkt;
+ }
+ }
+ return NULL;
+}
+
+bool
+pgp_signature_t::has_subpkt(pgp_sig_subpacket_type_t stype, bool hashed) const
+{
+ if (version < PGP_V4) {
+ return false;
+ }
+ for (auto &subpkt : subpkts) {
+ /* if hashed is false then accept any hashed/not hashed subpacket */
+ if ((subpkt.type == stype) && (!hashed || subpkt.hashed)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+pgp_signature_t::has_keyid() const
+{
+ return (version < PGP_V4) || has_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false) ||
+ has_keyfp();
+}
+
+pgp_key_id_t
+pgp_signature_t::keyid() const
+{
+ /* version 3 uses signature field */
+ if (version < PGP_V4) {
+ return signer;
+ }
+
+ /* version 4 and up use subpackets */
+ pgp_key_id_t res;
+ static_assert(std::tuple_size<decltype(res)>::value == PGP_KEY_ID_SIZE,
+ "pgp_key_id_t size mismatch");
+
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false);
+ if (subpkt) {
+ memcpy(res.data(), subpkt->fields.issuer, PGP_KEY_ID_SIZE);
+ return res;
+ }
+ if ((subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR))) {
+ memcpy(res.data(),
+ subpkt->fields.issuer_fp.fp + subpkt->fields.issuer_fp.len - PGP_KEY_ID_SIZE,
+ PGP_KEY_ID_SIZE);
+ return res;
+ }
+ throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
+}
+
+void
+pgp_signature_t::set_keyid(const pgp_key_id_t &id)
+{
+ if (version < PGP_V4) {
+ signer = id;
+ return;
+ }
+
+ static_assert(std::tuple_size<std::remove_reference<decltype(id)>::type>::value ==
+ PGP_KEY_ID_SIZE,
+ "pgp_key_id_t size mismatch");
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, PGP_KEY_ID_SIZE, true);
+ subpkt.parsed = true;
+ subpkt.hashed = false;
+ memcpy(subpkt.data, id.data(), PGP_KEY_ID_SIZE);
+ subpkt.fields.issuer = subpkt.data;
+}
+
+bool
+pgp_signature_t::has_keyfp() const
+{
+ if (version < PGP_V4) {
+ return false;
+ }
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR);
+ return subpkt && (subpkt->fields.issuer_fp.len <= PGP_FINGERPRINT_SIZE);
+}
+
+pgp_fingerprint_t
+pgp_signature_t::keyfp() const
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR);
+ pgp_fingerprint_t res;
+ if (!subpkt || (subpkt->fields.issuer_fp.len > sizeof(res.fingerprint))) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+ res.length = subpkt->fields.issuer_fp.len;
+ memcpy(res.fingerprint, subpkt->fields.issuer_fp.fp, subpkt->fields.issuer_fp.len);
+ return res;
+}
+
+void
+pgp_signature_t::set_keyfp(const pgp_fingerprint_t &fp)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR, 1 + fp.length, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = 4;
+ memcpy(subpkt.data + 1, fp.fingerprint, fp.length);
+ subpkt.fields.issuer_fp.len = fp.length;
+ subpkt.fields.issuer_fp.version = subpkt.data[0];
+ subpkt.fields.issuer_fp.fp = subpkt.data + 1;
+}
+
+uint32_t
+pgp_signature_t::creation() const
+{
+ if (version < PGP_V4) {
+ return creation_time;
+ }
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_CREATION_TIME);
+ return subpkt ? subpkt->fields.create : 0;
+}
+
+void
+pgp_signature_t::set_creation(uint32_t ctime)
+{
+ if (version < PGP_V4) {
+ creation_time = ctime;
+ return;
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_CREATION_TIME, 4, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ STORE32BE(subpkt.data, ctime);
+ subpkt.fields.create = ctime;
+}
+
+uint32_t
+pgp_signature_t::expiration() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_EXPIRATION_TIME);
+ return subpkt ? subpkt->fields.expiry : 0;
+}
+
+void
+pgp_signature_t::set_expiration(uint32_t etime)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_EXPIRATION_TIME, 4, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ STORE32BE(subpkt.data, etime);
+ subpkt.fields.expiry = etime;
+}
+
+uint32_t
+pgp_signature_t::key_expiration() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY);
+ return subpkt ? subpkt->fields.expiry : 0;
+}
+
+void
+pgp_signature_t::set_key_expiration(uint32_t etime)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEY_EXPIRY, 4, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ STORE32BE(subpkt.data, etime);
+ subpkt.fields.expiry = etime;
+}
+
+uint8_t
+pgp_signature_t::key_flags() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS);
+ return subpkt ? subpkt->fields.key_flags : 0;
+}
+
+void
+pgp_signature_t::set_key_flags(uint8_t flags)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEY_FLAGS, 1, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = flags;
+ subpkt.fields.key_flags = flags;
+}
+
+bool
+pgp_signature_t::primary_uid() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PRIMARY_USER_ID);
+ return subpkt ? subpkt->fields.primary_uid : false;
+}
+
+void
+pgp_signature_t::set_primary_uid(bool primary)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_PRIMARY_USER_ID, 1, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = primary;
+ subpkt.fields.primary_uid = primary;
+}
+
+std::vector<uint8_t>
+pgp_signature_t::preferred(pgp_sig_subpacket_type_t type) const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(type);
+ return subpkt ? std::vector<uint8_t>(subpkt->fields.preferred.arr,
+ subpkt->fields.preferred.arr +
+ subpkt->fields.preferred.len) :
+ std::vector<uint8_t>();
+}
+
+void
+pgp_signature_t::set_preferred(const std::vector<uint8_t> &data, pgp_sig_subpacket_type_t type)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+
+ if (data.empty()) {
+ pgp_sig_subpkt_t *subpkt = get_subpkt(type);
+ if (subpkt) {
+ remove_subpkt(subpkt);
+ }
+ return;
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(type, data.size(), true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ memcpy(subpkt.data, data.data(), data.size());
+ subpkt.fields.preferred.arr = subpkt.data;
+ subpkt.fields.preferred.len = data.size();
+}
+
+std::vector<uint8_t>
+pgp_signature_t::preferred_symm_algs() const
+{
+ return preferred(PGP_SIG_SUBPKT_PREFERRED_SKA);
+}
+
+void
+pgp_signature_t::set_preferred_symm_algs(const std::vector<uint8_t> &algs)
+{
+ set_preferred(algs, PGP_SIG_SUBPKT_PREFERRED_SKA);
+}
+
+std::vector<uint8_t>
+pgp_signature_t::preferred_hash_algs() const
+{
+ return preferred(PGP_SIG_SUBPKT_PREFERRED_HASH);
+}
+
+void
+pgp_signature_t::set_preferred_hash_algs(const std::vector<uint8_t> &algs)
+{
+ set_preferred(algs, PGP_SIG_SUBPKT_PREFERRED_HASH);
+}
+
+std::vector<uint8_t>
+pgp_signature_t::preferred_z_algs() const
+{
+ return preferred(PGP_SIG_SUBPKT_PREF_COMPRESS);
+}
+
+void
+pgp_signature_t::set_preferred_z_algs(const std::vector<uint8_t> &algs)
+{
+ set_preferred(algs, PGP_SIG_SUBPKT_PREF_COMPRESS);
+}
+
+uint8_t
+pgp_signature_t::key_server_prefs() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS);
+ return subpkt ? subpkt->data[0] : 0;
+}
+
+void
+pgp_signature_t::set_key_server_prefs(uint8_t prefs)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_KEYSERV_PREFS, 1, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = prefs;
+ subpkt.fields.ks_prefs.no_modify = prefs & 0x80;
+}
+
+std::string
+pgp_signature_t::key_server() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV);
+ return subpkt ? std::string((char *) subpkt->data, subpkt->len) : "";
+}
+
+void
+pgp_signature_t::set_key_server(const std::string &uri)
+{
+ if (version < PGP_V4) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+
+ if (uri.empty()) {
+ pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV);
+ if (subpkt) {
+ remove_subpkt(subpkt);
+ }
+ return;
+ }
+
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_PREF_KEYSERV, uri.size(), true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ memcpy(subpkt.data, uri.data(), uri.size());
+ subpkt.fields.preferred_ks.uri = (char *) subpkt.data;
+ subpkt.fields.preferred_ks.len = uri.size();
+}
+
+uint8_t
+pgp_signature_t::trust_level() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_TRUST);
+ return subpkt ? subpkt->fields.trust.level : 0;
+}
+
+uint8_t
+pgp_signature_t::trust_amount() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_TRUST);
+ return subpkt ? subpkt->fields.trust.amount : 0;
+}
+
+void
+pgp_signature_t::set_trust(uint8_t level, uint8_t amount)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_TRUST, 2, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = level;
+ subpkt.data[1] = amount;
+ subpkt.fields.trust.level = level;
+ subpkt.fields.trust.amount = amount;
+}
+
+bool
+pgp_signature_t::revocable() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCABLE);
+ return subpkt ? subpkt->fields.revocable : true;
+}
+
+void
+pgp_signature_t::set_revocable(bool status)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_REVOCABLE, 1, true);
+ subpkt.parsed = true;
+ subpkt.hashed = true;
+ subpkt.data[0] = status;
+ subpkt.fields.revocable = status;
+}
+
+std::string
+pgp_signature_t::revocation_reason() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON);
+ return subpkt ? std::string(subpkt->fields.revocation_reason.str,
+ subpkt->fields.revocation_reason.len) :
+ "";
+}
+
+pgp_revocation_type_t
+pgp_signature_t::revocation_code() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON);
+ return subpkt ? subpkt->fields.revocation_reason.code : PGP_REVOCATION_NO_REASON;
+}
+
+void
+pgp_signature_t::set_revocation_reason(pgp_revocation_type_t code, const std::string &reason)
+{
+ size_t datalen = 1 + reason.size();
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON, datalen, true);
+ subpkt.hashed = true;
+ subpkt.data[0] = code;
+ memcpy(subpkt.data + 1, reason.data(), reason.size());
+
+ if (!signature_parse_subpacket(subpkt)) {
+ throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
+ }
+}
+
+bool
+pgp_signature_t::key_has_features(pgp_key_feature_t flags) const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_FEATURES);
+ return subpkt ? subpkt->data[0] & flags : false;
+}
+
+void
+pgp_signature_t::set_key_features(pgp_key_feature_t flags)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_FEATURES, 1, true);
+ subpkt.hashed = true;
+ subpkt.data[0] = flags;
+ subpkt.fields.features = flags;
+ subpkt.parsed = true;
+}
+
+std::string
+pgp_signature_t::signer_uid() const
+{
+ const pgp_sig_subpkt_t *subpkt = get_subpkt(PGP_SIG_SUBPKT_SIGNERS_USER_ID);
+ return subpkt ? std::string(subpkt->fields.signer.uid, subpkt->fields.signer.len) : "";
+}
+
+void
+pgp_signature_t::set_signer_uid(const std::string &uid)
+{
+ pgp_sig_subpkt_t &subpkt = add_subpkt(PGP_SIG_SUBPKT_SIGNERS_USER_ID, uid.size(), true);
+ subpkt.hashed = true;
+ memcpy(subpkt.data, uid.data(), uid.size());
+ subpkt.fields.signer.uid = (const char *) subpkt.data;
+ subpkt.fields.signer.len = subpkt.len;
+ subpkt.parsed = true;
+}
+
+pgp_sig_subpkt_t &
+pgp_signature_t::add_subpkt(pgp_sig_subpacket_type_t type, size_t datalen, bool reuse)
+{
+ if (version < PGP_V4) {
+ RNP_LOG("wrong signature version");
+ throw std::invalid_argument("version");
+ }
+
+ uint8_t *newdata = (uint8_t *) calloc(1, datalen);
+ if (!newdata) {
+ RNP_LOG("Allocation failed");
+ throw std::bad_alloc();
+ }
+
+ pgp_sig_subpkt_t *subpkt = NULL;
+ if (reuse && (subpkt = get_subpkt(type))) {
+ *subpkt = {};
+ } else {
+ subpkts.push_back({});
+ subpkt = &subpkts.back();
+ }
+
+ subpkt->data = newdata;
+ subpkt->type = type;
+ subpkt->len = datalen;
+ return *subpkt;
+}
+
+void
+pgp_signature_t::remove_subpkt(pgp_sig_subpkt_t *subpkt)
+{
+ for (auto it = subpkts.begin(); it < subpkts.end(); it++) {
+ if (&*it == subpkt) {
+ subpkts.erase(it);
+ return;
+ }
+ }
+}
+
+bool
+pgp_signature_t::matches_onepass(const pgp_one_pass_sig_t &onepass) const
+{
+ if (!has_keyid()) {
+ return false;
+ }
+ return (halg == onepass.halg) && (palg == onepass.palg) && (type_ == onepass.type) &&
+ (onepass.keyid == keyid());
+}
--- a/third_party/rnp/src/librepgp/stream-sig.h
+++ b/third_party/rnp/src/librepgp/stream-sig.h
@@ -42,262 +42,23 @@ typedef struct pgp_signature_info_t {
bool no_signer; /* no signer's public key available */
bool expired; /* signature is expired */
bool signer_valid; /* assume that signing key is valid */
bool ignore_expiry; /* ignore signer's key expiration time */
} pgp_signature_info_t;
typedef std::vector<pgp_signature_t> pgp_signature_list_t;
-/**
- * @brief Check whether signature packet matches one-pass signature packet.
- * @param sig pointer to the read signature packet
- * @param onepass pointer to the read one-pass signature packet
- * @return true if sig corresponds to onepass or false otherwise
- */
-bool signature_matches_onepass(pgp_signature_t *sig, pgp_one_pass_sig_t *onepass);
-
-/**
- * @brief Get v4 signature's subpacket of the specified type
- * @param sig loaded or populated signature, could not be NULL
- * @param type type of the subpacket to lookup for
- * @return pointer to the subpacket structure or NULL if it was not found or error occurred
- */
-pgp_sig_subpkt_t *signature_get_subpkt(pgp_signature_t *sig, pgp_sig_subpacket_type_t type);
-const pgp_sig_subpkt_t *signature_get_subpkt(const pgp_signature_t * sig,
- pgp_sig_subpacket_type_t type);
-
-/**
- * @brief Add subpacket of the specified type to v4 signature
- * @param sig loaded or populated signature, could not be NULL
- * @param type type of the subpacket
- * @param datalen length of the subpacket body
- * @param reuse replace already existing subpacket of the specified type if any
- * @return pointer to the subpacket structure or NULL if error occurred
- */
-pgp_sig_subpkt_t *signature_add_subpkt(pgp_signature_t * sig,
- pgp_sig_subpacket_type_t type,
- size_t datalen,
- bool reuse);
-
-/**
- * @brief Remove signature's subpacket
- * @param sig loaded or populated signature, could not be NULL
- * @param subpkt subpacket to remove. If not in the subpackets list then no action is taken.
- */
-void signature_remove_subpkt(pgp_signature_t *sig, pgp_sig_subpkt_t *subpkt);
-
-/**
- * @brief Get type of the signature.
- * @param sig loaded or populated signature, could not be NULL
- * @return type of the signature
- */
-pgp_sig_type_t signature_get_type(const pgp_signature_t *sig);
-
-/**
- * @brief Check whether signature has signing key fingerprint
- * @param sig loaded or populated v4 signature, could not be NULL
- * @return true if fingerprint is available or false otherwise
- */
-bool signature_has_keyfp(const pgp_signature_t *sig);
-
-/**
- * @brief Get signing key's fingerprint if it is available
- * @param sig loaded or populated v4 signature, could not be NULL
- * @param fp reference to the fingerprint structure
- * @return true if fingerprint is available and returned or false otherwise
- */
-bool signature_get_keyfp(const pgp_signature_t *sig, pgp_fingerprint_t &fp);
-
-/**
- * @brief Set signing key fingerprint
- * @param sig v4 signature being populated
- * @param fp fingerprint structure
- * @return true on success or false otherwise;
- */
-bool signature_set_keyfp(pgp_signature_t *sig, const pgp_fingerprint_t &fp);
-
-/**
- * @brief Check whether signature has signing key id
- * @param sig populated or loaded signature
- * @return true if key id available (via v3 field, or v4 key id/key fp subpacket)
- */
-bool signature_has_keyid(const pgp_signature_t *sig);
-
-/**
- * @brief Get signature's signing key id
- * @param sig populated or loaded signature
- * @param id reference to return key identifier
- * @return true on success or false otherwise
- */
-bool signature_get_keyid(const pgp_signature_t *sig, pgp_key_id_t &id);
-
-/**
- * @brief Set the signature's key id
- * @param sig signature being populated. Version should be set prior of setting key id.
- * @param id reference to key identifier
- * @return true on success or false otherwise
- */
-bool signature_set_keyid(pgp_signature_t *sig, const pgp_key_id_t &id);
-
-/**
- * @brief Get signature's creation time
- * @param sig pointer to the loaded or populated signature.
- * @return time in seconds since the Jan 1, 1970 UTC. 0 is the default value and returned even
- * if creation time is not available
- */
-uint32_t signature_get_creation(const pgp_signature_t *sig);
-
-/**
- * @brief Set signature's creation time
- * @param sig signature being populated
- * @param ctime creation time in seconds since the Jan 1, 1970 UTC.
- * @return true on success or false otherwise
- */
-bool signature_set_creation(pgp_signature_t *sig, uint32_t ctime);
-
-/**
- * @brief Get the signature's expiration time
- * @param sig populated or loaded signature
- * @return expiration time in seconds since the creation time. 0 if signature never expires.
- */
-uint32_t signature_get_expiration(const pgp_signature_t *sig);
-
-/**
- * @brief Set the signature's expiration time
- * @param sig signature being populated
- * @param etime expiration time
- * @return true on success or false otherwise
- */
-bool signature_set_expiration(pgp_signature_t *sig, uint32_t etime);
-
-/**
- * @brief Check whether signature has key expiration
- * @param sig populated or loaded signature
- * @return true if signature has key expiration time or false otherwise
- */
-bool signature_has_key_expiration(const pgp_signature_t *sig);
-
-/**
- * @brief Get the key expiration time
- * @param sig populated or loaded signature
- * @return expiration time in seconds since the creation time. 0 if key never expires.
- */
-uint32_t signature_get_key_expiration(const pgp_signature_t *sig);
-
-/**
- * @brief Set the key expiration time
- * @param sig signature being populated
- * @param etime expiration time
- * @return true on success or false otherwise
- */
-bool signature_set_key_expiration(pgp_signature_t *sig, uint32_t etime);
-
-/**
- * @brief Check whether signature has key flags
- * @param sig populated or loaded signature
- * @return true if key flags are available or false otherwise
- */
-bool signature_has_key_flags(const pgp_signature_t *sig);
-
-/**
- * @brief Get the key flags
- * @param sig populated or loaded signature
- * @return byte of key flags. If there is no corresponding subpackets then 0 is returned.
- */
-uint8_t signature_get_key_flags(const pgp_signature_t *sig);
-
-/**
- * @brief Set the key flags
- * @param sig signature being populated
- * @param flags byte of key flags
- * @return true on success or false otherwise
- */
-bool signature_set_key_flags(pgp_signature_t *sig, uint8_t flags);
-
-/**
- * @brief Get the primary user id flag
- * @param sig populated or loaded signature
- * @return true if user id is marked as primary or false otherwise
- */
-bool signature_get_primary_uid(pgp_signature_t *sig);
-
-/**
- * @brief Set the primary user id flag
- * @param sig signature being populated
- * @param primary true if user id should be marked as primary
- * @return true on success or false otherwise
- */
-bool signature_set_primary_uid(pgp_signature_t *sig, bool primary);
-
-bool signature_has_preferred_symm_algs(const pgp_signature_t *sig);
-
-bool signature_get_preferred_symm_algs(const pgp_signature_t *sig,
- uint8_t ** algs,
- size_t * count);
-
-bool signature_set_preferred_symm_algs(pgp_signature_t *sig, uint8_t algs[], size_t len);
-
-bool signature_has_preferred_hash_algs(const pgp_signature_t *sig);
-
-bool signature_get_preferred_hash_algs(const pgp_signature_t *sig,
- uint8_t ** algs,
- size_t * count);
-
-bool signature_set_preferred_hash_algs(pgp_signature_t *sig, uint8_t algs[], size_t len);
-
-bool signature_has_preferred_z_algs(const pgp_signature_t *sig);
-
-bool signature_get_preferred_z_algs(const pgp_signature_t *sig, uint8_t **algs, size_t *count);
-
-bool signature_set_preferred_z_algs(pgp_signature_t *sig, uint8_t algs[], size_t len);
-
-bool signature_has_key_server_prefs(const pgp_signature_t *sig);
-
-uint8_t signature_get_key_server_prefs(const pgp_signature_t *sig);
-
-bool signature_set_key_server_prefs(pgp_signature_t *sig, uint8_t prefs);
-
-bool signature_set_preferred_key_server(pgp_signature_t *sig, const char *uri);
-
-bool signature_has_trust(const pgp_signature_t *sig);
-
-bool signature_get_trust(const pgp_signature_t *sig, uint8_t *level, uint8_t *amount);
-
-bool signature_set_trust(pgp_signature_t *sig, uint8_t level, uint8_t amount);
-
-bool signature_get_revocable(const pgp_signature_t *sig);
-
-bool signature_set_revocable(pgp_signature_t *sig, bool revocable);
-
-bool signature_set_features(pgp_signature_t *sig, uint8_t features);
-
-bool signature_set_signer_uid(pgp_signature_t *sig, uint8_t *uid, size_t len);
-
bool signature_set_embedded_sig(pgp_signature_t *sig, pgp_signature_t *esig);
bool signature_add_notation_data(pgp_signature_t *sig,
bool readable,
const char * name,
const char * value);
-bool signature_has_key_server(const pgp_signature_t *sig);
-
-char *signature_get_key_server(const pgp_signature_t *sig);
-
-bool signature_has_revocation_reason(const pgp_signature_t *sig);
-
-bool signature_get_revocation_reason(const pgp_signature_t *sig,
- pgp_revocation_type_t *code,
- char ** reason);
-
-bool signature_set_revocation_reason(pgp_signature_t * sig,
- pgp_revocation_type_t code,
- const char * reason);
-
/**
* @brief Fill signature's hashed data. This includes all the fields from signature which are
* hashed after the previous document or key fields.
* @param sig Signature being populated
* @return true if sig->hashed_data is filled up correctly or false otherwise
*/
bool signature_fill_hashed_data(pgp_signature_t *sig);
--- a/third_party/rnp/src/librepgp/stream-write.cpp
+++ b/third_party/rnp/src/librepgp/stream-write.cpp
@@ -131,26 +131,24 @@ typedef struct pgp_dest_partial_param_t
size_t partlen; /* length of the current part, up to PARTIAL_PKT_BLOCK_SIZE */
size_t len; /* bytes cached in part */
} pgp_dest_partial_param_t;
static rnp_result_t
partial_dst_write(pgp_dest_t *dst, const void *buf, size_t len)
{
pgp_dest_partial_param_t *param = (pgp_dest_partial_param_t *) dst->param;
- int wrlen;
-
if (!param) {
RNP_LOG("wrong param");
return RNP_ERROR_BAD_PARAMETERS;
}
if (len > param->partlen - param->len) {
/* we have full part - in block and in buf */
- wrlen = param->partlen - param->len;
+ size_t wrlen = param->partlen - param->len;
dst_write(param->writedst, ¶m->parthdr, 1);
dst_write(param->writedst, param->part, param->len);
dst_write(param->writedst, buf, wrlen);
buf = (uint8_t *) buf + wrlen;
len -= wrlen;
param->len = 0;
@@ -499,17 +497,17 @@ static rnp_result_t
encrypted_add_recipient(pgp_write_handler_t *handler,
pgp_dest_t * dst,
pgp_key_t * userkey,
const uint8_t * key,
const unsigned keylen)
{
uint8_t enckey[PGP_MAX_KEY_SIZE + 3];
unsigned checksum = 0;
- pgp_pk_sesskey_t pkey = {0};
+ pgp_pk_sesskey_t pkey;
pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param;
rnp_result_t ret = RNP_ERROR_GENERIC;
/* Use primary key if good for encryption, otherwise look in subkey list */
userkey =
find_suitable_key(PGP_OP_ENCRYPT_SYM, userkey, handler->key_provider, PGP_KF_ENCRYPT);
if (!userkey) {
return RNP_ERROR_NO_SUITABLE_KEY;
@@ -620,17 +618,17 @@ encrypted_sesk_set_ad(pgp_crypt_t *crypt
static rnp_result_t
encrypted_add_password(rnp_symmetric_pass_info_t * pass,
pgp_dest_encrypted_param_t *param,
uint8_t * key,
const unsigned keylen,
bool singlepass)
{
- pgp_sk_sesskey_t skey = {0};
+ pgp_sk_sesskey_t skey = {};
unsigned s2keylen; /* length of the s2k key */
pgp_crypt_t kcrypt;
uint8_t nonce[PGP_AEAD_MAX_NONCE_LEN];
bool res;
skey.alg = param->ctx->ealg;
skey.s2k = pass->s2k;
@@ -844,49 +842,44 @@ init_encrypted_dst(pgp_write_handler_t *
param->aalg = handler->ctx->aalg;
param->ctx = handler->ctx;
param->pkt.origdst = writedst;
dst->write = param->aead ? encrypted_dst_write_aead : encrypted_dst_write_cfb;
dst->finish = encrypted_dst_finish;
dst->close = encrypted_dst_close;
dst->type = PGP_STREAM_ENCRYPTED;
- pkeycount = list_length(handler->ctx->recipients);
- skeycount = list_length(handler->ctx->passwords);
+ pkeycount = handler->ctx->recipients.size();
+ skeycount = handler->ctx->passwords.size();
if (!pkeycount && !skeycount) {
RNP_LOG("no recipients");
ret = RNP_ERROR_BAD_PARAMETERS;
goto finish;
}
if ((pkeycount > 0) || (skeycount > 1) || param->aead) {
if (!rng_get_data(rnp_ctx_rng_handle(handler->ctx), enckey, keylen)) {
ret = RNP_ERROR_RNG;
goto finish;
}
singlepass = false;
}
/* Configuring and writing pk-encrypted session keys */
- if (pkeycount > 0) {
- for (list_item *recipient = list_front(handler->ctx->recipients); recipient;
- recipient = list_next(recipient)) {
- ret =
- encrypted_add_recipient(handler, dst, *(pgp_key_t **) recipient, enckey, keylen);
- if (ret != RNP_SUCCESS) {
- goto finish;
- }
+ for (auto recipient : handler->ctx->recipients) {
+ ret = encrypted_add_recipient(handler, dst, recipient, enckey, keylen);
+ if (ret) {
+ goto finish;
}
}
/* Configuring and writing sk-encrypted session key(s) */
- for (list_item *pi = list_front(handler->ctx->passwords); pi; pi = list_next(pi)) {
- ret = encrypted_add_password(
- (rnp_symmetric_pass_info_t *) pi, param, enckey, keylen, singlepass);
+ for (auto &passinfo : handler->ctx->passwords) {
+ ret = encrypted_add_password(&passinfo, param, enckey, keylen, singlepass);
if (ret != RNP_SUCCESS) {
goto finish;
}
}
/* Initializing partial packet writer */
param->pkt.partial = true;
param->pkt.indeterminate = false;
@@ -906,28 +899,22 @@ init_encrypted_dst(pgp_write_handler_t *
if (param->aead) {
/* initialize AEAD encryption */
ret = encrypted_start_aead(param, enckey);
} else {
/* initialize old CFB or CFB with MDC */
ret = encrypted_start_cfb(param, enckey);
}
-
finish:
- for (list_item *pi = list_front(handler->ctx->passwords); pi; pi = list_next(pi)) {
- rnp_symmetric_pass_info_t *pass = (rnp_symmetric_pass_info_t *) pi;
- pgp_forget(pass, sizeof(*pass));
- }
- list_destroy(&handler->ctx->passwords);
+ handler->ctx->passwords.clear();
pgp_forget(enckey, sizeof(enckey));
- if (ret != RNP_SUCCESS) {
+ if (ret) {
encrypted_dst_close(dst, true);
}
-
return ret;
}
static rnp_result_t
signed_dst_write(pgp_dest_t *dst, const void *buf, size_t len)
{
pgp_dest_signed_param_t *param = (pgp_dest_signed_param_t *) dst->param;
dst_write(param->writedst, buf, len);
@@ -1065,26 +1052,29 @@ cleartext_dst_write(pgp_dest_t *dst, con
static rnp_result_t
signed_fill_signature(pgp_dest_signed_param_t *param,
pgp_signature_t * sig,
pgp_dest_signer_info_t * signer)
{
pgp_key_pkt_t * deckey = NULL;
pgp_hash_t hash;
pgp_password_ctx_t ctx = {.op = PGP_OP_SIGN, .key = signer->key};
- bool res;
rnp_result_t ret = RNP_ERROR_GENERIC;
/* fill signature fields */
- res = signature_set_keyfp(sig, pgp_key_get_fp(signer->key)) &&
- signature_set_keyid(sig, pgp_key_get_keyid(signer->key)) &&
- signature_set_creation(sig, signer->sigcreate ? signer->sigcreate : time(NULL)) &&
- signature_set_expiration(sig, signer->sigexpire) && signature_fill_hashed_data(sig);
-
- if (!res) {
+ try {
+ sig->set_keyfp(pgp_key_get_fp(signer->key));
+ sig->set_keyid(pgp_key_get_keyid(signer->key));
+ sig->set_creation(signer->sigcreate ? signer->sigcreate : time(NULL));
+ sig->set_expiration(signer->sigexpire);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to setup signature fields: %s", e.what());
+ return RNP_ERROR_OUT_OF_MEMORY;
+ }
+ if (!signature_fill_hashed_data(sig)) {
RNP_LOG("failed to fill the signature data");
return RNP_ERROR_OUT_OF_MEMORY;
}
if (!pgp_hash_copy(&hash, pgp_hash_list_get(param->hashes, sig->halg))) {
RNP_LOG("failed to obtain hash");
return RNP_ERROR_BAD_PARAMETERS;
}
@@ -1118,21 +1108,21 @@ signed_write_signature(pgp_dest_signed_p
{
pgp_signature_t sig;
rnp_result_t ret;
sig.version = (pgp_version_t) 4;
if (signer->onepass.version) {
sig.halg = signer->onepass.halg;
sig.palg = signer->onepass.palg;
- sig.type = signer->onepass.type;
+ sig.set_type(signer->onepass.type);
} else {
sig.halg = pgp_hash_adjust_alg_to_key(signer->halg, pgp_key_get_pkt(signer->key));
sig.palg = pgp_key_get_alg(signer->key);
- sig.type = param->ctx->detached ? PGP_SIG_BINARY : PGP_SIG_TEXT;
+ sig.set_type(param->ctx->detached ? PGP_SIG_BINARY : PGP_SIG_TEXT);
}
if (!(ret = signed_fill_signature(param, &sig, signer))) {
ret = stream_write_signature(&sig, writedst) ? RNP_SUCCESS : RNP_ERROR_WRITE;
}
return ret;
}
@@ -1323,18 +1313,18 @@ init_signed_dst(pgp_write_handler_t *han
} else {
dst->type = PGP_STREAM_SIGNED;
dst->write = signed_dst_write;
dst->finish = param->ctx->detached ? signed_detached_dst_finish : signed_dst_finish;
}
dst->close = signed_dst_close;
/* Getting signer's infos, writing one-pass signatures if needed */
- for (list_item *sg = list_front(handler->ctx->signers); sg; sg = list_next(sg)) {
- ret = signed_add_signer(param, (rnp_signer_info_t *) sg, !list_next(sg));
+ for (auto &sg : handler->ctx->signers) {
+ ret = signed_add_signer(param, &sg, &sg == &handler->ctx->signers.back());
if (ret) {
RNP_LOG("failed to add one-pass signature for signer");
goto finish;
}
}
/* Do we have any signatures? */
if (param->hashes.empty()) {
@@ -1639,17 +1629,17 @@ literal_dst_close(pgp_dest_t *dst, bool
dst->param = NULL;
}
static rnp_result_t
init_literal_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *writedst)
{
pgp_dest_packet_param_t *param;
rnp_result_t ret = RNP_ERROR_GENERIC;
- int flen = 0;
+ size_t flen = 0;
uint8_t buf[4];
if (!init_dst_common(dst, sizeof(*param))) {
return RNP_ERROR_OUT_OF_MEMORY;
}
param = (pgp_dest_packet_param_t *) dst->param;
dst->write = literal_dst_write;
@@ -1664,27 +1654,25 @@ init_literal_dst(pgp_write_handler_t *ha
if (!init_streamed_packet(param, writedst)) {
RNP_LOG("failed to init streamed packet");
ret = RNP_ERROR_BAD_PARAMETERS;
goto finish;
}
/* content type - forcing binary now */
buf[0] = (uint8_t) 'b';
/* filename */
- if (handler->ctx->filename) {
- flen = strlen(handler->ctx->filename);
- if (flen > 255) {
- RNP_LOG("filename too long, truncating");
- flen = 255;
- }
+ flen = handler->ctx->filename.size();
+ if (flen > 255) {
+ RNP_LOG("filename too long, truncating");
+ flen = 255;
}
buf[1] = (uint8_t) flen;
dst_write(param->writedst, buf, 2);
- if (flen > 0) {
- dst_write(param->writedst, handler->ctx->filename, flen);
+ if (flen) {
+ dst_write(param->writedst, handler->ctx->filename.c_str(), flen);
}
/* timestamp */
STORE32BE(buf, handler->ctx->filemtime);
dst_write(param->writedst, buf, 4);
ret = RNP_SUCCESS;
finish:
if (ret != RNP_SUCCESS) {
literal_dst_close(dst, true);
@@ -1931,80 +1919,77 @@ finish:
}
return ret;
}
rnp_result_t
rnp_compress_src(pgp_source_t &src, pgp_dest_t &dst, pgp_compression_type_t zalg, int zlevel)
{
pgp_write_handler_t handler = {};
- rnp_ctx_t ctx = {};
+ rnp_ctx_t ctx;
ctx.zalg = zalg;
ctx.zlevel = zlevel;
handler.ctx = &ctx;
pgp_dest_t compressed = {};
rnp_result_t ret = init_compressed_dst(&handler, &compressed, &dst);
if (ret) {
goto done;
}
ret = dst_write_src(&src, &compressed);
done:
dst_close(&compressed, ret);
- rnp_ctx_free(&ctx);
return ret;
}
rnp_result_t
rnp_wrap_src(pgp_source_t &src, pgp_dest_t &dst, const std::string &filename, uint32_t modtime)
{
pgp_write_handler_t handler = {};
- rnp_ctx_t ctx = {};
- ctx.filename = strdup(filename.c_str());
+ rnp_ctx_t ctx;
+ ctx.filename = filename;
ctx.filemtime = modtime;
handler.ctx = &ctx;
pgp_dest_t literal = {};
rnp_result_t ret = init_literal_dst(&handler, &literal, &dst);
if (ret) {
goto done;
}
ret = dst_write_src(&src, &literal);
done:
dst_close(&literal, ret);
- rnp_ctx_free(&ctx);
return ret;
}
rnp_result_t
rnp_raw_encrypt_src(pgp_source_t &src, pgp_dest_t &dst, const std::string &password)
{
pgp_write_handler_t handler = {};
- rnp_ctx_t ctx = {};
+ rnp_ctx_t ctx;
rng_t rng = {};
if (!rng_init(&rng, RNG_SYSTEM)) {
return RNP_ERROR_BAD_STATE;
}
ctx.rng = &rng;
ctx.ealg = DEFAULT_PGP_SYMM_ALG;
handler.ctx = &ctx;
pgp_dest_t encrypted = {};
rnp_result_t ret = rnp_ctx_add_encryption_password(
- &ctx, password.c_str(), DEFAULT_PGP_HASH_ALG, DEFAULT_PGP_SYMM_ALG, 0);
+ ctx, password.c_str(), DEFAULT_PGP_HASH_ALG, DEFAULT_PGP_SYMM_ALG, 0);
if (ret) {
goto done;
}
ret = init_encrypted_dst(&handler, &encrypted, &dst);
if (ret) {
goto done;
}
ret = dst_write_src(&src, &encrypted);
done:
dst_close(&encrypted, ret);
- rnp_ctx_free(&ctx);
rng_destroy(&rng);
return ret;
}
--- a/third_party/rnp/src/rnp/fficli.h
+++ b/third_party/rnp/src/rnp/fficli.h
@@ -26,16 +26,17 @@
#ifndef FFICLI_H_
#define FFICLI_H_
#include <stddef.h>
#include <stdbool.h>
#include <time.h>
#include "rnp/rnp.h"
+#include "rnp/rnp_err.h"
#include "rnpcfg.h"
#include "json.h"
typedef struct cli_rnp_t {
rnp_ffi_t ffi;
rnp_cfg_t cfg;
FILE * resfp; /* where to put result messages, defaults to stdout */
FILE * passfp; /* file pointer for password input */
--- a/third_party/rnp/src/rnpkeys/rnpkeys.cpp
+++ b/third_party/rnp/src/rnpkeys/rnpkeys.cpp
@@ -159,72 +159,86 @@ imported_key_changed(json_object *key)
return sec && ((!strcmp(sec, "updated") || !strcmp(sec, "new")));
}
static bool
import_keys(cli_rnp_t *rnp, const char *file)
{
rnp_input_t input = NULL;
bool res = false;
+ bool updated = false;
if (rnp_input_from_path(&input, file)) {
ERR_MSG("failed to open file %s", file);
return false;
}
- uint32_t flags = RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS;
- char * results = NULL;
- json_object *jso = NULL;
- json_object *keys = NULL;
+ uint32_t flags =
+ RNP_LOAD_SAVE_PUBLIC_KEYS | RNP_LOAD_SAVE_SECRET_KEYS | RNP_LOAD_SAVE_SINGLE;
bool permissive = rnp_cfg_getbool(cli_rnp_cfg(rnp), CFG_PERMISSIVE);
if (permissive) {
flags |= RNP_LOAD_SAVE_PERMISSIVE;
}
- if (rnp_import_keys(rnp->ffi, input, flags, &results)) {
- ERR_MSG("failed to import keys from file %s", file);
- goto done;
- }
- // print information about imported key(s)
- jso = json_tokener_parse(results);
- if (!jso || !json_object_object_get_ex(jso, "keys", &keys)) {
- ERR_MSG("invalid key import result");
- goto done;
- }
+ do {
+ /* load keys one-by-one */
+ char * results = NULL;
+ rnp_result_t ret = rnp_import_keys(rnp->ffi, input, flags, &results);
+ if (ret == RNP_ERROR_EOF) {
+ res = true;
+ break;
+ }
+ if (ret) {
+ ERR_MSG("failed to import key(s), from file %s, stopping.", file);
+ break;
+ }
- for (size_t idx = 0; idx < (size_t) json_object_array_length(keys); idx++) {
- json_object * keyinfo = json_object_array_get_idx(keys, idx);
- rnp_key_handle_t key = NULL;
- if (!keyinfo || !imported_key_changed(keyinfo)) {
- continue;
+ // print information about imported key(s)
+ json_object *jso = json_tokener_parse(results);
+ rnp_buffer_destroy(results);
+ if (!jso) {
+ ERR_MSG("invalid key import resulting JSON");
+ break;
+ }
+ json_object *keys = NULL;
+ if (!json_object_object_get_ex(jso, "keys", &keys)) {
+ ERR_MSG("invalid key import JSON contents");
+ json_object_put(jso);
+ break;
}
- const char *fphex = json_obj_get_str(keyinfo, "fingerprint");
- if (rnp_locate_key(rnp->ffi, "fingerprint", fphex, &key) || !key) {
- ERR_MSG("failed to locate key with fingerprint %s", fphex);
- continue;
+ for (size_t idx = 0; idx < (size_t) json_object_array_length(keys); idx++) {
+ json_object * keyinfo = json_object_array_get_idx(keys, idx);
+ rnp_key_handle_t key = NULL;
+ if (!keyinfo || !imported_key_changed(keyinfo)) {
+ continue;
+ }
+ const char *fphex = json_obj_get_str(keyinfo, "fingerprint");
+ if (rnp_locate_key(rnp->ffi, "fingerprint", fphex, &key) || !key) {
+ ERR_MSG("failed to locate key with fingerprint %s", fphex);
+ continue;
+ }
+ cli_rnp_print_key_info(stdout, rnp->ffi, key, true, false);
+ rnp_key_handle_destroy(key);
+ updated = true;
}
- cli_rnp_print_key_info(stdout, rnp->ffi, key, true, false);
- rnp_key_handle_destroy(key);
- }
+ json_object_put(jso);
+ } while (1);
- // set default key if we didn't have one
- if (cli_rnp_defkey(rnp).empty()) {
- cli_rnp_set_default_key(rnp);
- }
+ if (updated) {
+ // set default key if we didn't have one
+ if (cli_rnp_defkey(rnp).empty()) {
+ cli_rnp_set_default_key(rnp);
+ }
- // save public and secret keyrings
- if (!cli_rnp_save_keyrings(rnp)) {
- ERR_MSG("failed to save keyrings");
- goto done;
+ // save public and secret keyrings
+ if (!cli_rnp_save_keyrings(rnp)) {
+ ERR_MSG("failed to save keyrings");
+ }
}
- res = true;
-done:
- json_object_put(jso);
- rnp_buffer_destroy(results);
rnp_input_destroy(input);
return res;
}
static bool
import_sigs(cli_rnp_t *rnp, const char *file)
{
rnp_input_t input = NULL;
--- a/third_party/rnp/src/tests/CMakeLists.txt
+++ b/third_party/rnp/src/tests/CMakeLists.txt
@@ -63,20 +63,23 @@ add_executable(rnp_tests
../rnp/fficli.cpp
../rnp/rnp.cpp
../rnpkeys/rnpkeys.cpp
../rnpkeys/main.cpp
../rnpkeys/tui.cpp
../fuzzing/keyring.c
../fuzzing/keyring_g10.cpp
../fuzzing/keyring_kbx.c
+ ../fuzzing/keyimport.c
cipher.cpp
cli.cpp
exportkey.cpp
ffi.cpp
+ ffi-enc.cpp
+ file-utils.cpp
generatekey.cpp
kbx-nsigs-test.cpp
key-add-userid.cpp
key-grip.cpp
key-prefs.cpp
key-protect.cpp
key-store-search.cpp
key-unlock.cpp
@@ -94,19 +97,21 @@ add_executable(rnp_tests
support.cpp
user-prefs.cpp
utils-hex2bin.cpp
utils-list.cpp
utils-rnpcfg.cpp
issues/1030.cpp
issues/1115.cpp
issues/1171.cpp
+ issues/oss-fuzz-25489.cpp
fuzz_keyring.cpp
fuzz_keyring_g10.cpp
fuzz_keyring_kbx.cpp
+ fuzz_keyimport.cpp
)
if(MSVC)
find_package(WindowsSDK)
GetUMWindowsSDKLibraryDir(WIN_LIBRARY_DIR)
message (STATUS "WIN_LIBRARY_DIR: ${WIN_LIBRARY_DIR}")
find_library(SHLWAPI_LIBRARY
PATHS
${WIN_LIBRARY_DIR}
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/tests/data/issue1188/armored_revocation_signature.pgp
@@ -0,0 +1,12 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+wsD2BCABCAAgFiEEjfYTgEZi8VK4srNzBBUFBnoZpfIFAl796EQCHQAACgkQBBUFBnoZpfKpMwv8
+CLJNFLb2H5I302hprJPAvFo4VynMZqM9HVRfRQ8sdWJ/qM3cT90L/rS8kAO8Qs/MYtAYQ8Wc07XS
+1/oaljqxVL8ARL0+Bw5OdMy93FW9ot5DbQolGF9L1MN3+T7j9ChbyXOtpiO3JuzIbEZTUyDGn85J
+yMtHaFnOx5V3pGqMUgR8eaPnsg00zUpfFHrzGku5SPKAe0Rf5HfO28fOwEacNYLp21rRQZarAZ7j
+YXF/A/aIWzWxXdu7hzToqmtkWNiL3wKBCjx/xsTRHLq2o2XjllN6WXtDiPjeeCJT912vy0WwS2ih
+yXiq9qIE33nYXz/CPanJUCPajgC1AmWM+LUgHK/fuNULPUQLhzek8iw9GHnqoS6Ywl30WL9sbpA1
+NS3oQSLY3HVYE2p/jMXXNeLwTiunSwiVqfDL5ki6VMI5b/GXEb1omQT9AkWqyh+xAmm7+OJQ3fhy
+bfI3Nv1l+YwuWHZgjb3bHwjOXCgPX7GblCxEMTbl2sHohjYcTgBT/3Gg
+=Yqti
+-----END PGP PUBLIC KEY BLOCK-----
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/tests/data/keyrings/1/pubring.gpg.asc
@@ -0,0 +1,67 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mI0EWXDg3AEEAMedwkPY1lO/5eJSo7T/t2+7/bZk15AMDZ5yitSvL81l6wY9QtkAvf40dxrF8CMw
+DlDIi+X8w1syR/t4i44ZZYu3+LA1vRUnGXD2pAGRizjU2v7ZoR2ovEciOC2bWOEiFJdk9J15tDeL
+y191ney3TsYZ9bdYoBBra3UpJqFgtVWJABEBAAG0CWtleTAtdWlkMIi5BBMBAgAjBQJZcODcAhsD
+BwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQe8ZwmxXCOkobpwQAukuqm19euXuEE/cM3vMS
+/W5XoQ5Mutsuq9sE7f4SbTInLaAwot6sWfqLh/pal78dN0NoazadNFOGLVqaidM1vPcHnFW4iMkm
+nY9imNA1H2nIYXywWlacYJuJdCM0OzwM/VLLPXSzy/iNLCehGNgbSrtPdRcfwcIwgnu+rPSf/JCw
+AgADtAlrZXkwLXVpZDGIuQQTAQIAIwUCWXDg7AIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheA
+AAoJEHvGcJsVwjpKChYD/2l/ektJfkwBbeqKBNHcCb/pt33xomA/sogAC4nByJkQ1UbjAzx+wwz7
+DyQELgWNYRFw6/WZ/OMYAm75ffLVoH0BAAgp+7spSMod7/rJynxsmUNRLPyZnEu2gVOqNaSDsi5T
+RCCEDieg1IsWDirG+17PD1w3b46OP1XV4izi7XtZsAIAA7QJa2V5MC11aWQyiLkEEwECACMFAllw
+4PYCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRB7xnCbFcI6Sl5rBADB2EI6KbcJr+NP
+G+k3ybLh9zFmTCvrkDmENRrR/PFgxDWbND8MB+8Od9Iu65xhUgAIRd0RtG/SH7Wl4dN0QOAK4x0W
+OqtuvZ2J7nTM24hi2lWKaHIZST729y1TNaSHYMhDGCXUa0wn2b8zWogvkgNB52pIePqxb48QCozn
+YYGdebACAAO4jQRZcODcAQQAvekEPqI9CZyz/MPugFY7tVv9VpLWLFA5Q0+uRPA0S0clBFW/E5Oc
+sbIZonRunLlA/Rc75E4Sxmtbu7kk+HSuP0hAEaweLUNiOYuLTijnqiIVdwz2Xp5NNbOn9eZvUt5B
+JN+07u1AbD54rrWaqBRW30Au6A6u7G6TCTfWHtxBFAsAEQEAAYifBBgBAgAJBQJZcODcAhsMAAoJ
+EHvGcJsVwjpKZJ4EAJlEDW7qetP78SOPjdf7V52aCfuasqJin7LaUB4TAAz5Yp2NRAwU213XRLDL
+ur3BEUE0uIfODVUuU3lhbSweWyHA6BH0tMFPTC7vWC/Zq/eamEQWLrz4oy/WBpVZi1goLW6MWt1r
+L5/hrJt9St/6IWNsK/w/DeFzHbRPF4Yz5iqIsAIAA7kBogRZcOD7EQQArLsczgqNlY3iLdTkvePy
+UaIQrLpXjoSyyftM/OBbFynqPVcUie5R07WSkhMsbiteb6I/msRRLScy71LNesE8Prqfwi05bqTl
+xU8GJB1fKaWuB1M1HKaNEM7a3bPienzPR80zX11k8BdD+TyAE3yfMKzOVf7v9FR79Y0rej/ZjUsA
+oNmnbzRTIXhMYQXR/p0ChSblvcGpA/9MGHbFU9c78nNsT9OBHfuV/SBN0FCmkrRHX/jeom0u6kAj
+58XA3bIQkn1v39TU0++5h2zr6B8GIOHIlThAIxmCuZaE/tXF5d6zqCyCCFsL0gC1BLj8UlXS/8Nm
+8Ydy2AcE8BJYbWPbQouTiuSlv0215B+JTqBGv9ED6aJYivhsDAP9E4IPn76M9as0CHl4btquKnqX
+jfXk7QAF+mLmVZgotD2z9hISI1W2VQu19jeQetLPda6Qk65k7/umWQi8D6ZqlNV0PnW336PH1f8u
+8VMnfnTt7ABFYcLEmQbKloLfZCF4s/65CVsYN2+cSggtaVYdZDZEZUwf7AmgvnmRsjhWEwmI7QQY
+AQIADwUCWXDg+wIbAgUJAKIogABSCRB7xnCbFcI6SkcgBBkRAgAGBQJZcOD7AAoJEB1+ilOTyZeo
+7z0An2pChTN7ZDCQImlH1gY6N0eaEjLDAJ9bjnURqyJSOURQNltbckktHmGF+7pqA/4r3ROm5FII
+GXJ8/gM3kbV7cJUgmdt4gVF1lvKgdsrD5MfOEI/vY0hUxayEBN8L7c/Bsn9nL6qgLMc2YRMNz4nI
+e0HJGW/Ers8OvSQtr/QRsiMmZKjCBzR7GsbrQs6OFfUAq7UKLleorWo36LMpCQSMCrNXDZObBXa7
+vVCrC6aII7ACAAO4jQRZcOEoAQQA6THC3fTRsTHdOUOTWTEUSuY9EKJeDug3FGSulfNDBbgA5qR3
+64DEax7CYciJeCKn+0Uw+HNTIoDpWyOqV+5O+inP0MT5+VwatxYeqEcP3mfNXpkZUeQsxJswbnsv
+SIrKLjxny3V9kR2J/ycE+YuvWOyd1P4evBvIbUg/BrAg+vsAEQEAAYifBBgBAgAJBQJZcOEoAhsM
+AAoJEHvGcJsVwjpKTIAEALOhKe7VP9fLQSObAaD7OcqXkivFbTgcaYdghVkUed5puDh8/v/ZP5uJ
+Eps/oa9k5i7ivbXBcCcyP2G/aMCGBVEVg/Bth3jqb7Eqr1cUBfgFs2ntFxMYUIMi8ut5TlmYoIhP
+vlq1oe6v+soc4siKypc4xXUitECMdYupwHnA+OROsAIAA5kBogRZcOFaEQQAkGRX4UkBAr8Sy2EJ
+yuxT92hX0rmnRY4luWFEYALwnHtjsGWcd2fV1FxGim7RAUknTm7FmwUkdg9sFYAsA3PmTan8qsBf
+gru4relznL+rJnN4rj9oYmJe9f4BA3AevvNmZCxzt2Iy1s42FhI2Zbxtqwr7pmbfSzY/C0SDDqpU
+cksAoKBeTvLaPzy3xhil+YSeGyjnBbIHA/0bIz8I4Ljq4LYNxeXuxU76FiVuPVUsPGOdkIAZEdYx
+g3hpA+yT3zJqvgT1GjSqeuzEw3yIVkSsjpL+FajFX5efhmPMOJuoBimSnEUCDYkiGS3mzeo9QYJO
+U4SQ4yxsGOal4xl3G/xQj5h7/t3Q5G6FzUOVTz69RCfAZ6ZO67p9dQP9Gh0mC3LNlWHhlTDfksT1
+Ddvs2svhu83GtLPuxJGZQH77WSJEi2nVWAe1Nbux93yv3jzzFSm0B1zTJsLW+QWEF2SRPEJHowAL
+/RZOu+WFbs4MmbVL1Sy6R9ncAf2jN4pB6Yv5OEW+Hn1xTc1qD7PG6sB6Cp0kMQ5kNL9ZPGNPQHm0
+CWtleTEtdWlkMIh0BBMRAgA0AhsDBQl7x2AAAh4BAheAAwsIAwMVAgsDFgEABQJZfSAhEhhoa3A6
+Ly9wZ3AubWl0LmVkdQAKCRAvyt8F/6UBu40IAJ9KY/DSmvuz0jHhh9Hq82fDrQwjLwCbBo3T2hDN
+t+mdx68XQ6AGDeEKEtSwAgADtAlrZXkxLXVpZDKIaQQTEQIAKQUCWXDiKQIbAwUJe8dgAAcLCQgH
+AwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEC/K3wX/pQG70S0An0iQvBGrwULpDUEKv0VHSI2FDZhD
+AJ4qj0rhQu65iAliJLXV3kfgRBBoJbACAAO0CWtleTEtdWlkMYhpBBMRAgApBQJZcOIjAhsDBQl7
+x2AABwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQL8rfBf+lAbvJsQCfdDWu1z6PfYp1RqwM
+y8dPfvuB61EAnAo2ZqfwSIloMDIj+fSLLPjOr8FOsAIAA7kBDQRZcOFaEAQA/2KSo7bsUAtIMTG1
+Y2rLbsfVFjtb4WI9bO/JGwTOsJ9P9yCLKdL7U2bFQlhXHC8TZYkJ9q1BZ18eC7HVToWuyO/J0FAS
+y/73BJjVRVwVQUZGKJIrhEyANdIcK0bTnLTQzS/Enebrwf5GxAJaxbF+w9F1VOrlMpCqdI65m5IA
+8ecAAwUD/RAkyaPFzC4MoSfoYtxtho4kviWU4SYjgjMG6usTBQUMF992F+d9fHUIRZpyHiI0p1K6
+pHE4jQllEdOQCC/mBpXkIHklGrU5Q0bnybod/YmT55h5CMjD1XHQxS4v4qM53HKGwhuFWoYA7oOp
+OrBDanuSFkbRZB0l3qp960qGBFOkiE8EGBECAA8FAllw4VoCGwwFCXvHYAAACgkQL8rfBf+lAbvg
+FgCdEb+zLoVdQjKfXJouI78wqSJrbeIAnAo4wlgDWNGZ/KVWa4X/CFdxMBVMsAIAA7kBDQRZcOI1
+EAQAzndho+iMhKoZYsa+leoN4rOcQI/hT12BQhZa2cG7GgosW6yjAWI5iAG9Yj/j7tDXvJoFyGwB
+fZ16QFe7W6PjfSdhw5sjtuwsmJ2C3GJI63pI2PxWgKikqaIr1fnfdAYAsI19KBEj354RmRrs7kRj
+XC+kmUTyq0UEAE2q7N+AHLsAAwUD/01QFjQlR69N3H532lNZ/Qr/pEoIPhT4kBcvzNR9AnC0ZvGl
+9BMCRD+B28jS+N7bI+yRvFqVuO3fEdUN9NAO9dK4RK0olXr17ozaeIaFuBU4xSLgnbikS5RWerBQ
+n8jHXHodRqH3+PXn0ci++JrY73ho1iG0zVh7x1TZO97JvT3NiEkEGBECAAkFAllw4jUCGwwACgkQ
+L8rfBf+lAbsH5gCfcwC7T4ham51ZeOs+8zuYq9F0RTIAniQmTM2k7QshZYNRCxHwW/DWskEQsAIA
+Aw==
+=hqEl
+-----END PGP PUBLIC KEY BLOCK-----
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5f674c45a78119311ff97cd56eec776a10f7d31c
GIT binary patch
literal 1105
zc$_<C%o4}4Utf$<n~jl$@s>M3BO|+m`iFGhlXEN-ng4Cwemds7tm>~R3?6TCYu#7&
zx3QmSvOg>6n3I{DT4$38q8y6y3hWL|U=bGMV6YHVWGQ~jGf{H=iAT5ho_)#^=rAqw
z|2-R4CXg*m(#)*foE+>-Y@%G89NbJSVoc18Omd7&;tdR3oB}Y#DsvhB`$etSv+{F%
zvQ^jaWBRd$OV-YGkh{OOQFixLmIaNX<pzul`!4-o_by}8`Q+nyEh{^|NqVqL-IiE&
z=1+gj-nV+GhFs^uS>o9E4hnH<t1vS&aRB|r#LN=oZ({dcv}w)zV15zT3ZMEr?=lZx
z<nHG$^sajx>sPSUnSa~zXv5}^6b7*c-#0rlGrI9{xn@6KXKWw&XZtS0<IId4?1w5?
zB!FI30DJWeHm?G$Ws>GW_R_)yj0{`;UOzp5TL12tRTtE^t&KS6_$Twlvw*t{D*Bvj
z4mw_TX830`Z_-QFPTg2<{@B+q0+u;*N$c8OUwAi1=a_{Ovx)=rp;8tNpv|(lZ9dEJ
z0?FDJZ~xasZDFuEt;O{I1!t(alg9gyT>F^w{_$7&Z@*ly`Sw*VO=gCFs<*WrN^UHg
z`0CgU8Ix`K)=#{mPd9&9cJpel*MTaFUChU@rV(8baB_9`^iv3M4^Y67Mig+R5v<Oq
za~g@pkw*BzX#^(5J2(<cfXZD4V1l7mV)^}dp~-*o|KAYSM!jYDU$f-}?!=<W#msP9
KRr?>_!~y`Y|Fziw
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/tests/data/test_fuzz_keyimport/crash_e932261875271ccf497715de56adf7caf30ca8a7
@@ -0,0 +1,3 @@
+¬bmessage.txt_»4This is test message to be signed, and/or encrypted, cleartext signed and detached signed.
+It will use keys from keyrings/1.
+End of message.
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6510447f44c0752df53b31eeefe24d6b432ef591
GIT binary patch
literal 925
zc$}MJ%@W75Utf$<n~jl$@s>M3BO|+m`iFGhlXEN-ng4Cwemds7tm>~R3?6TCYu#7&
zx3QmSvj5MJ%HZx7%DhF;F()%QRlz0^L^%}Y71(u5U=bGMV6YHVWGQ}oW}@W!6OV51
zJ^Pd;&|zBU|9dv9Od#8sq?uW{IXT#w*hINFIk=fv#F&^FndBIm#2Xm6I0ayeRpv7M
z_lsJuXXWSkWUH>-$Mj<hm#m%XAa{RlqwMahEDIV%%MBPA_FekF?p?;F^U25aT2^*^
zlk{Mhx-GHl%%A?4y>InW4Y}qlVu_pC>?q8t-N?eg#l*}KeB?uSLh=pO6)s_Bw@>}J
z`E{Po@vg;l@&xmu*PMC~{>Jg-?S<F>bACzI+`c`oaAo&=yUlx&Q*XUYn(tX|7Uh@t
zkDZxG)o`-MHHl}+Z;gWEKZqRqz1Ds~U{^cKL1octa|4Q(Z_2oxo#9@6!piNK$CpI!
z)4qA%cBv(9e8F&M$x@3eiBr9v3q>ECtuRO6(b;Q{W5srKyl0UBhMEHIPy_maNt%hF
z5fM6N3M`Vs91OBRJ?Ecp5ZU*{cCO0j_ZCW@7l|KuVtE>(2NawzksVx&3@74Qeyi$~
zw6<t_zgc(c%T_)6kX^ms*%~ArRad>;@!~xrL&Luv{}%^29nNsQ@~m@i?WT}<uG^P;
z{z+Uo$;#wI2CIT92g6_aMV20W*M3;llD{gwuJmqf_+5ryv!~A6e%-ig_w&!+r!o95
zUd|Y{{nxv<jor7NhS~AFwonpck2~PASzI)UKV)}4@0?XEacq1Cg*dfUn3<V4fQb$m
zF){uocF#qd*1Qkq7jdodslW3s^YBIPe*Qx5y2r781xuazw=Iu0Yz|3b5L@tlvm-O3
z8y}Zz_Vabd_K|<K?=n2j%*eqGiX4L`YtCJlF9*GC^<TDS&u06}b2Z(+I`Fu3tT?UZ
z?8f_=eR;%BS%sayjH*k2@P3VdS7^W7f-&fv8TWe=2X4c=8jt5@#$DI!Jh^MyK6l17
zzdI@jMGnv>Owv5aNq6A_Mushaub-Yjt$%mSstfAd)<&Fj{FC|OS-@Qe6@AV%2OTdv
oGyF4}H|Zs7r*5n_f9&fQ0n41Zq;>7CFT9(hbId}CS;c`F0FYjZW&i*H
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8bca1b0bd04b7441a066eccf620dccb6e5d2bc64
GIT binary patch
literal 925
zc$}MJ%@W75Utf$<n~jl$@s>M3BO|+m`iFGhlXEN-ng4Cwemds7tm>~R3?6TCYu#7&
zx3QmSvj5MJ$`I=3?YBkHF()%QRlz0^L^%}Y71(u5U=bGMV6YHVWGQ}oW}@W!6OV51
zJ^Pd;&|zBU|9dv9Od#8sq?uW{IXT#w*hINFIk=fv#F&^FndBIm#2Xm6I0ayeRpv7M
z_lsJuXXWSkWUH>-$Mj<hm#m%XAa{RlqwMahEDIV%%MBPA_FekF?p?;F^U25aT2^*^
zlk{Mhx-GHl%%A?4y>InW4Y}qlVu_pC>?q8t-N?eg#l*}KeB?uSLh=pO6)s_Bw@>}J
z`E{Po@vg;l@&xmu*PMC~{>Jg-?S<F>bACzI+`c`oaAo&=yUlx&Q*XUYn(tX|7Uh@t
zkDZxG)o`-MHHl}+Z;gWEKZqRqz1Ds~U{^cKL1octa|4Q(Z_2oxo#9@6!piNK$CpI!
z)4qA%cBv(9e8F&M$x@3eiBr9v3q>ECtuRO6(b;Q{W5srKyl0UBhMEHIPy_maNt%hF
z5fM6N3M`Vs91OBRJ?Ecp5ZU*{cCO0j_ZCW@7l|KuVtE>(2NawzksVx&3@74Qeyi$~
zw6<t_zgc(c%T_)6kX^ms*%~ArRad>;@!~xrL&Luv{}%^29nNsQ@~m@i?WT}<uG^P;
z{z+Uo$;#wI2CIT92g6_aMV20W*M3;llD{gwuJmqf_+5ryv!~A6e%-ig_w&!+r!o95
zUd|Y{{nxv<jor7NhS~AFwonpck2~PASzI)UKV)}4@0?XEacq1Cg*dfUn3<V4fQb$m
zF){uocF#qd*1Qkq7jdodslW3s^YBIPe*Qx5y2r781xuazw=Iu0Yz|3b5L@tlvm-O3
z8y}Zz_Vabd_K|<K?=n2j%*eqGiX4L`YtCJlF9*GC^<TDS&u06}b2Z(+I`Fu3tT?UZ
z?8f_=eR;%BS%sayjH*k2@P3VdS7^W7f-&fv8TWe=2X4c=8jt5@#$DI!Jh^MyK6l17
zzdI@jMGnv>Owv5aNq6A_Mushaub-Yjt$%mSstfAd)<&Fj{FC|OS-@Qe6@AV%2OTdv
oGyF4}H|Zs7r*5n_f9&fQ0n41Zq;>7CFT9(hbId}CS;c`F0GoV?wEzGB
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ff4ad28d87c4b7b5f0581378ffc81ab8346be66d
GIT binary patch
literal 2017
zc$|%tc{tRI8i0Q@^RtYdu_jBV6Jmx$L#45GsAQWnwmC;e(<$4GN2aVDNtrQ?#FZG6
zF_oOS)QriNWGl;!>>*^0Y}G*+#;wkCuXCUKJomZ(e}8=M_q^|Sn+f`ay?YA*ftTz$
z`!~I~n#nPbyQN!Yl&Z}qq`p)c**oFM-6bZk&diEi+w}w0BJ+zo8b2aU<=mPWlN<E}
zGe==0BSqs3qipq&MYW2)M%c<d$W4Z2_kgHBPpjamqn;&-<vpsWoJm?@N0nk2t*5B$
zxiXg*8p~zg9EIRus^OkIe*vBjC_(^8DLnX0lqrfDNHV3>fCvZ_K#D=XEeO?wNl3#b
zC16m9xQZkcE+q}BLSYc7HUz2`4=BJDVqS!?RO${M7lQ-9)|Tc25U4!ykafzhA|?^>
zMP~R9rA@L|o}6>#Ai8i6oEIsDn(3oBrrhBopLIskx^HHU7RLTu@By|t?i$KBo8D#d
z^ov9ezMR&)hkYa9_G=5Bz$RksBVW%Pe-=FgX@2Oi%%(@Hbp*e4m1(S>r~XFsc$F(v
zO{ccbG$H0$(NgY4>Nd+hTE$;j=KeQ})HaKhDr_t8x9AhcE;&O&KO}=4Z{amFWpSUl
z{#YIjkfzr*WhwOhI1W2}sa{4XzZ*o0F^P&{v&&f<<LXfITHNOzP8<Y~G!#}DI<;sm
zt~a;DhGf~h8*gOgoOp5>_t4_r6&@PrpqnVC&*^5U%I$q2^lO*@8AC})!Qy+yjK}6<
ze6}gf{)1xW|EBN@27%f)b_Wg1;3ea(nlqSY-sqQozd9SurdlOh?C99|<lkVyGRMkD
zEXrN%M9=0BJpjq0LyD!8P94Gh(XI%acT(e8ss{_n)ol7g#6JdU0R#BtbKx4tj;wq^
z;VkYY`8V0C|Ii)mtlwX=-<M{R2D5!1<P^F7m~ulw>iT=)Wp-5gzcsI(0grI4;W_+`
z`h|GULjuC4XIihZo0Yw5vBO966OKQC_!>ld&SRbiH-el~VY8`rXu?J5MKGbNV)tr9
zG1kdOu}B+bA7I5`xEQ>DsHbvKX2tK$Nelji<td8Cu<h=V(uH}OkRy@Bg6sli&k-B+
zv|RBVIUSDa)qZQMEd5<`+I>*{>m}j;a$DxV4JO?Ifh-4E@`vay;V0w`W}ncDoedXe
z^SA-Iya6|D1R%2(z-BtgC=dS9=kTbtvbt8$*1SBaO%{*FMG-@dwF$ePPb)5!*19^Q
z7rjmT3%_LFc2Gq>UA=44E1u!Q@HRk^ulo)Ko8*obvEq)8tnWG<Vzhyk9X+pA>Z*2a
z|I}Vu1%&(UY(hm4D5~1oCdJHPj-k3Is>eUOa}|mzy;2f+%|hpmcLX)V57u7F^ab}W
zL0THZm~7-n;bOBJ+)?^wiyp6{YY!i(%&kLNk?&15x{B}CI%RmjSORCUGoPu@HZa5=
zi;it~e6|17FQkuZ_G^dZ5wW?ZMQwP|;?hqs%S@waY(Mh^!0CTLF~{wSbS8>*h}h7p
zdnT)Ee}`>3t6ylu^&R?rKE$=_vX(GoQ}^U+xBRqH$5X4r+)(rf8|3@O=R-V&v^dI0
zcX!ufMN-J@w2rv$Xj6uz4N@ba;#Q)lr*U$aUtpXdNs#UY1Yr4w2flNw{?|`Q;cq0s
zk4oO5rw8pA>B$rKYfcI#bm%UeA8R^bGhFZF)esrjCL%#T_u2L3LUYNeNb*4O-snu`
z^29tKwjMBrzim)z&0kScLgJs`r3EXP)acH3YH@0MF=<hl?<4tCK0oMhJrPH!Wg~ZA
z_H3a);q)&>%+CQwiFFNG;w`rlMo7CN`JxIqK^;TMIWCC`^wc69a5&?vGY989i@M3P
z^hCgE^WR;P|L&3ystNt-57!_b@YpuWQ5V!ugaYD!j(lrV>ryf<y*aaB(Hh7Nvb(xJ
zhGd$m7wFh4eh}lBtz=dY<PuV-iiLU}Rt|0l2!!xsC~e|ZVPz0ZWHf}xpYV{>2#*!P
zFgFD;VHvtvgOQirskc6JF0|B7ylhjrv3T0)r^cd0a722(y_WaeS(Aqx<Ch1B2-$Xe
zQ;co12Bo36U9NgJs$@x#hulLdsFN^{+3{l5t}R7n87LG;p}h+J9)y|Z8^XcsQhYDj
zbe7nKs%p1F>3kaUd)UrV0ZS2wiO@p#{mm3_L;KIP+6)(TudxoM0tsW{^gd$Dq0
z>fXiK_=aHZI${$&QtyHAsOjo?oL>A40r}8t!DZdB{dL3I+Rr=6RJ98n<%iF{^2^e2
zpD=D<nUZ5noRVA6htIZB<8ErvxAeg^Mv3<vyIZ9FRI@462`m0ccU|~r$+_Dlj~aX{
z`7fW(IUWS~d4>x;*uGX<Bn!e3TD4@R88wDl?hH)wzv`nLH5^!O87tcA$Fk^3ENos0
zX$n17EvOCCH^UNZ&ON^-=B{$(V`x(32g>8UC0@#6t781Xc{PN(+ZDafvr#TSw>dP|
jXTE~Gg_8A_onuYOEt!^$RJ~H0>r}??&!e8NPPqINC;WJH
--- a/third_party/rnp/src/tests/data/test_key_validity/case5/generate.cpp
+++ b/third_party/rnp/src/tests/data/test_key_validity/case5/generate.cpp
@@ -91,17 +91,17 @@ main(int argc, char **argv)
binding->hashed_data = NULL;
binding->hashed_len = 0;
pgp_keyid(keyid, sizeof(keyid), &tskey.key);
pgp_fingerprint(&keyfp, &tskey.key);
binding->halg = pgp_hash_adjust_alg_to_key(binding->halg, &tskey.key);
binding->palg = tskey.key.alg;
- signature_set_keyfp(binding, &keyfp);
+ binding->set_keyfp(keyfp);
pgp_hash_t hash = {};
pgp_hash_t hashcp = {};
if (!signature_fill_hashed_data(binding) ||
!signature_hash_binding(binding, &tpkey.key, &subkey->subkey, &hash) ||
!pgp_hash_copy(&hashcp, &hash)) {
RNP_LOG("failed to hash signature");
@@ -114,17 +114,17 @@ main(int argc, char **argv)
return 1;
}
if (signature_calculate(binding, &tskey.key.material, &hash, &rng)) {
RNP_LOG("failed to calculate signature");
return 1;
}
- pgp_key_flags_t realkf = (pgp_key_flags_t) signature_get_key_flags(binding);
+ pgp_key_flags_t realkf = (pgp_key_flags_t) binding.key_flags();
if (!realkf) {
realkf = pgp_pk_alg_capabilities(subkey->subkey.alg);
}
if (realkf & PGP_KF_SIGN) {
pgp_signature_t embsig = {};
bool embres;
if (!calculate_primary_binding(
@@ -135,18 +135,20 @@ main(int argc, char **argv)
embres = signature_set_embedded_sig(binding, &embsig);
free_signature(&embsig);
if (!embres) {
RNP_LOG("failed to add primary key binding signature");
return 1;
}
}
- if (!signature_set_keyid(binding, keyid)) {
- RNP_LOG("failed to set issuer key id");
+ try {
+ binding->set_keyid(keyid);
+ } catch (const std::exception &e) {
+ RNP_LOG("failed to set issuer key id: %s", e.what());
return 1;
}
if (!transferable_key_to_public(&tpkey)) {
RNP_LOG("Failed to extract public key part.");
return 1;
}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..54697b2b844fef865a79918e4edcb76a6723f6f7
GIT binary patch
literal 1702
zc$|&WX<X6?9>?)N@K-_cK)lF7O`OaWbW9>EZ)dEeR2aP2Q8AhwFYx7Psc2KKjR#?-
zW92~*mAUCs1CptciD_D!PF|&^=GCP}wq6P1ZtZKgnP>C-_u%*WzTO=?Fe3T+GYAOW
z=PUf44pLiYCMlQdHyYT@>o=KCijn#kQVRR8J3l%+tL@=C1jsdRM>n;<!?_p)cXDUc
zZFJWFRXVo_bC}z(dV?r8wZ|kcUxu9F?(84d3|++5+zznaiLVTwur)cyT;yleleiC~
z)A(}@2RkrJ4dFtggoHGQEf-^Cv;qJH0U(bM35PRW@M&>O7eyn8hCl(F7WCtTP)nGO
z9s;fdgF>`T;ZTIG9%u%IL7-L;sQGa~7h%NdNUk(h?AmX66$F|BuT@4zHF9#%E6A~b
z8LzX#E*g-VMhLYd;Jn5-$<-b&bP<i!MXYi2)*{cfU`c*IB<$e3QGdoqRuuFRZ?EW7
z(Qf5;ZQ-AeJ^vfgI<AwEbt5vgDyFg^73a2l4|1LI&?8m)aFyp|f6?Np<^JZNG;`}#
zg-Z_SPTitFUHrM?t3OoC{pku_GuTGlPnm)Hj*%frZwkT3&k!xI8?qNfF<z2<K(C;+
zv)pLln<?0yV{J&4p&dxj;xSOkvrFabDGMm;L-zXtVKxMSJE)o+_CCNW*Sa2LC6@bz
zIH}940&kw6UL#)qn}k61x5+iI7xr__47PQsqIwMfLSh#cdC>+YohIiw5uYnu|4^~~
zrz@foK%n)h?=FW1#Pz8l%h#kX$;8T6-;*6@i`{dHn;xqdV(t+u-Mo-GN`s@lgxM+v
z1%Q7&imGS#TFb6X^rd<~*PX(e?W$$T`2}xN|2dK$J4`G5AqBI~b9n_%C0@>p>GZSs
zvOj@rKh&~4GT*rb=JPUsZ~EG=?9)cNr(QBn@H4vq4_y8l^b~m@s-)_+x5q<w%joN&
zC4)}E?tVdH|95VI0bhc&7IbOVuM&(Xl~vW~y>7mH`k-+~0=>D>ZZ%cxwbvU}XNC8R
zb?0&qZhd*p*7PWHIqJdzqV($03pQoU$8Nm-?YwuQXS!HcQDYK1?oD`QAf98DB1nT)
z&wNbuJ^@z<K#Tt@iTIyt<nQ-lUI2k|e|^@Q%s$lu?lkX-DvV!&P*q4ou>#3(uoW6W
zeu(As{E;Rj-#zia@vuqWit=&0mDjCLBTzFKNlsSu&39j+7VBGs$OL7$^HA+d#d&`-
z!tK>d&V$-z5!~>tc-E=N(FA9~L|tX}{_(ZVhY}stUiuS1V(Wv<f8PFLTYmT5$&Z7n
zP#{p({6)7euZ%Z|@1K@Wy$=x?)is3`<x09#Wc72pxx*WeFq49}A$_uv60{S`F^Vnn
zs<;<|w|7-i9%Z)f@oW+(@b0Y3GwngzcGzf#D`Fig@r!DnQTOnubTTumC*aZc=<k^C
z%>6#>IgZW}xYTviG|I(qIZHgpOs^qcARrvN%66k}PA4<89&7l}lUruwt$&AYkS&h1
zQ=ja9|6^iM-wCX$Y~AL-Z^6|i^#ReVW1=L&8*kjp_Pe7Jqmpd)cz=JNvN11l_La4^
z%|vI}PH!A0r}1pAW}tm$Oj_fV1E=ft0y6NHnnLT{X#0L4FXgEY_|7;y>ClKTx3qBj
zO3MM+v~|Hj;WsUhVXsBug{z53*g87LP;lqeQmq?2Bb_xY-j;cew=_KuXsyM*pq<}Z
z?;%|_HpbCz()47@q~grpo-}cBshFu$RY$;Y8&=2vGLY(-)-ZnQ{=f!dfogv&b$$-`
znxVK?uKnO_&Ny>(x>VDMpj(jGRr}%ixKJ!}hyP)+^&CQYC*zD{XDAw>xQqY9$nX;*
z71R={g#bibj{}s?m;!7-3<?Tp|M%o0GwiWKYH8QG8l?vyi1$6Yox^k~wv7uI)ZRr3
zs4#YI0|fM<G*qoE#oa%62c4d>4{yadscMRcX><)zcI>CM8P)Bb||PlFMw$N77G(
zq@8^)Jo2Dz`hK_3Y2~54-?rD~g5!GgJ*|?T{_1>9=yZPv1Fhdv(8=-X!m#g&dko}u
z`0I-(32qCsMxo=z+0-%X+g)V31k}oO31Kz=h$p?0Iv~JPy3#QH(n_r(&GO({z3P12
FzX4s<>7@Vw
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..da34c19d4ce6052791144c398b72f2ca38070624
GIT binary patch
literal 2006
zc$|%sdpy$%AIE>&elBxouE{0qgxE+l3L`pHa@(2P&XH-I5;iYcxpq{FS(7*tv&<?v
z@lcy3B+Mn3Cn{73x#oU5?qi-)&+B=5&U5}b|9}7ZzCW+`yO9C<hJE@70fCn+fy0M)
zxa!d%&wHiYWt7UTr=<6(GO~BWlRHaHUY(v2w>jJmREf+l?r4}tn##F1(MLDy2xd;g
zNP3FKX?oe(V~Z*keT}e{`;c37%g!EAcb-<kb0<AZ6w_x=PdSsc#EL4#&|6PZS<_{%
zjT*~kK5T{HV5;GsyZ}C)1}H)R$SZj8=_peaHHc&?C<hS`D1a1$et8h836qe9OG?0?
z5OEbrC|pV!RE5GIP;CfQEgq19E5tO0F;xTyk7+&xfr{ggm?!<qV-gUnGX1|RZIQk6
z<XkFx(S^O>j7TZeOdrKI<@6W%ZqO4q{4%SxFb-#f53tN}*HM1iv<{2ss}ec*XGzU_
zST_UjytdE@Y9huy_VdaKVA3Lx=7+3hwme&HB6zK93}gK~^$(iID&44RI<*4RD={yM
zmU1^!zftV_6UFr3rjSyFZ3q1lef;Pp7f9%2GWg~ryn3Q6Zh;ek<t72rwA!XDg|6?1
zVb+)GWQ6j&L9`fys2Dc2oV7Wu4kfS0Eq1ZvAb_Nyu+q@EMQd)Oxg|Cv%fZ8VGb`u#
z)62L=7Wc1m(Ktul1UY?nCtX!;Z==w^UH(T5B_#!m?;0{5nu+oKMq&0Rij}`j;U5eF
zwI2>2G%SOc47+JgV4AsutNVU-F`7!XO0d}RW^*B+-hye4m64c}yZ9D8l|%FdB#-nd
zmQvp8@E;6zMA&_j8rD)hSV*p7(Pkt5*_#yDgHJviu5r|MWfg_9xStr%<e>gtXRwQY
zclCb1B$G6l{pWMeksD7aHx;CAd?sFIMYa7`@Tv*WmSY3Y;ceE<#(N#&6Sln4-Wj`F
zIk*)&&YK^1`VPcbBhqu8a5Xp)<eYN5Eww`<u1bx;gv#>WYZ1j*XFJ6rZInZx6`k&C
z@cEIR%0-zK|GOtFcn_DyD4zZHy9Y{VXY4|3Ba8Xj1<GCncIa`r;%Ra^9P>{5qrI~9
zSHT6jp!y$6!vABn%>V91x(fnXj<V#*=nmlm@+RZG(3_PF7iM!gfw|lscWne9vmVG|
zILavZ{`B7Qacf0Yt)jj8v&1%8JQ^283^mp!?5Y`8Tq><~b3xDfm~<DeX5VpCML%D=
zXYx)w!<X)3fFj@U>kBr?9V}wT9UIu#bt=SY6DvD-UaQni?fU+)y-95~Lth3HDuO^!
z<<2%KMh0UD)j3i%yy(GED5~&IN#HgMT{b@v)C?zWyp?IQ9v%F&G=wqP$e+T&X4iY5
z^v&ixUq#ni+g9WXP*&voqYZB2yR}XlJ}8#JS?tVbD75wT@rI&f+nrwRKlu}BUd>_M
zIvx?5Yg*KX7tJmG5VOoMipF*`jsxuOhZJ+%u1FW6*c%ZGdTq~WRqb!EZ5Q<m4Y>D*
z7SD&cbzIgGW^C!6c<r8_R_b(et)CN$p0q=LZm8+wDx}3x20A-C=E@U8rp9%|bqAX=
zEbWjQSITcEh`Jg^`*{V%S0oA2Zvj5|Y||6}cDwH9g~ad=65za&Pw1)M!}Rpzkq6Z$
z_#-+rSN8YSZ(tJ~pX9X=8Q2!$ihS;i8_R{}l2MW5p5ndHnT+L;89;0!a14LPpwx!9
zqNIexKgCP)S1_s3Z`-NGsp-X}Ibpu9<a7D_bH8>)*iy>|?!D~VMlay>FGb8u14oF0
z`YiF5+gAoiyCQj_ayUU9L&-TNi3;-4A{}r%?V>XcXTONL#kKT8zy&p^uNujJ)kp}{
zgo?odjzK)&`AsG#T~I?23W)#v<cnrnmy&Vm&6x#rHbCyV!`Jr5kW5qcf}GxoAH+Ci
zE1A^+xr7v|VxgX=m81Is0wMe;N}G61SaA*}GU`L*k9bOIgvW|tm|OgqungU--pI=y
z)Z2^f3oUgcFWVGu&Yg1pp`j=N9FU%AujT%7#^e#(_~ij2LbjdO6l344L8&ipm#f;1
zDp^wGBKMFA1QO;kI~u1Bx232o1BHAkw0FTj&SA!RhH&tP6wg~Wohf#qvdX<sIzI{d
zHR3^oKO&ykC+J&x^JHJ2l|#DkKILO$HVPbnxp9m#sW{_z2eD_s*!_!B@%6#l0%8*_
zQtzSgi0RsSoL>9{0r|*#)^)?M{dN8N`j0!xRJ9A7<onOO^3T%n7%{GAnv!EooReG7
z)@NF&aksQ++xp--y~Jml)hW_`uGtjoj1_;ZyCM8b#DfO^7qLq`2=MX@XS=ZPTkVld
z2wP~?l9^`I5Nf$IC^6uguX0p>&@;<e(RMeMNmF8C^GZl#=%FfpZJ53pmRNnZ=DL`N
z%GLSM#K=j?lf5P0%3^C`yr3C1gu44xy~U|0SKmAAB)1oS{Jhzcjh3B5P01~pmJL+B
RQo9>e`foK+HEScT{{lJQcUb@c
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..49fa1c572f732f8fe96c73453e09d66bb2d66f42
GIT binary patch
literal 1398
zc$|&WeLT|%0LSs)wjZ_;V|iFwWSzB`Br}N=mC6cR%hMfJ)8%nq&I&_uI%ZAcB(XD+
zT%5YGge3E<L!Qb*$kX+J7UwBry6*ny)qnl}{p0(7y*`b6&^_eUO9%)w2_*J?&uKN2
zW7Jz^>*cJfwFk@>DJmO&3r*^|x3kT6O3}uyAE=g_U)a>}0cWb}+{~L?t@AW<kcIP-
zF}}R=<@=;+O*|%KF&}b`XW26#@6W{+K5{UyBxbpd8f?s9&I=;S$h@cCY{7K-iAKyq
zxtkCb5WprF=K6@~TtFQHK-v%iz7eKGwja|}QURhNPynX@{d^Fr3sX`?z?EQ7h@vJO
zia;uZT2L4Sx&;E&z62l<C{ANYmZrq&nC=}AsC2xW<?U6$iAOJ~4F99C7VMg<N~s()
zDH;T4<QhR{c%slWZ@Acfg_p46kx_#s+n)=t5SY_`A$r{8c9R}0DP_|iCbk#~uAaW}
zjHKt+%!s=0aVpy<iyMYB-)pV1Mty1%R{C_AZ;a2?>C-({<;2$3tCg6>aUK`X=d7lD
zQSACkG5yU7q!w)5?_#9m(HIIO=v@-n`4Um{wmf<^&&O7j2q<%Fn=?_phsR;oF?A|3
zwQZn@0-vECGPRJoI<5l^{un*iD~yH!aDuFgaHJJ0U1@2J3e2>3F<#Bgc6<;^yGzRd
zS!6;xs2{J27xwV9RChGWygJmrC$o~1ZRx#Z#$z)a_b&>wuM~^ltndl|f!aPhD?&Nq
z-nf(QTXKtNbZOUFiqTZco_Nxx&ed6;dQz6Tt%{OV^+K1)R5pVOzz+?nm$AC^#J5Mg
z!}h;Ij$^f~ih`>J-1lLB4JMu*peLOR#T?zYxJ0Cp@)LZT?RCEE383KnYj%4i?o5Rp
zc<p~AeC1EpRTT2dYeuXfqW#I(=fY*`AW&SjxgE(*=Z_J4CaTBhT=G!Gm9EM0q81rt
z^_8bK;hl}^M(%r;ZgFZV+Bn$Ai<M`4v)+Y>H<MD^B5SSpRpv;DdxG;P8=MrkVZ8~r
zOO$A&%>{f^`@m4?SY%X(L)&ieADADs?LS&yLPzD87Pr&o()p8|1-?<FZ9m@;5cc0;
znbWq0Qy2=Jasl+R;be8~@33`>&iMw~i@kF{1v+)dVrA)T`p2I+7o?UscrOp<1)03t
zk9*zlWJrWcjb@GX^mI!r5(1~*=qc)tHm6(e$6?|suE)!J8zzTK3ytI8p2}T-7<{-&
zrFX5@ot;ex?Nb6jXt)KP8MNc2B~9F}IWC^i<DL*6uIYrm&2vjy4pf1yq2ttY9$#4~
zGKWWm2M?6&h|J(GOw0fZE2saa-`HMeQ@W_3fuld5D~lJ&DUn?r?2?qU5~fsE;0}MJ
zR^b0@Z`eL|`N*xN-gT2%8a^g$W*Ruekkn@?wqB1LVQvjCl~*7<b;zvjV{oG1DJ;|C
zpf5#l8X<ffaZO}-3XPCFA%Z&p2B!93U^1vKQ~?3xZNCIizr^IA4`S4zfa3p?&zWIk
zl4xly8HG|CAjjYC@@@{(G{wNr;klv}+2N*!Ssjq$naox%GNA4`=xpKX8G4ksg>hL{
z=?{||4WSDrsBlbZlpIFBCgy~s>t_yz$GWhu&k4`B)=f0EqpnKN968xg91o5t&vev^
zF8;XluF$y2f`Q)9!ENRoXu+`ROFC4mw-N8ntBY`k%tDEhIcHPjlwEtW<^oV8Mw+-5
e{^3u4Q%XR9SCFNy8`82A&R11C7bzDc;ywXubz+(T
new file mode 100644
--- /dev/null
+++ b/third_party/rnp/src/tests/ffi-enc.cpp
@@ -0,0 +1,897 @@
+/*
+ * Copyright (c) 2020 [Ribose Inc](https://www.ribose.com).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <fstream>
+#include <vector>
+#include <string>
+
+#include <rnp/rnp.h>
+#include "rnp_tests.h"
+#include "support.h"
+#include "librepgp/stream-common.h"
+#include "librepgp/stream-packet.h"
+#include "librepgp/stream-sig.h"
+#include <json.h>
+#include <vector>
+#include <string>
+#include "file-utils.h"
+#include <librepgp/stream-ctx.h>
+#include "pgp-key.h"
+#include "ffi-priv-types.h"
+
+static bool
+getpasscb_once(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ const char **pass = (const char **) app_ctx;
+ if (!*pass) {
+ return false;
+ }
+ size_t pass_len = strlen(*pass);
+ if (pass_len >= buf_len) {
+ return false;
+ }
+ memcpy(buf, *pass, pass_len);
+ *pass = NULL;
+ return true;
+}
+
+static bool
+getpasscb_inc(rnp_ffi_t ffi,
+ void * app_ctx,
+ rnp_key_handle_t key,
+ const char * pgp_context,
+ char * buf,
+ size_t buf_len)
+{
+ int * num = (int *) app_ctx;
+ std::string pass = "pass" + std::to_string(*num);
+ (*num)++;
+ strncpy(buf, pass.c_str(), buf_len - 1);
+ return true;
+}
+
+#define TBL_MAX_USERIDS 4
+typedef struct key_tbl_t {
+ const uint8_t *key_data;
+ size_t key_data_size;
+ bool secret;
+ const char * keyid;
+ const char * grip;
+ const char * userids[TBL_MAX_USERIDS + 1];
+} key_tbl_t;
+
+static void
+tbl_getkeycb(rnp_ffi_t ffi,
+ void * app_ctx,
+ const char *identifier_type,
+ const char *identifier,
+ bool secret)
+{
+ key_tbl_t *found = NULL;
+ for (key_tbl_t *tbl = (key_tbl_t *) app_ctx; tbl && tbl->key_data && !found; tbl++) {
+ if (tbl->secret != secret) {
+ continue;
+ }
+ if (!strcmp(identifier_type, "keyid") && !strcmp(identifier, tbl->keyid)) {
+ found = tbl;
+ break;
+ } else if (!strcmp(identifier_type, "grip") && !strcmp(identifier, tbl->grip)) {
+ found = tbl;
+ break;
+ } else if (!strcmp(identifier_type, "userid")) {
+ for (size_t i = 0; i < TBL_MAX_USERIDS; i++) {
+ if (!strcmp(identifier, tbl->userids[i])) {
+ found = tbl;
+ break;
+ }
+ }
+ }
+ }
+ if (found) {
+ char *format = NULL;
+ assert_rnp_success(
+ rnp_detect_key_format(found->key_data, found->key_data_size, &format));
+ assert_non_null(format);
+ uint32_t flags = secret ? RNP_LOAD_SAVE_SECRET_KEYS : RNP_LOAD_SAVE_PUBLIC_KEYS;
+ rnp_input_t input = NULL;
+ assert_rnp_success(
+ rnp_input_from_memory(&input, found->key_data, found->key_data_size, true));
+ assert_non_null(input);
+ assert_rnp_success(rnp_load_keys(ffi, format, input, flags));
+ free(format);
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ }
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pass)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ // load our keyrings
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+
+ // write out some data
+ FILE *fp = fopen("plaintext", "wb");
+ assert_non_null(fp);
+ assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp));
+ assert_int_equal(0, fclose(fp));
+
+ // create input+output w/ bad paths (should fail)
+ input = NULL;
+ assert_rnp_failure(rnp_input_from_path(&input, "noexist"));
+ assert_null(input);
+ assert_rnp_failure(rnp_output_to_path(&output, ""));
+ assert_null(output);
+
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ assert_non_null(output);
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add password (using all defaults)
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass1", NULL, 0, NULL));
+ // add password
+ assert_rnp_success(rnp_op_encrypt_add_password(op, "pass2", "SM3", 12345, "TWOFISH"));
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ // execute the operation
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (pass1)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_int_equal(
+ RNP_SUCCESS,
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass1"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ // decrypt (pass2)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass2"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pass_provider)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char *plaintext = "Data encrypted with password provided via password provider.";
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // write out some data
+ FILE *fp = fopen("plaintext", "wb");
+ assert_non_null(fp);
+ assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp));
+ assert_int_equal(0, fclose(fp));
+ // create input + output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add password with NULL password provider set - should fail
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_failure(rnp_op_encrypt_add_password(op, NULL, NULL, 0, NULL));
+ // add password with password provider set.
+ int pswdnum = 1;
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_inc, &pswdnum));
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, NULL, 0, NULL));
+ // add another password with different encryption parameters
+ assert_rnp_success(rnp_op_encrypt_add_password(op, NULL, "SM3", 12345, "TWOFISH"));
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAMELLIA256"));
+ // execute the operation
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+
+ /* decrypt with pass1 */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "pass1"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ /* decrypt with pass2 via provider */
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ pswdnum = 2;
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_inc, &pswdnum));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ unlink("decrypted");
+
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ // load our keyrings
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+
+ // write out some data
+ FILE *fp = fopen("plaintext", "wb");
+ assert_non_null(fp);
+ assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp));
+ assert_int_equal(0, fclose(fp));
+
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ assert_non_null(output);
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add recipients
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ // execute the operation
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // read in the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk_key_provider)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+ uint8_t * primary_sec_key_data = NULL;
+ size_t primary_sec_size = 0;
+ uint8_t * sub_sec_key_data = NULL;
+ size_t sub_sec_size = 0;
+
+ /* first, let's generate some encrypted data */
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_non_null(ffi);
+ // load our keyrings
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ // write out some data
+ FILE *fp = fopen("plaintext", "wb");
+ assert_non_null(fp);
+ assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp));
+ assert_int_equal(0, fclose(fp));
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ assert_non_null(output);
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add recipient 1
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ // cleanup
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // add recipient 2
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ // save the primary key data for later
+ assert_rnp_success(rnp_get_secret_key_data(key, &primary_sec_key_data, &primary_sec_size));
+ assert_non_null(primary_sec_key_data);
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // save the appropriate encrypting subkey for the key provider to use during decryption
+ // later
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "8A05B89FAD5ADED1", &key));
+ assert_non_null(key);
+ assert_rnp_success(rnp_get_secret_key_data(key, &sub_sec_key_data, &sub_sec_size));
+ assert_non_null(sub_sec_key_data);
+ // cleanup
+ assert_rnp_success(rnp_key_handle_destroy(key));
+ key = NULL;
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ // execute the operation
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+ assert_rnp_success(rnp_ffi_destroy(ffi));
+ ffi = NULL;
+
+ /* decrypt */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ // load the primary
+ input = NULL;
+ assert_rnp_success(
+ rnp_input_from_memory(&input, primary_sec_key_data, primary_sec_size, true));
+ assert_non_null(input);
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+
+ // decrypt (no key to decrypt, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_int_equal(RNP_ERROR_NO_SUITABLE_KEY, rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // key_data key_data_size secret keyid grip userids
+ const key_tbl_t keydb[] = {
+ {sub_sec_key_data, sub_sec_size, true, "8A05B89FAD5ADED1", NULL, {NULL}}, {0}};
+
+ // decrypt
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(rnp_ffi_set_key_provider(ffi, tbl_getkeycb, (void *) keydb));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+ free(sub_sec_key_data);
+ free(primary_sec_key_data);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_and_sign)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ rnp_op_sign_signature_t signsig = NULL;
+ const char * plaintext = "data1";
+ rnp_key_handle_t key = NULL;
+ const uint32_t issued = 1516211899; // Unix epoch, nowish
+ const uint32_t expires = 1000000000; // expires later
+ const uint32_t issued2 = 1516211900; // Unix epoch, nowish
+ const uint32_t expires2 = 2000000000; // expires later
+
+ // setup FFI
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+
+ // load our keyrings
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/pubring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+ input = NULL;
+
+ // write out some data
+ FILE *fp = fopen("plaintext", "wb");
+ assert_non_null(fp);
+ assert_int_equal(1, fwrite(plaintext, strlen(plaintext), 1, fp));
+ assert_int_equal(0, fclose(fp));
+
+ // create input+output
+ assert_rnp_success(rnp_input_from_path(&input, "plaintext"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "encrypted"));
+ assert_non_null(output);
+ // create encrypt operation
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ // add recipients
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set the data encryption cipher
+ assert_rnp_success(rnp_op_encrypt_set_cipher(op, "CAST5"));
+ // enable armoring
+ assert_rnp_success(rnp_op_encrypt_set_armor(op, true));
+ // add signature
+ assert_rnp_success(rnp_op_encrypt_set_hash(op, "SHA1"));
+ assert_rnp_success(rnp_op_encrypt_set_creation_time(op, 0));
+ assert_rnp_success(rnp_op_encrypt_set_expiration_time(op, 0));
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid1", &key));
+ assert_rnp_success(rnp_op_encrypt_add_signature(op, key, NULL));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // add second signature with different hash/issued/expiration
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key1-uid2", &key));
+ assert_rnp_success(rnp_op_encrypt_add_signature(op, key, &signsig));
+ assert_rnp_success(rnp_op_sign_signature_set_creation_time(signsig, issued2));
+ assert_rnp_success(rnp_op_sign_signature_set_expiration_time(signsig, expires2));
+ assert_rnp_success(rnp_op_sign_signature_set_hash(signsig, "SHA512"));
+ rnp_key_handle_destroy(key);
+ key = NULL;
+ // set default sig parameters after the signature is added - those should be picked up
+ assert_rnp_success(rnp_op_encrypt_set_hash(op, "SHA256"));
+ assert_rnp_success(rnp_op_encrypt_set_creation_time(op, issued));
+ assert_rnp_success(rnp_op_encrypt_set_expiration_time(op, expires));
+ // execute the operation
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+
+ // make sure the output file was created
+ assert_true(rnp_file_exists("encrypted"));
+
+ // cleanup
+ assert_rnp_success(rnp_input_destroy(input));
+ input = NULL;
+ assert_rnp_success(rnp_output_destroy(output));
+ output = NULL;
+ assert_rnp_success(rnp_op_encrypt_destroy(op));
+ op = NULL;
+
+ /* decrypt */
+
+ // decrypt (no pass provider, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, NULL, NULL));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt (wrong pass, should fail)
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ const char *pass = "wrong1";
+ assert_rnp_success(rnp_ffi_set_pass_provider(ffi, getpasscb_once, &pass));
+ assert_rnp_failure(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+
+ // decrypt
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "decrypted"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+ assert_rnp_success(rnp_decrypt(ffi, input, output));
+ // cleanup
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("decrypted").c_str(), plaintext);
+ // verify and check signatures
+ rnp_op_verify_t verify;
+ assert_rnp_success(rnp_input_from_path(&input, "encrypted"));
+ assert_non_null(input);
+ assert_rnp_success(rnp_output_to_path(&output, "verified"));
+ assert_non_null(output);
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+ // check signatures
+ rnp_op_verify_signature_t sig;
+ size_t sig_count;
+ uint32_t sig_create;
+ uint32_t sig_expires;
+ char * hname = NULL;
+
+ assert_rnp_success(rnp_op_verify_get_signature_count(verify, &sig_count));
+ assert_int_equal(sig_count, 2);
+ // signature 1
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 0, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ assert_rnp_success(rnp_op_verify_signature_get_times(sig, &sig_create, &sig_expires));
+ assert_int_equal(sig_create, issued);
+ assert_int_equal(sig_expires, expires);
+ assert_rnp_success(rnp_op_verify_signature_get_hash(sig, &hname));
+ assert_string_equal(hname, "SHA256");
+ rnp_buffer_destroy(hname);
+ hname = NULL;
+ // signature 2
+ assert_rnp_success(rnp_op_verify_get_signature_at(verify, 1, &sig));
+ assert_rnp_success(rnp_op_verify_signature_get_status(sig));
+ assert_rnp_success(rnp_op_verify_signature_get_times(sig, &sig_create, &sig_expires));
+ assert_int_equal(sig_create, issued2);
+ assert_int_equal(sig_expires, expires2);
+ assert_rnp_success(rnp_op_verify_signature_get_hash(sig, &hname));
+ assert_string_equal(hname, "SHA512");
+ rnp_buffer_destroy(hname);
+ hname = NULL;
+ // cleanup
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ input = NULL;
+ rnp_output_destroy(output);
+ output = NULL;
+ // compare the decrypted file
+ assert_string_equal(file_to_str("verified").c_str(), plaintext);
+ // final cleanup
+ rnp_ffi_destroy(ffi);
+}
+
+TEST_F(rnp_tests, test_ffi_encrypt_pk_subkey_selection)
+{
+ rnp_ffi_t ffi = NULL;
+ rnp_input_t input = NULL;
+ rnp_output_t output = NULL;
+ rnp_op_encrypt_t op = NULL;
+ const char * plaintext = "data1";
+
+ /* check whether a latest subkey is selected for encryption */
+ assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
+ assert_rnp_success(
+ rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
+
+ /* case 1: three encryption subkeys, second expired, third has later creation time */
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_key_load/key0-sub02.pgp"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ rnp_key_handle_t key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "userid", "key0-uid0", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ /* get output */
+ uint8_t *buf = NULL;
+ size_t len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, true));
+ assert_true(buf && len);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ rnp_op_encrypt_destroy(op);
+ /* decrypt */
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_memory(&input, buf, len, true));
+ rnp_buffer_destroy(buf);
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ rnp_op_verify_t verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+
+ /* check whether we used correct subkey */
+ size_t count = 0;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ rnp_recipient_handle_t recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ char *keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "8A05B89FAD5ADED1");
+ rnp_buffer_destroy(keyid);
+
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* case 2: only subkeys 1-2, make sure that latest but expired subkey is not selected */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(
+ rnp_input_from_path(&input, "data/test_stream_key_load/key0-sub01.pgp"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_success(rnp_op_encrypt_execute(op));
+ /* get output */
+ buf = NULL;
+ len = 0;
+ assert_rnp_success(rnp_output_memory_get_buf(output, &buf, &len, true));
+ assert_true(buf && len);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+ rnp_op_encrypt_destroy(op);
+ /* decrypt */
+ assert_rnp_success(rnp_input_from_path(&input, "data/keyrings/1/secring.gpg"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_SECRET_KEYS));
+ rnp_input_destroy(input);
+
+ assert_rnp_success(rnp_input_from_memory(&input, buf, len, true));
+ rnp_buffer_destroy(buf);
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+
+ verify = NULL;
+ assert_rnp_success(rnp_op_verify_create(&verify, ffi, input, output));
+ assert_rnp_success(rnp_op_verify_execute(verify));
+
+ /* check whether we used correct subkey */
+ count = 0;
+ assert_rnp_success(rnp_op_verify_get_recipient_count(verify, &count));
+ assert_int_equal(count, 1);
+ recipient = NULL;
+ assert_rnp_success(rnp_op_verify_get_recipient_at(verify, 0, &recipient));
+ assert_non_null(recipient);
+ keyid = NULL;
+ assert_rnp_success(rnp_recipient_get_keyid(recipient, &keyid));
+ assert_non_null(keyid);
+ assert_string_equal(keyid, "1ED63EE56FADC34D");
+ rnp_buffer_destroy(keyid);
+
+ rnp_op_verify_destroy(verify);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ /* case 3: only expired subkey, make sure encryption operation fails */
+ assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC | RNP_KEY_UNLOAD_SECRET));
+ assert_rnp_success(rnp_input_from_path(&input, "data/test_stream_key_load/key0-sub1.pgp"));
+ assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
+ rnp_input_destroy(input);
+
+ assert_rnp_success(
+ rnp_input_from_memory(&input, (uint8_t *) plaintext, strlen(plaintext), false));
+ assert_rnp_success(rnp_output_to_memory(&output, 0));
+ /* create encrypt operation, add recipient and execute */
+ assert_rnp_success(rnp_op_encrypt_create(&op, ffi, input, output));
+ key = NULL;
+ assert_rnp_success(rnp_locate_key(ffi, "keyid", "7bc6709b15c23a4a", &key));
+ assert_rnp_success(rnp_op_encrypt_add_recipient(op, key));
+ rnp_key_handle_destroy(key);
+ assert_rnp_failure(rnp_op_encrypt_execute(op));
+ rnp_op_encrypt_destroy(op);
+ rnp_input_destroy(input);
+ rnp_output_destroy(output);
+
+ rnp_ffi_destroy(ffi);
+}
--- a/third_party/rnp/src/tests/ffi.cpp
+++ b/third_party/rnp/src/tests/ffi.cpp
@@ -49,119 +49,117 @@ TEST_F(rnp_tests, test_ffi_homedir)
char * pub_path = NULL;
char * sec_format = NULL;
char * sec_path = NULL;
rnp_input_t input = NULL;
// get the default homedir (not a very thorough test)
{
char *homedir = NULL;
- assert_int_equal(RNP_SUCCESS, rnp_get_default_homedir(&homedir));
+ assert_rnp_success(rnp_get_default_homedir(&homedir));
assert_non_null(homedir);
rnp_buffer_destroy(homedir);
}
// detect the formats+paths
- assert_int_equal(RNP_SUCCESS,
- rnp_detect_homedir_info(
- "data/keyrings/1", &pub_format, &pub_path, &sec_format, &sec_path));
+ assert_rnp_success(rnp_detect_homedir_info(
+ "data/keyrings/1", &pub_format, &pub_path, &sec_format, &sec_path));
// check formats
- assert_int_equal(0, strcmp(pub_format, "GPG"));
- assert_int_equal(0, strcmp(sec_format, "GPG"));
+ assert_string_equal(pub_format, "GPG");
+ assert_string_equal(sec_format, "GPG");
// check paths
- assert_int_equal(0, strcmp(pub_path, "data/keyrings/1/pubring.gpg"));