Bug 1692909 - Update RNP to v0.14.0. r=rjl

--HG--
extra : rebase_source : bfda12a4f20c1acf3e2c69ee8eaf74294de3566b
extra : amend_source : 82ae78224921b2444f910a485153e840f71db267
This commit is contained in:
Kai Engert 2021-02-15 21:10:14 +01:00
Родитель 1becec9846
Коммит 71873001c1
112 изменённых файлов: 9322 добавлений и 6873 удалений

2
third_party/README.rnp поставляемый
Просмотреть файл

@ -1,7 +1,7 @@
Directory ./rnp contains a copy of rnp which has been obtained from:
https://github.com/rnpgp/rnp
[commit a2c5ecd3a84a33450f5d8cda09cf5549410b5e70]
[commit 7c8492b44ab5105dab410cfd00f35b492b68d48e]
For licensing information, please refer to the included documentation.

Просмотреть файл

@ -1,21 +1,13 @@
# HG changeset patch
# User Kai Engert <kaie@kuix.de>
# Date 1598528704 -7200
# Node ID 2cab33d64909409be0ca9b008631fb9dd6dbfa2d
# Parent 0d45417c5ad6ba182de5b41d8698e9ae3530c9c6
Bug 1641720 - Patch RNP to disable several nonstandard or obsolete ciphers. r=mkmelin a=rjl
diff --git a/third_party/rnp/src/lib/crypto/signatures.cpp b/third_party/rnp/src/lib/crypto/signatures.cpp
--- a/third_party/rnp/src/lib/crypto/signatures.cpp
+++ b/third_party/rnp/src/lib/crypto/signatures.cpp
@@ -181,29 +181,90 @@ signature_calculate(pgp_signature_t *
break;
@@ -188,29 +188,90 @@ signature_calculate(pgp_signature_t *
sig->write_material(material);
return RNP_SUCCESS;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_GENERIC;
}
if (!ret) {
write_signature_material(*sig, material);
}
return ret;
}
+static bool is_hash_alg_allowed_in_sig(const pgp_hash_alg_t hash_alg)
@ -100,5 +92,3 @@ diff --git a/third_party/rnp/src/lib/crypto/signatures.cpp b/third_party/rnp/src
}
/* Finalize hash */

242
third_party/rnp/CHANGELOG.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,242 @@
## Changelog
### 0.14.0 [2021-01-15]
#### General
* Improved key validation: require to have at least one valid, non-expiring self signature.
* Added support for 'stripped' keys without userids and certifications but with valid subkey binding signature.
* Added support for Windows via MinGW/MSYS2.
* Added support for Windows via MSVC.
* Fixed secret key locking when it is updated with new signatures/subkeys.
* Fixed key expiry/flags calculation (take in account only the latest valid self-signature/subkey binding).
* Fixed MDC reading if it appears on 8k boundary.
* Disabled logging by default in release builds and added support for environment variable `RNP_LOG_CONSOLE` to enable it back.
* Fixed leading zeroes for secp521r1 b & n field constants.
* Allowed keys and signatures with invalid MPI bit count.
* Added support for private/experimental signature subpackets, used by GnuPG and other implementations.
* Added support for reserved/placeholder signatures.
* Added support for zero-size userid/attr packet.
* Relaxed packet dumping, ignoring invalid packets and allowing to find wrong packet easier.
* Improved logging of errored keys/subkeys information for easier debugging.
* Fixed support for old RSA sign-only/encrypt-only and ElGamal encrypt-and-sign keys.
* Fixed support for ElGamal keys larger then 3072 bits.
* Fixed symbol visibility so only FFI functions are exposed outside of the library.
* Added support for unwrapping of raw literal packets.
* Fixed crash with non-detached signature input, fed into the `rnp_op_verify_detached_create()`.
* Significantly reduced memory usage for the keys large number of signatures.
* Fixed long armor header lines processing.
* Added basic support for GnuPG's offline primary keys (`gnupg --export-secret-subkeys`) and secret keys, stored on card.
* Fixed primary key binding signature validation when hash algorithm differs from the one used in the subkey binding signature.
* Fixed multiple memory leaks related to invalid algorithms/versions/etc.
* Fixed possible crashes during processing of malformed armored input.
* Limited allowed nesting levels for OpenPGP packets.
* Fixed support for text-mode signatures.
* Replaced strcpy calls with std::string and memcpy where applicable.
* Removed usage of mktemp, replacing it with mkstemp.
* Replaced usage of deprecated `botan_pbkdf()` with `botan_pwdhash()`.
* Added support for the marker packet, issued by some implementations.
* Added support for unknown experimental s2ks.
* Fixed armored message contents detection (so armored revocation signature is not more reported as the public key).
* Changed behaviour to use latest encryption subkey by default.
* Fixed support for widechar parameters/file names on Windows.
* Implemented userid validity checks so only certified/non-expired/non-revoked userid may be searched.
* Fixed GnuPG compatibility issues with CR (`\r`) characters in text-mode and cleartext-signed documents.
* Improved performance of the key/uid signatures access.
* Migrated tests to the Python 3.
* Migrated most of the internal code to C++.
#### CLI
* Do not load keyring when it is not required, avoiding extra `keyring not found` output.
* Input/output data via the tty, if available, instead of stdin/stdout.
* Fixed possible crash when HOME variable is not set.
* rnpkeys: Added `--import-sigs` and changed behavior of `--import` to check whether input is key or signature.
* rnpkeys: Added `--export-rev` command to export key's revocation, parameters `--rev-type`, `--rev-reason`.
* rnpkeys: Added `--revoke-key` command.
* rnpkeys: Added `--permissive` parameter to `--import-keys` command.
* rnpkeys: Added `--password` options, allowing to specify password and/or generate unprotected key.
#### FFI
* Added keystore type constants `RNP_KEYSTORE_*`.
* Added `rnp_import_signatures`.
* Added `rnp_key_export_revocation`.
* Added `rnp_key_revoke`.
* Added `rnp_request_password`.
* Added `rnp_key_set_expiration` to update key's/subkey's expiration time.
* Added flag `RNP_LOAD_SAVE_PERMISSIVE` to `rnp_import_keys`, allowing to skip erroneous packets.
* Added flag `RNP_LOAD_SAVE_SINGLE`, allowing to import keys one-by-one.
* Added `rnp_op_verify_get_protection_info` to check mode and cipher used to encrypt message.
* Added functions to retrieve recipients information (`rnp_op_verify_get_recipient_count`, `rnp_op_verify_get_symenc_count`, etc.).
* Added flag `RNP_KEY_REMOVE_SUBKEYS` to `rnp_key_remove` function.
* Added function `rnp_output_pipe` allowing to write data from input to the output.
* Added function `rnp_output_armor_set_line_length` allowing to change base64 encoding line length.
* Added function `rnp_key_export_autocrypt` to export public key in autocrypt-compatible format.
* Added functions to retrieve information about the secret key's protection (`rnp_key_get_protection_type`, etc.).
* Added functions `rnp_uid_get_type`, `rnp_uid_get_data`, `rnp_uid_is_primary`.
* Added function `rnp_uid_is_valid`.
* Added functions `rnp_key_get_revocation_signature` and `rnp_uid_get_revocation_signature`.
* Added function `rnp_signature_get_type`.
* Added function `rnp_signature_is_valid`.
* Added functions `rnp_key_is_valid` and `rnp_key_valid_till`.
* Added exception guard to FFI boundary.
* Fixed documentation for the `rnp_unload_keys` function.
#### Security
* Removed version header from armored messages (see https://mailarchive.ietf.org/arch/msg/openpgp/KikdJaxvdulxIRX_yxU2_i3lQ7A/ ).
* Enabled fuzzing via oss-fuzz and fixed reported issues.
* Fixed a bunch of issues reported by static analyzer.
* Require at least Botan 2.14.0.
### 0.13.1 [2020-01-15]
#### Security
* rnpkeys: Fix issue #1030 where rnpkeys would generate unprotected secret keys.
### 0.13.0 [2019-12-31]
#### General
* Fixed a double-free on invalid armor headers.
* Fixed broken versioning when used as a git submodule.
* Fixed an infinite loop on parsing truncated armored keys.
* Fixed armored stream parsing to be more flexible and allow blank lines before trailer.
* Fixed the armor header for detached signatures (previously MESSAGE, now SIGNATURE).
* Improved setting of default qbits for DSA.
* Fixed a crash when retrieving signature revocation reason.
* Stop using expensive tests for key material validation.
#### CLI
* rnpkeys: Removed a few redundant commands (--get-key, --print-sigs, --trusted-keys, ...).
* rnpkeys: Added --secret option.
* rnpkeys: Display 'ssb' for secret subkeys.
* rnp: Added `--list-packets` parameters (`--json`, etc.).
* rnp: Removed `--show-keys`.
#### FFI
* Added `rnp_version_commit_timestamp` to retrieve the commit timestamp
(for non-release builds).
* Added a new (non-JSON) key generation API (`rnp_op_generate_create` etc.).
* Added `rnp_unload_keys` function to unload all keys.
* Added `rnp_key_remove` to unload a single key.
* Expanded bit length support for JSON key generation.
* Added `rnp_key_get_subkey_count`/`rnp_key_get_subkey_at`.
* Added various key property accessors (`rnp_key_get_bits`, `rnp_key_get_curve`).
* Added `rnp_op_generate_set_protection_password`.
* Added `rnp_key_packets_to_json`/`rnp_dump_packets_to_json`.
* Added `rnp_key_get_creation`, `rnp_key_get_expiration`.
* Added `rnp_key_get_uid_handle_at`, `rnp_uid_is_revoked`, etc.
* Added `rnp_key_is_revoked` and related functions to check for revocation.
* Added `rnp_output_to_path` and `rnp_output_finish`.
* Added `rnp_import_keys`.
* Added `rnp_calculate_iterations`.
* Added `rnp_supports_feature`/`rnp_supported_features`.
* Added `rnp_enable_debug`/`rnp_disable_debug`.
* Added `rnp_key_get_primary_grip`.
* Added `rnp_output_to_armor`.
* Added `rnp_op_generate_set_request_password`.
* Added `rnp_dump_packets_to_output`.
* Added `rnp_output_write`.
* Added `rnp_guess_contents`.
* Implemented `rnp_op_set_file_name`/`rnp_op_set_file_mtime`.
* Added `rnp_op_encrypt_set_aead_bits`.
* Added `rnp_op_verify_signature_get_handle`.
* Added `rnp_signature_packet_to_json`.
#### Packaging
* RPM: Split packages into librnp0, librnp0-devel, and rnp0.
### 0.12.0 [2019-01-13]
#### General
* We now require Botan 2.8+.
* Fixed key grip calculations for various key types.
* Fixed SM2 signatures hashing the hash of the message. See comment in issue #436.
* Added support for G10 ECC keys.
* Fixed dumping of partial-length packets.
* Added support for extra ECC curves:
* Brainpool p256, p384, p512 ECDSA/ECDH
* secp256k1 ECDSA/ECDH
* x25519
* Fixed AEAD with newer versions of Botan.
* Removed a lot of legacy code.
#### CLI
* rnp: Added -f/--keyfile option to load keys directly from a file.
* rnp: Fixed issue with selecting G10 secret keys via userid.
* rnpkeys: Added support for SM2 with arbitrary hashes.
* redumper: Added -g option to dump fingerprints and grips.
* redumper: Display key id/fingerprint/grip in packet listings.
#### FFI
* Added FFI examples.
* Fixed a regression with loading subkeys directly.
* Implemented support for per-signature hash and creation/expiration time.
* Added AEAD support.
### 0.11.0 [2018-09-16]
#### General
* Remove some old SSH key support.
* Add support for dynamically calculating the S2K iterations.
* Add support for extracing the public key from the secret key.
* Add support for merging information between keys.
#### CLI
* Add options for custom S2K iterations/times (dynamic by default).
### 0.10.0 [2018-08-20]
#### General
* Fixed some compiler warnings.
* Switched armoring to use PRIVATE KEY instead of SECRET KEY.
#### ECDSA
* Use the matching hash to be used for the deterministic nonce generation.
* Check that the input is of the expected length.
* Removed the code to truncate the ECDSA input since this is now handled by Botan.
#### FFI
* Added enarmor and dearmor support.
* Added library version retrieval.
* Removed rnp_export_public_key, added rnp_key_export.
### 0.9.2 [2018-08-13]
#### General
* Support for generation and verification of embedded signature subpacket for signing subkeys
* Verification of public key signatures and key material
* Improved performance of assymetric operations (key material is now validated on load)
#### FFI
* Fixed rnp_op_add_signature for G10 keys
### 0.9.1 [2018-07-12]
#### General
* Added issuer fingerprint to certifications and subkey bindings.
#### CLI
* Added support for keyid/fpr usage with (some) spaces and 0x prefix in
operations (--sign, etc).
#### FFI
* Fixed key search by fingerprint.
### 0.9.0 [2018-06-27]
* First official release.

8
third_party/rnp/docs/installation.adoc поставляемый
Просмотреть файл

@ -28,14 +28,14 @@ yum install -y rnp
----
# Clone the repository by version tag (or omit it to get the latest sources)
sudo apt install git
git clone https://github.com/rnpgp/rnp.git -b v0.13.1
git clone https://github.com/rnpgp/rnp.git -b v0.14.0
# Install required packages
sudo apt install g++-8 cmake libbz2-dev zlib1g-dev libjson-c-dev build-essential python-minimal
# Download, build and install Botan2
wget -qO- https://botan.randombit.net/releases/Botan-2.12.1.tar.xz | tar xvJ
cd Botan-2.12.1
wget -qO- https://botan.randombit.net/releases/Botan-2.14.0.tar.xz | tar xvJ
cd Botan-2.14.0
./configure.py --prefix=/usr
make
sudo make install
@ -57,7 +57,7 @@ sudo make install
----
# Clone the repository by version tag (or omit it to get the latest sources)
sudo apt install git
git clone https://github.com/rnpgp/rnp.git -b v0.13.1
git clone https://github.com/rnpgp/rnp.git -b v0.14.0
# Enable access to `testing` packages by editing /etc/apt/sources.list
# deb http://deb.debian.org/debian testing main

2
third_party/rnp/include/repgp/repgp_def.h поставляемый
Просмотреть файл

@ -452,7 +452,7 @@ typedef enum pgp_op_t {
PGP_OP_ADD_SUBKEY = 1, /* adding a subkey, primary key password required */
PGP_OP_SIGN = 2, /* signing file or data */
PGP_OP_DECRYPT = 3, /* decrypting file or data */
PGP_OP_UNLOCK = 4, /* unlocking a key with pgp_key_unlock */
PGP_OP_UNLOCK = 4, /* unlocking a key with key->unlock() */
PGP_OP_PROTECT = 5, /* adding protection to a key */
PGP_OP_UNPROTECT = 6, /* removing protection from a (locked) key */
PGP_OP_DECRYPT_SYM = 7, /* symmetric decryption */

1
third_party/rnp/include/rnp.h поставляемый
Просмотреть файл

@ -38,7 +38,6 @@
#include "list.h"
#include "crypto/rng.h"
#include <rnp/rnp_def.h>
#include <rekey/rnp_key_store.h>
#include "utils.h"
#endif // RNP_RNP_H

146
third_party/rnp/include/rnp/rnp.h поставляемый
Просмотреть файл

@ -85,6 +85,12 @@ typedef uint32_t rnp_result_t;
#define RNP_OUTPUT_FILE_OVERWRITE (1U << 0)
#define RNP_OUTPUT_FILE_RANDOM (1U << 1)
/**
* User id type
*/
#define RNP_USER_ID (1U)
#define RNP_USER_ATTR (2U)
/**
* Return a constant string describing the result code
*/
@ -479,7 +485,8 @@ RNP_API rnp_result_t rnp_save_keys(rnp_ffi_t ffi,
RNP_API rnp_result_t rnp_get_public_key_count(rnp_ffi_t ffi, size_t *count);
RNP_API rnp_result_t rnp_get_secret_key_count(rnp_ffi_t ffi, size_t *count);
/** search for the key
/** Search for the key
* Note: only valid userids are checked while searching by userid.
*
* @param ffi
* @param identifier_type string with type of the identifier: userid, keyid, fingerprint, grip
@ -963,7 +970,10 @@ RNP_API rnp_result_t rnp_enarmor(rnp_input_t input, rnp_output_t output, const c
RNP_API rnp_result_t rnp_dearmor(rnp_input_t input, rnp_output_t output);
/** Get key's primary user id.
*
* Note: userid considered as primary if it has marked as primary in self-certification, and
* is valid (i.e. both certification and key are valid, not expired and not revoked). If
* there is no userid marked as primary then the first valid userid handle will be
* returned.
* @param key key handle.
* @param uid pointer to the string with primary user id will be stored here.
* You must free it using the rnp_buffer_destroy().
@ -1002,6 +1012,44 @@ RNP_API rnp_result_t rnp_key_get_uid_handle_at(rnp_key_handle_t key,
size_t idx,
rnp_uid_handle_t *uid);
/** Get userid's type. Currently two possible values are defined:
* - RNP_USER_ID - string representation of user's name and email.
* - RNP_USER_ATTR - binary photo of the user
* @param uid uid handle, cannot be NULL.
* @param type on success userid type will be stored here.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_uid_get_type(rnp_uid_handle_t uid, uint32_t *type);
/** Get userid's data. Representation of data depends on userid type (see rnp_uid_get_type()
* function)
*
* @param uid uid handle, cannot be NULL.
* @param data cannot be NULL. On success pointer to the allocated buffer with data will be
* stored here. Must be deallocated by caller via rnp_buffer_destroy().
* @param size cannot be NULL. On success size of the data will be stored here.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_uid_get_data(rnp_uid_handle_t uid, void **data, size_t *size);
/** Check whether uid is marked as primary.
*
* @param uid uid handle, cannot be NULL
* @param primary cannot be NULL. On success true or false will be stored here.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_uid_is_primary(rnp_uid_handle_t uid, bool *primary);
/** Get userid validity status. Userid is considered as valid if it has at least one
* valid, non-expired self-certification.
*
* @param uid user id handle.
* @param valid validity status will be stored here on success.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_uid_is_valid(rnp_uid_handle_t uid, bool *valid);
/** Get number of key's signatures.
* Note: this will not count user id certifications and subkey(s) signatures if any.
* I.e. it will return only number of direct-key and key revocation signatures for the
@ -1027,6 +1075,17 @@ RNP_API rnp_result_t rnp_key_get_signature_at(rnp_key_handle_t key,
size_t idx,
rnp_signature_handle_t *sig);
/**
* @brief Get key's revocation signature handle, if any.
*
* @param key key handle
* @param sig signature handle or NULL will be stored here on success. NULL will be stored in
* case when there is no valid revocation signature.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_key_get_revocation_signature(rnp_key_handle_t key,
rnp_signature_handle_t *sig);
/** Get the number of user id's signatures.
*
* @param uid user id handle.
@ -1047,6 +1106,34 @@ RNP_API rnp_result_t rnp_uid_get_signature_at(rnp_uid_handle_t uid,
size_t idx,
rnp_signature_handle_t *sig);
/**
* @brief Get signature's type.
*
* @param sig signature handle.
* @param type on success string with signature type will be saved here. Cannot be NULL.
* You must free it using the rnp_buffer_destroy().
* Currently defined values are:
* - 'binary' : signature of a binary document
* - 'text' : signature of a canonical text document
* - 'standalone' : standalone signature
* - 'certification (generic)` : generic certification of a user id
* - 'certification (persona)' : persona certification of a user id
* - 'certification (casual)' : casual certification of a user id
* - 'certification (positive)' : positive certification of a user id
* - 'subkey binding' : subkey binding signature
* - 'primary key binding' : primary key binding signature
* - 'direct' : direct-key signature
* - 'key revocation' : primary key revocation signature
* - 'subkey revocation' : subkey revocation signature
* - 'certification revocation' : certification revocation signature
* - 'timestamp' : timestamp signature
* - 'third-party' : third party confirmation signature
* - 'uknown: 0..255' : unknown signature with it's type specified as number
*
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_get_type(rnp_signature_handle_t sig, char **type);
/** Get signature's algorithm.
*
* @param sig signature handle.
@ -1089,11 +1176,31 @@ RNP_API rnp_result_t rnp_signature_get_keyid(rnp_signature_handle_t sig, char **
* @param sig signature handle
* @param key on success and key availability will contain signing key's handle. You must
* destroy it using the rnp_key_handle_destroy() function.
* @return RNP_SUCCESS or error code if f4ailed.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_signature_get_signer(rnp_signature_handle_t sig,
rnp_key_handle_t * key);
/**
* @brief Get signature validity, revalidating it if didn't before.
*
* @param sig key/userid signature handle
* @param flags validation flags, currently must be zero.
* @return Following error codes represents the validation status:
* RNP_SUCCESS : operation succeeds and signature is valid
* RNP_ERROR_KEY_NOT_FOUND : signer's key not found
* RNP_ERROR_VERIFICATION_FAILED: verification failed, so validity cannot be checked
* RNP_ERROR_SIGNATURE_EXPIRED: signature is valid but expired
* RNP_ERROR_SIGNATURE_INVALID: signature is invalid (corrupted, malformed, was issued
* by invalid key, whatever else.)
*
* Please also note that other error codes may be returned because of wrong
* function call (included, but not limited to):
* RNP_ERROR_NULL_POINTER: sig as well as some of it's fields are NULL
* RNP_ERROR_BAD_PARAMETERS: invalid parameter value (unsupported flag, etc).
*/
RNP_API rnp_result_t rnp_signature_is_valid(rnp_signature_handle_t sig, uint32_t flags);
/** Dump signature packet to JSON, obtaining the whole information about it.
*
* @param sig sigmature handle, cannot be NULL
@ -1122,6 +1229,16 @@ RNP_API rnp_result_t rnp_signature_handle_destroy(rnp_signature_handle_t sig);
*/
RNP_API rnp_result_t rnp_uid_is_revoked(rnp_uid_handle_t uid, bool *result);
/** Retrieve uid revocation signature, if any.
*
* @param uid user id handle, should not be NULL.
* @param sig on success signature handle or NULL will be stored here. NULL will be stored in
* case when uid is not revoked.
* @return RNP_SUCCESS or error code if failed.
*/
RNP_API rnp_result_t rnp_uid_get_revocation_signature(rnp_uid_handle_t uid,
rnp_signature_handle_t *sig);
/** Destroy previously allocated user id handle.
*
* @param uid user id handle.
@ -1302,6 +1419,29 @@ RNP_API rnp_result_t rnp_key_get_expiration(rnp_key_handle_t key, uint32_t *resu
*/
RNP_API rnp_result_t rnp_key_set_expiration(rnp_key_handle_t key, uint32_t expiry);
/**
* @brief Check whether public key is valid. This includes checks of the self-signatures,
* expiration times, revocations and so on.
* Note: it doesn't take in account secret key, if it is available.
*
* @param key key's handle.
* @param result on success true or false will be stored here. Cannot be NULL.
* @return RNP_SUCCESS or error code on failure.
*/
RNP_API rnp_result_t rnp_key_is_valid(rnp_key_handle_t key, bool *result);
/**
* @brief Get the timestamp till which key can be considered as valid.
* Note: this will take into account not only key's expiration, but revocations as well.
* For the subkey primary key's validity time will be also checked.
* @param key key's handle.
* @param result on success timestamp will be stored here. If key doesn't expire then maximum
* value will be stored here. If key was never valid then zero value will be
* stored here.
* @return RNP_SUCCESS or error code on failure.
*/
RNP_API rnp_result_t rnp_key_valid_till(rnp_key_handle_t key, uint32_t *result);
/**
* @brief Check whether key is revoked.
*

1
third_party/rnp/include/rnp/rnp_err.h поставляемый
Просмотреть файл

@ -62,6 +62,7 @@ enum {
RNP_ERROR_NO_SIGNATURES_FOUND,
RNP_ERROR_SIGNATURE_EXPIRED,
RNP_ERROR_VERIFICATION_FAILED,
/* Parsing */
RNP_ERROR_NOT_ENOUGH_DATA = 0x13000000,

2
third_party/rnp/include/rnp/rnp_sdk.h поставляемый
Просмотреть файл

@ -52,6 +52,8 @@ char *rnp_compose_path_ex(char **buf, size_t *buf_len, const char *first, ...);
bool rnp_path_exists(const char *path);
bool rnp_dir_exists(const char *path);
bool rnp_file_exists(const char *path);
int rnp_unlink(const char *path);
bool rnp_hex_encode(
const uint8_t *buf, size_t buf_len, char *hex, size_t hex_len, rnp_hex_format_t format);

260
third_party/rnp/src/common/file-utils.cpp поставляемый
Просмотреть файл

@ -34,21 +34,177 @@
#include <stdio.h>
#include "uniwin.h"
#include <errno.h>
#include <locale>
#include <codecvt>
#include <random>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif // !_MSC_VER
#ifdef _WIN32
#include <random> // for rnp_mkstemp
#include "str-utils.h"
#define CATCH_AND_RETURN(v) \
catch (...) \
{ \
errno = ENOMEM; \
return v; \
}
#else
#include <string.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <rnp/rnp_sdk.h>
extern "C" {
int
rnp_unlink(const char *filename)
{
#ifdef _WIN32
try {
return _wunlink(wstr_from_utf8(filename).c_str());
}
CATCH_AND_RETURN(-1)
#else
#include <sys/stat.h>
#endif // _MSC_VER
return unlink(filename);
#endif
}
bool
rnp_file_exists(const char *path)
{
struct stat st;
return stat(path, &st) == 0 && S_ISREG(st.st_mode);
return rnp_stat(path, &st) == 0 && S_ISREG(st.st_mode);
}
bool
rnp_dir_exists(const char *path)
{
struct stat st;
return rnp_stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}
bool
rnp_path_exists(const char *path)
{
struct stat st;
return rnp_stat(path, &st) == 0;
}
}
int
rnp_open(const char *filename, int oflag, int pmode)
{
#ifdef _WIN32
try {
return _wopen(wstr_from_utf8(filename).c_str(), oflag, pmode);
}
CATCH_AND_RETURN(-1)
#else
return open(filename, oflag, pmode);
#endif
}
FILE *
rnp_fopen(const char *filename, const char *mode)
{
#ifdef _WIN32
try {
return _wfopen(wstr_from_utf8(filename).c_str(), wstr_from_utf8(mode).c_str());
}
CATCH_AND_RETURN(NULL)
#else
return fopen(filename, mode);
#endif
}
int
rnp_stat(const char *filename, struct stat *statbuf)
{
#ifdef _WIN32
static_assert(sizeof(struct stat) == sizeof(struct _stat64i32),
"stat is expected to match _stat64i32");
try {
return _wstat64i32(wstr_from_utf8(filename).c_str(), (struct _stat64i32 *) statbuf);
}
CATCH_AND_RETURN(-1)
#else
return stat(filename, statbuf);
#endif
}
#ifdef _WIN32
int
rnp_mkdir(const char *path)
{
try {
return _wmkdir(wstr_from_utf8(path).c_str());
}
CATCH_AND_RETURN(-1)
}
#endif
int
rnp_rename(const char *oldpath, const char *newpath)
{
#ifdef _WIN32
try {
return _wrename(wstr_from_utf8(oldpath).c_str(), wstr_from_utf8(newpath).c_str());
}
CATCH_AND_RETURN(-1)
#else
return rename(oldpath, newpath);
#endif
}
#ifdef _WIN32
_WDIR *
#else
DIR *
#endif
rnp_opendir(const char *path)
{
#ifdef _WIN32
try {
return _wopendir(wstr_from_utf8(path).c_str());
}
CATCH_AND_RETURN(NULL)
#else
return opendir(path);
#endif
}
std::string
#ifdef _WIN32
rnp_readdir_name(_WDIR *dir)
{
_wdirent *ent;
for (;;) {
if ((ent = _wreaddir(dir)) == NULL) {
return std::string();
}
if (wcscmp(ent->d_name, L".") && wcscmp(ent->d_name, L"..")) {
break;
}
}
try {
return wstr_to_utf8(ent->d_name);
}
CATCH_AND_RETURN(std::string())
#else
rnp_readdir_name(DIR *dir)
{
dirent *ent;
for (;;) {
if ((ent = readdir(dir)) == NULL) {
return std::string();
}
if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) {
break;
}
}
return std::string(ent->d_name);
#endif
}
/* return the file modification time */
@ -57,14 +213,14 @@ rnp_filemtime(const char *path)
{
struct stat st;
if (stat(path, &st) != 0) {
if (rnp_stat(path, &st) != 0) {
return 0;
} else {
return st.st_mtime;
}
}
#ifdef _MSC_VER
#ifdef _WIN32
static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/** @private
@ -76,49 +232,51 @@ static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
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;
try {
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 tmpl_w = wstr_from_utf8(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 + wstr_from_utf8(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;
}
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;
CATCH_AND_RETURN(-1)
}
#endif // _MSC_VER
#endif // _WIN32

18
third_party/rnp/src/common/file-utils.h поставляемый
Просмотреть файл

@ -28,9 +28,25 @@
#define RNP_FILE_UTILS_H_
#include <stdint.h>
#include <stdio.h>
#include <dirent.h>
#include <string>
bool rnp_file_exists(const char *path);
int64_t rnp_filemtime(const char *path);
int rnp_open(const char *filename, int oflag, int pmode);
FILE * rnp_fopen(const char *filename, const char *mode);
int rnp_stat(const char *filename, struct stat *statbuf);
int rnp_rename(const char *oldpath, const char *newpath);
#ifdef _WIN32
#define rnp_closedir _wclosedir
int rnp_mkdir(const char *path);
_WDIR * rnp_opendir(const char *path);
std::string rnp_readdir_name(_WDIR *dir);
#else
#define rnp_closedir closedir
DIR * rnp_opendir(const char *path);
std::string rnp_readdir_name(DIR *dir);
#endif
/** @private
* generate a temporary file name based on TMPL. TMPL must match the

39
third_party/rnp/src/common/str-utils.cpp поставляемый
Просмотреть файл

@ -30,6 +30,10 @@
#include "str-utils.h"
#include <cstddef>
#include <cstring>
#ifdef _WIN32
#include <locale>
#include <codecvt>
#endif
using std::size_t;
using std::strlen;
@ -45,3 +49,38 @@ rnp_strip_eol(char *s)
return s;
}
#ifdef _WIN32
std::wstring
wstr_from_utf8(const char *s)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8conv;
return utf8conv.from_bytes(s);
}
std::wstring
wstr_from_utf8(const char *first, const char *last)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8conv;
return utf8conv.from_bytes(first, last);
}
std::wstring
wstr_from_utf8(const std::string &s)
{
return wstr_from_utf8(s.c_str());
}
std::string
wstr_to_utf8(const wchar_t *ws)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8conv;
return utf8conv.to_bytes(ws);
}
std::string
wstr_to_utf8(const std::wstring &ws)
{
return wstr_to_utf8(ws.c_str());
}
#endif

9
third_party/rnp/src/common/str-utils.h поставляемый
Просмотреть файл

@ -28,5 +28,12 @@
#define RNP_STR_UTILS_H_
char *rnp_strip_eol(char *s);
#ifdef _WIN32
#include <string>
std::wstring wstr_from_utf8(const char *s);
std::wstring wstr_from_utf8(const char *first, const char *last);
std::wstring wstr_from_utf8(const std::string &s);
std::string wstr_to_utf8(const wchar_t *ws);
std::string wstr_to_utf8(const std::wstring &ws);
#endif // _WIN32
#endif

6
third_party/rnp/src/fuzzing/dump.c поставляемый
Просмотреть файл

@ -26,8 +26,14 @@
#include <rnp/rnp.h>
#ifdef RNP_RUN_TESTS
int dump_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
int
dump_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;

Просмотреть файл

@ -27,8 +27,14 @@
#include <rnp/rnp.h>
#include "string.h"
#ifdef RNP_RUN_TESTS
int verify_detached_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
int
verify_detached_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
#else
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
#endif
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;

2
third_party/rnp/src/lib/CMakeLists.txt поставляемый
Просмотреть файл

@ -31,7 +31,7 @@ find_package(ZLIB REQUIRED)
# required packages
find_package(JSON-C 0.11 REQUIRED)
find_package(Botan2 2.8.0 REQUIRED)
find_package(Botan2 2.14.0 REQUIRED)
# generate a config.h
include(CheckIncludeFileCXX)

2
third_party/rnp/src/lib/config.h.in поставляемый
Просмотреть файл

@ -24,7 +24,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#define PACKAGE_STRING "rnp 0.13.1+git20201030.a2c5ecd3.MZLA"
#define PACKAGE_STRING "rnp 0.14+git20210121.7c8492b4.MZLA"
#define PACKAGE_BUGREPORT "https://bugzilla.mozilla.org/enter_bug.cgi?product=Thunderbird"
#undef HAVE_BZLIB_H

27
third_party/rnp/src/lib/crypto.cpp поставляемый
Просмотреть файл

@ -227,30 +227,3 @@ validate_pgp_key_material(const pgp_key_material_t *material, rng_t *rng)
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:
case PGP_PKA_RSA_SIGN_ONLY:
return 8 * mpi_bytes(&key->rsa.n);
case PGP_PKA_DSA:
return 8 * mpi_bytes(&key->dsa.p);
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
return 8 * mpi_bytes(&key->eg.y);
case PGP_PKA_ECDH:
case PGP_PKA_ECDSA:
case PGP_PKA_EDDSA:
case PGP_PKA_SM2: {
// bn_num_bytes returns value <= curve order
const ec_curve_desc_t *curve = get_curve_desc(key->ec.curve);
return curve ? curve->bitlen : 0;
}
default:
RNP_LOG("Unknown public key alg in key_bitlength");
return 0;
}
}

2
third_party/rnp/src/lib/crypto.h поставляемый
Просмотреть файл

@ -138,6 +138,4 @@ bool key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t
rnp_result_t validate_pgp_key_material(const pgp_key_material_t *material, rng_t *rng);
size_t key_bitlength(const pgp_key_material_t *key);
#endif /* CRYPTO_H_ */

6
third_party/rnp/src/lib/crypto/dsa.cpp поставляемый
Просмотреть файл

@ -380,9 +380,3 @@ dsa_choose_qsize_by_psize(size_t psize)
return (psize == 1024) ? 160 :
(psize <= 2047) ? 224 : (psize <= 3072) ? DSA_MAX_Q_BITLEN : 0;
}
size_t
dsa_qbits(const pgp_dsa_key_t *key)
{
return 8 * mpi_bytes(&key->q);
}

2
third_party/rnp/src/lib/crypto/dsa.h поставляемый
Просмотреть файл

@ -142,6 +142,4 @@ pgp_hash_alg_t dsa_get_min_hash(size_t qsize);
*/
size_t dsa_choose_qsize_by_psize(size_t psize);
size_t dsa_qbits(const pgp_dsa_key_t *key);
#endif

20
third_party/rnp/src/lib/crypto/signatures.cpp поставляемый
Просмотреть файл

@ -27,6 +27,7 @@
#include <string.h>
#include "crypto/signatures.h"
#include "librepgp/stream-packet.h"
#include "librepgp/stream-sig.h"
#include "utils.h"
/**
@ -180,10 +181,16 @@ signature_calculate(pgp_signature_t * sig,
RNP_LOG("Unsupported algorithm %d", sig->palg);
break;
}
if (!ret) {
write_signature_material(*sig, material);
if (ret) {
return ret;
}
try {
sig->write_material(material);
return RNP_SUCCESS;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_GENERIC;
}
return ret;
}
static bool is_hash_alg_allowed_in_sig(const pgp_hash_alg_t hash_alg)
@ -282,7 +289,12 @@ signature_validate(const pgp_signature_t *sig, const pgp_key_material_t *key, pg
/* validate signature */
pgp_signature_material_t material = {};
parse_signature_material(*sig, material);
try {
sig->parse_material(material);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
switch (sig->palg) {
case PGP_PKA_DSA:
ret = dsa_verify(&material.dsa, hval, hlen, &key->dsa);

24
third_party/rnp/src/lib/fingerprint.cpp поставляемый
Просмотреть файл

@ -38,12 +38,12 @@
#include "utils.h"
rnp_result_t
pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t *key)
pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key)
{
pgp_hash_t hash = {0};
if ((key->version == PGP_V2) || (key->version == PGP_V3)) {
if (!is_rsa_key_alg(key->alg)) {
if ((key.version == PGP_V2) || (key.version == PGP_V3)) {
if (!is_rsa_key_alg(key.alg)) {
RNP_LOG("bad algorithm");
return RNP_ERROR_NOT_SUPPORTED;
}
@ -51,19 +51,19 @@ pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t *key)
RNP_LOG("bad md5 alloc");
return RNP_ERROR_NOT_SUPPORTED;
}
(void) mpi_hash(&key->material.rsa.n, &hash);
(void) mpi_hash(&key->material.rsa.e, &hash);
(void) mpi_hash(&key.material.rsa.n, &hash);
(void) mpi_hash(&key.material.rsa.e, &hash);
fp.length = pgp_hash_finish(&hash, fp.fingerprint);
RNP_DHEX("v2/v3 fingerprint", fp.fingerprint, fp.length);
return RNP_SUCCESS;
}
if (key->version == PGP_V4) {
if (key.version == PGP_V4) {
if (!pgp_hash_create(&hash, PGP_HASH_SHA1)) {
RNP_LOG("bad sha1 alloc");
return RNP_ERROR_NOT_SUPPORTED;
}
if (!signature_hash_key(key, &hash)) {
if (!signature_hash_key(&key, &hash)) {
return RNP_ERROR_GENERIC;
}
fp.length = pgp_hash_finish(&hash, fp.fingerprint);
@ -83,19 +83,19 @@ pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t *key)
*/
rnp_result_t
pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t *key)
pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key)
{
pgp_fingerprint_t fp;
rnp_result_t ret;
size_t n;
if ((key->version == PGP_V2) || (key->version == PGP_V3)) {
if (!is_rsa_key_alg(key->alg)) {
if ((key.version == PGP_V2) || (key.version == PGP_V3)) {
if (!is_rsa_key_alg(key.alg)) {
RNP_LOG("bad algorithm");
return RNP_ERROR_NOT_SUPPORTED;
}
n = mpi_bytes(&key->material.rsa.n);
(void) memcpy(keyid.data(), key->material.rsa.n.mpi + n - keyid.size(), keyid.size());
n = mpi_bytes(&key.material.rsa.n);
(void) memcpy(keyid.data(), key.material.rsa.n.mpi + n - keyid.size(), keyid.size());
return RNP_SUCCESS;
}

4
third_party/rnp/src/lib/fingerprint.h поставляемый
Просмотреть файл

@ -32,8 +32,8 @@
#include <stdlib.h>
#include "types.h"
rnp_result_t pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t *key);
rnp_result_t pgp_fingerprint(pgp_fingerprint_t &fp, const pgp_key_pkt_t &key);
rnp_result_t pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t *key);
rnp_result_t pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key);
#endif

67
third_party/rnp/src/lib/generate-key.cpp поставляемый
Просмотреть файл

@ -83,11 +83,11 @@ load_generated_g10_key(pgp_key_t * dst,
pgp_key_provider_t prov = {};
// this should generally be zeroed
assert(pgp_key_get_type(dst) == 0);
assert(dst->type() == 0);
// if a primary is provided, make sure it's actually a primary key
assert(!primary_key || pgp_key_is_primary_key(primary_key));
assert(!primary_key || primary_key->is_primary());
// if a pubkey is provided, make sure it's actually a public key
assert(!pubkey || pgp_key_is_public(pubkey));
assert(!pubkey || pubkey->is_public());
// G10 always needs pubkey here
assert(pubkey);
@ -131,8 +131,7 @@ load_generated_g10_key(pgp_key_t * dst,
goto end;
}
// if a primary key is provided, it should match the sub with regards to type
assert(!primary_key ||
(pgp_key_is_secret(primary_key) == pgp_key_is_secret(&key_store->keys.front())));
assert(!primary_key || (primary_key->is_secret() == key_store->keys.front().is_secret()));
try {
*dst = pgp_key_t(key_store->keys.front());
ok = true;
@ -334,18 +333,6 @@ keygen_primary_merge_defaults(rnp_keygen_primary_desc_t &desc)
}
}
static void
pgp_key_mark_valid(pgp_key_t *key)
{
key->valid = true;
key->validated = true;
for (size_t i = 0; i < pgp_key_get_subsig_count(key); i++) {
pgp_subsig_t *sub = pgp_key_get_subsig(key, i);
sub->validated = true;
sub->valid = true;
}
}
bool
pgp_generate_primary_key(rnp_keygen_primary_desc_t *desc,
bool merge_defaults,
@ -357,7 +344,7 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t *desc,
if (!desc || !primary_pub || !primary_sec) {
return false;
}
if (pgp_key_get_type(primary_sec) || pgp_key_get_type(primary_pub)) {
if (primary_sec->type() || primary_pub->type()) {
RNP_LOG("invalid parameters (should be zeroed)");
return false;
}
@ -399,19 +386,19 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t *desc,
pgp_transferable_key_t tkeypub;
try {
tkeypub = pgp_transferable_key_t(tkeysec, true);
*primary_pub = tkeypub;
} catch (const std::exception &e) {
RNP_LOG("failed to copy public key part: %s", e.what());
return false;
}
if (!rnp_key_from_transferable_key(primary_pub, &tkeypub)) {
return false;
}
switch (secformat) {
case PGP_KEY_STORE_GPG:
case PGP_KEY_STORE_KBX:
if (!rnp_key_from_transferable_key(primary_sec, &tkeysec)) {
try {
*primary_sec = tkeysec;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
break;
@ -427,10 +414,10 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t *desc,
}
/* mark it as valid */
pgp_key_mark_valid(primary_pub);
pgp_key_mark_valid(primary_sec);
primary_pub->mark_valid();
primary_sec->mark_valid();
/* refresh key's data */
return pgp_key_refresh_data(primary_pub) && pgp_key_refresh_data(primary_sec);
return primary_pub->refresh_data() && primary_sec->refresh_data();
}
static bool
@ -479,12 +466,12 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t * desc,
RNP_LOG("NULL args");
goto end;
}
if (!pgp_key_is_primary_key(primary_sec) || !pgp_key_is_primary_key(primary_pub) ||
!pgp_key_is_secret(primary_sec) || !pgp_key_is_public(primary_pub)) {
if (!primary_sec->is_primary() || !primary_pub->is_primary() ||
!primary_sec->is_secret() || !primary_pub->is_public()) {
RNP_LOG("invalid parameters");
goto end;
}
if (pgp_key_get_type(subkey_sec) || pgp_key_get_type(subkey_pub)) {
if (subkey_sec->type() || subkey_pub->type()) {
RNP_LOG("invalid parameters (should be zeroed)");
goto end;
}
@ -502,14 +489,14 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t * desc,
ctx = {.op = PGP_OP_ADD_SUBKEY, .key = primary_sec};
// decrypt the primary seckey if needed (for signatures)
if (pgp_key_is_encrypted(primary_sec)) {
if (primary_sec->encrypted()) {
decrypted_primary_seckey = pgp_decrypt_seckey(primary_sec, password_provider, &ctx);
if (!decrypted_primary_seckey) {
goto end;
}
primary_seckey = decrypted_primary_seckey;
} else {
primary_seckey = pgp_key_get_pkt(primary_sec);
primary_seckey = &primary_sec->pkt();
}
// generate the raw key pair
@ -524,20 +511,19 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t * desc,
}
try {
tskeypub = pgp_transferable_subkey_t(tskeysec, true);
*subkey_pub = pgp_key_t(pgp_transferable_subkey_t(tskeysec, true), primary_pub);
} catch (const std::exception &e) {
RNP_LOG("failed to copy public subkey part: %s", e.what());
goto end;
}
if (!rnp_key_from_transferable_subkey(subkey_pub, &tskeypub, primary_pub)) {
goto end;
}
switch (secformat) {
case PGP_KEY_STORE_GPG:
case PGP_KEY_STORE_KBX:
if (!rnp_key_from_transferable_subkey(subkey_sec, &tskeysec, primary_sec)) {
try {
*subkey_sec = pgp_key_t(tskeysec, primary_sec);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
goto end;
}
break;
@ -553,10 +539,9 @@ pgp_generate_subkey(rnp_keygen_subkey_desc_t * desc,
break;
}
pgp_key_mark_valid(subkey_pub);
pgp_key_mark_valid(subkey_sec);
ok = pgp_subkey_refresh_data(subkey_pub, primary_pub) &&
pgp_subkey_refresh_data(subkey_sec, primary_sec);
subkey_pub->mark_valid();
subkey_sec->mark_valid();
ok = subkey_pub->refresh_data(primary_pub) && subkey_sec->refresh_data(primary_sec);
end:
if (decrypted_primary_seckey) {
delete decrypted_primary_seckey;

15
third_party/rnp/src/lib/key-provider.cpp поставляемый
Просмотреть файл

@ -41,13 +41,13 @@ rnp_key_matches_search(const pgp_key_t *key, const pgp_key_search_t *search)
}
switch (search->type) {
case PGP_KEY_SEARCH_KEYID:
return pgp_key_get_keyid(key) == search->by.keyid;
return key->keyid() == search->by.keyid;
case PGP_KEY_SEARCH_FINGERPRINT:
return pgp_key_get_fp(key) == search->by.fingerprint;
return key->fp() == search->by.fingerprint;
case PGP_KEY_SEARCH_GRIP:
return pgp_key_get_grip(key) == search->by.grip;
return key->grip() == search->by.grip;
case PGP_KEY_SEARCH_USERID:
if (pgp_key_has_userid(key, search->by.userid)) {
if (key->has_uid(search->by.userid)) {
return true;
}
break;
@ -69,7 +69,7 @@ pgp_request_key(const pgp_key_provider_t *provider, const pgp_key_request_ctx_t
return NULL;
}
// confirm that the key actually matches the search criteria
if (!rnp_key_matches_search(key, &ctx->search) && pgp_key_is_secret(key) == ctx->secret) {
if (!rnp_key_matches_search(key, &ctx->search) && key->is_secret() == ctx->secret) {
return NULL;
}
return key;
@ -81,8 +81,7 @@ rnp_key_provider_key_ptr_list(const pgp_key_request_ctx_t *ctx, void *userdata)
list key_list = (list) userdata;
for (list_item *item = list_front(key_list); item; item = list_next(item)) {
pgp_key_t *key = *(pgp_key_t **) item;
if (rnp_key_matches_search(key, &ctx->search) &&
pgp_key_is_secret(key) == ctx->secret) {
if (rnp_key_matches_search(key, &ctx->search) && (key->is_secret() == ctx->secret)) {
return key;
}
}
@ -111,7 +110,7 @@ rnp_key_provider_store(const pgp_key_request_ctx_t *ctx, void *userdata)
for (pgp_key_t *key = rnp_key_store_search(ks, &ctx->search, NULL); key;
key = rnp_key_store_search(ks, &ctx->search, key)) {
if (pgp_key_is_secret(key) == ctx->secret) {
if (key->is_secret() == ctx->secret) {
return key;
}
}

16
third_party/rnp/src/lib/misc.cpp поставляемый
Просмотреть файл

@ -86,7 +86,7 @@ __RCSID("$NetBSD: misc.c,v 1.41 2012/03/05 02:20:18 christos Exp $");
#include "utils.h"
#include "json_utils.h"
#ifdef WIN32
#ifdef _WIN32
#define vsnprintf _vsnprintf
#endif
@ -402,20 +402,6 @@ rnp_compose_path_ex(char **buf, size_t *buf_len, const char *first, ...)
return path;
}
bool
rnp_path_exists(const char *path)
{
struct stat st;
return stat(path, &st) == 0;
}
bool
rnp_dir_exists(const char *path)
{
struct stat st;
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}
bool
rnp_hex_encode(
const uint8_t *buf, size_t buf_len, char *hex, size_t hex_len, rnp_hex_format_t format)

3081
third_party/rnp/src/lib/pgp-key.cpp поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

613
third_party/rnp/src/lib/pgp-key.h поставляемый
Просмотреть файл

@ -55,97 +55,305 @@
#include <stdbool.h>
#include <stdio.h>
#include <vector>
#include <unordered_map>
#include "pass-provider.h"
#include "../librepgp/stream-key.h"
#include <rekey/rnp_key_store.h>
#include "../librepgp/stream-packet.h"
#include "crypto/symmetric.h"
#include "types.h"
/* describes a user's key */
struct pgp_key_t {
std::vector<pgp_userid_t> uids{}; /* array of user ids */
std::vector<pgp_subsig_t> subsigs{}; /* array of key signatures */
std::vector<pgp_revoke_t> revokes{}; /* array of revocations */
std::vector<pgp_fingerprint_t>
subkey_fps{}; /* array of subkey fingerprints (for primary keys) */
pgp_fingerprint_t primary_fp{}; /* fingerprint of primary key (for subkeys) */
bool primary_fp_set{};
time_t expiration{}; /* key expiration time, if available */
pgp_key_pkt_t pkt{}; /* pubkey/seckey data packet */
pgp_rawpacket_t rawpkt{}; /* key raw packet */
uint8_t key_flags{}; /* key flags */
pgp_key_id_t keyid{};
pgp_fingerprint_t fingerprint{};
pgp_key_grip_t grip{};
uint32_t uid0{}; /* primary uid index in uids array */
unsigned uid0_set : 1; /* flag for the above */
uint8_t revoked{}; /* key has been revoked */
pgp_revoke_t revocation{}; /* revocation reason */
pgp_key_store_format_t format{}; /* the format of the key in packets[0] */
bool valid{}; /* this key is valid and usable */
bool validated{}; /* this key was validated */
/** pgp_rawpacket_t */
typedef struct pgp_rawpacket_t {
pgp_pkt_type_t tag;
std::vector<uint8_t> raw;
pgp_key_t() = default;
pgp_key_t(const pgp_key_t &src, bool pubonly = false);
pgp_key_t &operator=(pgp_key_t &&);
/* make sure we use only empty constructor/move operator */
pgp_key_t(pgp_key_t &&src) = delete;
pgp_key_t &operator=(const pgp_key_t &) = delete;
};
pgp_rawpacket_t() = default;
pgp_rawpacket_t(const uint8_t *data, size_t len, pgp_pkt_type_t tag)
: tag(tag),
raw(data ? std::vector<uint8_t>(data, data + len) : std::vector<uint8_t>()){};
pgp_rawpacket_t(const pgp_signature_t &sig);
pgp_rawpacket_t(pgp_key_pkt_t &key);
pgp_rawpacket_t(const pgp_userid_pkt_t &uid);
void write(pgp_dest_t &dst) const;
} pgp_rawpacket_t;
/* validity information for the signature/key/userid */
typedef struct pgp_validity_t {
bool validated{}; /* item was validated */
bool valid{}; /* item is valid by signature/key checks and calculations.
Still may be revoked or expired. */
bool expired{}; /* item is expired */
void mark_valid();
void reset();
} pgp_validity_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_sig_id_t sigid{}; /* signature identifier */
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 */
pgp_validity_t validity{}; /* signature validity information */
pgp_subsig_t() = delete;
pgp_subsig_t(const pgp_signature_t &sig);
bool valid() const;
} pgp_subsig_t;
typedef std::unordered_map<pgp_sig_id_t, pgp_subsig_t> pgp_sig_map_t;
/* userid, built on top of userid packet structure */
typedef struct pgp_userid_t {
private:
std::vector<pgp_sig_id_t> sigs_{}; /* all signatures related to this userid */
public:
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 */
bool valid{}; /* User ID is valid, i.e. has valid, non-expired self-signature */
bool revoked{};
pgp_revoke_t revocation{};
pgp_userid_t(const pgp_userid_pkt_t &pkt);
size_t sig_count() const;
const pgp_sig_id_t &get_sig(size_t idx) const;
bool has_sig(const pgp_sig_id_t &id) const;
void add_sig(const pgp_sig_id_t &sig);
void replace_sig(const pgp_sig_id_t &id, const pgp_sig_id_t &newsig);
} pgp_userid_t;
#define PGP_UID_NONE ((uint32_t) -1)
typedef struct rnp_key_store_t rnp_key_store_t;
/**
* @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);
/* describes a user's key */
struct pgp_key_t {
private:
pgp_sig_map_t sigs_map_{}; /* map with subsigs stored by their id */
std::vector<pgp_sig_id_t> sigs_{}; /* subsig ids to lookup actual sig in map */
std::vector<pgp_sig_id_t> keysigs_{}; /* direct-key signature ids in the original order */
std::vector<pgp_userid_t> uids_{}; /* array of user ids */
pgp_key_pkt_t pkt_{}; /* pubkey/seckey data packet */
uint8_t flags_{}; /* key flags */
time_t expiration_{}; /* key expiration time, if available */
pgp_key_id_t keyid_{};
pgp_fingerprint_t fingerprint_{};
pgp_key_grip_t grip_{};
pgp_fingerprint_t primary_fp_{}; /* fingerprint of the primary key (for subkeys) */
bool primary_fp_set_{};
std::vector<pgp_fingerprint_t>
subkey_fps_{}; /* array of subkey fingerprints (for primary keys) */
pgp_rawpacket_t rawpkt_{}; /* key raw packet */
uint32_t uid0_{}; /* primary uid index in uids array */
bool uid0_set_{}; /* flag for the above */
bool revoked_{}; /* key has been revoked */
pgp_revoke_t revocation_{}; /* revocation reason */
pgp_validity_t validity_{}; /* key's validity */
const pgp_key_pkt_t *pgp_key_get_pkt(const pgp_key_t *);
pgp_subsig_t *latest_uid_selfcert(uint32_t uid);
void validate_primary(rnp_key_store_t &keyring);
void merge_validity(const pgp_validity_t &src);
uint32_t valid_till_common(bool expiry) const;
const pgp_key_material_t *pgp_key_get_material(const pgp_key_t *key);
public:
pgp_key_store_format_t format{}; /* the format of the key in packets[0] */
pgp_pubkey_alg_t pgp_key_get_alg(const pgp_key_t *key);
pgp_key_t() = default;
pgp_key_t(const pgp_key_pkt_t &pkt);
pgp_key_t(const pgp_key_t &src, bool pubonly = false);
pgp_key_t(const pgp_transferable_key_t &src);
pgp_key_t(const pgp_transferable_subkey_t &src, pgp_key_t *primary);
size_t pgp_key_get_dsa_qbits(const pgp_key_t *key);
size_t sig_count() const;
pgp_subsig_t & get_sig(size_t idx);
const pgp_subsig_t &get_sig(size_t idx) const;
bool has_sig(const pgp_sig_id_t &id) const;
pgp_subsig_t & replace_sig(const pgp_sig_id_t &id, const pgp_signature_t &newsig);
pgp_subsig_t & get_sig(const pgp_sig_id_t &id);
const pgp_subsig_t &get_sig(const pgp_sig_id_t &id) const;
pgp_subsig_t & add_sig(const pgp_signature_t &sig, size_t uid = PGP_UID_NONE);
size_t keysig_count() const;
pgp_subsig_t & get_keysig(size_t idx);
size_t uid_count() const;
pgp_userid_t & get_uid(size_t idx);
const pgp_userid_t &get_uid(size_t idx) const;
pgp_userid_t & add_uid(const pgp_transferable_userid_t &uid);
bool has_uid(const std::string &uid) const;
bool has_primary_uid() const;
uint32_t get_primary_uid() const;
bool revoked() const;
const pgp_revoke_t &revocation() const;
void clear_revokes();
size_t pgp_key_get_bits(const pgp_key_t *key);
const pgp_key_pkt_t &pkt() const;
pgp_key_pkt_t & pkt();
void set_pkt(const pgp_key_pkt_t &pkt);
pgp_curve_t pgp_key_get_curve(const pgp_key_t *key);
const pgp_key_material_t &material() const;
pgp_version_t pgp_key_get_version(const pgp_key_t *key);
pgp_pubkey_alg_t alg() const;
pgp_curve_t curve() const;
pgp_version_t version() const;
pgp_pkt_type_t type() const;
bool encrypted() const;
uint8_t flags() const;
bool can_sign() const;
bool can_certify() const;
bool can_encrypt() const;
/** @brief Get key's expiration time in seconds. If 0 then it doesn't expire. */
uint32_t expiration() const;
/** @brief Check whether key is expired. Must be validated before that. */
bool expired() const;
/** @brief Get key's creation time in seconds since Jan, 1 1970. */
uint32_t creation() const;
bool is_public() const;
bool is_secret() const;
bool is_primary() const;
bool is_subkey() const;
/** @brief check if a key is currently locked, i.e. secret fields are not decrypted.
* Note: Key locking does not apply to unprotected keys.
*/
bool is_locked() const;
/** @brief check if a key is currently protected, i.e. it's secret data is encrypted */
bool is_protected() const;
pgp_pkt_type_t pgp_key_get_type(const pgp_key_t *key);
bool valid() const;
bool validated() const;
/** @brief return time till which primary key is considered to be valid */
uint32_t valid_till() const;
/** @brief return time till which subkey is considered to be valid */
uint32_t valid_till(const pgp_key_t &primary) const;
bool pgp_key_is_encrypted(const pgp_key_t *);
/** @brief Get key's id */
const pgp_key_id_t &keyid() const;
/** @brief Get key's fingerprint */
const pgp_fingerprint_t &fp() const;
/** @brief Get key's grip */
const pgp_key_grip_t &grip() const;
/** @brief Get primary key's fingerprint for the subkey, if it is available.
* Note: will throw if it is not available, use has_primary_fp() to check.
*/
const pgp_fingerprint_t &primary_fp() const;
/** @brief Check whether key has primary key's fingerprint */
bool has_primary_fp() const;
/** @brief Clean primary_fp */
void unset_primary_fp();
/** @brief Link key with subkey via primary_fp and subkey_fps list */
void link_subkey_fp(pgp_key_t &subkey);
/**
* @brief Add subkey fp to key's list.
* Note: this function will check for duplicates.
*/
void add_subkey_fp(const pgp_fingerprint_t &fp);
/** @brief Get the number of pgp key's subkeys. */
size_t subkey_count() const;
/** @brief Remove subkey fingerprint from key's list. */
void remove_subkey_fp(const pgp_fingerprint_t &fp);
/**
* @brief Get the pgp key's subkey fingerprint
* @return fingerprint or throws std::out_of_range exception
*/
const pgp_fingerprint_t & get_subkey_fp(size_t idx) const;
const std::vector<pgp_fingerprint_t> &subkey_fps() const;
uint8_t pgp_key_get_flags(const pgp_key_t *key);
bool pgp_key_can_sign(const pgp_key_t *key);
bool pgp_key_can_certify(const pgp_key_t *key);
bool pgp_key_can_encrypt(const pgp_key_t *key);
size_t rawpkt_count() const;
pgp_rawpacket_t & rawpkt();
const pgp_rawpacket_t &rawpkt() const;
void set_rawpkt(const pgp_rawpacket_t &src);
/**
* @brief Get key's expiration time in seconds. If 0 then it doesn't expire.
*
* @param key populated key, could not be NULL
* @return key expiration time
*/
uint32_t pgp_key_get_expiration(const pgp_key_t *key);
/** @brief Unlock a key, i.e. decrypt it's secret data so it can be used for
*signing/decryption. Note: Key locking does not apply to unprotected keys.
*
* @param pass_provider the password provider that may be used
* to unlock the key, if necessary
* @return true if the key was unlocked, false otherwise
**/
bool unlock(const pgp_password_provider_t &provider);
/** @brief Lock a key, i.e. cleanup decrypted secret data.
* Note: Key locking does not apply to unprotected keys.
*
* @param key the key
* @return true if the key was locked, false otherwise
**/
bool lock();
/** @brief Add protection to an unlocked key, i.e. encrypt it's secret data with specified
* parameters. */
bool add_protection(pgp_key_store_format_t format,
const rnp_key_protection_params_t &protection,
const pgp_password_provider_t & password_provider);
/** @brief Add protection to a key */
bool protect(pgp_key_pkt_t & decrypted_seckey,
pgp_key_store_format_t format,
const rnp_key_protection_params_t &protection,
const std::string & new_password);
/** @brief Remove protection from a key, i.e. leave secret fields unencrypted */
bool unprotect(const pgp_password_provider_t &password_provider);
/**
* @brief Get key's creation time in seconds since Jan, 1 1980.
*
* @param key populated key, could not be NULL
* @return key creation time
*/
uint32_t pgp_key_get_creation(const pgp_key_t *key);
/** @brief Write key's packets to the output. */
void write(pgp_dest_t &dst) const;
/**
* @brief Write OpenPGP key packets (including subkeys) to the specified stream
*
* @param dst stream to write packets
* @param keyring keyring, which will be searched for subkeys. Pass NULL to skip subkeys.
* @return void, but error may be checked via dst.werr
*/
void write_xfer(pgp_dest_t &dst, const rnp_key_store_t *keyring = NULL) const;
/**
* @brief Export key with subkey as it is required by Autocrypt (5-packet sequence: key,
* uid, sig, subkey, sig).
*
* @param dst stream to write packets
* @param sub subkey
* @param uid index of uid to export
* @return true on success or false otherwise
*/
bool write_autocrypt(pgp_dest_t &dst, pgp_key_t &sub, uint32_t uid);
bool pgp_key_is_public(const pgp_key_t *);
bool pgp_key_is_secret(const pgp_key_t *);
bool pgp_key_is_primary_key(const pgp_key_t *key);
bool pgp_key_is_subkey(const pgp_key_t *key);
/**
* @brief Get the latest valid self-signature with information about the primary key,
* containing the specified subpacket. It could be userid certification or direct-key
* signature.
*
* @param subpkt subpacket type. Pass PGP_SIG_SUBPKT_UNKNOWN to return just latest
* signature.
* @return pointer to signature object or NULL if failed/not found.
*/
pgp_subsig_t *latest_selfsig(pgp_sig_subpacket_type_t subpkt = PGP_SIG_SUBPKT_UNKNOWN);
/**
* @brief Get the latest valid subkey binding. Should be called on subkey.
*
* @param validated set to true whether binding signature must be validated
* @return pointer to signature object or NULL if failed/not found.
*/
pgp_subsig_t *latest_binding(bool validated = true);
void validate_self_signatures();
void validate_self_signatures(pgp_key_t &primary);
void validate(rnp_key_store_t &keyring);
void validate_subkey(pgp_key_t *primary = NULL);
void revalidate(rnp_key_store_t &keyring);
void mark_valid();
/** @brief Refresh internal fields after primary key is updated */
bool refresh_data();
/** @brief Refresh internal fields after subkey is updated */
bool refresh_data(pgp_key_t *primary);
/** @brief Merge primary key with the src, i.e. add all new userids/signatures/subkeys */
bool merge(const pgp_key_t &src);
/** @brief Merge subkey with the source, i.e. add all new signatures */
bool merge(const pgp_key_t &src, pgp_key_t *primary);
};
pgp_key_pkt_t *pgp_decrypt_seckey_pgp(const uint8_t *,
size_t,
@ -157,155 +365,29 @@ pgp_key_pkt_t *pgp_decrypt_seckey(const pgp_key_t *,
const pgp_password_ctx_t *);
/**
* @brief Get key's keyid
* @brief Get the signer's key for signature
*
* @param key populated key, should not be NULL
* @return reference to keyid object
* @param sig signature
* @param keyring keyring to search for the key. May be NULL.
* @param prov key provider to request needed key, may be NULL.
* @return pointer to the key or NULL if key is not found.
*/
const pgp_key_id_t &pgp_key_get_keyid(const pgp_key_t *key);
pgp_key_t *pgp_sig_get_signer(const pgp_subsig_t &sig,
rnp_key_store_t * keyring,
pgp_key_provider_t *prov);
/**
* @brief Get key's fingerprint
* @brief Validate key's signature.
*
* @param key populated key, should not be NULL
* @return reference to the fingerprint structure
* @param key key (primary or subkey) which signature belongs to.
* @param signer signing key/subkey.
* @param primary primary key when it is applicable (for the subkey binding signature, or NULL.
* @param sig signature to validate.
*/
const pgp_fingerprint_t &pgp_key_get_fp(const pgp_key_t *key);
/**
* @brief Get key's grip
*
* @param key populated key, should not be NULL
* @return key's grip
*/
const pgp_key_grip_t &pgp_key_get_grip(const pgp_key_t *key);
/**
* @brief Get primary key's fingerprint for the subkey, if available.
*
* @param key subkey, which primary key's fingerprint should be returned
* @return reference to the fingerprint or NULL if it is not available
*/
const pgp_fingerprint_t &pgp_key_get_primary_fp(const pgp_key_t *key);
bool pgp_key_has_primary_fp(const pgp_key_t *key);
/**
* @brief Set primary key's fingerprint for the subkey
*
* @param key subkey
* @param fp buffer with fingerprint
* @return void
*/
void pgp_key_set_primary_fp(pgp_key_t *key, const pgp_fingerprint_t &fp);
/**
* @brief Link key with subkey via primary_fp and subkey_fps list
*
* @param key primary key
* @param subkey subkey of the primary key
* @return true on success or false otherwise (allocation failed, wrong key types)
*/
bool pgp_key_link_subkey_fp(pgp_key_t *key, pgp_key_t *subkey);
size_t pgp_key_get_userid_count(const pgp_key_t *);
const pgp_userid_t *pgp_key_get_userid(const pgp_key_t *, size_t);
pgp_userid_t *pgp_key_get_userid(pgp_key_t *, size_t);
const pgp_revoke_t *pgp_key_get_userid_revoke(const pgp_key_t *, size_t userid);
bool pgp_key_has_userid(const pgp_key_t *, const char *);
pgp_userid_t *pgp_key_add_userid(pgp_key_t *);
pgp_revoke_t *pgp_key_add_revoke(pgp_key_t *);
size_t pgp_key_get_revoke_count(const pgp_key_t *);
const pgp_revoke_t *pgp_key_get_revoke(const pgp_key_t *, size_t);
pgp_revoke_t *pgp_key_get_revoke(pgp_key_t *key, size_t idx);
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_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);
/**
* @brief Get the latest valid self-signature with information about the primary key,
* containing the specified subpacket. It could be userid certification or direct-key
* signature.
*
* @param key key which should be searched for signature.
* @param subpkt subpacket type. Pass 0 to return just latest signature.
* @return pointer to signature object or NULL if failed/not found.
*/
pgp_subsig_t *pgp_key_latest_selfsig(pgp_key_t *key, pgp_sig_subpacket_type_t subpkt);
/**
* @brief Get the latest valid subkey binding.
*
* @param subkey subkey which should be searched for signature.
* @param validated set to true whether binding signature must be validated
* @return pointer to signature object or NULL if failed/not found.
*/
pgp_subsig_t *pgp_key_latest_binding(pgp_key_t *subkey, bool validated);
bool pgp_key_refresh_data(pgp_key_t *key);
bool pgp_subkey_refresh_data(pgp_key_t *sub, pgp_key_t *key);
size_t pgp_key_get_rawpacket_count(const pgp_key_t *);
pgp_rawpacket_t & pgp_key_get_rawpacket(pgp_key_t *);
const pgp_rawpacket_t &pgp_key_get_rawpacket(const pgp_key_t *);
/**
* @brief Get the number of pgp key's subkeys.
*
* @param key pointer to the primary key
* @return number of the subkeys
*/
size_t pgp_key_get_subkey_count(const pgp_key_t *key);
/**
* @brief Add subkey fp to key's list.
* Note: this function will check for duplicates.
*
* @param key key pointer to the primary key
* @param fp subkey's fingerprint.
* @return true if succeeded (fingerprint already exists in list or added), or false otherwise.
*/
bool pgp_key_add_subkey_fp(pgp_key_t *key, const pgp_fingerprint_t &fp);
/**
* @brief Remove subkey fingerprint from key's list.
*
* @param key key pointer to the primary key
* @param fp subkey's fingerprint.
*/
void pgp_key_remove_subkey_fp(pgp_key_t *key, const pgp_fingerprint_t &fp);
/**
* @brief Get the pgp key's subkey fingerprint
*
* @param key key pointer to the primary key
* @param idx index of the subkey
* @return grip or throws std::out_of_range exception
*/
const pgp_fingerprint_t &pgp_key_get_subkey_fp(const pgp_key_t *key, size_t idx);
void pgp_key_validate_signature(pgp_key_t & key,
pgp_key_t & signer,
pgp_key_t * primary,
pgp_subsig_t &sig);
/**
* @brief Get the key's subkey by it's index
@ -319,79 +401,6 @@ pgp_key_t *pgp_key_get_subkey(const pgp_key_t *key, rnp_key_store_t *store, size
pgp_key_flags_t pgp_pk_alg_capabilities(pgp_pubkey_alg_t alg);
/** check if a key is currently locked
*
* Note: Key locking does not apply to unprotected keys.
*
* @param key the key
* @return true if the key is locked, false otherwise
**/
bool pgp_key_is_locked(const pgp_key_t *key);
/** unlock a key
*
* Note: Key locking does not apply to unprotected keys.
*
* @param key the key
* @param pass_provider the password provider that may be used
* to unlock the key, if necessary
* @return true if the key was unlocked, false otherwise
**/
bool pgp_key_unlock(pgp_key_t *key, const pgp_password_provider_t *provider);
/** lock a key
*
* Note: Key locking does not apply to unprotected keys.
*
* @param key the key
* @return true if the key was unlocked, false otherwise
**/
bool pgp_key_lock(pgp_key_t *key);
/** add protection to an unlocked key
*
* @param key the key, which must be unlocked
* @param format
* @param protection
* @param password_provider the password provider, which is used to retrieve
* the new password for the key.
* @return true if key was successfully protected, false otherwise
**/
bool rnp_key_add_protection(pgp_key_t * key,
pgp_key_store_format_t format,
rnp_key_protection_params_t * protection,
const pgp_password_provider_t *password_provider);
/** add protection to a key
*
* @param key
* @param decrypted_seckey
* @param format
* @param protection
* @param new_password
* @return true if key was successfully protected, false otherwise
**/
bool pgp_key_protect(pgp_key_t * key,
pgp_key_pkt_t * decrypted_seckey,
pgp_key_store_format_t format,
rnp_key_protection_params_t *protection,
const char * new_password);
/** remove protection from a key
*
* @param key
* @param password_provider
* @return true if protection was successfully removed, false otherwise
**/
bool pgp_key_unprotect(pgp_key_t *key, const pgp_password_provider_t *password_provider);
/** check if a key is currently protected
*
* @param key
* @return true if the key is protected, false otherwise
**/
bool pgp_key_is_protected(const pgp_key_t *key);
/** add a new certified userid to a key
*
* @param key
@ -408,37 +417,13 @@ bool pgp_key_add_userid_certified(pgp_key_t * key,
bool pgp_key_set_expiration(pgp_key_t * key,
pgp_key_t * signer,
uint32_t expiry,
const pgp_password_provider_t *prov);
const pgp_password_provider_t &prov);
bool pgp_subkey_set_expiration(pgp_key_t * sub,
pgp_key_t * primsec,
pgp_key_t * secsub,
uint32_t expiry,
const pgp_password_provider_t *prov);
bool pgp_key_write_packets(const pgp_key_t *key, pgp_dest_t *dst);
/**
* @brief Write OpenPGP key packets (including subkeys) to the specified stream
*
* @param dst stream to write packets
* @param key key
* @param keyring keyring, which will be searched for subkeys
* @return true on success or false otherwise
*/
bool pgp_key_write_xfer(pgp_dest_t *dst, const pgp_key_t *key, const rnp_key_store_t *keyring);
/**
* @brief Export key with subkey as it is required by Autocrypt (5-packet sequence: key, uid,
* sig, subkey, sig).
*
* @param dst stream to write packets
* @param key primary key
* @param sub subkey
* @param uid index of uid to export
* @return true on success or false otherwise
*/
bool pgp_key_write_autocrypt(pgp_dest_t &dst, pgp_key_t &key, pgp_key_t &sub, size_t uid);
const pgp_password_provider_t &prov);
/** find a key suitable for a particular operation
*
@ -474,10 +459,4 @@ pgp_key_t *find_suitable_key(pgp_op_t op,
*/
pgp_hash_alg_t pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey);
void pgp_key_validate_subkey(pgp_key_t *subkey, pgp_key_t *key);
void pgp_key_validate(pgp_key_t *key, rnp_key_store_t *keyring);
void pgp_key_revalidate_updated(pgp_key_t *key, rnp_key_store_t *keyring);
#endif // RNP_PACKET_KEY_H

762
third_party/rnp/src/lib/rnp.cpp поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

435
third_party/rnp/src/lib/types.h поставляемый
Просмотреть файл

@ -56,6 +56,7 @@
#include <vector>
#include <array>
#include <cstring>
#include <type_traits>
#include <rnp/rnp_def.h>
#include "list.h"
@ -95,6 +96,8 @@ typedef struct pgp_fingerprint_t {
bool operator!=(const pgp_fingerprint_t &src) const;
} pgp_fingerprint_t;
typedef std::array<uint8_t, PGP_KEY_GRIP_SIZE> pgp_sig_id_t;
namespace std {
template <> struct hash<pgp_fingerprint_t> {
std::size_t
@ -102,11 +105,27 @@ template <> struct hash<pgp_fingerprint_t> {
{
/* since fingerprint value is hash itself, we may use it's low bytes */
size_t res = 0;
static_assert(sizeof(fp.fingerprint) == PGP_FINGERPRINT_SIZE,
"pgp_fingerprint_t size mismatch");
static_assert(PGP_FINGERPRINT_SIZE >= sizeof(res), "pgp_fingerprint_t size mismatch");
std::memcpy(&res, fp.fingerprint, sizeof(res));
return res;
}
};
} // namespace std
template <> struct hash<pgp_sig_id_t> {
std::size_t
operator()(pgp_sig_id_t const &sigid) const noexcept
{
/* since signature id value is hash itself, we may use it's low bytes */
size_t res = 0;
static_assert(std::tuple_size<pgp_sig_id_t>::value >= sizeof(res),
"pgp_sig_id_t size mismatch");
std::memcpy(&res, sigid.data(), sizeof(res));
return res;
}
};
}; // namespace std
typedef std::array<uint8_t, PGP_KEY_GRIP_SIZE> pgp_key_grip_t;
@ -124,7 +143,7 @@ class rnp_exception : public std::exception {
return "rnp_exception";
};
rnp_result_t
code()
code() const
{
return code_;
};
@ -144,6 +163,9 @@ typedef struct pgp_key_material_t {
pgp_eg_key_t eg;
pgp_ec_key_t ec;
};
size_t bits() const;
size_t qbits() const;
} pgp_key_material_t;
/**
@ -193,56 +215,9 @@ typedef struct pgp_key_protection_t {
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 */
pgp_pubkey_alg_t alg;
uint16_t v3_days; /* v2/v3 validity time */
uint8_t *hashed_data; /* key's hashed data used for signature calculation */
size_t hashed_len;
pgp_key_material_t material;
/* secret key data, if available. sec_len == 0, sec_data == NULL for public key/subkey */
pgp_key_protection_t sec_protection;
uint8_t * sec_data;
size_t sec_len;
pgp_key_pkt_t()
: tag(PGP_PKT_RESERVED), version(PGP_VUNKNOWN), creation_time(0), alg(PGP_PKA_NOTHING),
v3_days(0), hashed_data(NULL), hashed_len(0), material({}), sec_protection({}),
sec_data(NULL), sec_len(0){};
pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly = false);
pgp_key_pkt_t(pgp_key_pkt_t &&src);
pgp_key_pkt_t &operator=(pgp_key_pkt_t &&src);
pgp_key_pkt_t &operator=(const pgp_key_pkt_t &src);
~pgp_key_pkt_t();
} pgp_key_pkt_t;
typedef struct pgp_key_t pgp_key_t;
/** Struct to hold userid or userattr packet. We don't parse userattr now, just storing the
* binary blob as it is. It may be distinguished by tag field.
*/
typedef struct pgp_userid_pkt_t {
pgp_pkt_type_t tag;
uint8_t * uid;
size_t uid_len;
pgp_userid_pkt_t() : tag(PGP_PKT_RESERVED), uid(NULL), uid_len(0){};
pgp_userid_pkt_t(const pgp_userid_pkt_t &src);
pgp_userid_pkt_t(pgp_userid_pkt_t &&src);
pgp_userid_pkt_t &operator=(pgp_userid_pkt_t &&src);
pgp_userid_pkt_t &operator=(const pgp_userid_pkt_t &src);
bool operator==(const pgp_userid_pkt_t &src) const;
bool operator!=(const pgp_userid_pkt_t &src) const;
~pgp_userid_pkt_t();
} pgp_userid_pkt_t;
typedef struct pgp_signature_t pgp_signature_t;
typedef struct pgp_key_pkt_t pgp_key_pkt_t;
typedef struct pgp_userid_pkt_t pgp_userid_pkt_t;
typedef struct pgp_signature_t pgp_signature_t;
/* Signature subpacket, see 5.2.3.1 in RFC 4880 and RFC 4880 bis 02 */
typedef struct pgp_sig_subpkt_t {
@ -330,319 +305,16 @@ typedef struct pgp_sig_subpkt_t {
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();
bool parse();
} 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_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()
: 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;
pgp_rawpacket_t(const uint8_t *data, size_t len, pgp_pkt_type_t tag)
: tag(tag),
raw(data ? std::vector<uint8_t>(data, data + len) : std::vector<uint8_t>()){};
pgp_rawpacket_t(const pgp_signature_t &sig);
pgp_rawpacket_t(pgp_key_pkt_t &key);
pgp_rawpacket_t(const pgp_userid_pkt_t &uid);
} pgp_rawpacket_t;
typedef enum {
/* first octet */
PGP_KEY_SERVER_NO_MODIFY = 0x80
} pgp_key_server_prefs_t;
/** pgp_one_pass_sig_t */
typedef struct pgp_one_pass_sig_t {
uint8_t version;
pgp_sig_type_t type;
pgp_hash_alg_t halg;
pgp_pubkey_alg_t palg;
pgp_key_id_t keyid;
unsigned nested;
} pgp_one_pass_sig_t;
typedef struct pgp_literal_hdr_t {
uint8_t format;
char fname[256];
@ -668,33 +340,17 @@ typedef enum {
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{};
pgp_encrypted_material_t material{};
} pgp_pk_sesskey_t;
/** pkp_sk_sesskey_t */
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_sk_sesskey_t;
/* user revocation info */
typedef struct pgp_subsig_t pgp_subsig_t;
typedef struct pgp_revoke_t {
uint32_t uid; /* index in uid array */
pgp_revocation_type_t code; /* revocation code */
uint32_t uid{}; /* index in uid array */
pgp_revocation_type_t code{}; /* revocation code */
std::string reason; /* revocation reason */
pgp_sig_id_t sigid; /* id of the corresponding subsig */
pgp_revoke_t() = default;
pgp_revoke_t(pgp_subsig_t &sig);
} pgp_revoke_t;
typedef struct pgp_user_prefs_t {
@ -719,25 +375,6 @@ typedef struct pgp_user_prefs_t {
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;
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;
struct rnp_keygen_ecc_params_t {
pgp_curve_t curve;
};

9
third_party/rnp/src/lib/utils.h поставляемый
Просмотреть файл

@ -51,12 +51,12 @@ void set_rnp_log_switch(int8_t);
#define RNP_LOG_KEY(msg, key) \
do { \
if (!key) { \
if (!(key)) { \
RNP_LOG(msg, "(null)"); \
break; \
} \
char keyid[PGP_KEY_ID_SIZE * 2 + 1] = {0}; \
const pgp_key_id_t &id = pgp_key_get_keyid(key); \
const pgp_key_id_t &id = key->keyid(); \
rnp_hex_encode(id.data(), id.size(), keyid, sizeof(keyid), RNP_HEX_LOWERCASE); \
RNP_LOG(msg, keyid); \
} while (0)
@ -135,7 +135,7 @@ void set_rnp_log_switch(int8_t);
/* Formating helpers */
#define PRItime "ll"
#ifdef WIN32
#ifdef _WIN32
#define PRIsize "I"
#else
#define PRIsize "z"
@ -151,8 +151,9 @@ void set_rnp_log_switch(int8_t);
#define RNP_CONST_TO_VOID_PTR(a) (reinterpret_cast<void *>(const_cast<char *>(a)))
#endif
int rnp_mkdir(const char *path);
#ifdef _WIN32
#define RNP_MKDIR(pathname, mode) mkdir(pathname)
#define RNP_MKDIR(pathname, mode) rnp_mkdir(pathname)
#else
#define RNP_MKDIR(pathname, mode) mkdir(pathname, mode)
#endif

10
third_party/rnp/src/lib/version.h поставляемый
Просмотреть файл

@ -24,13 +24,13 @@
*/
#define RNP_VERSION_MAJOR 0
#define RNP_VERSION_MINOR 13
#define RNP_VERSION_PATCH 1
#define RNP_VERSION_MINOR 14
#define RNP_VERSION_PATCH 0
#define RNP_VERSION_STRING "0.13.1"
#define RNP_VERSION_STRING_FULL "0.13.1+git20201030.a2c5ecd3.MZLA"
#define RNP_VERSION_STRING "0.14"
#define RNP_VERSION_STRING_FULL "0.14+git20210121.7c8492b4.MZLA"
#define RNP_VERSION_COMMIT_TIMESTAMP 1604058640
#define RNP_VERSION_COMMIT_TIMESTAMP 1611250701
// using a 32-bit version with 10 bits per component
#define RNP_VERSION_COMPONENT_MASK 0x3ff

Просмотреть файл

@ -1062,38 +1062,37 @@ g10_decrypt_seckey(const uint8_t * data,
}
static bool
copy_secret_fields(pgp_key_pkt_t *dst, const pgp_key_pkt_t *src)
copy_secret_fields(pgp_key_pkt_t &dst, const pgp_key_pkt_t &src)
{
switch (src->alg) {
switch (src.alg) {
case PGP_PKA_DSA:
dst->material.dsa.x = src->material.dsa.x;
dst.material.dsa.x = src.material.dsa.x;
break;
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
case PGP_PKA_RSA_SIGN_ONLY:
dst->material.rsa.d = src->material.rsa.d;
dst->material.rsa.p = src->material.rsa.p;
dst->material.rsa.q = src->material.rsa.q;
dst->material.rsa.u = src->material.rsa.u;
dst.material.rsa.d = src.material.rsa.d;
dst.material.rsa.p = src.material.rsa.p;
dst.material.rsa.q = src.material.rsa.q;
dst.material.rsa.u = src.material.rsa.u;
break;
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
dst->material.eg.x = src->material.eg.x;
dst.material.eg.x = src.material.eg.x;
break;
case PGP_PKA_ECDSA:
case PGP_PKA_ECDH:
case PGP_PKA_EDDSA:
dst->material.ec.x = src->material.ec.x;
dst.material.ec.x = src.material.ec.x;
break;
default:
RNP_LOG("Unsupported public key algorithm: %d", (int) src->alg);
RNP_LOG("Unsupported public key algorithm: %d", (int) src.alg);
return false;
}
dst->material.secret = src->material.secret;
dst->sec_protection = src->sec_protection;
dst->tag = is_subkey_pkt(dst->tag) ? PGP_PKT_SECRET_SUBKEY : PGP_PKT_SECRET_KEY;
dst.material.secret = src.material.secret;
dst.sec_protection = src.sec_protection;
dst.tag = is_subkey_pkt(dst.tag) ? PGP_PKT_SECRET_SUBKEY : PGP_PKT_SECRET_KEY;
return true;
}
@ -1143,16 +1142,16 @@ rnp_key_store_g10_from_src(rnp_key_store_t * key_store,
goto done;
}
if (!copy_secret_fields(&key.pkt, &seckey)) {
if (!copy_secret_fields(key.pkt(), seckey)) {
goto done;
}
} else {
key.pkt = std::move(seckey);
key.set_pkt(std::move(seckey));
}
try {
key.rawpkt = pgp_rawpacket_t(
(uint8_t *) mem_src_get_memory(&memsrc), memsrc.size, PGP_PKT_RESERVED);
key.set_rawpkt(pgp_rawpacket_t(
(uint8_t *) mem_src_get_memory(&memsrc), memsrc.size, PGP_PKT_RESERVED));
} catch (const std::exception &e) {
RNP_LOG("failed to add packet: %s", e.what());
goto done;
@ -1559,14 +1558,11 @@ error:
bool
rnp_key_store_g10_key_to_dst(pgp_key_t *key, pgp_dest_t *dest)
{
if (!pgp_key_get_rawpacket_count(key)) {
return false;
}
if (key->format != PGP_KEY_STORE_G10) {
RNP_LOG("incorrect format: %d", key->format);
return false;
}
pgp_rawpacket_t &packet = pgp_key_get_rawpacket(key);
pgp_rawpacket_t &packet = key->rawpkt();
dst_write(dest, packet.raw.data(), packet.raw.size());
return dest->werr == RNP_SUCCESS;
}

Просмотреть файл

@ -569,14 +569,14 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
goto finish;
}
if (!pu16(&memdst, 1 + key->subkey_fps.size())) { // number of keys in keyblock
if (!pu16(&memdst, 1 + key->subkey_count())) { // number of keys in keyblock
goto finish;
}
if (!pu16(&memdst, 28)) { // size of key info structure)
goto finish;
}
if (!pbuf(&memdst, pgp_key_get_fp(key).fingerprint, PGP_FINGERPRINT_SIZE) ||
if (!pbuf(&memdst, key->fp().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
@ -584,17 +584,17 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
}
// same as above, for each subkey
for (auto &sfp : key->subkey_fps) {
const pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp);
if (!pbuf(&memdst, pgp_key_get_fp(subkey).fingerprint, PGP_FINGERPRINT_SIZE) ||
for (auto &sfp : key->subkey_fps()) {
pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp);
if (!pbuf(&memdst, subkey->fp().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 = pgp_key_get_subsig(subkey, i)->sig.key_expiration();
for (i = 0; i < subkey->sig_count(); i++) {
expiration = subkey->get_sig(i).sig.key_expiration();
if (list_append(&subkey_sig_expirations, &expiration, sizeof(expiration)) ==
NULL) {
goto finish;
@ -608,13 +608,13 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
// skip serial number
if (!pu16(&memdst, pgp_key_get_userid_count(key)) || !pu16(&memdst, 12)) {
if (!pu16(&memdst, key->uid_count()) || !pu16(&memdst, 12)) {
goto finish;
}
uid_start = memdst.writeb;
for (i = 0; i < pgp_key_get_userid_count(key); i++) {
for (i = 0; i < key->uid_count(); i++) {
if (!pu32(&memdst, 0) ||
!pu32(&memdst, 0)) { // UID offset and length, update when blob has done
goto finish;
@ -629,13 +629,13 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
}
}
if (!pu16(&memdst, pgp_key_get_subsig_count(key) + list_length(subkey_sig_expirations)) ||
if (!pu16(&memdst, key->sig_count() + list_length(subkey_sig_expirations)) ||
!pu16(&memdst, 4)) {
goto finish;
}
for (i = 0; i < pgp_key_get_subsig_count(key); i++) {
if (!pu32(&memdst, pgp_key_get_subsig(key, i)->sig.key_expiration())) {
for (i = 0; i < key->sig_count(); i++) {
if (!pu32(&memdst, key->get_sig(i).sig.key_expiration())) {
goto finish;
}
}
@ -666,18 +666,18 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
}
// wrtite UID, we might redesign PGP write and use this information from keyblob
for (i = 0; i < pgp_key_get_userid_count(key); i++) {
const char *uid = (const char *) pgp_key_get_userid(key, i);
for (i = 0; i < key->uid_count(); i++) {
const pgp_userid_t &uid = key->get_uid(i);
p = (uint8_t *) mem_dest_get_memory(&memdst) + uid_start + (12 * i);
/* store absolute uid offset in the output stream */
pt = memdst.writeb + dst->writeb;
STORE32BE(p, pt);
/* and uid length */
pt = strlen(uid);
pt = uid.str.size();
p = (uint8_t *) mem_dest_get_memory(&memdst) + uid_start + (12 * i) + 4;
STORE32BE(p, pt);
/* uid data itself */
if (!pbuf(&memdst, uid, pt)) {
if (!pbuf(&memdst, uid.str.c_str(), pt)) {
goto finish;
}
}
@ -688,13 +688,15 @@ rnp_key_store_kbx_write_pgp(rnp_key_store_t *key_store, pgp_key_t *key, pgp_dest
p = (uint8_t *) mem_dest_get_memory(&memdst) + 8;
STORE32BE(p, pt);
if (!pgp_key_write_packets(key, &memdst)) {
key->write(memdst);
if (memdst.werr) {
goto finish;
}
for (auto &sfp : key->subkey_fps) {
for (auto &sfp : key->subkey_fps()) {
const pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp);
if (!pgp_key_write_packets(subkey, &memdst)) {
subkey->write(memdst);
if (memdst.werr) {
goto finish;
}
}
@ -765,7 +767,7 @@ rnp_key_store_kbx_to_dst(rnp_key_store_t *key_store, pgp_dest_t *dst)
}
for (auto &key : key_store->keys) {
if (!pgp_key_is_primary_key(&key)) {
if (!key.is_primary()) {
continue;
}
if (!rnp_key_store_kbx_write_pgp(key_store, &key, dst)) {

167
third_party/rnp/src/librekey/key_store_pgp.cpp поставляемый
Просмотреть файл

@ -67,106 +67,44 @@ __RCSID("$NetBSD: keyring.c,v 1.50 2011/06/25 00:37:44 agc Exp $");
#include "key_store_pgp.h"
#include "pgp-key.h"
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)) {
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)
{
for (auto &sig : signatures) {
if (!rnp_key_add_signature(key, &sig)) {
return false;
}
}
return true;
}
bool
rnp_key_store_add_transferable_subkey(rnp_key_store_t * keyring,
pgp_transferable_subkey_t *tskey,
pgp_key_t * pkey)
{
pgp_key_t skey;
/* create subkey */
if (!rnp_key_from_transferable_subkey(&skey, tskey, pkey)) {
RNP_LOG_KEY_PKT("failed to create subkey %s", &tskey->subkey);
try {
/* create subkey */
pgp_key_t skey(*tskey, pkey);
/* add it to the storage */
return rnp_key_store_add_key(keyring, &skey);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
RNP_LOG_KEY_PKT("failed to create subkey %s", tskey->subkey);
RNP_LOG_KEY("primary key is %s", pkey);
return false;
}
/* add it to the storage */
return rnp_key_store_add_key(keyring, &skey);
}
bool
rnp_key_add_transferable_userid(pgp_key_t *key, pgp_transferable_userid_t *uid)
{
pgp_userid_t *userid = pgp_key_add_userid(key);
if (!userid) {
RNP_LOG("Failed to add userid");
return false;
}
try {
userid->rawpkt = pgp_rawpacket_t(uid->uid);
} catch (const std::exception &e) {
RNP_LOG("Raw packet allocation failed: %s", e.what());
return false;
}
try {
if (uid->uid.tag == PGP_PKT_USER_ID) {
userid->str = std::string(uid->uid.uid, uid->uid.uid + uid->uid.uid_len);
} else {
userid->str = "(photo)";
}
} catch (const std::exception &e) {
RNP_LOG(
"%s alloc failed: %s", uid->uid.tag == PGP_PKT_USER_ID ? "uid" : "uattr", e.what());
return false;
}
try {
userid->pkt = uid->uid;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
return rnp_key_add_signatures(key, uid->signatures);
}
bool
rnp_key_store_add_transferable_key(rnp_key_store_t *keyring, pgp_transferable_key_t *tkey)
{
pgp_key_t key;
pgp_key_t *addkey = NULL;
/* create key from transferable key */
if (!rnp_key_from_transferable_key(&key, tkey)) {
RNP_LOG_KEY_PKT("failed to create key %s", &tkey->key);
try {
pgp_key_t key(*tkey);
/* temporary disable key validation */
keyring->disable_validation = true;
/* add key to the storage before subkeys */
addkey = rnp_key_store_add_key(keyring, &key);
} catch (const std::exception &e) {
keyring->disable_validation = false;
RNP_LOG_KEY_PKT("failed to add key %s", tkey->key);
return false;
}
/* temporary disable key validation */
keyring->disable_validation = true;
/* add key to the storage before subkeys */
addkey = rnp_key_store_add_key(keyring, &key);
if (!addkey) {
keyring->disable_validation = false;
RNP_LOG("Failed to add key to key store.");
return false;
}
@ -175,13 +113,14 @@ rnp_key_store_add_transferable_key(rnp_key_store_t *keyring, pgp_transferable_ke
for (auto &subkey : tkey->subkeys) {
if (!rnp_key_store_add_transferable_subkey(keyring, &subkey, addkey)) {
RNP_LOG("Failed to add subkey to key store.");
keyring->disable_validation = false;
goto error;
}
}
/* now validate/refresh the whole key with subkeys */
keyring->disable_validation = false;
pgp_key_revalidate_updated(addkey, keyring);
addkey->revalidate(*keyring);
return true;
error:
/* during key addition all fields are copied so will be cleaned below */
@ -189,56 +128,6 @@ error:
return false;
}
bool
rnp_key_from_transferable_key(pgp_key_t *key, pgp_transferable_key_t *tkey)
{
*key = pgp_key_t();
/* create key */
if (!pgp_key_from_pkt(key, &tkey->key)) {
return false;
}
/* add direct-key signatures */
if (!rnp_key_add_signatures(key, tkey->signatures)) {
return false;
}
/* add userids and their signatures */
for (auto &uid : tkey->userids) {
if (!rnp_key_add_transferable_userid(key, &uid)) {
return false;
}
}
return true;
}
bool
rnp_key_from_transferable_subkey(pgp_key_t * subkey,
pgp_transferable_subkey_t *tskey,
pgp_key_t * primary)
{
*subkey = pgp_key_t();
/* create key */
if (!pgp_key_from_pkt(subkey, &tskey->subkey)) {
return false;
}
/* add subkey binding signatures */
if (!rnp_key_add_signatures(subkey, tskey->signatures)) {
RNP_LOG("failed to add subkey signatures");
return false;
}
/* setup key grips if primary is available */
if (primary && !pgp_key_link_subkey_fp(primary, subkey)) {
return false;
}
return true;
}
rnp_result_t
rnp_key_store_pgp_read_key_from_src(rnp_key_store_t &keyring,
pgp_source_t & src,
@ -308,8 +197,8 @@ rnp_key_to_src(const pgp_key_t *key, pgp_source_t *src)
return false;
}
res = pgp_key_write_packets(key, &dst) &&
!init_mem_src(src, mem_dest_own_memory(&dst), dst.writeb, true);
key->write(dst);
res = !dst.werr && !init_mem_src(src, mem_dest_own_memory(&dst), dst.writeb, true);
dst_close(&dst, true);
return res;
}
@ -318,11 +207,11 @@ static bool
do_write(rnp_key_store_t *key_store, pgp_dest_t *dst, bool secret)
{
for (auto &key : key_store->keys) {
if (pgp_key_is_secret(&key) != secret) {
if (key.is_secret() != secret) {
continue;
}
// skip subkeys, they are written below (orphans are ignored)
if (!pgp_key_is_primary_key(&key)) {
if (!key.is_primary()) {
continue;
}
@ -330,16 +219,18 @@ do_write(rnp_key_store_t *key_store, pgp_dest_t *dst, bool secret)
RNP_LOG("incorrect format (conversions not supported): %d", key.format);
return false;
}
if (!pgp_key_write_packets(&key, dst)) {
key.write(*dst);
if (dst->werr) {
return false;
}
for (auto &sfp : key.subkey_fps) {
for (auto &sfp : key.subkey_fps()) {
pgp_key_t *subkey = rnp_key_store_get_key_by_fpr(key_store, sfp);
if (!subkey) {
RNP_LOG("Missing subkey");
continue;
}
if (!pgp_key_write_packets(subkey, dst)) {
subkey->write(*dst);
if (dst->werr) {
return false;
}
}

10
third_party/rnp/src/librekey/key_store_pgp.h поставляемый
Просмотреть файл

@ -78,16 +78,6 @@ bool rnp_key_store_add_transferable_subkey(rnp_key_store_t * keyring,
bool rnp_key_store_add_transferable_key(rnp_key_store_t * keyring,
pgp_transferable_key_t *tkey);
bool rnp_key_from_transferable_key(pgp_key_t *key, pgp_transferable_key_t *tkey);
bool rnp_key_from_transferable_subkey(pgp_key_t * subkey,
pgp_transferable_subkey_t *tskey,
pgp_key_t * primary);
bool rnp_key_add_transferable_userid(pgp_key_t *key, pgp_transferable_userid_t *uid);
bool rnp_key_add_signature(pgp_key_t *key, const pgp_signature_t *sig);
bool rnp_key_to_src(const pgp_key_t *key, pgp_source_t *src);
#endif /* KEY_STORE_PGP_H_ */

389
third_party/rnp/src/librekey/rnp_key_store.cpp поставляемый
Просмотреть файл

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, [Ribose Inc](https://www.ribose.com).
* Copyright (c) 2017-2020 [Ribose Inc](https://www.ribose.com).
* All rights reserved.
*
* This code is originally derived from software contributed to
@ -58,46 +58,44 @@
#include "pgp-key.h"
#include "fingerprint.h"
#include "crypto/hash.h"
#include "file-utils.h"
#ifdef _WIN32
#include "str-utils.h"
#endif
bool
rnp_key_store_load_from_path(rnp_key_store_t * key_store,
const pgp_key_provider_t *key_provider)
{
DIR * dir;
bool rc;
pgp_source_t src = {};
struct dirent *ent;
char path[MAXPATHLEN];
bool rc;
pgp_source_t src = {};
std::string dirname;
if (key_store->format == PGP_KEY_STORE_G10) {
dir = opendir(key_store->path.c_str());
auto dir = rnp_opendir(key_store->path.c_str());
if (dir == NULL) {
RNP_LOG(
"Can't open G10 directory %s: %s", key_store->path.c_str(), strerror(errno));
return false;
}
while ((ent = readdir(dir)) != NULL) {
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
errno = 0;
while (!((dirname = rnp_readdir_name(dir)).empty())) {
std::string path = key_store->path + '/' + dirname;
RNP_DLOG("Loading G10 key from file '%s'", path.c_str());
if (init_file_src(&src, path.c_str())) {
RNP_LOG("failed to read file %s", path.c_str());
continue;
}
snprintf(path, sizeof(path), "%s/%s", key_store->path.c_str(), ent->d_name);
RNP_DLOG("Loading G10 key from file '%s'", path);
if (init_file_src(&src, path)) {
RNP_LOG("failed to read file %s", path);
continue;
}
// G10 may don't read one file, so, ignore it!
if (!rnp_key_store_g10_from_src(key_store, &src, key_provider)) {
RNP_LOG("Can't parse file: %s", path);
RNP_LOG("Can't parse file: %s", path.c_str()); // TODO: %S ?
}
src_close(&src);
}
closedir(dir);
return true;
rnp_closedir(dir);
return errno ? false : true;
}
/* init file source and load from it */
@ -142,7 +140,7 @@ rnp_key_store_write_to_path(rnp_key_store_t *key_store)
char grips[PGP_FINGERPRINT_HEX_SIZE];
struct stat path_stat;
if (stat(key_store->path.c_str(), &path_stat) != -1) {
if (rnp_stat(key_store->path.c_str(), &path_stat) != -1) {
if (!S_ISDIR(path_stat.st_mode)) {
RNP_LOG("G10 keystore should be a directory: %s", key_store->path.c_str());
return false;
@ -159,12 +157,11 @@ rnp_key_store_write_to_path(rnp_key_store_t *key_store)
}
for (auto &key : key_store->keys) {
const pgp_key_grip_t &grip = pgp_key_get_grip(&key);
snprintf(path,
sizeof(path),
"%s/%s.key",
key_store->path.c_str(),
rnp_strhexdump_upper(grips, grip.data(), grip.size(), ""));
rnp_strhexdump_upper(grips, key.grip().data(), key.grip().size(), ""));
if (init_tmpfile_dest(&keydst, path, true)) {
RNP_LOG("failed to create file");
@ -242,134 +239,10 @@ rnp_key_store_get_key_count(const rnp_key_store_t *keyring)
return keyring->keys.size();
}
static bool
rnp_key_store_merge_subkey(pgp_key_t *dst, const pgp_key_t *src, pgp_key_t *primary)
{
pgp_transferable_subkey_t dstkey;
pgp_transferable_subkey_t srckey;
pgp_key_t tmpkey;
if (!pgp_key_is_subkey(dst) || !pgp_key_is_subkey(src)) {
RNP_LOG("wrong subkey merge call");
return false;
}
if (transferable_subkey_from_key(dstkey, *dst)) {
RNP_LOG("failed to get transferable key from dstkey");
return false;
}
if (transferable_subkey_from_key(srckey, *src)) {
RNP_LOG("failed to get transferable key from srckey");
return false;
}
/* if src is secret key then merged key will become secret as well. */
if (is_secret_key_pkt(srckey.subkey.tag) && !is_secret_key_pkt(dstkey.subkey.tag)) {
pgp_key_pkt_t tmp = dstkey.subkey;
dstkey.subkey = srckey.subkey;
srckey.subkey = tmp;
}
if (transferable_subkey_merge(dstkey, srckey)) {
RNP_LOG("failed to merge transferable subkeys");
return false;
}
if (!rnp_key_from_transferable_subkey(&tmpkey, &dstkey, primary)) {
RNP_LOG("failed to process subkey");
return false;
}
/* check whether key was unlocked and assign secret key data */
if (pgp_key_is_secret(dst) && !pgp_key_is_locked(dst)) {
/* we may do thing below only because key material is opaque structure without
* pointers! */
tmpkey.pkt.material = dst->pkt.material;
} else if (pgp_key_is_secret(src) && !pgp_key_is_locked(src)) {
tmpkey.pkt.material = src->pkt.material;
}
/* copy validity status */
tmpkey.valid = dst->valid && src->valid;
/* we may safely leave validated status only if both merged subkeys are valid && validated.
* Otherwise we'll need to revalidate. For instance, one validated but invalid subkey may
* add revocation signature, or valid subkey may add binding to the invalid one. */
tmpkey.validated = dst->validated && src->validated && tmpkey.valid;
*dst = std::move(tmpkey);
return true;
}
static bool
rnp_key_store_merge_key(pgp_key_t *dst, const pgp_key_t *src)
{
pgp_transferable_key_t dstkey;
pgp_transferable_key_t srckey;
pgp_key_t tmpkey;
if (pgp_key_is_subkey(dst) || pgp_key_is_subkey(src)) {
RNP_LOG("wrong key merge call");
return false;
}
if (transferable_key_from_key(dstkey, *dst)) {
RNP_LOG("failed to get transferable key from dstkey");
return false;
}
if (transferable_key_from_key(srckey, *src)) {
RNP_LOG("failed to get transferable key from srckey");
return false;
}
/* if src is secret key then merged key will become secret as well. */
if (is_secret_key_pkt(srckey.key.tag) && !is_secret_key_pkt(dstkey.key.tag)) {
pgp_key_pkt_t tmp = dstkey.key;
dstkey.key = srckey.key;
srckey.key = tmp;
/* no subkey processing here - they are separated from the main key */
}
if (transferable_key_merge(dstkey, srckey)) {
RNP_LOG("failed to merge transferable keys");
return false;
}
if (!rnp_key_from_transferable_key(&tmpkey, &dstkey)) {
RNP_LOG("failed to process key");
return false;
}
/* move existing subkey grips since they are not present in transferable key */
tmpkey.subkey_fps = std::move(dst->subkey_fps);
for (auto &fp : src->subkey_fps) {
if (!pgp_key_add_subkey_fp(&tmpkey, fp)) {
RNP_LOG("failed to add subkey grip");
}
}
/* check whether key was unlocked and assign secret key data */
if (pgp_key_is_secret(dst) && !pgp_key_is_locked(dst)) {
/* we may do thing below only because key material is opaque structure without
* pointers! */
tmpkey.pkt.material = dst->pkt.material;
} else if (pgp_key_is_secret(src) && !pgp_key_is_locked(src)) {
tmpkey.pkt.material = src->pkt.material;
}
/* copy validity status */
tmpkey.valid = dst->valid && src->valid;
/* We may safely leave validated status only if both merged keys are valid && validated.
* Otherwise we'll need to revalidate. For instance, one validated but invalid key may add
* revocation signature, or valid key may add certification to the invalid one. */
tmpkey.validated = dst->validated && src->validated && tmpkey.valid;
*dst = std::move(tmpkey);
return true;
}
static bool
rnp_key_store_refresh_subkey_grips(rnp_key_store_t *keyring, pgp_key_t *key)
{
if (pgp_key_is_subkey(key)) {
if (key->is_subkey()) {
RNP_LOG("wrong argument");
return false;
}
@ -378,28 +251,33 @@ rnp_key_store_refresh_subkey_grips(rnp_key_store_t *keyring, pgp_key_t *key)
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)) {
if (!skey.is_subkey() || skey.has_primary_fp()) {
continue;
}
for (unsigned i = 0; i < pgp_key_get_subsig_count(&skey); i++) {
const pgp_subsig_t *subsig = pgp_key_get_subsig(&skey, i);
for (size_t i = 0; i < skey.sig_count(); i++) {
const pgp_subsig_t &subsig = skey.get_sig(i);
if (subsig->sig.type() != PGP_SIG_SUBKEY) {
if (subsig.sig.type() != PGP_SIG_SUBKEY) {
continue;
}
if (subsig->sig.has_keyfp() && (pgp_key_get_fp(key) == subsig->sig.keyfp())) {
if (subsig.sig.has_keyfp() && (key->fp() == subsig.sig.keyfp())) {
found = true;
break;
}
if (subsig->sig.has_keyid() && (pgp_key_get_keyid(key) == subsig->sig.keyid())) {
if (subsig.sig.has_keyid() && (key->keyid() == subsig.sig.keyid())) {
found = true;
break;
}
}
if (found && !pgp_key_link_subkey_fp(key, &skey)) {
return false;
if (found) {
try {
key->link_subkey_fp(skey);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
}
}
@ -419,17 +297,16 @@ rnp_key_store_add_subkey(rnp_key_store_t *keyring, pgp_key_t *srckey, pgp_key_t
if (oldkey) {
/* check for the weird case when same subkey has different primary keys */
if (pgp_key_has_primary_fp(srckey) && pgp_key_has_primary_fp(oldkey) &&
(pgp_key_get_primary_fp(srckey) != pgp_key_get_primary_fp(oldkey))) {
if (srckey->has_primary_fp() && oldkey->has_primary_fp() &&
(srckey->primary_fp() != oldkey->primary_fp())) {
RNP_LOG_KEY("Warning: different primary keys for subkey %s", srckey);
pgp_key_t *srcprim =
rnp_key_store_get_key_by_fpr(keyring, pgp_key_get_primary_fp(srckey));
if (srcprim != primary) {
pgp_key_remove_subkey_fp(srcprim, pgp_key_get_fp(srckey));
pgp_key_t *srcprim = rnp_key_store_get_key_by_fpr(keyring, srckey->primary_fp());
if (srcprim && (srcprim != primary)) {
srcprim->remove_subkey_fp(srckey->fp());
}
}
/* in case we already have key let's merge it in */
if (!rnp_key_store_merge_subkey(oldkey, srckey, primary)) {
if (!oldkey->merge(*srckey, primary)) {
RNP_LOG_KEY("failed to merge subkey %s", srckey);
RNP_LOG_KEY("primary key is %s", primary);
return NULL;
@ -438,33 +315,29 @@ rnp_key_store_add_subkey(rnp_key_store_t *keyring, pgp_key_t *srckey, pgp_key_t
try {
keyring->keys.emplace_back();
oldkey = &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 {
keyring->keybyfp[srckey->fp()] = std::prev(keyring->keys.end());
*oldkey = pgp_key_t(*srckey);
if (primary) {
primary->link_subkey_fp(*oldkey);
}
} catch (const std::exception &e) {
RNP_LOG_KEY("key %s copying failed", srckey);
RNP_LOG_KEY("primary key is %s", primary);
RNP_LOG("%s", e.what());
keyring->keys.pop_back();
keyring->keybyfp.erase(pgp_key_get_fp(srckey));
if (oldkey) {
keyring->keys.pop_back();
keyring->keybyfp.erase(srckey->fp());
}
return NULL;
}
if (primary && !pgp_key_link_subkey_fp(primary, oldkey)) {
RNP_LOG_KEY("failed to link subkey %s grip", oldkey);
RNP_LOG_KEY("primary key is %s", primary);
}
}
RNP_DLOG("keyc %lu", (long unsigned) rnp_key_store_get_key_count(keyring));
/* validate all added keys if not disabled */
if (!keyring->disable_validation && !oldkey->validated) {
pgp_key_validate_subkey(oldkey, primary);
if (!keyring->disable_validation && !oldkey->validated()) {
oldkey->validate_subkey(primary);
}
if (!pgp_subkey_refresh_data(oldkey, primary)) {
if (!oldkey->refresh_data(primary)) {
RNP_LOG_KEY("Failed to refresh subkey %s data", srckey);
RNP_LOG_KEY("primary key is %s", primary);
}
@ -475,19 +348,19 @@ rnp_key_store_add_subkey(rnp_key_store_t *keyring, pgp_key_t *srckey, pgp_key_t
pgp_key_t *
rnp_key_store_add_key(rnp_key_store_t *keyring, pgp_key_t *srckey)
{
assert(pgp_key_get_type(srckey) && pgp_key_get_version(srckey));
pgp_key_t *added_key = rnp_key_store_get_key_by_fpr(keyring, pgp_key_get_fp(srckey));
assert(srckey->type() && srckey->version());
pgp_key_t *added_key = rnp_key_store_get_key_by_fpr(keyring, srckey->fp());
/* we cannot merge G10 keys - so just return it */
if (added_key && (srckey->format == PGP_KEY_STORE_G10)) {
return added_key;
}
/* different processing for subkeys */
if (pgp_key_is_subkey(srckey)) {
if (srckey->is_subkey()) {
return rnp_key_store_add_subkey(keyring, srckey, added_key);
}
if (added_key) {
if (!rnp_key_store_merge_key(added_key, srckey)) {
if (!added_key->merge(*srckey)) {
RNP_LOG_KEY("failed to merge key %s", srckey);
return NULL;
}
@ -495,12 +368,7 @@ rnp_key_store_add_key(rnp_key_store_t *keyring, pgp_key_t *srckey)
try {
keyring->keys.emplace_back();
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 {
keyring->keybyfp[srckey->fp()] = std::prev(keyring->keys.end());
*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)) {
@ -509,17 +377,19 @@ rnp_key_store_add_key(rnp_key_store_t *keyring, pgp_key_t *srckey)
} 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));
if (added_key) {
keyring->keys.pop_back();
keyring->keybyfp.erase(srckey->fp());
}
return NULL;
}
}
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)) {
if (!keyring->disable_validation && !added_key->validated()) {
added_key->revalidate(*keyring);
} else if (!added_key->refresh_data()) {
RNP_LOG_KEY("Failed to refresh key %s data", srckey);
}
return added_key;
@ -532,8 +402,8 @@ rnp_key_store_import_key(rnp_key_store_t * keyring,
pgp_key_import_status_t *status)
{
/* add public key */
pgp_key_t *exkey = rnp_key_store_get_key_by_fpr(keyring, pgp_key_get_fp(srckey));
size_t expackets = exkey ? pgp_key_get_rawpacket_count(exkey) : 0;
pgp_key_t *exkey = rnp_key_store_get_key_by_fpr(keyring, srckey->fp());
size_t expackets = exkey ? exkey->rawpkt_count() : 0;
keyring->disable_validation = true;
try {
pgp_key_t keycp(*srckey, pubkey);
@ -548,10 +418,10 @@ rnp_key_store_import_key(rnp_key_store_t * keyring,
RNP_LOG("failed to add key to the keyring");
return NULL;
}
bool changed = pgp_key_get_rawpacket_count(exkey) > expackets;
if (changed || !exkey->validated) {
bool changed = exkey->rawpkt_count() > expackets;
if (changed || !exkey->validated()) {
/* this will revalidated primary key with all subkeys */
pgp_key_revalidate_updated(exkey, keyring);
exkey->revalidate(*keyring);
}
if (status) {
*status = changed ?
@ -589,30 +459,35 @@ rnp_key_store_import_subkey_signature(rnp_key_store_t * keyring,
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)) {
if (!primary || !key->has_primary_fp()) {
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)) {
if (primary->fp() != key->primary_fp()) {
RNP_LOG("Wrong subkey signature's signer.");
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_subkey_refresh_data(&tmpkey, primary)) {
RNP_LOG("Failed to add signature to the key.");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
try {
pgp_key_t tmpkey(key->pkt());
tmpkey.add_sig(*sig);
if (!tmpkey.refresh_data(primary)) {
RNP_LOG("Failed to add signature to the key.");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
size_t expackets = pgp_key_get_rawpacket_count(key);
key = rnp_key_store_add_key(keyring, &tmpkey);
if (!key) {
RNP_LOG("Failed to add key with imported sig to the keyring");
size_t expackets = key->rawpkt_count();
key = rnp_key_store_add_key(keyring, &tmpkey);
if (!key) {
RNP_LOG("Failed to add key with imported sig to the keyring");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
return (key->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
PGP_SIG_IMPORT_STATUS_UNCHANGED;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
return (pgp_key_get_rawpacket_count(key) > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
PGP_SIG_IMPORT_STATUS_UNCHANGED;
}
pgp_sig_import_status_t
@ -620,7 +495,7 @@ 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)) {
if (key->is_subkey()) {
return rnp_key_store_import_subkey_signature(keyring, key, sig);
}
if ((sig->type() != PGP_SIG_DIRECT) && (sig->type() != PGP_SIG_REV_KEY)) {
@ -628,21 +503,26 @@ rnp_key_store_import_key_signature(rnp_key_store_t * keyring,
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;
}
try {
pgp_key_t tmpkey(key->pkt());
tmpkey.add_sig(*sig);
if (!tmpkey.refresh_data()) {
RNP_LOG("Failed to add signature to the key.");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
size_t expackets = pgp_key_get_rawpacket_count(key);
key = rnp_key_store_add_key(keyring, &tmpkey);
if (!key) {
RNP_LOG("Failed to add key with imported sig to the keyring");
size_t expackets = key->rawpkt_count();
key = rnp_key_store_add_key(keyring, &tmpkey);
if (!key) {
RNP_LOG("Failed to add key with imported sig to the keyring");
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
return (key->rawpkt_count() > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
PGP_SIG_IMPORT_STATUS_UNCHANGED;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return PGP_SIG_IMPORT_STATUS_UNKNOWN;
}
return (pgp_key_get_rawpacket_count(key) > expackets) ? PGP_SIG_IMPORT_STATUS_NEW :
PGP_SIG_IMPORT_STATUS_UNCHANGED;
}
pgp_key_t *
@ -662,7 +542,7 @@ rnp_key_store_import_signature(rnp_key_store_t * keyring,
}
pgp_key_t *res_key = rnp_key_store_get_signer_key(keyring, sig);
if (!res_key || !pgp_key_is_primary_key(res_key)) {
if (!res_key || !res_key->is_primary()) {
*status = PGP_SIG_IMPORT_STATUS_UNKNOWN_KEY;
return NULL;
}
@ -673,15 +553,15 @@ rnp_key_store_import_signature(rnp_key_store_t * keyring,
bool
rnp_key_store_remove_key(rnp_key_store_t *keyring, const pgp_key_t *key, bool subkeys)
{
auto it = keyring->keybyfp.find(pgp_key_get_fp(key));
auto it = keyring->keybyfp.find(key->fp());
if (it == keyring->keybyfp.end()) {
return false;
}
/* cleanup primary_grip (or subkey)/subkey_grips */
if (pgp_key_is_primary_key(key) && pgp_key_get_subkey_count(key)) {
for (size_t i = 0; i < pgp_key_get_subkey_count(key); i++) {
auto it = keyring->keybyfp.find(pgp_key_get_subkey_fp(key, i));
if (key->is_primary() && key->subkey_count()) {
for (size_t i = 0; i < key->subkey_count(); i++) {
auto it = keyring->keybyfp.find(key->get_subkey_fp(i));
if (it == keyring->keybyfp.end()) {
continue;
}
@ -691,14 +571,13 @@ rnp_key_store_remove_key(rnp_key_store_t *keyring, const pgp_key_t *key, bool su
keyring->keybyfp.erase(it);
continue;
}
it->second->primary_fp = {};
it->second->primary_fp_set = false;
it->second->unset_primary_fp();
}
}
if (pgp_key_is_subkey(key) && pgp_key_has_primary_fp(key)) {
if (key->is_subkey() && key->has_primary_fp()) {
pgp_key_t *primary = rnp_key_store_get_primary_key(keyring, key);
if (primary) {
pgp_key_remove_subkey_fp(primary, pgp_key_get_fp(key));
primary->remove_subkey_fp(key->fp());
}
}
@ -743,9 +622,9 @@ rnp_key_store_get_key_by_id(rnp_key_store_t * keyring,
it = std::next(it);
}
it = std::find_if(it, keyring->keys.end(), [keyid](const pgp_key_t &key) {
const pgp_key_id_t &id = pgp_key_get_keyid(&key);
return (id == keyid) ||
!memcmp(id.data() + PGP_KEY_ID_SIZE / 2, keyid.data(), PGP_KEY_ID_SIZE / 2);
return (key.keyid() == keyid) || !memcmp(key.keyid().data() + PGP_KEY_ID_SIZE / 2,
keyid.data(),
PGP_KEY_ID_SIZE / 2);
});
return (it == keyring->keys.end()) ? NULL : &(*it);
}
@ -753,20 +632,18 @@ rnp_key_store_get_key_by_id(rnp_key_store_t * keyring,
const pgp_key_t *
rnp_key_store_get_key_by_grip(const rnp_key_store_t *keyring, const pgp_key_grip_t &grip)
{
auto it =
std::find_if(keyring->keys.begin(), keyring->keys.end(), [grip](const pgp_key_t &key) {
return pgp_key_get_grip(&key) == grip;
});
auto it = std::find_if(keyring->keys.begin(),
keyring->keys.end(),
[grip](const pgp_key_t &key) { return key.grip() == grip; });
return (it == keyring->keys.end()) ? NULL : &(*it);
}
pgp_key_t *
rnp_key_store_get_key_by_grip(rnp_key_store_t *keyring, const pgp_key_grip_t &grip)
{
auto it =
std::find_if(keyring->keys.begin(), keyring->keys.end(), [grip](const pgp_key_t &key) {
return pgp_key_get_grip(&key) == grip;
});
auto it = std::find_if(keyring->keys.begin(),
keyring->keys.end(),
[grip](const pgp_key_t &key) { return key.grip() == grip; });
return (it == keyring->keys.end()) ? NULL : &(*it);
}
@ -793,26 +670,26 @@ rnp_key_store_get_key_by_fpr(rnp_key_store_t *keyring, const pgp_fingerprint_t &
pgp_key_t *
rnp_key_store_get_primary_key(rnp_key_store_t *keyring, const pgp_key_t *subkey)
{
if (!pgp_key_is_subkey(subkey)) {
if (!subkey->is_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));
if (subkey->has_primary_fp()) {
return rnp_key_store_get_key_by_fpr(keyring, subkey->primary_fp());
}
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) {
for (size_t i = 0; i < subkey->sig_count(); i++) {
const pgp_subsig_t &subsig = subkey->get_sig(i);
if (subsig.sig.type() != PGP_SIG_SUBKEY) {
continue;
}
if (subsig->sig.has_keyfp()) {
return rnp_key_store_get_key_by_fpr(keyring, subsig->sig.keyfp());
if (subsig.sig.has_keyfp()) {
return rnp_key_store_get_key_by_fpr(keyring, subsig.sig.keyfp());
}
if (subsig->sig.has_keyid()) {
return rnp_key_store_get_key_by_id(keyring, subsig->sig.keyid(), NULL);
if (subsig.sig.has_keyid()) {
return rnp_key_store_get_key_by_id(keyring, subsig.sig.keyid(), NULL);
}
}

Просмотреть файл

@ -40,6 +40,7 @@
#include "stream-packet.h"
#include "crypto/hash.h"
#include "types.h"
#include "utils.h"
#define ARMORED_BLOCK_SIZE (4096)
#define ARMORED_MIN_LINE_LENGTH (16)

123
third_party/rnp/src/librepgp/stream-common.cpp поставляемый
Просмотреть файл

@ -42,13 +42,11 @@
#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 "file-utils.h"
#include <algorithm>
bool
@ -400,14 +398,31 @@ file_src_close(pgp_source_t *src)
}
}
static rnp_result_t
init_fd_src(pgp_source_t *src, int fd, uint64_t *size)
{
if (!init_src_common(src, sizeof(pgp_source_file_param_t))) {
return RNP_ERROR_OUT_OF_MEMORY;
}
pgp_source_file_param_t *param = (pgp_source_file_param_t *) src->param;
param->fd = fd;
src->read = file_src_read;
src->close = file_src_close;
src->type = PGP_STREAM_FILE;
src->size = size ? *size : 0;
src->knownsize = !!size;
return RNP_SUCCESS;
}
rnp_result_t
init_file_src(pgp_source_t *src, const char *path)
{
int fd;
struct stat st;
pgp_source_file_param_t *param;
int fd;
struct stat st;
if (stat(path, &st) != 0) {
if (rnp_stat(path, &st) != 0) {
RNP_LOG("can't stat '%s'", path);
return RNP_ERROR_READ;
}
@ -426,27 +441,18 @@ init_file_src(pgp_source_t *src, const char *path)
flags |= _O_BINARY;
#endif
#endif
fd = open(path, flags);
fd = rnp_open(path, flags, 0);
if (fd < 0) {
RNP_LOG("can't open '%s'", path);
return RNP_ERROR_READ;
}
if (!init_src_common(src, sizeof(pgp_source_file_param_t))) {
uint64_t size = st.st_size;
rnp_result_t ret = init_fd_src(src, fd, &size);
if (ret) {
close(fd);
return RNP_ERROR_OUT_OF_MEMORY;
}
param = (pgp_source_file_param_t *) src->param;
param->fd = fd;
src->read = file_src_read;
src->close = file_src_close;
src->type = PGP_STREAM_FILE;
src->size = st.st_size;
src->knownsize = 1;
return RNP_SUCCESS;
return ret;
}
rnp_result_t
@ -757,7 +763,7 @@ file_dst_close(pgp_dest_t *dst, bool discard)
if (dst->type == PGP_STREAM_FILE) {
close(param->fd);
if (discard) {
unlink(param->path);
rnp_unlink(param->path);
}
}
@ -803,7 +809,7 @@ init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite)
}
/* check whether file/dir already exists */
if (!stat(path, &st)) {
if (!rnp_stat(path, &st)) {
if (!overwrite) {
RNP_LOG("file already exists: '%s'", path);
return RNP_ERROR_WRITE;
@ -827,7 +833,8 @@ init_file_dest(pgp_dest_t *dst, const char *path, bool overwrite)
flags |= _O_BINARY;
#endif
#endif
fd = open(path, flags, S_IRUSR | S_IWUSR);
fd = rnp_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;
@ -866,7 +873,7 @@ file_tmpdst_finish(pgp_dest_t *dst)
param->fd = -1;
/* check if file already exists */
if (!stat(origpath, &st)) {
if (!rnp_stat(origpath, &st)) {
if (!param->overwrite) {
RNP_LOG("target path already exists");
return RNP_ERROR_BAD_STATE;
@ -874,7 +881,7 @@ file_tmpdst_finish(pgp_dest_t *dst)
#ifdef _WIN32
/* rename() call on Windows fails if destination exists */
else {
unlink(origpath);
rnp_unlink(origpath);
}
#endif
@ -885,7 +892,7 @@ file_tmpdst_finish(pgp_dest_t *dst)
}
}
if (rename(param->path, origpath)) {
if (rnp_rename(param->path, origpath)) {
RNP_LOG("failed to rename temporary path to target file: %s", strerror(errno));
return RNP_ERROR_BAD_STATE;
}
@ -906,7 +913,7 @@ file_tmpdst_close(pgp_dest_t *dst, bool discard)
if (!dst->finished && (dst->type == PGP_STREAM_FILE)) {
close(param->fd);
if (discard) {
unlink(param->path);
rnp_unlink(param->path);
}
}
@ -927,7 +934,7 @@ init_tmpfile_dest(pgp_dest_t *dst, const char *path, bool overwrite)
RNP_LOG("failed to build file path");
return RNP_ERROR_BAD_PARAMETERS;
}
#ifdef HAVE_MKSTEMP
#if defined(HAVE_MKSTEMP) && !defined(_WIN32)
int fd = mkstemp(tmp);
#else
int fd = rnp_mkstemp(tmp);
@ -1150,28 +1157,46 @@ init_null_dest(pgp_dest_t *dst)
}
rnp_result_t
dst_write_src(pgp_source_t *src, pgp_dest_t *dst)
dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit)
{
uint8_t readbuf[PGP_INPUT_CACHE_SIZE];
rnp_result_t res = RNP_SUCCESS;
size_t read;
while (!src->eof) {
if (!src_read(src, readbuf, sizeof(readbuf), &read)) {
res = RNP_ERROR_GENERIC;
break;
}
if (!read) {
continue;
}
dst_write(dst, readbuf, read);
if (dst->werr) {
RNP_LOG("failed to output data");
res = RNP_ERROR_WRITE;
break;
}
const size_t bufsize = PGP_INPUT_CACHE_SIZE;
uint8_t * readbuf = (uint8_t *) malloc(bufsize);
if (!readbuf) {
return RNP_ERROR_OUT_OF_MEMORY;
}
if (res) {
rnp_result_t res = RNP_SUCCESS;
try {
size_t read;
uint64_t totalread = 0;
while (!src->eof) {
if (!src_read(src, readbuf, bufsize, &read)) {
res = RNP_ERROR_GENERIC;
break;
}
if (!read) {
continue;
}
totalread += read;
if (limit && totalread > limit) {
res = RNP_ERROR_GENERIC;
break;
}
if (dst) {
dst_write(dst, readbuf, read);
if (dst->werr) {
RNP_LOG("failed to output data");
res = RNP_ERROR_WRITE;
break;
}
}
}
} catch (...) {
free(readbuf);
throw;
}
free(readbuf);
if (res || !dst) {
return res;
}
dst_flush(dst);

Просмотреть файл

@ -30,6 +30,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include "types.h"
#define PGP_INPUT_CACHE_SIZE 32768
#define PGP_OUTPUT_CACHE_SIZE 32768
@ -358,8 +359,11 @@ rnp_result_t init_null_dest(pgp_dest_t *dst);
/** @brief reads from source and writes to destination
* @param src initialized source
* @param dst initialized destination
* @param limit sets the maximum amount of bytes to be read,
* returning an error if the source hasn't come to eof after that amount
* if 0, no limit is imposed
* @return RNP_SUCCESS or error code
**/
rnp_result_t dst_write_src(pgp_source_t *src, pgp_dest_t *dst);
rnp_result_t dst_write_src(pgp_source_t *src, pgp_dest_t *dst, uint64_t limit = 0);
#endif

1
third_party/rnp/src/librepgp/stream-ctx.h поставляемый
Просмотреть файл

@ -33,6 +33,7 @@
#include "types.h"
#include <string>
#include <list>
#include "pgp-key.h"
typedef enum rnp_operation_t {
RNP_OP_UNKNOWN = 0,

4
third_party/rnp/src/librepgp/stream-def.h поставляемый
Просмотреть файл

@ -35,6 +35,7 @@
#define CH_SPACE (' ')
#define CH_TAB ('\t')
#define CH_COMMA (',')
#define ST_CR ("\r")
#define ST_LF ("\n")
#define ST_CRLF ("\r\n")
#define ST_CRLFCRLF ("\r\n\r\n")
@ -63,4 +64,7 @@
/* Maximum OpenPGP packet nesting level */
#define MAXIMUM_NESTING_LEVEL 32
/* Maximum text line length supported by GnuPG */
#define MAXIMUM_GNUPG_LINELEN 19995
#endif /* !STREAM_DEF_H_ */

160
third_party/rnp/src/librepgp/stream-dump.cpp поставляемый
Просмотреть файл

@ -725,8 +725,12 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t
indent_dest_increase(dst);
pgp_signature_material_t material = {};
parse_signature_material(*sig, material);
try {
sig->parse_material(material);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return;
}
switch (sig->palg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
@ -760,15 +764,21 @@ static void
stream_dump_signature(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst)
{
pgp_signature_t sig;
rnp_result_t ret;
dst_printf(dst, "Signature packet\n");
if (stream_parse_signature(src, &sig)) {
try {
ret = sig.parse(*src);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_GENERIC;
}
if (ret) {
indent_dest_increase(dst);
dst_printf(dst, "failed to parse\n");
indent_dest_decrease(dst);
return;
}
stream_dump_signature_pkt(ctx, &sig, dst);
}
@ -779,7 +789,13 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst)
rnp_result_t ret;
pgp_fingerprint_t keyfp = {};
if ((ret = stream_parse_key(src, &key))) {
try {
ret = key.parse(*src);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -862,14 +878,14 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst)
}
pgp_key_id_t keyid = {};
if (!pgp_keyid(keyid, &key)) {
if (!pgp_keyid(keyid, key)) {
dst_print_hex(dst, "keyid", keyid.data(), keyid.size(), false);
} else {
dst_printf(dst, "keyid: failed to calculate");
}
if ((key.version > PGP_V3) && (ctx->dump_grips)) {
if (!pgp_fingerprint(keyfp, &key)) {
if (!pgp_fingerprint(keyfp, key)) {
dst_print_hex(dst, "fingerprint", keyfp.fingerprint, keyfp.length, false);
} else {
dst_printf(dst, "fingerprint: failed to calculate");
@ -896,7 +912,12 @@ stream_dump_userid(pgp_source_t *src, pgp_dest_t *dst)
rnp_result_t ret;
const char * utype;
if ((ret = stream_parse_userid(src, &uid))) {
try {
ret = uid.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -933,10 +954,19 @@ stream_dump_userid(pgp_source_t *src, pgp_dest_t *dst)
static rnp_result_t
stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst)
{
pgp_pk_sesskey_t pkey;
rnp_result_t ret;
pgp_pk_sesskey_t pkey;
pgp_encrypted_material_t material;
rnp_result_t ret;
if ((ret = stream_parse_pk_sesskey(src, &pkey))) {
try {
ret = pkey.parse(*src);
if (!pkey.parse_material(material)) {
ret = RNP_ERROR_BAD_FORMAT;
}
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -953,22 +983,22 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
case PGP_PKA_RSA_SIGN_ONLY:
dst_print_mpi(dst, "rsa m", &pkey.material.rsa.m, ctx->dump_mpi);
dst_print_mpi(dst, "rsa m", &material.rsa.m, ctx->dump_mpi);
break;
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
dst_print_mpi(dst, "eg g", &pkey.material.eg.g, ctx->dump_mpi);
dst_print_mpi(dst, "eg m", &pkey.material.eg.m, ctx->dump_mpi);
dst_print_mpi(dst, "eg g", &material.eg.g, ctx->dump_mpi);
dst_print_mpi(dst, "eg m", &material.eg.m, ctx->dump_mpi);
break;
case PGP_PKA_SM2:
dst_print_mpi(dst, "sm2 m", &pkey.material.sm2.m, ctx->dump_mpi);
dst_print_mpi(dst, "sm2 m", &material.sm2.m, ctx->dump_mpi);
break;
case PGP_PKA_ECDH:
dst_print_mpi(dst, "ecdh p", &pkey.material.ecdh.p, ctx->dump_mpi);
dst_print_mpi(dst, "ecdh p", &material.ecdh.p, ctx->dump_mpi);
if (ctx->dump_mpi) {
dst_print_hex(dst, "ecdh m", pkey.material.ecdh.m, pkey.material.ecdh.mlen, true);
dst_print_hex(dst, "ecdh m", material.ecdh.m, material.ecdh.mlen, true);
} else {
dst_printf(dst, "ecdh m: %d bytes\n", (int) pkey.material.ecdh.mlen);
dst_printf(dst, "ecdh m: %d bytes\n", (int) material.ecdh.mlen);
}
break;
default:
@ -986,7 +1016,12 @@ stream_dump_sk_session_key(pgp_source_t *src, pgp_dest_t *dst)
pgp_sk_sesskey_t skey;
rnp_result_t ret;
if ((ret = stream_parse_sk_sesskey(src, &skey))) {
try {
ret = skey.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -1083,7 +1118,12 @@ stream_dump_one_pass(pgp_source_t *src, pgp_dest_t *dst)
pgp_one_pass_sig_t onepass;
rnp_result_t ret;
if ((ret = stream_parse_one_pass(src, &onepass))) {
try {
ret = onepass.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -1747,7 +1787,12 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx,
goto done;
}
parse_signature_material(*sig, sigmaterial);
try {
sig->parse_material(sigmaterial);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
switch (sig->palg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
@ -1790,7 +1835,14 @@ static rnp_result_t
stream_dump_signature_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt)
{
pgp_signature_t sig;
if (stream_parse_signature(src, &sig)) {
rnp_result_t ret;
try {
ret = sig.parse(*src);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return RNP_SUCCESS;
}
return stream_dump_signature_pkt_json(ctx, &sig, pkt);
@ -1805,7 +1857,13 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt)
pgp_fingerprint_t keyfp = {};
json_object * material = NULL;
if ((ret = stream_parse_key(src, &key))) {
try {
ret = key.parse(*src);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -1908,13 +1966,12 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt)
}
}
if (pgp_keyid(keyid, &key) ||
!obj_add_hex_json(pkt, "keyid", keyid.data(), keyid.size())) {
if (pgp_keyid(keyid, key) || !obj_add_hex_json(pkt, "keyid", keyid.data(), keyid.size())) {
goto done;
}
if (ctx->dump_grips) {
if (pgp_fingerprint(keyfp, &key) ||
if (pgp_fingerprint(keyfp, key) ||
!obj_add_hex_json(pkt, "fingerprint", keyfp.fingerprint, keyfp.length)) {
goto done;
}
@ -1936,7 +1993,12 @@ stream_dump_userid_json(pgp_source_t *src, json_object *pkt)
pgp_userid_pkt_t uid;
rnp_result_t ret;
if ((ret = stream_parse_userid(src, &uid))) {
try {
ret = uid.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -1960,10 +2022,19 @@ stream_dump_userid_json(pgp_source_t *src, json_object *pkt)
static rnp_result_t
stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt)
{
pgp_pk_sesskey_t pkey;
rnp_result_t ret;
pgp_pk_sesskey_t pkey;
pgp_encrypted_material_t pkmaterial;
rnp_result_t ret;
if ((ret = stream_parse_pk_sesskey(src, &pkey))) {
try {
ret = pkey.parse(*src);
if (!pkey.parse_material(pkmaterial)) {
ret = RNP_ERROR_BAD_FORMAT;
}
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
@ -1982,30 +2053,30 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
case PGP_PKA_RSA_SIGN_ONLY:
if (!obj_add_mpi_json(material, "m", &pkey.material.rsa.m, ctx->dump_mpi)) {
if (!obj_add_mpi_json(material, "m", &pkmaterial.rsa.m, ctx->dump_mpi)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
break;
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
if (!obj_add_mpi_json(material, "g", &pkey.material.eg.g, ctx->dump_mpi) ||
!obj_add_mpi_json(material, "m", &pkey.material.eg.m, ctx->dump_mpi)) {
if (!obj_add_mpi_json(material, "g", &pkmaterial.eg.g, ctx->dump_mpi) ||
!obj_add_mpi_json(material, "m", &pkmaterial.eg.m, ctx->dump_mpi)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
break;
case PGP_PKA_SM2:
if (!obj_add_mpi_json(material, "m", &pkey.material.sm2.m, ctx->dump_mpi)) {
if (!obj_add_mpi_json(material, "m", &pkmaterial.sm2.m, ctx->dump_mpi)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
break;
case PGP_PKA_ECDH:
if (!obj_add_mpi_json(material, "p", &pkey.material.ecdh.p, ctx->dump_mpi) ||
if (!obj_add_mpi_json(material, "p", &pkmaterial.ecdh.p, ctx->dump_mpi) ||
!obj_add_field_json(
material, "m.bytes", json_object_new_int(pkey.material.ecdh.mlen))) {
material, "m.bytes", json_object_new_int(pkmaterial.ecdh.mlen))) {
return RNP_ERROR_OUT_OF_MEMORY;
}
if (ctx->dump_mpi &&
!obj_add_hex_json(material, "m", pkey.material.ecdh.m, pkey.material.ecdh.mlen)) {
!obj_add_hex_json(material, "m", pkmaterial.ecdh.m, pkmaterial.ecdh.mlen)) {
return RNP_ERROR_OUT_OF_MEMORY;
}
break;
@ -2021,9 +2092,15 @@ stream_dump_sk_session_key_json(pgp_source_t *src, json_object *pkt)
pgp_sk_sesskey_t skey;
rnp_result_t ret;
if ((ret = stream_parse_sk_sesskey(src, &skey))) {
try {
ret = skey.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}
if (!obj_add_field_json(pkt, "version", json_object_new_int(skey.version)) ||
!obj_add_intstr_json(pkt, "algorithm", skey.alg, symm_alg_map)) {
return RNP_ERROR_OUT_OF_MEMORY;
@ -2076,7 +2153,12 @@ stream_dump_one_pass_json(pgp_source_t *src, json_object *pkt)
pgp_one_pass_sig_t onepass;
rnp_result_t ret;
if ((ret = stream_parse_one_pass(src, &onepass))) {
try {
ret = onepass.parse(*src);
} catch (const std::exception &e) {
ret = RNP_ERROR_GENERIC;
}
if (ret) {
return ret;
}

843
third_party/rnp/src/librepgp/stream-key.cpp поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

37
third_party/rnp/src/librepgp/stream-key.h поставляемый
Просмотреть файл

@ -33,6 +33,43 @@
#include "rnp.h"
#include "stream-common.h"
#include "stream-sig.h"
#include "stream-packet.h"
/** 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 */
pgp_pubkey_alg_t alg;
uint16_t v3_days; /* v2/v3 validity time */
uint8_t *hashed_data; /* key's hashed data used for signature calculation */
size_t hashed_len;
pgp_key_material_t material;
/* secret key data, if available. sec_len == 0, sec_data == NULL for public key/subkey */
pgp_key_protection_t sec_protection;
uint8_t * sec_data;
size_t sec_len;
pgp_key_pkt_t()
: tag(PGP_PKT_RESERVED), version(PGP_VUNKNOWN), creation_time(0), alg(PGP_PKA_NOTHING),
v3_days(0), hashed_data(NULL), hashed_len(0), material({}), sec_protection({}),
sec_data(NULL), sec_len(0){};
pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly = false);
pgp_key_pkt_t(pgp_key_pkt_t &&src);
pgp_key_pkt_t &operator=(pgp_key_pkt_t &&src);
pgp_key_pkt_t &operator=(const pgp_key_pkt_t &src);
~pgp_key_pkt_t();
void write(pgp_dest_t &dst);
rnp_result_t parse(pgp_source_t &src);
/** @brief Fills the hashed (signed) data part of the key packet. Must be called before
* pgp_key_pkt_t::write() on the newly generated key */
void fill_hashed_data();
bool equals(const pgp_key_pkt_t &key, bool pubonly = false) const noexcept;
} pgp_key_pkt_t;
/* userid/userattr with all the corresponding signatures */
typedef struct pgp_transferable_userid_t {

2565
third_party/rnp/src/librepgp/stream-packet.cpp поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

355
third_party/rnp/src/librepgp/stream-packet.h поставляемый
Просмотреть файл

@ -30,12 +30,15 @@
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include "rnp.h"
#include "types.h"
#include "stream-common.h"
/* maximum size of the 'small' packet */
#define PGP_MAX_PKT_SIZE 0x100000
/* maximum size of indeterminate-size packet allowed with old length format */
#define PGP_MAX_OLD_LEN_INDETERMINATE_PKT_SIZE 0x40000000
typedef struct pgp_packet_hdr_t {
pgp_pkt_type_t tag;
uint8_t hdr[PGP_MAX_HEADER_SIZE];
@ -47,17 +50,181 @@ typedef struct pgp_packet_hdr_t {
/* structure for convenient writing or parsing of non-stream packets */
typedef struct pgp_packet_body_t {
pgp_pkt_type_t tag; /* packet tag */
uint8_t * data; /* packet body data */
size_t len; /* length of the data */
size_t allocated; /* allocated bytes in data */
private:
pgp_pkt_type_t tag_; /* packet tag */
std::vector<uint8_t> data_; /* packet bytes */
/* fields below are filled only for parsed packet */
uint8_t hdr[PGP_MAX_HEADER_SIZE]; /* packet header bytes */
size_t hdr_len; /* number of bytes in hdr */
size_t pos; /* current read position in packet data */
uint8_t hdr_[PGP_MAX_HEADER_SIZE]{}; /* packet header bytes */
size_t hdr_len_{}; /* number of bytes in hdr */
size_t pos_{}; /* current read position in packet data */
bool secure_{}; /* contents of the packet are secure so must be wiped in the destructor */
public:
/** @brief initialize writing of packet body
* @param tag tag of the packet
**/
pgp_packet_body_t(pgp_pkt_type_t tag);
/** @brief init packet body (without headers) with memory. Used for easier data parsing.
* @param data buffer with packet body part
* @param len number of available bytes in mem
*/
pgp_packet_body_t(const uint8_t *data, size_t len);
pgp_packet_body_t(const pgp_packet_body_t &src) = delete;
pgp_packet_body_t(pgp_packet_body_t &&src) = delete;
pgp_packet_body_t &operator=(const pgp_packet_body_t &) = delete;
pgp_packet_body_t &operator=(pgp_packet_body_t &&) = delete;
~pgp_packet_body_t();
/** @brief pointer to the data, kept in the packet */
uint8_t *data() noexcept;
/** @brief number of bytes, kept in the packet (without the header) */
size_t size() const noexcept;
/** @brief number of bytes left to read */
size_t left() const noexcept;
/** @brief get next byte from the packet body, populated with read() call.
* @param val result will be stored here on success
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get(uint8_t &val) noexcept;
/** @brief get next big-endian uint16 from the packet body, populated with read() call.
* @param val result will be stored here on success
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get(uint16_t &val) noexcept;
/** @brief get next big-endian uint32 from the packet body, populated with read() call.
* @param val result will be stored here on success
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get(uint32_t &val) noexcept;
/** @brief get some bytes from the packet body, populated with read() call.
* @param val packet body bytes will be stored here. Must be capable of storing len bytes.
* @param len number of bytes to read
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get(uint8_t *val, size_t len) noexcept;
/** @brief get next keyid from the packet body, populated with read() call.
* @param val result will be stored here on success
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get(pgp_key_id_t &val) noexcept;
/** @brief get next mpi from the packet body, populated with read() call.
* @param val result will be stored here on success
* @return true on success or false otherwise (if end of the packet is reached
* or mpi is ill-formed)
**/
bool get(pgp_mpi_t &val) noexcept;
/** @brief Read ECC key curve and convert it to pgp_curve_t */
bool get(pgp_curve_t &val) noexcept;
/** @brief read s2k from the packet */
bool get(pgp_s2k_t &s2k) noexcept;
/** @brief append some bytes to the packet body */
void add(const void *data, size_t len);
/** @brief append single byte to the packet body */
void add_byte(uint8_t bt);
/** @brief append big endian 16-bit value to the packet body */
void add_uint16(uint16_t val);
/** @brief append big endian 32-bit value to the packet body */
void add_uint32(uint32_t val);
/** @brief append keyid to the packet body */
void add(const pgp_key_id_t &val);
/** @brief add pgp mpi (including header) to the packet body */
void add(const pgp_mpi_t &val);
/**
* @brief add pgp signature subpackets (including their length) to the packet body
* @param sig signature, containing subpackets
* @param hashed whether write hashed or not hashed subpackets
*/
void add_subpackets(const pgp_signature_t &sig, bool hashed);
/** @brief add ec curve description to the packet body */
void add(const pgp_curve_t curve);
/** @brief add s2k description to the packet body */
void add(const pgp_s2k_t &s2k);
/** @brief read 'short-length' packet body (including tag and length bytes) from the source
* @param src source to read from
* @return RNP_SUCCESS or error code if operation failed
**/
rnp_result_t read(pgp_source_t &src) noexcept;
/** @brief write packet header, length and body to the dst
* @param dst destination to write to.
* @param hdr write packet's header or not
**/
void write(pgp_dest_t &dst, bool hdr = true) noexcept;
/** @brief mark contents as secure, so pgp_forget() must be called in the destructor */
void mark_secure(bool secure = true) noexcept;
} pgp_packet_body_t;
/** 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{};
std::vector<uint8_t> material_buf{};
void write(pgp_dest_t &dst) const;
rnp_result_t parse(pgp_source_t &src);
/**
* @brief Parse encrypted material which is stored in packet in raw.
* @param material on success parsed material will be stored here.
* @return true on success or false otherwise. May also throw an exception.
*/
bool parse_material(pgp_encrypted_material_t &material) const;
/**
* @brief Write encrypted material to the material_buf.
* @param material populated encrypted material.
*/
void write_material(const pgp_encrypted_material_t &material);
} pgp_pk_sesskey_t;
/** pkp_sk_sesskey_t */
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{};
void write(pgp_dest_t &dst) const;
rnp_result_t parse(pgp_source_t &src);
} pgp_sk_sesskey_t;
/** pgp_one_pass_sig_t */
typedef struct pgp_one_pass_sig_t {
uint8_t version{};
pgp_sig_type_t type{};
pgp_hash_alg_t halg{};
pgp_pubkey_alg_t palg{};
pgp_key_id_t keyid{};
unsigned nested{};
void write(pgp_dest_t &dst) const;
rnp_result_t parse(pgp_source_t &src);
} pgp_one_pass_sig_t;
/** Struct to hold userid or userattr packet. We don't parse userattr now, just storing the
* binary blob as it is. It may be distinguished by tag field.
*/
typedef struct pgp_userid_pkt_t {
pgp_pkt_type_t tag;
uint8_t * uid;
size_t uid_len;
pgp_userid_pkt_t() : tag(PGP_PKT_RESERVED), uid(NULL), uid_len(0){};
pgp_userid_pkt_t(const pgp_userid_pkt_t &src);
pgp_userid_pkt_t(pgp_userid_pkt_t &&src);
pgp_userid_pkt_t &operator=(pgp_userid_pkt_t &&src);
pgp_userid_pkt_t &operator=(const pgp_userid_pkt_t &src);
bool operator==(const pgp_userid_pkt_t &src) const;
bool operator!=(const pgp_userid_pkt_t &src) const;
~pgp_userid_pkt_t();
void write(pgp_dest_t &dst) const;
rnp_result_t parse(pgp_source_t &src);
} pgp_userid_pkt_t;
uint16_t read_uint16(const uint8_t *buf);
uint32_t read_uint32(const uint8_t *buf);
@ -91,7 +258,7 @@ int stream_pkt_type(pgp_source_t *src);
**/
bool stream_pkt_hdr_len(pgp_source_t *src, size_t *hdrlen);
bool stream_intedeterminate_pkt_len(pgp_source_t *src);
bool stream_old_indeterminate_pkt_len(pgp_source_t *src);
bool stream_partial_pkt_len(pgp_source_t *src);
@ -116,113 +283,6 @@ bool stream_read_pkt_len(pgp_source_t *src, size_t *pktlen);
**/
bool stream_read_partial_chunk_len(pgp_source_t *src, size_t *clen, bool *last);
/** @brief initialize writing of packet body
* @param body preallocated structure
* @param tag tag of the packet
* @return true on success or false otherwise
**/
bool init_packet_body(pgp_packet_body_t *body, pgp_pkt_type_t tag);
/** @brief append chunk of the data to packet body
* @param body pointer to the structure, initialized with init_packet_body
* @param data non-NULL pointer to the data
* @param len number of bytes to add
* @return true if data was copied successfully, or false otherwise
**/
bool add_packet_body(pgp_packet_body_t *body, const void *data, size_t len);
/** @brief append single byte to packet body
* @param body pointer to the structure, initialized with init_packet_body
* @param byte byte to append
* @return true if byte was appended successfully, or false otherwise
**/
bool add_packet_body_byte(pgp_packet_body_t *body, uint8_t byte);
/** @brief append big endian 16-bit value to packet body
* @param body pointer to the structure, initialized with init_packet_body
* @param val value to append
* @return true if value was appended successfully, or false otherwise
**/
bool add_packet_body_uint16(pgp_packet_body_t *body, uint16_t val);
/** @brief append big endian 32-bit value to packet body
* @param body pointer to the structure, initialized with init_packet_body
* @param val value to append
* @return true if value was appended successfully, or false otherwise
**/
bool add_packet_body_uint32(pgp_packet_body_t *body, uint32_t val);
/** @brief add pgp mpi (including header) to packet body
* @param body pointer to the structure, initialized with init_packet_body
* @param val pointer to structure with mpi data
* @return true if mpi was added successfully, or false otherwise
**/
bool add_packet_body_mpi(pgp_packet_body_t *body, const pgp_mpi_t *val);
/**
* @brief add pgp signature subpackets (including their length) to the packet body
*
* @param body pointer to the structure, initialized with init_packet_body
* @param sig signature, containing subpackets
* @param hashed whether write hashed or not hashed subpackets
* @return true on success or false otherwise (if out of memory)
*/
bool add_packet_body_subpackets(pgp_packet_body_t * body,
const pgp_signature_t *sig,
bool hashed);
/** @brief get next byte from the packet body
* @param body pointer to the structure. It must be filled via stream_read_packet_body
* @param val result will be stored here
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get_packet_body_byte(pgp_packet_body_t *body, uint8_t *val);
/** @brief get next big-endian uint16 from the packet body
* @param body pointer to the structure. It must be filled via stream_read_packet_body
* @param val result will be stored here
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get_packet_body_uint16(pgp_packet_body_t *body, uint16_t *val);
/** @brief get next big-endian uint32 from the packet body
* @param body pointer to the structure. It must be filled via stream_read_packet_body
* @param val result will be stored here
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get_packet_body_uint32(pgp_packet_body_t *body, uint32_t *val);
/** @brief get some bytes from the packet body
* @param body pointer to the structure. It must be filled via stream_read_packet_body
* @param val packet body bytes will be stored here. Must be capable of storing len bytes.
* @param len number of bytes to read
* @return true on success or false otherwise (if end of the packet is reached)
**/
bool get_packet_body_buf(pgp_packet_body_t *body, uint8_t *val, size_t len);
/** @brief get next mpi from the packet body
* @param body pointer to the structure. It must be filled via stream_read_packet_body
* @param val pointer to structure where result will be stored
* @return true on success or false otherwise (if end of the packet is reached
* or mpi is ill-formed)
**/
bool get_packet_body_mpi(pgp_packet_body_t *body, pgp_mpi_t *val);
/** @brief deallocate data inside of packet body structure
* @param body initialized packet body
* @return void
**/
void free_packet_body(pgp_packet_body_t *body);
/** @brief write packet header, length and body to the dest
* This will also deallocate internally used memory, so no free_packet_body call is needed
*
* @param body populated with data packet body
* @param dst destination to write to
* @return void
**/
void stream_flush_packet_body(pgp_packet_body_t *body, pgp_dest_t *dst);
/** @brief get and parse OpenPGP packet header to the structure.
* Note: this will not read but just peek required bytes.
*
@ -232,21 +292,6 @@ void stream_flush_packet_body(pgp_packet_body_t *body, pgp_dest_t *dst);
**/
rnp_result_t stream_peek_packet_hdr(pgp_source_t *src, pgp_packet_hdr_t *hdr);
/** @brief read 'short-length' packet body (including tag and length bytes) from the source
* @param src source to read from
* @param body pre-allocated body structure. Do not call init_packet_body on it!
* @return RNP_SUCCESS or error code if operation failed
**/
rnp_result_t stream_read_packet_body(pgp_source_t *src, pgp_packet_body_t *body);
/** @brief put part of the packet body, i.e. without headers, to structure.
* Used for easier data parsing, using get_packet_body_* functions. Mem is not copied.
* @param mem buffer with packet body part
* @param len number of available bytes in mem
* @param body pre-allocated body structure
*/
void packet_body_part_from_mem(pgp_packet_body_t *body, const void *mem, size_t len);
/* Packet handling functions */
/** @brief read OpenPGP packet from the stream, and write it's contents to another stream.
@ -261,38 +306,6 @@ rnp_result_t stream_skip_packet(pgp_source_t *src);
rnp_result_t stream_parse_marker(pgp_source_t &src);
/* Symmetric-key encrypted session key */
bool stream_write_sk_sesskey(pgp_sk_sesskey_t *skey, pgp_dest_t *dst);
rnp_result_t stream_parse_sk_sesskey(pgp_source_t *src, pgp_sk_sesskey_t *skey);
/* Public-key encrypted session key */
bool stream_write_pk_sesskey(pgp_pk_sesskey_t *pkey, pgp_dest_t *dst);
rnp_result_t stream_parse_pk_sesskey(pgp_source_t *src, pgp_pk_sesskey_t *pkey);
/* One-pass signature */
bool stream_write_one_pass(pgp_one_pass_sig_t *onepass, pgp_dest_t *dst);
rnp_result_t stream_parse_one_pass(pgp_source_t *src, pgp_one_pass_sig_t *onepass);
/* Signature */
bool stream_write_signature(const pgp_signature_t *sig, pgp_dest_t *dst);
bool write_signature_material(pgp_signature_t &sig, const pgp_signature_material_t &material);
bool signature_parse_subpacket(pgp_sig_subpkt_t &subpkt);
rnp_result_t stream_parse_signature_body(pgp_packet_body_t *pkt, pgp_signature_t *sig);
rnp_result_t stream_parse_signature(pgp_source_t *src, pgp_signature_t *sig);
bool parse_signature_material(const pgp_signature_t &sig, pgp_signature_material_t &material);
/* Public/Private key or Subkey */
bool is_key_pkt(int tag);
@ -307,18 +320,4 @@ bool is_secret_key_pkt(int tag);
bool is_rsa_key_alg(pgp_pubkey_alg_t alg);
bool key_fill_hashed_data(pgp_key_pkt_t *key);
bool stream_write_key(pgp_key_pkt_t *key, pgp_dest_t *dst);
rnp_result_t stream_parse_key(pgp_source_t *src, pgp_key_pkt_t *key);
bool key_pkt_equal(const pgp_key_pkt_t *key1, const pgp_key_pkt_t *key2, bool pubonly);
/* User ID packet */
bool stream_write_userid(const pgp_userid_pkt_t *userid, pgp_dest_t *dst);
rnp_result_t stream_parse_userid(pgp_source_t *src, pgp_userid_pkt_t *userid);
#endif

267
third_party/rnp/src/librepgp/stream-parse.cpp поставляемый
Просмотреть файл

@ -116,7 +116,10 @@ typedef struct pgp_source_signed_param_t {
uint8_t out[CT_BUF_LEN]; /* cleartext output cache for easier parsing */
size_t outlen; /* total bytes in out */
size_t outpos; /* offset of first available byte in out */
bool lastcr; /* text sig: last char of previous chunk was cr */
bool max_line_warn; /* warning about too long line is already issued */
size_t text_line_len; /* length of a current line in a text document */
long stripped_crs; /* number of trailing CR characters stripped from the end of the last
processed chunk */
std::vector<pgp_one_pass_sig_t> onepasses; /* list of one-pass singatures */
std::list<pgp_signature_t> sigs; /* list of signatures */
@ -779,6 +782,18 @@ signed_validate_signature(pgp_source_signed_param_t *param, pgp_signature_info_t
signature_check(sinfo, &shash);
}
static long
stripped_line_len(uint8_t *begin, uint8_t *end)
{
uint8_t *stripped_end = end;
while (stripped_end >= begin && (*stripped_end == CH_CR || *stripped_end == CH_LF)) {
stripped_end--;
}
return stripped_end - begin + 1;
}
static void
signed_src_update(pgp_source_t *src, const void *buf, size_t len)
{
@ -797,40 +812,57 @@ signed_src_update(pgp_source_t *src, const void *buf, size_t len)
if (param->txt_hashes.empty()) {
return;
}
/* check whether we had CR at the end of last chunk and LF at the beginning */
uint8_t *ch = (uint8_t *) buf;
if (param->lastcr && (*ch == CH_LF)) {
ch++;
}
uint8_t *linebeg = ch;
uint8_t *end = (uint8_t *) buf + len;
/* we support CR, LF and CRLF line endings */
/* we support LF and CRLF line endings */
while (ch < end) {
/* continue if not reached CR or LF */
if ((*ch != CH_CR) && (*ch != CH_LF)) {
/* continue if not reached LF */
if (*ch != CH_LF) {
if (*ch != CH_CR && param->stripped_crs > 0) {
while (param->stripped_crs--) {
pgp_hash_list_update(param->txt_hashes, ST_CR, 1);
}
param->stripped_crs = 0;
}
if (!param->max_line_warn && param->text_line_len >= MAXIMUM_GNUPG_LINELEN) {
RNP_LOG("Canonical text document signature: line is too long, may cause "
"incompatibility with other implementations. Consider using binary "
"signature instead.");
param->max_line_warn = true;
}
ch++;
param->text_line_len++;
continue;
}
/* reached eol: dump line contents */
param->stripped_crs = 0;
param->text_line_len = 0;
if (ch > linebeg) {
pgp_hash_list_update(param->txt_hashes, linebeg, ch - linebeg);
long stripped_len = stripped_line_len(linebeg, ch);
if (stripped_len > 0) {
pgp_hash_list_update(param->txt_hashes, linebeg, stripped_len);
}
}
/* dump EOL */
pgp_hash_list_update(param->txt_hashes, ST_CRLF, 2);
/* skip one more char if we have CRLF */
if ((*ch == CH_CR) && ((ch + 1 < end) && (*(ch + 1) == CH_LF))) {
ch++;
}
ch++;
linebeg = ch;
}
/* check if we have undumped line contents */
if (linebeg < end) {
pgp_hash_list_update(param->txt_hashes, linebeg, end - linebeg);
long stripped_len = stripped_line_len(linebeg, end - 1);
if (stripped_len < end - linebeg) {
param->stripped_crs = end - linebeg - stripped_len;
}
if (stripped_len > 0) {
pgp_hash_list_update(param->txt_hashes, linebeg, stripped_len);
}
}
/* set lastcr to true to correctly react to case when CR is on the end of one chunk, and LF
* is at the beginning of the next chunk */
param->lastcr = *(end - 1) == CH_CR;
}
static bool
@ -859,51 +891,40 @@ signed_read_single_signature(pgp_source_signed_param_t *param,
pgp_source_t * readsrc,
pgp_signature_t ** sig)
{
uint8_t ptag;
int ptype;
pgp_signature_t readsig;
pgp_signature_info_t *siginfo;
uint8_t ptag;
if (!src_peek_eq(readsrc, &ptag, 1)) {
RNP_LOG("failed to read signature packet header");
return RNP_ERROR_READ;
}
ptype = get_packet_type(ptag);
int ptype = get_packet_type(ptag);
if (ptype != PGP_PKT_SIGNATURE) {
RNP_LOG("unexpected packet %d", ptype);
return RNP_ERROR_BAD_FORMAT;
}
try {
param->siginfos.push_back({});
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
siginfo = &param->siginfos.back();
if (stream_parse_signature(readsrc, &readsig) != RNP_SUCCESS) {
RNP_LOG("failed to parse signature");
siginfo->unknown = true;
param->siginfos.emplace_back();
pgp_signature_info_t &siginfo = param->siginfos.back();
pgp_signature_t readsig;
if (readsig.parse(*readsrc)) {
RNP_LOG("failed to parse signature");
siginfo.unknown = true;
if (sig) {
*sig = NULL;
}
return RNP_SUCCESS;
}
param->sigs.push_back(std::move(readsig));
siginfo.sig = &param->sigs.back();
if (sig) {
*sig = NULL;
*sig = siginfo.sig;
}
return RNP_SUCCESS;
}
try {
param->sigs.push_back(std::move(readsig));
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
}
siginfo->sig = &param->sigs.back();
if (sig) {
*sig = &param->sigs.back();
}
return RNP_SUCCESS;
}
static rnp_result_t
@ -1143,7 +1164,9 @@ cleartext_process_line(pgp_source_t *src, const uint8_t *buf, size_t len, bool e
/* if we have eol after this line then strip trailing spaces and tabs */
if (eol) {
for (; (bufen >= buf) && ((*bufen == CH_SPACE) || (*bufen == CH_TAB)); bufen--)
for (; (bufen >= buf) &&
((*bufen == CH_SPACE) || (*bufen == CH_TAB) || (*bufen == CH_CR));
bufen--)
;
}
@ -1339,20 +1362,25 @@ encrypted_try_key(pgp_source_encrypted_param_t *param,
{
uint8_t decbuf[PGP_MPINT_SIZE];
rnp_result_t err;
size_t declen;
size_t keylen;
pgp_fingerprint_t fingerprint;
pgp_symm_alg_t salg;
unsigned checksum = 0;
bool res = false;
pgp_key_material_t *keymaterial = &seckey->material;
pgp_encrypted_material_t encmaterial;
try {
if (!sesskey->parse_material(encmaterial)) {
return false;
}
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
/* Decrypting session key value */
size_t declen = 0;
switch (sesskey->alg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY:
err =
rsa_decrypt_pkcs1(rng, decbuf, &declen, &sesskey->material.rsa, &keymaterial->rsa);
err = rsa_decrypt_pkcs1(rng, decbuf, &declen, &encmaterial.rsa, &keymaterial->rsa);
if (err) {
RNP_LOG("RSA decryption failure");
return false;
@ -1360,7 +1388,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param,
break;
case PGP_PKA_SM2:
declen = sizeof(decbuf);
err = sm2_decrypt(decbuf, &declen, &sesskey->material.sm2, &keymaterial->ec);
err = sm2_decrypt(decbuf, &declen, &encmaterial.sm2, &keymaterial->ec);
if (err != RNP_SUCCESS) {
RNP_LOG("SM2 decryption failure, error %x", (int) err);
return false;
@ -1369,7 +1397,7 @@ encrypted_try_key(pgp_source_encrypted_param_t *param,
case PGP_PKA_ELGAMAL:
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: {
const rnp_result_t ret =
elgamal_decrypt_pkcs1(rng, decbuf, &declen, &sesskey->material.eg, &keymaterial->eg);
elgamal_decrypt_pkcs1(rng, decbuf, &declen, &encmaterial.eg, &keymaterial->eg);
if (ret) {
RNP_LOG("ElGamal decryption failure [%X]", ret);
return false;
@ -1377,13 +1405,14 @@ encrypted_try_key(pgp_source_encrypted_param_t *param,
break;
}
case PGP_PKA_ECDH: {
if (pgp_fingerprint(fingerprint, seckey)) {
pgp_fingerprint_t fingerprint;
if (pgp_fingerprint(fingerprint, *seckey)) {
RNP_LOG("ECDH fingerprint calculation failed");
return false;
}
declen = sizeof(decbuf);
err = ecdh_decrypt_pkcs5(
decbuf, &declen, &sesskey->material.ecdh, &keymaterial->ec, fingerprint);
decbuf, &declen, &encmaterial.ecdh, &keymaterial->ec, fingerprint);
if (err != RNP_SUCCESS) {
RNP_LOG("ECDH decryption error %u", err);
return false;
@ -1396,19 +1425,20 @@ encrypted_try_key(pgp_source_encrypted_param_t *param,
}
/* Check algorithm and key length */
salg = (pgp_symm_alg_t) decbuf[0];
pgp_symm_alg_t salg = (pgp_symm_alg_t) decbuf[0];
if (!pgp_is_sa_supported(salg)) {
RNP_LOG("unsupported symmetric algorithm %d", (int) salg);
return false;
}
keylen = pgp_key_size(salg);
size_t keylen = pgp_key_size(salg);
if (declen != keylen + 3) {
RNP_LOG("invalid symmetric key length");
return false;
}
/* Validate checksum */
unsigned checksum = 0;
for (unsigned i = 1; i <= keylen; i++) {
checksum += decbuf[i];
}
@ -1601,7 +1631,7 @@ init_packet_params(pgp_source_packet_param_t *param)
param->partial = true;
param->origsrc = param->readsrc;
param->readsrc = partsrc;
} else if (stream_intedeterminate_pkt_len(param->readsrc)) {
} else if (stream_old_indeterminate_pkt_len(param->readsrc)) {
param->indeterminate = true;
src_skip(param->readsrc, 1);
} else {
@ -1680,7 +1710,13 @@ init_literal_src(pgp_source_t *src, pgp_source_t *readsrc)
((uint32_t) tstbuf[2] << 8) | (uint32_t) tstbuf[3];
if (!param->pkt.indeterminate && !param->pkt.partial) {
src->size = param->pkt.len - (1 + 1 + bt + 4);
/* format filename-length filename timestamp */
const uint16_t nbytes = 1 + 1 + bt + 4;
if (param->pkt.len < nbytes) {
ret = RNP_ERROR_BAD_FORMAT;
goto finish;
}
src->size = param->pkt.len - nbytes;
src->knownsize = 1;
}
@ -1819,59 +1855,64 @@ get_aead_src_hdr(pgp_source_t *src, pgp_aead_hdr_t *hdr)
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;
pgp_pk_sesskey_t pkey;
int ptype;
/* 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);
if (ptype == PGP_PKT_SK_SESSION_KEY) {
if ((errcode = stream_parse_sk_sesskey(param->pkt.readsrc, &skey))) {
return errcode;
try {
bool stop = false;
while (!stop) {
uint8_t ptag;
if (!src_peek_eq(param->pkt.readsrc, &ptag, 1)) {
RNP_LOG("failed to read packet header");
return RNP_ERROR_READ;
}
try {
ptype = get_packet_type(ptag);
switch (ptype) {
case PGP_PKT_SK_SESSION_KEY: {
pgp_sk_sesskey_t skey;
rnp_result_t ret = skey.parse(*param->pkt.readsrc);
if (ret) {
return ret;
}
param->symencs.push_back(skey);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
break;
}
} else if (ptype == PGP_PKT_PK_SESSION_KEY) {
if ((errcode = stream_parse_pk_sesskey(param->pkt.readsrc, &pkey))) {
return errcode;
}
try {
case PGP_PKT_PK_SESSION_KEY: {
pgp_pk_sesskey_t pkey;
rnp_result_t ret = pkey.parse(*param->pkt.readsrc);
if (ret) {
return ret;
}
param->pubencs.push_back(pkey);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_OUT_OF_MEMORY;
break;
}
case PGP_PKT_SE_DATA:
case PGP_PKT_SE_IP_DATA:
case PGP_PKT_AEAD_ENCRYPTED:
stop = true;
break;
default:
RNP_LOG("unknown packet type: %d", ptype);
return RNP_ERROR_BAD_FORMAT;
}
} else if ((ptype == PGP_PKT_SE_DATA) || (ptype == PGP_PKT_SE_IP_DATA) ||
(ptype == PGP_PKT_AEAD_ENCRYPTED)) {
break;
} else {
RNP_LOG("unknown packet type: %d", ptype);
return RNP_ERROR_BAD_FORMAT;
}
} catch (const rnp::rnp_exception &e) {
RNP_LOG("%s: %d", e.what(), e.code());
return e.code();
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_GENERIC;
}
/* Reading packet length/checking whether it is partial */
if ((errcode = init_packet_params(&param->pkt))) {
rnp_result_t errcode = init_packet_params(&param->pkt);
if (errcode) {
return errcode;
}
/* Reading header of encrypted packet */
if (ptype == PGP_PKT_AEAD_ENCRYPTED) {
param->aead = true;
uint8_t hdr[4];
if (!src_peek_eq(param->pkt.readsrc, hdr, 4)) {
return RNP_ERROR_READ;
}
@ -1902,6 +1943,7 @@ encrypted_read_packet_data(pgp_source_encrypted_param_t *param)
memcpy(param->aead_ad + 1, hdr, 4);
memset(param->aead_ad + 5, 0, 8);
} else if (ptype == PGP_PKT_SE_IP_DATA) {
uint8_t mdcver;
if (!src_read_eq(param->pkt.readsrc, &mdcver, 1)) {
return RNP_ERROR_READ;
}
@ -1988,7 +2030,7 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t
continue;
}
/* Decrypt key */
if (pgp_key_is_encrypted(seckey)) {
if (seckey->encrypted()) {
pgp_password_ctx_t pass_ctx{.op = PGP_OP_DECRYPT, .key = seckey};
decrypted_seckey =
pgp_decrypt_seckey(seckey, handler->password_provider, &pass_ctx);
@ -1997,7 +2039,7 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t
continue;
}
} else {
decrypted_seckey = &(seckey->pkt);
decrypted_seckey = &seckey->pkt();
}
/* Try to initialize the decryption */
@ -2011,7 +2053,7 @@ init_encrypted_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t
}
/* Destroy decrypted key */
if (pgp_key_is_encrypted(seckey)) {
if (seckey->encrypted()) {
delete decrypted_seckey;
decrypted_seckey = NULL;
}
@ -2107,6 +2149,8 @@ pgp_source_signed_param_t::~pgp_source_signed_param_t()
}
}
#define MAX_SIG_ERRORS 65536
static rnp_result_t
init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *readsrc)
{
@ -2116,6 +2160,7 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
int ptype;
pgp_signature_t * sig = NULL;
bool cleartext;
size_t sigerrors = 0;
if (!init_src_common(src, 0)) {
return RNP_ERROR_OUT_OF_MEMORY;
@ -2132,6 +2177,7 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
param->readsrc = readsrc;
param->handler = handler;
param->cleartext = cleartext;
param->stripped_crs = 0;
src->read = cleartext ? cleartext_src_read : signed_src_read;
src->close = signed_src_close;
src->finish = signed_src_finish;
@ -2151,6 +2197,13 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
/* Reading one-pass and signature packets */
while (true) {
/* stop early if we are in zip-bomb with erroneous packets */
if (sigerrors >= MAX_SIG_ERRORS) {
RNP_LOG("Too many one-pass/signature errors. Stopping.");
errcode = RNP_ERROR_BAD_FORMAT;
goto finish;
}
size_t readb = readsrc->readb;
if (!src_peek_eq(readsrc, &ptag, 1)) {
RNP_LOG("failed to read packet header");
@ -2161,8 +2214,12 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
ptype = get_packet_type(ptag);
if (ptype == PGP_PKT_ONE_PASS_SIG) {
pgp_one_pass_sig_t onepass = {};
errcode = stream_parse_one_pass(readsrc, &onepass);
pgp_one_pass_sig_t onepass;
try {
errcode = onepass.parse(*readsrc);
} catch (const std::exception &e) {
errcode = RNP_ERROR_GENERIC;
}
if (errcode) {
if (errcode == RNP_ERROR_READ) {
goto finish;
@ -2171,6 +2228,7 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
errcode = RNP_ERROR_BAD_FORMAT;
goto finish;
}
sigerrors++;
continue;
}
@ -2197,7 +2255,9 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
}
} else if (ptype == PGP_PKT_SIGNATURE) {
/* no need to check the error here - we already know tag */
signed_read_single_signature(param, readsrc, &sig);
if (signed_read_single_signature(param, readsrc, &sig)) {
sigerrors++;
}
/* adding hash context */
if (sig && !add_hash_for_sig(param, sig->type(), sig->halg)) {
RNP_LOG(
@ -2214,7 +2274,6 @@ init_signed_src(pgp_parse_handler_t *handler, pgp_source_t *src, pgp_source_t *r
errcode = RNP_ERROR_BAD_FORMAT;
goto finish;
}
/* for detached signature we'll get eof */
if (src_eof(readsrc)) {
param->detached = true;

1
third_party/rnp/src/librepgp/stream-parse.h поставляемый
Просмотреть файл

@ -33,6 +33,7 @@
#include "rnp.h"
#include "stream-common.h"
#include "stream-ctx.h"
#include "stream-packet.h"
typedef struct pgp_parse_handler_t pgp_parse_handler_t;
typedef struct pgp_signature_info_t pgp_signature_info_t;

636
third_party/rnp/src/librepgp/stream-sig.cpp поставляемый
Просмотреть файл

@ -58,8 +58,10 @@ signature_set_embedded_sig(pgp_signature_t *sig, pgp_signature_t *esig)
RNP_LOG("alloc failed");
return false;
}
if (!stream_write_signature(esig, &memdst)) {
RNP_LOG("failed to write signature");
try {
esig->write(memdst);
} catch (const std::exception &e) {
RNP_LOG("failed to write signature: %s", e.what());
goto finish;
}
if (init_mem_src(&memsrc, mem_dest_get_memory(&memdst), memdst.writeb, false)) {
@ -119,7 +121,7 @@ signature_add_notation_data(pgp_signature_t *sig,
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);
return subpkt.parse();
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
@ -129,45 +131,37 @@ signature_add_notation_data(pgp_signature_t *sig,
bool
signature_fill_hashed_data(pgp_signature_t *sig)
{
pgp_packet_body_t hbody;
bool res;
if (!sig) {
RNP_LOG("null signature");
return false;
}
/* we don't have a need to write v2-v3 signatures */
if ((sig->version < PGP_V2) || (sig->version > PGP_V4)) {
RNP_LOG("don't know version %d", (int) sig->version);
return false;
}
try {
pgp_packet_body_t hbody(PGP_PKT_RESERVED);
if (sig->version < PGP_V4) {
hbody.add_byte(sig->type());
hbody.add_uint32(sig->creation_time);
} else {
hbody.add_byte(sig->version);
hbody.add_byte(sig->type());
hbody.add_byte(sig->palg);
hbody.add_byte(sig->halg);
hbody.add_subpackets(*sig, true);
}
if (!init_packet_body(&hbody, PGP_PKT_RESERVED)) {
RNP_LOG("allocation failed");
free(sig->hashed_data);
sig->hashed_data = (uint8_t *) malloc(hbody.size());
if (!sig->hashed_data) {
RNP_LOG("allocation failed");
return false;
}
memcpy(sig->hashed_data, hbody.data(), hbody.size());
sig->hashed_len = hbody.size();
return true;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
if (sig->version < PGP_V4) {
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->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 */
sig->hashed_data = hbody.data;
sig->hashed_len = hbody.len;
return res;
}
free_packet_body(&hbody);
return res;
}
bool
@ -188,7 +182,8 @@ signature_hash_key(const pgp_key_pkt_t *key, pgp_hash_t *hash)
/* call self recursively if hashed data is not filled, to overcome const restriction */
try {
pgp_key_pkt_t keycp(*key, true);
return key_fill_hashed_data(&keycp) && signature_hash_key(&keycp, hash);
keycp.fill_hashed_data();
return signature_hash_key(&keycp, hash);
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
@ -327,9 +322,8 @@ signature_check(pgp_signature_info_t *sinfo, pgp_hash_t *hash)
}
/* Validate signature itself */
if (sinfo->signer_valid || sinfo->signer->valid) {
sinfo->valid =
!signature_validate(sinfo->sig, pgp_key_get_material(sinfo->signer), hash);
if (sinfo->signer_valid || sinfo->signer->valid()) {
sinfo->valid = !signature_validate(sinfo->sig, &sinfo->signer->material(), hash);
} else {
sinfo->valid = false;
RNP_LOG("invalid or untrusted key");
@ -351,21 +345,21 @@ signature_check(pgp_signature_info_t *sinfo, pgp_hash_t *hash)
}
/* check key creation time vs signature creation */
kcreate = pgp_key_get_creation(sinfo->signer);
kcreate = sinfo->signer->creation();
if (kcreate > create) {
RNP_LOG("key is newer than signature");
sinfo->valid = false;
}
/* 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)) {
if (!sinfo->ignore_expiry && sinfo->signer->expiration() &&
(kcreate + sinfo->signer->expiration() < create)) {
RNP_LOG("signature made after key expiration");
sinfo->valid = false;
}
/* Check signer's fingerprint */
if (sinfo->sig->has_keyfp() && (sinfo->sig->keyfp() != pgp_key_get_fp(sinfo->signer))) {
if (sinfo->sig->has_keyfp() && (sinfo->sig->keyfp() != sinfo->signer->fp())) {
RNP_LOG("issuer fingerprint doesn't match signer's one");
sinfo->valid = false;
}
@ -402,7 +396,7 @@ signature_check_binding(pgp_signature_info_t *sinfo,
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)) {
if (!signature_hash_binding(sinfo->sig, key, &subkey->pkt(), &hash)) {
return RNP_ERROR_BAD_FORMAT;
}
@ -433,7 +427,7 @@ signature_check_binding(pgp_signature_info_t *sinfo,
return res;
}
if (!signature_hash_binding(subpkt->fields.sig, key, pgp_key_get_pkt(subkey), &hash)) {
if (!signature_hash_binding(subpkt->fields.sig, key, &subkey->pkt(), &hash)) {
return RNP_ERROR_BAD_FORMAT;
}
pgp_signature_info_t bindinfo = {};
@ -504,15 +498,14 @@ armoredpass:
try {
sigs.emplace_back();
if ((ret = sigs.back().parse(*src))) {
goto finish;
}
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
ret = RNP_ERROR_OUT_OF_MEMORY;
goto finish;
}
if ((ret = stream_parse_signature(src, &sigs.back()))) {
sigs.pop_back();
goto finish;
}
}
/* file may have multiple armored keys */
@ -545,7 +538,7 @@ pgp_sig_subpkt_t::pgp_sig_subpkt_t(const pgp_sig_subpkt_t &src)
critical = src.critical;
hashed = src.hashed;
parsed = false;
signature_parse_subpacket(*this);
parse();
}
pgp_sig_subpkt_t::pgp_sig_subpkt_t(pgp_sig_subpkt_t &&src)
@ -606,10 +599,194 @@ pgp_sig_subpkt_t::operator=(const pgp_sig_subpkt_t &src)
hashed = src.hashed;
parsed = false;
fields = {};
signature_parse_subpacket(*this);
parse();
return *this;
}
bool
pgp_sig_subpkt_t::parse()
{
bool oklen = true;
bool checked = true;
switch (type) {
case PGP_SIG_SUBPKT_CREATION_TIME:
if (!hashed) {
RNP_LOG("creation time subpacket must be hashed");
checked = false;
}
if ((oklen = len == 4)) {
fields.create = read_uint32(data);
}
break;
case PGP_SIG_SUBPKT_EXPIRATION_TIME:
case PGP_SIG_SUBPKT_KEY_EXPIRY:
if ((oklen = len == 4)) {
fields.expiry = read_uint32(data);
}
break;
case PGP_SIG_SUBPKT_EXPORT_CERT:
if ((oklen = len == 1)) {
fields.exportable = data[0] != 0;
}
break;
case PGP_SIG_SUBPKT_TRUST:
if ((oklen = len == 2)) {
fields.trust.level = data[0];
fields.trust.amount = data[1];
}
break;
case PGP_SIG_SUBPKT_REGEXP:
fields.regexp.str = (const char *) data;
fields.regexp.len = len;
break;
case PGP_SIG_SUBPKT_REVOCABLE:
if ((oklen = len == 1)) {
fields.revocable = data[0] != 0;
}
break;
case PGP_SIG_SUBPKT_PREFERRED_SKA:
case PGP_SIG_SUBPKT_PREFERRED_HASH:
case PGP_SIG_SUBPKT_PREF_COMPRESS:
case PGP_SIG_SUBPKT_PREFERRED_AEAD:
fields.preferred.arr = data;
fields.preferred.len = len;
break;
case PGP_SIG_SUBPKT_REVOCATION_KEY:
if ((oklen = len == 22)) {
fields.revocation_key.klass = data[0];
fields.revocation_key.pkalg = (pgp_pubkey_alg_t) data[1];
fields.revocation_key.fp = &data[2];
}
break;
case PGP_SIG_SUBPKT_ISSUER_KEY_ID:
if ((oklen = len == 8)) {
fields.issuer = data;
}
break;
case PGP_SIG_SUBPKT_NOTATION_DATA:
if ((oklen = len >= 8)) {
memcpy(fields.notation.flags, data, 4);
fields.notation.nlen = read_uint16(&data[4]);
fields.notation.vlen = read_uint16(&data[6]);
if (len != 8 + fields.notation.nlen + fields.notation.vlen) {
oklen = false;
} else {
fields.notation.name = (const char *) &data[8];
fields.notation.value = (const char *) &data[8 + fields.notation.nlen];
}
}
break;
case PGP_SIG_SUBPKT_KEYSERV_PREFS:
if ((oklen = len >= 1)) {
fields.ks_prefs.no_modify = (data[0] & 0x80) != 0;
}
break;
case PGP_SIG_SUBPKT_PREF_KEYSERV:
fields.preferred_ks.uri = (const char *) data;
fields.preferred_ks.len = len;
break;
case PGP_SIG_SUBPKT_PRIMARY_USER_ID:
if ((oklen = len == 1)) {
fields.primary_uid = data[0] != 0;
}
break;
case PGP_SIG_SUBPKT_POLICY_URI:
fields.policy.uri = (const char *) data;
fields.policy.len = len;
break;
case PGP_SIG_SUBPKT_KEY_FLAGS:
if ((oklen = len >= 1)) {
fields.key_flags = data[0];
}
break;
case PGP_SIG_SUBPKT_SIGNERS_USER_ID:
fields.signer.uid = (const char *) data;
fields.signer.len = len;
break;
case PGP_SIG_SUBPKT_REVOCATION_REASON:
if ((oklen = len >= 1)) {
fields.revocation_reason.code = (pgp_revocation_type_t) data[0];
fields.revocation_reason.str = (const char *) &data[1];
fields.revocation_reason.len = len - 1;
}
break;
case PGP_SIG_SUBPKT_FEATURES:
if ((oklen = len >= 1)) {
fields.features = data[0];
}
break;
case PGP_SIG_SUBPKT_SIGNATURE_TARGET:
if ((oklen = len >= 18)) {
fields.sig_target.pkalg = (pgp_pubkey_alg_t) data[0];
fields.sig_target.halg = (pgp_hash_alg_t) data[1];
fields.sig_target.hash = &data[2];
fields.sig_target.hlen = len - 2;
}
break;
case PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE:
try {
/* parse signature */
pgp_packet_body_t pkt(data, len);
pgp_signature_t sig;
oklen = checked = !sig.parse(pkt);
if (checked) {
fields.sig = new pgp_signature_t(std::move(sig));
}
break;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return false;
}
case PGP_SIG_SUBPKT_ISSUER_FPR:
if ((oklen = len >= 21)) {
fields.issuer_fp.version = data[0];
fields.issuer_fp.fp = &data[1];
fields.issuer_fp.len = len - 1;
}
break;
case PGP_SIG_SUBPKT_PRIVATE_100:
case PGP_SIG_SUBPKT_PRIVATE_101:
case PGP_SIG_SUBPKT_PRIVATE_102:
case PGP_SIG_SUBPKT_PRIVATE_103:
case PGP_SIG_SUBPKT_PRIVATE_104:
case PGP_SIG_SUBPKT_PRIVATE_105:
case PGP_SIG_SUBPKT_PRIVATE_106:
case PGP_SIG_SUBPKT_PRIVATE_107:
case PGP_SIG_SUBPKT_PRIVATE_108:
case PGP_SIG_SUBPKT_PRIVATE_109:
case PGP_SIG_SUBPKT_PRIVATE_110:
oklen = true;
checked = !critical;
if (!checked) {
RNP_LOG("unknown critical private subpacket %d", (int) type);
}
break;
case PGP_SIG_SUBPKT_RESERVED_1:
case PGP_SIG_SUBPKT_RESERVED_8:
case PGP_SIG_SUBPKT_PLACEHOLDER:
case PGP_SIG_SUBPKT_RESERVED_13:
case PGP_SIG_SUBPKT_RESERVED_14:
case PGP_SIG_SUBPKT_RESERVED_15:
case PGP_SIG_SUBPKT_RESERVED_17:
case PGP_SIG_SUBPKT_RESERVED_18:
case PGP_SIG_SUBPKT_RESERVED_19:
/* do not report reserved/placeholder subpacket */
return !critical;
default:
RNP_LOG("unknown subpacket : %d", (int) type);
return !critical;
}
if (!oklen) {
RNP_LOG("wrong len %d of subpacket type %d", (int) len, (int) type);
} else {
parsed = 1;
}
return oklen && checked;
}
pgp_sig_subpkt_t::~pgp_sig_subpkt_t()
{
if (parsed && (type == PGP_SIG_SUBPKT_EMBEDDED_SIGNATURE)) {
@ -755,6 +932,24 @@ pgp_signature_t::~pgp_signature_t()
free(material_buf);
}
pgp_sig_id_t
pgp_signature_t::get_id() const
{
pgp_hash_t hash = {};
if (!pgp_hash_create(&hash, PGP_HASH_SHA1)) {
RNP_LOG("bad sha1 alloc");
throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
}
pgp_hash_add(&hash, hashed_data, hashed_len);
pgp_hash_add(&hash, material_buf, material_len);
pgp_sig_id_t res;
static_assert(std::tuple_size<decltype(res)>::value == PGP_SHA1_HASH_SIZE,
"pgp_sig_id_t size mismatch");
pgp_hash_finish(&hash, res.data());
return res;
}
pgp_sig_subpkt_t *
pgp_signature_t::get_subpkt(pgp_sig_subpacket_type_t stype, bool hashed)
{
@ -1183,7 +1378,7 @@ pgp_signature_t::set_revocation_reason(pgp_revocation_type_t code, const std::st
subpkt.data[0] = code;
memcpy(subpkt.data + 1, reason.data(), reason.size());
if (!signature_parse_subpacket(subpkt)) {
if (!subpkt.parse()) {
throw rnp::rnp_exception(RNP_ERROR_BAD_STATE);
}
}
@ -1271,3 +1466,342 @@ pgp_signature_t::matches_onepass(const pgp_one_pass_sig_t &onepass) const
return (halg == onepass.halg) && (palg == onepass.palg) && (type_ == onepass.type) &&
(onepass.keyid == keyid());
}
rnp_result_t
pgp_signature_t::parse_v3(pgp_packet_body_t &pkt)
{
/* parse v3-specific fields, not the whole signature */
uint8_t buf[16] = {};
if (!pkt.get(buf, 16)) {
RNP_LOG("cannot get enough bytes");
return RNP_ERROR_BAD_FORMAT;
}
/* length of hashed data, 5 */
if (buf[0] != 5) {
RNP_LOG("wrong length of hashed data");
return RNP_ERROR_BAD_FORMAT;
}
/* hashed data */
free(hashed_data);
if (!(hashed_data = (uint8_t *) malloc(5))) {
RNP_LOG("allocation failed");
return RNP_ERROR_OUT_OF_MEMORY;
}
memcpy(hashed_data, &buf[1], 5);
hashed_len = 5;
/* signature type */
type_ = (pgp_sig_type_t) buf[1];
/* creation time */
creation_time = read_uint32(&buf[2]);
/* signer's key id */
static_assert(std::tuple_size<decltype(signer)>::value == PGP_KEY_ID_SIZE,
"v3 signer field size mismatch");
memcpy(signer.data(), &buf[6], PGP_KEY_ID_SIZE);
/* public key algorithm */
palg = (pgp_pubkey_alg_t) buf[14];
/* hash algorithm */
halg = (pgp_hash_alg_t) buf[15];
return RNP_SUCCESS;
}
bool
pgp_signature_t::parse_subpackets(uint8_t *buf, size_t len, bool hashed)
{
bool res = true;
while (len > 0) {
if (len < 2) {
RNP_LOG("got single byte %d", (int) *buf);
return false;
}
/* subpacket length */
size_t splen;
if (*buf < 192) {
splen = *buf;
buf++;
len--;
} else if (*buf < 255) {
splen = ((buf[0] - 192) << 8) + buf[1] + 192;
buf += 2;
len -= 2;
} else {
if (len < 5) {
RNP_LOG("got 4-byte len but only %d bytes in buffer", (int) len);
return false;
}
splen = read_uint32(&buf[1]);
buf += 5;
len -= 5;
}
if (splen < 1) {
RNP_LOG("got subpacket with 0 length, skipping");
continue;
}
/* subpacket data */
if (len < splen) {
RNP_LOG("got subpacket len %d, while only %d bytes left", (int) splen, (int) len);
return false;
}
pgp_sig_subpkt_t subpkt;
if (!(subpkt.data = (uint8_t *) malloc(splen - 1))) {
RNP_LOG("subpacket data allocation failed");
return false;
}
subpkt.type = (pgp_sig_subpacket_type_t)(*buf & 0x7f);
subpkt.critical = !!(*buf & 0x80);
subpkt.hashed = hashed;
subpkt.parsed = 0;
memcpy(subpkt.data, buf + 1, splen - 1);
subpkt.len = splen - 1;
res = res && subpkt.parse();
subpkts.push_back(std::move(subpkt));
len -= splen;
buf += splen;
}
return res;
}
rnp_result_t
pgp_signature_t::parse_v4(pgp_packet_body_t &pkt)
{
/* parse v4-specific fields, not the whole signature */
uint8_t buf[5];
if (!pkt.get(buf, 5)) {
RNP_LOG("cannot get first 5 bytes");
return RNP_ERROR_BAD_FORMAT;
}
/* signature type */
type_ = (pgp_sig_type_t) buf[0];
/* public key algorithm */
palg = (pgp_pubkey_alg_t) buf[1];
/* hash algorithm */
halg = (pgp_hash_alg_t) buf[2];
/* hashed subpackets length */
uint16_t splen = read_uint16(&buf[3]);
/* hashed subpackets length + 2 bytes of length of unhashed subpackets */
if (pkt.left() < splen + 2) {
RNP_LOG("wrong packet or hashed subpackets length");
return RNP_ERROR_BAD_FORMAT;
}
/* building hashed data */
free(hashed_data);
if (!(hashed_data = (uint8_t *) malloc(splen + 6))) {
RNP_LOG("allocation failed");
return RNP_ERROR_OUT_OF_MEMORY;
}
hashed_data[0] = version;
memcpy(hashed_data + 1, buf, 5);
if (!pkt.get(hashed_data + 6, splen)) {
RNP_LOG("cannot get hashed subpackets data");
return RNP_ERROR_BAD_FORMAT;
}
hashed_len = splen + 6;
/* parsing hashed subpackets */
if (!parse_subpackets(hashed_data + 6, splen, true)) {
RNP_LOG("failed to parse hashed subpackets");
return RNP_ERROR_BAD_FORMAT;
}
/* reading unhashed subpackets */
if (!pkt.get(splen)) {
RNP_LOG("cannot get unhashed len");
return RNP_ERROR_BAD_FORMAT;
}
if (pkt.left() < splen) {
RNP_LOG("not enough data for unhashed subpackets");
return RNP_ERROR_BAD_FORMAT;
}
std::vector<uint8_t> spbuf(splen);
if (!pkt.get(spbuf.data(), splen)) {
RNP_LOG("read of unhashed subpackets failed");
return RNP_ERROR_READ;
}
if (!parse_subpackets(spbuf.data(), splen, false)) {
RNP_LOG("failed to parse unhashed subpackets");
return RNP_ERROR_BAD_FORMAT;
}
return RNP_SUCCESS;
}
rnp_result_t
pgp_signature_t::parse(pgp_packet_body_t &pkt)
{
uint8_t ver = 0;
if (!pkt.get(ver)) {
return RNP_ERROR_BAD_FORMAT;
}
version = (pgp_version_t) ver;
/* v3 or v4 signature body */
rnp_result_t res;
if ((ver == PGP_V2) || (ver == PGP_V3)) {
res = parse_v3(pkt);
} else if (ver == PGP_V4) {
res = parse_v4(pkt);
} else {
RNP_LOG("unknown signature version: %d", (int) ver);
res = RNP_ERROR_BAD_FORMAT;
}
if (res) {
return res;
}
/* left 16 bits of the hash */
if (!pkt.get(lbits, 2)) {
RNP_LOG("not enough data for hash left bits");
return RNP_ERROR_BAD_FORMAT;
}
/* raw signature material */
material_len = pkt.left();
if (!material_len) {
RNP_LOG("No signature material");
return RNP_ERROR_BAD_FORMAT;
}
material_buf = (uint8_t *) malloc(material_len);
if (!material_buf) {
RNP_LOG("Allocation failed");
return RNP_ERROR_OUT_OF_MEMORY;
}
/* we cannot fail here */
pkt.get(material_buf, material_len);
/* check whether it can be parsed */
pgp_signature_material_t material = {};
if (!parse_material(material)) {
return RNP_ERROR_BAD_FORMAT;
}
return RNP_SUCCESS;
}
rnp_result_t
pgp_signature_t::parse(pgp_source_t &src)
{
pgp_packet_body_t pkt(PGP_PKT_SIGNATURE);
rnp_result_t res = pkt.read(src);
if (res) {
return res;
}
return parse(pkt);
}
bool
pgp_signature_t::parse_material(pgp_signature_material_t &material) const
{
pgp_packet_body_t pkt(material_buf, material_len);
switch (palg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_SIGN_ONLY:
if (!pkt.get(material.rsa.s)) {
return false;
}
break;
case PGP_PKA_DSA:
if (!pkt.get(material.dsa.r) || !pkt.get(material.dsa.s)) {
return false;
}
break;
case PGP_PKA_EDDSA:
if (version < PGP_V4) {
RNP_LOG("Warning! v3 EdDSA signature.");
}
/* FALLTHROUGH */
case PGP_PKA_ECDSA:
case PGP_PKA_SM2:
case PGP_PKA_ECDH:
if (!pkt.get(material.ecc.r) || !pkt.get(material.ecc.s)) {
return false;
}
break;
case PGP_PKA_ELGAMAL: /* we support reading it but will not validate */
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
if (!pkt.get(material.eg.r) || !pkt.get(material.eg.s)) {
return false;
}
break;
default:
RNP_LOG("Unknown pk algorithm : %d", (int) palg);
return false;
}
if (pkt.left()) {
RNP_LOG("extra %d bytes in signature packet", (int) pkt.left());
return false;
}
return true;
}
void
pgp_signature_t::write(pgp_dest_t &dst) const
{
if ((version < PGP_V2) || (version > PGP_V4)) {
RNP_LOG("don't know version %d", (int) version);
throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
}
pgp_packet_body_t pktbody(PGP_PKT_SIGNATURE);
if (version < PGP_V4) {
/* for v3 signatures hashed data includes only type + creation_time */
pktbody.add_byte(version);
pktbody.add_byte(hashed_len);
pktbody.add(hashed_data, hashed_len);
pktbody.add(signer);
pktbody.add_byte(palg);
pktbody.add_byte(halg);
} else {
/* for v4 sig->hashed_data must contain most of signature fields */
pktbody.add(hashed_data, hashed_len);
pktbody.add_subpackets(*this, false);
}
pktbody.add(lbits, 2);
/* write mpis */
pktbody.add(material_buf, material_len);
pktbody.write(dst);
}
void
pgp_signature_t::write_material(const pgp_signature_material_t &material)
{
pgp_packet_body_t pktbody(PGP_PKT_SIGNATURE);
switch (palg) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_SIGN_ONLY:
pktbody.add(material.rsa.s);
break;
case PGP_PKA_DSA:
pktbody.add(material.dsa.r);
pktbody.add(material.dsa.s);
break;
case PGP_PKA_EDDSA:
case PGP_PKA_ECDSA:
case PGP_PKA_SM2:
case PGP_PKA_ECDH:
pktbody.add(material.ecc.r);
pktbody.add(material.ecc.s);
break;
case PGP_PKA_ELGAMAL: /* we support writing it but will not generate */
case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
pktbody.add(material.eg.r);
pktbody.add(material.eg.s);
break;
default:
RNP_LOG("Unknown pk algorithm : %d", (int) palg);
throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS);
}
free(material_buf);
material_buf = (uint8_t *) malloc(pktbody.size());
if (!material_buf) {
RNP_LOG("allocation failed");
throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY);
}
memcpy(material_buf, pktbody.data(), pktbody.size());
material_len = pktbody.size();
}

343
third_party/rnp/src/librepgp/stream-sig.h поставляемый
Просмотреть файл

@ -32,21 +32,344 @@
#include <sys/types.h>
#include "rnp.h"
#include "stream-common.h"
#include "stream-packet.h"
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);
rnp_result_t parse_v3(pgp_packet_body_t &pkt);
rnp_result_t parse_v4(pgp_packet_body_t &pkt);
bool parse_subpackets(uint8_t *buf, size_t len, bool hashed);
public:
pgp_version_t version;
/* common v3 and v4 fields */
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()
: 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 Calculate the unique signature identifier by hashing signature's fields. */
pgp_sig_id_t get_id() const;
/**
* @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;
/**
* @brief Parse signature body (i.e. without checking the packet header).
*
* @param pkt packet body with data.
* @return RNP_SUCCESS or error code if failed. May also throw an exception.
*/
rnp_result_t parse(pgp_packet_body_t &pkt);
/**
* @brief Parse signature packet from source.
*
* @param src source with data.
* @return RNP_SUCCESS or error code if failed. May also throw an exception.
*/
rnp_result_t parse(pgp_source_t &src);
/**
* @brief Parse signature material, stored in the signature in raw.
*
* @param material on success parsed material will be stored here.
* @return true on success or false otherwise. May also throw an exception.
*/
bool parse_material(pgp_signature_material_t &material) const;
/**
* @brief Write signature to the destination. May throw an exception.
*/
void write(pgp_dest_t &dst) const;
/**
* @brief Write the signature material's raw representation. May throw an exception.
*
* @param material populated signature material.
*/
void write_material(const pgp_signature_material_t &material);
} pgp_signature_t;
typedef std::vector<pgp_signature_t> pgp_signature_list_t;
/* information about the validated signature */
typedef struct pgp_signature_info_t {
pgp_signature_t *sig; /* signature, or NULL if there were parsing error */
pgp_key_t * signer; /* signer's public key if found */
bool valid; /* signature is cryptographically valid (but may be expired) */
bool unknown; /* signature is unknown - parsing error, wrong version, etc */
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_t *sig{}; /* signature, or NULL if there were parsing error */
pgp_key_t * signer{}; /* signer's public key if found */
bool valid{}; /* signature is cryptographically valid (but may be expired) */
bool unknown{}; /* signature is unknown - parsing error, wrong version, etc */
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;
bool signature_set_embedded_sig(pgp_signature_t *sig, pgp_signature_t *esig);
bool signature_add_notation_data(pgp_signature_t *sig,

119
third_party/rnp/src/librepgp/stream-write.cpp поставляемый
Просмотреть файл

@ -512,15 +512,15 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
if (!userkey) {
return RNP_ERROR_NO_SUITABLE_KEY;
}
if (!userkey->valid) {
if (!userkey->valid()) {
RNP_LOG("attempt to use invalid key as recipient");
return RNP_ERROR_NO_SUITABLE_KEY;
}
/* Fill pkey */
pkey.version = PGP_PKSK_V3;
pkey.alg = pgp_key_get_alg(userkey);
pkey.key_id = pgp_key_get_keyid(userkey);
pkey.alg = userkey->alg();
pkey.key_id = userkey->keyid();
/* Encrypt the session key */
enckey[0] = param->ctx->ealg;
@ -533,14 +533,16 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
enckey[keylen + 1] = (checksum >> 8) & 0xff;
enckey[keylen + 2] = checksum & 0xff;
switch (pgp_key_get_alg(userkey)) {
pgp_encrypted_material_t material;
switch (userkey->alg()) {
case PGP_PKA_RSA:
case PGP_PKA_RSA_ENCRYPT_ONLY: {
ret = rsa_encrypt_pkcs1(rnp_ctx_rng_handle(handler->ctx),
&pkey.material.rsa,
&material.rsa,
enckey,
keylen + 3,
&pgp_key_get_material(userkey)->rsa);
&userkey->material().rsa);
if (ret) {
RNP_LOG("rsa_encrypt_pkcs1 failed");
goto finish;
@ -549,11 +551,11 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
}
case PGP_PKA_SM2: {
ret = sm2_encrypt(rnp_ctx_rng_handle(handler->ctx),
&pkey.material.sm2,
&material.sm2,
enckey,
keylen + 3,
PGP_HASH_SM3,
&pgp_key_get_material(userkey)->ec);
&userkey->material().ec);
if (ret != RNP_SUCCESS) {
RNP_LOG("sm2_encrypt failed");
goto finish;
@ -562,11 +564,11 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
}
case PGP_PKA_ECDH: {
ret = ecdh_encrypt_pkcs5(rnp_ctx_rng_handle(handler->ctx),
&pkey.material.ecdh,
&material.ecdh,
enckey,
keylen + 3,
&pgp_key_get_material(userkey)->ec,
pgp_key_get_fp(userkey));
&userkey->material().ec,
userkey->fp());
if (ret != RNP_SUCCESS) {
RNP_LOG("ECDH encryption failed %d", ret);
goto finish;
@ -575,10 +577,10 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
}
case PGP_PKA_ELGAMAL: {
ret = elgamal_encrypt_pkcs1(rnp_ctx_rng_handle(handler->ctx),
&pkey.material.eg,
&material.eg,
enckey,
keylen + 3,
&pgp_key_get_material(userkey)->eg);
&userkey->material().eg);
if (ret) {
RNP_LOG("pgp_elgamal_public_encrypt failed");
goto finish;
@ -586,17 +588,18 @@ encrypted_add_recipient(pgp_write_handler_t *handler,
break;
}
default:
RNP_LOG("unsupported alg: %d", pgp_key_get_alg(userkey));
RNP_LOG("unsupported alg: %d", (int) userkey->alg());
goto finish;
}
/* Writing symmetric key encrypted session key packet */
if (!stream_write_pk_sesskey(&pkey, param->pkt.origdst)) {
try {
pkey.write_material(material);
pkey.write(*param->pkt.origdst);
ret = param->pkt.origdst->werr;
} catch (const std::exception &e) {
ret = RNP_ERROR_WRITE;
goto finish;
}
ret = RNP_SUCCESS;
finish:
pgp_forget(enckey, sizeof(enckey));
pgp_forget(&checksum, sizeof(checksum));
@ -699,10 +702,12 @@ encrypted_add_password(rnp_symmetric_pass_info_t * pass,
}
/* Writing symmetric key encrypted session key packet */
if (!stream_write_sk_sesskey(&skey, param->pkt.origdst)) {
try {
skey.write(*param->pkt.origdst);
} catch (const std::exception &e) {
return RNP_ERROR_WRITE;
}
return RNP_SUCCESS;
return param->pkt.origdst->werr;
}
static rnp_result_t
@ -939,20 +944,15 @@ cleartext_dst_writeline(pgp_dest_signed_param_t *param,
dst_write(param->writedst, buf, len);
if (eol) {
/* skipping trailing eol - \n, or \r\n. For the last line eol may be true without \n */
bool hashcrlf = false;
ptr = buf + len - 1;
if (*ptr == CH_LF) {
ptr--;
hashcrlf = true;
if ((ptr >= buf) && (*ptr == CH_CR)) {
ptr--;
/* skipping trailing characters - space, tab, carriage return, line feed */
while ((ptr >= buf) && ((*ptr == CH_SPACE) || (*ptr == CH_TAB) || (*ptr == CH_CR) ||
(*ptr == CH_LF))) {
if (*ptr == CH_LF) {
hashcrlf = true;
}
}
/* skipping trailing spaces */
while ((ptr >= buf) && ((*ptr == CH_SPACE) || (*ptr == CH_TAB))) {
ptr--;
}
@ -1054,15 +1054,15 @@ 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};
rnp_result_t ret = RNP_ERROR_GENERIC;
const pgp_key_pkt_t *deckey = NULL;
pgp_hash_t hash;
pgp_password_ctx_t ctx = {.op = PGP_OP_SIGN, .key = signer->key};
rnp_result_t ret = RNP_ERROR_GENERIC;
/* fill signature fields */
try {
sig->set_keyfp(pgp_key_get_fp(signer->key));
sig->set_keyid(pgp_key_get_keyid(signer->key));
sig->set_keyfp(signer->key->fp());
sig->set_keyid(signer->key->keyid());
sig->set_creation(signer->sigcreate ? signer->sigcreate : time(NULL));
sig->set_expiration(signer->sigexpire);
} catch (const std::exception &e) {
@ -1080,7 +1080,7 @@ signed_fill_signature(pgp_dest_signed_param_t *param,
}
/* decrypt the secret key if needed */
if (pgp_key_is_encrypted(signer->key)) {
if (signer->key->encrypted()) {
deckey = pgp_decrypt_seckey(signer->key, param->password_provider, &ctx);
if (!deckey) {
RNP_LOG("wrong secret key password");
@ -1088,14 +1088,14 @@ signed_fill_signature(pgp_dest_signed_param_t *param,
return RNP_ERROR_BAD_PASSWORD;
}
} else {
deckey = &(signer->key->pkt);
deckey = &signer->key->pkt();
}
/* calculate the signature */
ret = signature_calculate(sig, &deckey->material, &hash, rnp_ctx_rng_handle(param->ctx));
/* destroy decrypted secret key */
if (pgp_key_is_encrypted(signer->key)) {
if (signer->key->encrypted()) {
delete deckey;
}
return ret;
@ -1107,23 +1107,28 @@ signed_write_signature(pgp_dest_signed_param_t *param,
pgp_dest_t * writedst)
{
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.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.halg = pgp_hash_adjust_alg_to_key(signer->halg, &signer->key->pkt());
sig.palg = signer->key->alg();
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;
rnp_result_t ret = signed_fill_signature(param, &sig, signer);
if (ret) {
return ret;
}
try {
sig.write(*writedst);
return writedst->werr;
} catch (const std::exception &e) {
RNP_LOG("%s", e.what());
return RNP_ERROR_WRITE;
}
return ret;
}
static rnp_result_t
@ -1216,7 +1221,7 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo
{
pgp_dest_signer_info_t sinfo = {};
if (!pgp_key_is_secret(signer->key)) {
if (!signer->key->is_secret()) {
RNP_LOG("secret key required for signing");
return RNP_ERROR_BAD_PARAMETERS;
}
@ -1227,7 +1232,7 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo
sinfo.sigexpire = signer->sigexpire;
/* Add hash to the list */
sinfo.halg = pgp_hash_adjust_alg_to_key(signer->halg, pgp_key_get_pkt(signer->key));
sinfo.halg = pgp_hash_adjust_alg_to_key(signer->halg, &signer->key->pkt());
if (!pgp_hash_list_add(param->hashes, sinfo.halg)) {
return RNP_ERROR_BAD_PARAMETERS;
}
@ -1248,8 +1253,8 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo
sinfo.onepass.version = 3;
sinfo.onepass.type = PGP_SIG_BINARY;
sinfo.onepass.halg = sinfo.halg;
sinfo.onepass.palg = pgp_key_get_alg(sinfo.key);
sinfo.onepass.keyid = pgp_key_get_keyid(sinfo.key);
sinfo.onepass.palg = sinfo.key->alg();
sinfo.onepass.keyid = sinfo.key->keyid();
sinfo.onepass.nested = false;
try {
param->siginfos.push_back(sinfo);
@ -1259,17 +1264,19 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo
}
// write onepasses in reverse order so signature order will match signers list
if (last) {
if (!last) {
return RNP_SUCCESS;
}
try {
for (auto it = param->siginfos.rbegin(); it != param->siginfos.rend(); it++) {
pgp_dest_signer_info_t &sinfo = *it;
sinfo.onepass.nested = &sinfo == &param->siginfos.front();
if (!stream_write_one_pass(&sinfo.onepass, param->writedst)) {
return RNP_ERROR_WRITE;
}
sinfo.onepass.write(*param->writedst);
}
return param->writedst->werr;
} catch (const std::exception &e) {
return RNP_ERROR_WRITE;
}
return RNP_SUCCESS;
}
pgp_dest_signed_param_t::~pgp_dest_signed_param_t()

119
third_party/rnp/src/rnp/fficli.cpp поставляемый
Просмотреть файл

@ -96,6 +96,83 @@ disable_core_dumps(void)
}
#endif
#ifdef _WIN32
#include "str-utils.h"
#include <windows.h>
#include <vector>
#include <stdexcept>
static std::vector<std::string>
get_utf8_args()
{
int arg_nb;
wchar_t **arg_w;
arg_w = CommandLineToArgvW(GetCommandLineW(), &arg_nb);
if (!arg_w) {
throw std::runtime_error("CommandLineToArgvW failed");
}
try {
std::vector<std::string> result;
result.reserve(arg_nb);
for (int i = 0; i < arg_nb; i++) {
auto utf8 = wstr_to_utf8(arg_w[i]);
result.push_back(utf8);
}
LocalFree(arg_w);
return result;
} catch (...) {
LocalFree(arg_w);
throw;
}
}
void
rnp_win_clear_args(int argc, char **argv)
{
for (int i = 0; i < argc; i++) {
if (argv[i]) {
free(argv[i]);
}
}
delete argv;
}
bool
rnp_win_substitute_cmdline_args(int *argc, char ***argv)
{
int argc_utf8 = 0;
char **argv_utf8_cstrs = NULL;
try {
auto argv_utf8_strings = get_utf8_args();
argc_utf8 = argv_utf8_strings.size();
if (argc_utf8 != *argc) {
throw std::range_error("Unexpected number of arguments from unicode command line");
}
argv_utf8_cstrs = new (std::nothrow) char *[argc_utf8]();
if (!argv_utf8_cstrs) {
throw std::bad_alloc();
}
for (int i = 0; i < argc_utf8; i++) {
auto arg_utf8 = strdup(argv_utf8_strings[i].c_str());
if (!arg_utf8) {
throw std::bad_alloc();
}
argv_utf8_cstrs[i] = arg_utf8;
}
} catch (...) {
if (argv_utf8_cstrs) {
rnp_win_clear_args(argc_utf8, argv_utf8_cstrs);
}
throw;
}
*argc = argc_utf8;
*argv = argv_utf8_cstrs;
return true;
}
#endif
static bool
set_pass_fd(FILE **file, int passfd)
{
@ -150,7 +227,7 @@ rnp_get_output_filename(
while (true) {
if (rnp_file_exists(newpath)) {
if (overwrite) {
unlink(newpath);
rnp_unlink(newpath);
return true;
}
@ -163,7 +240,7 @@ rnp_get_output_filename(
return false;
}
if (strlen(reply) > 0 && toupper(reply[0]) == 'Y') {
unlink(newpath);
rnp_unlink(newpath);
return true;
}
@ -410,12 +487,13 @@ cli_rnp_init(cli_rnp_t *rnp, rnp_cfg_t *cfg)
}
/* Configure the results stream. */
// TODO: UTF8?
const char *ress = rnp_cfg_getstr(cfg, CFG_IO_RESS);
if (!ress || !strcmp(ress, "<stderr>")) {
rnp->resfp = stderr;
} else if (strcmp(ress, "<stdout>") == 0) {
rnp->resfp = stdout;
} else if (!(rnp->resfp = fopen(ress, "w"))) {
} else if (!(rnp->resfp = rnp_fopen(ress, "w"))) {
ERR_MSG("cannot open results %s for writing", ress);
return false;
}
@ -853,7 +931,7 @@ cli_rnp_save_keyrings(cli_rnp_t *rnp)
// check whether we have G10 secret keyring - then need to create directory
if (cli_rnp_secformat(rnp) == "G10") {
struct stat path_stat;
if (stat(spath.c_str(), &path_stat) != -1) {
if (rnp_stat(spath.c_str(), &path_stat) != -1) {
if (!S_ISDIR(path_stat.st_mode)) {
ERR_MSG("G10 keystore should be a directory: %s", spath.c_str());
return false;
@ -977,17 +1055,21 @@ cli_rnp_generate_key(cli_rnp_t *rnp, const char *username)
ERR_MSG("Failed to obtain protection password.");
goto done;
}
rnp_result_t ret = rnp_key_protect(key,
password,
rnp_cfg_getstr(cfg, CFG_KG_PROT_ALG),
NULL,
rnp_cfg_getstr(cfg, CFG_KG_PROT_HASH),
rnp_cfg_getint(cfg, CFG_KG_PROT_ITERATIONS));
rnp_buffer_clear(password, strlen(password) + 1);
rnp_buffer_destroy(password);
if (ret) {
ERR_MSG("Failed to protect key.");
goto done;
if (*password) {
rnp_result_t ret = rnp_key_protect(key,
password,
rnp_cfg_getstr(cfg, CFG_KG_PROT_ALG),
NULL,
rnp_cfg_getstr(cfg, CFG_KG_PROT_HASH),
rnp_cfg_getint(cfg, CFG_KG_PROT_ITERATIONS));
rnp_buffer_clear(password, strlen(password) + 1);
rnp_buffer_destroy(password);
if (ret) {
ERR_MSG("Failed to protect key.");
goto done;
}
} else {
rnp_buffer_destroy(password);
}
}
res = cli_rnp_save_keyrings(rnp);
@ -1402,8 +1484,8 @@ rnp_cfg_set_ks_info(rnp_cfg_t *cfg)
secpath = rnp_path_compose(homedir, subdir, SECRING_G10);
struct stat st;
bool pubpath_exists = !stat(pubpath.c_str(), &st);
bool secpath_exists = !stat(secpath.c_str(), &st);
bool pubpath_exists = !rnp_stat(pubpath.c_str(), &st);
bool secpath_exists = !rnp_stat(secpath.c_str(), &st);
if (pubpath_exists && secpath_exists) {
ks_format = RNP_KEYSTORE_GPG21;
@ -1473,9 +1555,8 @@ conffile(const char *homedir, char *userid, size_t length)
static std::regex keyre("^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
std::regex_constants::extended);
#endif
(void) snprintf(buf, sizeof(buf), "%s/.gnupg/gpg.conf", homedir);
if ((fp = fopen(buf, "r")) == NULL) {
if ((fp = rnp_fopen(buf, "r")) == NULL) {
return false;
}
#ifndef RNP_USE_STD_REGEX

5
third_party/rnp/src/rnp/fficli.h поставляемый
Просмотреть файл

@ -135,6 +135,11 @@ const char *json_obj_get_str(json_object *obj, const char *key);
int64_t json_obj_get_int64(json_object *obj, const char *key);
bool rnp_casecmp(const std::string &str1, const std::string &str2);
#ifdef _WIN32
bool rnp_win_substitute_cmdline_args(int *argc, char ***argv);
void rnp_win_clear_args(int argc, char **argv);
#endif
/* TODO: we should decide what to do with functions/constants/defines below */
#define RNP_KEYID_SIZE 8
#define RNP_FP_SIZE 20

15
third_party/rnp/src/rnp/rnp.cpp поставляемый
Просмотреть файл

@ -621,6 +621,16 @@ rnp_main(int argc, char **argv)
return EXIT_ERROR;
}
#if !defined(RNP_RUN_TESTS) && defined(_WIN32)
bool args_are_substituted = false;
try {
args_are_substituted = rnp_win_substitute_cmdline_args(&argc, &argv);
} catch (std::exception &ex) {
RNP_LOG("Error converting arguments ('%s')", ex.what());
return EXIT_ERROR;
}
#endif
rnp_cfg_init(&cfg);
rnp_cfg_load_defaults(&cfg);
optindex = 0;
@ -755,5 +765,10 @@ rnp_main(int argc, char **argv)
finish:
rnp_cfg_free(&cfg);
cli_rnp_end(&rnp);
#if !defined(RNP_RUN_TESTS) && defined(_WIN32)
if (args_are_substituted) {
rnp_win_clear_args(argc, argv);
}
#endif
return ret;
}

22
third_party/rnp/src/rnpkeys/main.cpp поставляемый
Просмотреть файл

@ -36,7 +36,7 @@
#endif
#include <stdio.h>
#include <string.h>
#include "utils.h"
#include "rnp/rnpcfg.h"
#include "rnpkeys.h"
@ -68,6 +68,16 @@ rnpkeys_main(int argc, char **argv)
return EXIT_FAILURE;
}
#if !defined(RNP_RUN_TESTS) && defined(_WIN32)
bool args_are_substituted = false;
try {
args_are_substituted = rnp_win_substitute_cmdline_args(&argc, &argv);
} catch (std::exception &ex) {
RNP_LOG("Error converting arguments ('%s')", ex.what());
return EXIT_FAILURE;
}
#endif
rnp_cfg_init(&cfg);
while ((ch = getopt_long(argc, argv, "Vglo:", options, &optindex)) != -1) {
@ -107,6 +117,11 @@ rnpkeys_main(int argc, char **argv)
goto end;
}
if (!cli_rnp_setup(&rnp)) {
ret = EXIT_FAILURE;
goto end;
}
/* now do the required action for each of the command line args */
ret = EXIT_SUCCESS;
if (optind == argc) {
@ -124,5 +139,10 @@ rnpkeys_main(int argc, char **argv)
end:
rnp_cfg_free(&cfg);
cli_rnp_end(&rnp);
#if !defined(RNP_RUN_TESTS) && defined(_WIN32)
if (args_are_substituted) {
rnp_win_clear_args(argc, argv);
}
#endif
return ret;
}

10
third_party/rnp/src/rnpkeys/rnpkeys.cpp поставляемый
Просмотреть файл

@ -68,6 +68,8 @@ const char *usage = "--help OR\n"
"\t[--hash=<hash alg>] AND/OR\n"
"\t[--homedir=<homedir>] AND/OR\n"
"\t[--keyring=<keyring>] AND/OR\n"
"\t[--pass-fd=<fd>] OR\n"
"\t[--password=<password>] AND/OR\n"
"\t[--permissive] AND/OR\n"
"\t[--output=file] file OR\n"
"\t[--keystore-format=<format>] AND/OR\n"
@ -111,6 +113,7 @@ struct option options[] = {
{"s2k-msec", required_argument, NULL, OPT_S2K_MSEC},
{"verbose", no_argument, NULL, OPT_VERBOSE},
{"pass-fd", required_argument, NULL, OPT_PASSWDFD},
{"password", required_argument, NULL, OPT_PASSWD},
{"results", required_argument, NULL, OPT_RESULTS},
{"cipher", required_argument, NULL, OPT_CIPHER},
{"expert", no_argument, NULL, OPT_EXPERT},
@ -542,6 +545,13 @@ setoption(rnp_cfg_t *cfg, optdefs_t *cmd, int val, const char *arg)
}
ret = rnp_cfg_setstr(cfg, CFG_PASSFD, arg);
break;
case OPT_PASSWD:
if (arg == NULL) {
ERR_MSG("No password argument provided");
return false;
}
ret = rnp_cfg_setstr(cfg, CFG_PASSWD, arg);
break;
case OPT_RESULTS:
if (arg == NULL) {
ERR_MSG("No output filename argument provided");

1
third_party/rnp/src/rnpkeys/rnpkeys.h поставляемый
Просмотреть файл

@ -33,6 +33,7 @@ typedef enum {
OPT_VERBOSE,
OPT_COREDUMPS,
OPT_PASSWDFD,
OPT_PASSWD,
OPT_RESULTS,
OPT_CIPHER,
OPT_FORMAT,

6
third_party/rnp/src/tests/CMakeLists.txt поставляемый
Просмотреть файл

@ -69,11 +69,15 @@ add_executable(rnp_tests
../fuzzing/keyring_g10.cpp
../fuzzing/keyring_kbx.c
../fuzzing/keyimport.c
../fuzzing/dump.c
../fuzzing/verify_detached.c
cipher.cpp
cli.cpp
exportkey.cpp
ffi.cpp
ffi-enc.cpp
ffi-uid.cpp
ffi-key-sig.cpp
file-utils.cpp
generatekey.cpp
kbx-nsigs-test.cpp
@ -107,6 +111,8 @@ add_executable(rnp_tests
fuzz_keyring_g10.cpp
fuzz_keyring_kbx.cpp
fuzz_keyimport.cpp
fuzz_dump.cpp
fuzz_verify_detached.cpp
)
if(MSVC)
find_package(WindowsSDK)

8
third_party/rnp/src/tests/cipher.cpp поставляемый
Просмотреть файл

@ -220,7 +220,7 @@ TEST_F(rnp_tests, rnp_test_x25519)
key_desc.ecc.curve = PGP_CURVE_25519;
assert_true(pgp_generate_seckey(&key_desc, &seckey, true));
assert_rnp_success(pgp_fingerprint(fp, &seckey));
assert_rnp_success(pgp_fingerprint(fp, seckey));
assert_rnp_success(
ecdh_encrypt_pkcs5(&global_rng, &enc, in, sizeof(in), &seckey.material.ec, fp));
assert_true(enc.mlen > 16);
@ -340,7 +340,7 @@ TEST_F(rnp_tests, ecdh_roundtrip)
assert_true(pgp_generate_seckey(&key_desc, &ecdh_key1, true));
pgp_fingerprint_t ecdh_key1_fpr = {};
assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, &ecdh_key1));
assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1));
assert_rnp_success(ecdh_encrypt_pkcs5(
&global_rng, &enc, plaintext, plaintext_len, &ecdh_key1.material.ec, ecdh_key1_fpr));
@ -371,7 +371,7 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases)
assert_true(pgp_generate_seckey(&key_desc, &ecdh_key1, true));
pgp_fingerprint_t ecdh_key1_fpr = {};
assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, &ecdh_key1));
assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1));
assert_rnp_success(ecdh_encrypt_pkcs5(
&global_rng, &enc, plaintext, plaintext_len, &ecdh_key1.material.ec, ecdh_key1_fpr));
@ -699,7 +699,7 @@ read_key_pkt(pgp_key_pkt_t *key, const char *path)
if (init_file_src(&src, path)) {
return false;
}
bool res = !stream_parse_key(&src, key);
bool res = !key->parse(src);
src_close(&src);
return res;
}

150
third_party/rnp/src/tests/cli.cpp поставляемый
Просмотреть файл

@ -39,6 +39,11 @@
#endif
#endif
#ifdef _WIN32
#include <windows.h>
#include "str-utils.h"
#endif
int rnp_main(int argc, char **argv);
int rnpkeys_main(int argc, char **argv);
@ -90,12 +95,12 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt",
NULL);
assert_int_equal(ret, 0);
assert_true(file_exists(FILES "/hello.txt.pgp"));
assert_true(rnp_file_exists(FILES "/hello.txt.pgp"));
/* verify signed file */
ret =
call_rnp("rnp", "--keyfile", MKEYS "key-pub.asc", "-v", FILES "/hello.txt.pgp", NULL);
assert_int_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.pgp"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
/* sign with keyfile, using user id */
ret = call_rnp("rnp",
@ -110,7 +115,7 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt",
NULL);
assert_int_equal(ret, 0);
assert_true(file_exists(FILES "/hello.txt.asc"));
assert_true(rnp_file_exists(FILES "/hello.txt.asc"));
/* verify signed file */
ret = call_rnp("rnp", "-f", MKEYS "key-pub.asc", "-v", FILES "/hello.txt.asc", NULL);
assert_int_equal(ret, 0);
@ -118,12 +123,12 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
ret =
call_rnp("rnp", "-f", MKEYS "key-pub-just-key.pgp", "-v", FILES "/hello.txt.asc", NULL);
assert_int_not_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.asc"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.asc"), 0);
/* encrypt with keyfile, using default key */
ret = call_rnp("rnp", "--keyfile", MKEYS "key-pub.asc", "-e", FILES "/hello.txt", NULL);
assert_int_equal(ret, 0);
assert_true(file_exists(FILES "/hello.txt.pgp"));
assert_true(rnp_file_exists(FILES "/hello.txt.pgp"));
/* decrypt it with raw seckey, without userids and sigs */
ret = call_rnp("rnp",
"--keyfile",
@ -134,7 +139,7 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt.pgp",
NULL);
assert_int_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.pgp"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
/* try to encrypt with keyfile, using the signing subkey */
ret = call_rnp("rnp",
@ -147,7 +152,7 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt",
NULL);
assert_int_not_equal(ret, 0);
assert_false(file_exists(FILES "/hello.txt.asc"));
assert_false(rnp_file_exists(FILES "/hello.txt.asc"));
/* now encrypt with keyfile, using the encrypting subkey */
ret = call_rnp("rnp",
"--keyfile",
@ -159,7 +164,7 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt",
NULL);
assert_int_equal(ret, 0);
assert_true(file_exists(FILES "/hello.txt.asc"));
assert_true(rnp_file_exists(FILES "/hello.txt.asc"));
/* fail to decrypt it with pubkey */
ret = call_rnp("rnp",
"--keyfile",
@ -180,7 +185,7 @@ TEST_F(rnp_tests, test_cli_rnp_keyfile)
FILES "/hello.txt.asc",
NULL);
assert_int_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.asc"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.asc"), 0);
}
static bool
@ -208,7 +213,7 @@ test_cli_g10_key_sign(const char *userid)
if (ret) {
return false;
}
unlink(FILES "/hello.txt.pgp");
rnp_unlink(FILES "/hello.txt.pgp");
return true;
}
@ -235,7 +240,7 @@ test_cli_g10_key_encrypt(const char *userid)
if (ret) {
return false;
}
unlink(FILES "/hello.txt.pgp");
rnp_unlink(FILES "/hello.txt.pgp");
return true;
}
@ -251,7 +256,7 @@ TEST_F(rnp_tests, test_cli_g10_operations)
/* verify back */
ret = call_rnp("rnp", "--homedir", G10KEYS, "-v", FILES "/hello.txt.pgp", NULL);
assert_int_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.pgp"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
/* encrypt with default g10 key */
ret = call_rnp("rnp", "--homedir", G10KEYS, "-e", FILES "/hello.txt", NULL);
@ -267,7 +272,7 @@ TEST_F(rnp_tests, test_cli_g10_operations)
FILES "/hello.txt.pgp",
NULL);
assert_int_equal(ret, 0);
assert_int_equal(unlink(FILES "/hello.txt.pgp"), 0);
assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
/* check dsa/eg key */
assert_true(test_cli_g10_key_sign("c8a10a7d78273e10")); // signing key
@ -334,6 +339,125 @@ TEST_F(rnp_tests, test_cli_g10_operations)
assert_true(test_cli_g10_key_encrypt("7635401f90d3e533"));
}
TEST_F(rnp_tests, test_cli_rnpkeys_unicode)
{
#ifdef _WIN32
std::string uid_acp = "\x80@a.com";
std::wstring uid2_wide =
L"\x03C9\x0410@b.com"; // some Greek and Cyrillic for CreateProcessW test
char *rnpkeys_path = rnp_compose_path(original_dir(), "../rnpkeys/rnpkeys.exe", NULL);
std::string homedir_s = std::string(m_dir) + "/unicode";
rnp_mkdir(homedir_s.c_str());
std::string path_s = rnpkeys_path;
std::string cmdline_s = path_s + " --numbits 2048 --homedir " + homedir_s +
" --password password --userid " + uid_acp + " --generate-key";
UINT acp = GetACP();
STARTUPINFOA si;
ZeroMemory(&si, sizeof si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof pi);
BOOL res = CreateProcessA(NULL, // (LPSTR) path_s.c_str(), // Module name
(LPSTR) cmdline_s.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Handle inheritance
0, // Creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi); // Pointer to PROCESS_INFORMATION structure
assert_true(res);
assert_true(WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
std::wstring homedir_ws = wstr_from_utf8(homedir_s);
std::wstring path_ws = wstr_from_utf8(path_s);
std::wstring cmdline_ws = path_ws + L" --numbits 2048 --homedir " + homedir_ws +
L" --password password --userid " + uid2_wide +
L" --generate-key";
STARTUPINFOW siw;
ZeroMemory(&siw, sizeof siw);
ZeroMemory(&pi, sizeof pi);
res = CreateProcessW(NULL,
(LPWSTR) cmdline_ws.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Handle inheritance
0, // Creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&siw, // Pointer to STARTUPINFO structure
&pi); // Pointer to PROCESS_INFORMATION structure
assert_true(res);
assert_true(WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
// Load the keyring and check what was actually written
rnp_ffi_t ffi;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
rnp_input_t input = NULL;
assert_rnp_success(rnp_input_from_path(&input, "unicode/pubring.gpg"));
assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
// convert from ACP to wide char via Windows native mechanism
int convertResult = MultiByteToWideChar(acp, 0, uid_acp.c_str(), uid_acp.size(), NULL, 0);
assert_true(convertResult > 0);
std::wstring uid_wide;
uid_wide.resize(convertResult);
convertResult = MultiByteToWideChar(
acp, 0, uid_acp.c_str(), uid_acp.size(), &uid_wide[0], (int) uid_wide.size());
assert_true(convertResult > 0);
// we expect to find UID in UTF-8
std::string uid_utf8 = wstr_to_utf8(uid_wide);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", uid_utf8.c_str(), &key));
assert_non_null(key);
size_t uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_non_null(uid);
size_t size = 0;
char * data = NULL;
assert_rnp_success(rnp_uid_get_data(uid, (void **) &data, &size));
std::string uid_read(data, data + size);
assert_int_equal(0, uid_read.compare(uid_utf8));
rnp_buffer_destroy(data);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
uid_utf8 = wstr_to_utf8(uid2_wide);
key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", uid_utf8.c_str(), &key));
assert_non_null(key);
uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 1);
uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_non_null(uid);
size = 0;
data = NULL;
assert_rnp_success(rnp_uid_get_data(uid, (void **) &data, &size));
std::string uid2_read(data, data + size);
assert_int_equal(0, uid2_read.compare(uid_utf8));
rnp_buffer_destroy(data);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
#endif
}
TEST_F(rnp_tests, test_cli_rnp)
{
int ret;

5
third_party/rnp/src/tests/cli_common.py поставляемый
Просмотреть файл

@ -11,6 +11,7 @@ from subprocess import Popen, PIPE
RNP_ROOT = None
WORKDIR = ''
CONSOLE_ENCODING = 'UTF-8'
class CLIError(Exception):
def __init__(self, message, log = None):
@ -61,10 +62,10 @@ def pswd_pipe(password):
def random_text(path, size):
# Generate random text, with 50% probability good-compressible
if random.randint(0, 10) < 5:
st = ''.join(random.choice(string.ascii_letters + string.digits + " \t\n-,.")
st = ''.join(random.choice(string.ascii_letters + string.digits + " \t\r\n-,.")
for _ in range(size))
else:
st = ''.join(random.choice("abcdef0123456789 \t\n-,.") for _ in range(size))
st = ''.join(random.choice("abcdef0123456789 \t\r\n-,.") for _ in range(size))
with open(path, 'w+') as f:
f.write(st)

71
third_party/rnp/src/tests/cli_tests.py поставляемый
Просмотреть файл

@ -14,7 +14,7 @@ from os import path
import cli_common
from cli_common import (file_text, find_utility, is_windows, list_upto,
path_for_gpg, pswd_pipe, raise_err, random_text,
rnp_file_path, run_proc)
rnp_file_path, run_proc, CONSOLE_ENCODING)
from gnupg import GnuPG as GnuPG
from rnp import Rnp as Rnp
@ -31,6 +31,27 @@ TESTS_SUCCEEDED = []
TESTS_FAILED = []
TEST_WORKFILES = []
if sys.version_info >= (3,):
unichr = chr
UNICODE_LATIN_CAPITAL_A_GRAVE = unichr(192)
UNICODE_LATIN_SMALL_A_GRAVE = unichr(224)
UNICODE_LATIN_CAPITAL_A_MACRON = unichr(256)
UNICODE_LATIN_SMALL_A_MACRON = unichr(257)
UNICODE_GREEK_CAPITAL_HETA = unichr(880)
UNICODE_GREEK_SMALL_HETA = unichr(881)
UNICODE_GREEK_CAPITAL_OMEGA = unichr(937)
UNICODE_GREEK_SMALL_OMEGA = unichr(969)
UNICODE_CYRILLIC_CAPITAL_A = unichr(0x0410)
UNICODE_CYRILLIC_SMALL_A = unichr(0x0430)
UNICODE_CYRILLIC_CAPITAL_YA = unichr(0x042F)
UNICODE_CYRILLIC_SMALL_YA = unichr(0x044F)
UNICODE_SEQUENCE_1 = UNICODE_LATIN_CAPITAL_A_GRAVE + UNICODE_LATIN_SMALL_A_MACRON \
+ UNICODE_GREEK_CAPITAL_HETA + UNICODE_GREEK_SMALL_OMEGA \
+ UNICODE_CYRILLIC_CAPITAL_A + UNICODE_CYRILLIC_SMALL_YA
UNICODE_SEQUENCE_2 = UNICODE_LATIN_SMALL_A_GRAVE + UNICODE_LATIN_CAPITAL_A_MACRON \
+ UNICODE_GREEK_SMALL_HETA + UNICODE_GREEK_CAPITAL_OMEGA \
+ UNICODE_CYRILLIC_SMALL_A + UNICODE_CYRILLIC_CAPITAL_YA
# Key userids
KEY_ENCRYPT = 'encryption@rnp'
@ -1007,7 +1028,39 @@ class Keystore(unittest.TestCase):
match = re.match(RE_RNP_ENCRYPTED_KEY, out)
if not match:
raise_err('wrong encrypted secret key listing', err)
def test_generate_protection_password(self):
'''
Generate key with RNP, using the --password parameter, and make sure key is encrypted
'''
clear_keyrings()
params = ['--homedir', RNPDIR, '--password', 'password', '--userid', 'enc@rnp', '--generate-key']
ret, _, err = run_proc(RNPK, params)
if ret != 0:
raise_err('key generation failed', err)
# Check packets using the gpg
params = ['--homedir', RNPDIR, '--list-packets', path.join(RNPDIR, 'secring.gpg')]
ret, out, err = run_proc(RNP, params)
match = re.match(RE_RNP_ENCRYPTED_KEY, out)
if not match:
raise_err('wrong encrypted secret key listing', err)
def test_generate_unprotected_key(self):
'''
Generate key with RNP, using the --password parameter, and make sure key is encrypted
'''
clear_keyrings()
params = ['--homedir', RNPDIR, '--password=', '--userid', 'enc@rnp', '--generate-key']
ret, _, err = run_proc(RNPK, params)
if ret != 0:
raise_err('key generation failed', err)
# Check packets using the gpg
params = ['--homedir', RNPDIR, '--list-packets', path.join(RNPDIR, 'secring.gpg')]
ret, out, err = run_proc(RNP, params)
match = re.match(RE_RNP_ENCRYPTED_KEY, out)
if match:
raise_err('wrong unprotected secret key listing', err)
def test_import_signatures(self):
clear_keyrings()
# Import command without the path parameter
@ -1323,6 +1376,22 @@ class Misc(unittest.TestCase):
def tearDown(self):
clear_workfiles()
def test_encryption_unicode(self):
if sys.version_info >= (3,):
filename = UNICODE_SEQUENCE_1
else:
filename = UNICODE_SEQUENCE_1.encode(CONSOLE_ENCODING)
src, dst, dec = reg_workfiles(filename, '.txt', '.rnp', '.dec')
# Generate random file of required size
random_text(src, 128000)
rnp_encrypt_file_ex(src, dst, [KEY_ENCRYPT])
rnp_decrypt_file(dst, dec)
compare_files(src, dec, 'rnp decrypted data differs')
remove_files(src, dst, dec)
def test_encryption_no_mdc(self):
src, dst, dec = reg_workfiles('cleartext', '.txt', '.gpg', '.rnp')
# Generate random file of required size

Просмотреть файл

@ -1,5 +1,6 @@
# for test_ffi_op_verify_sig_count
test_messages/message-32k-crlf.txt -text
test_messages/message-trailing-cr.txt -text
# for test_stream_signatures
test_stream_signatures/source*.txt -text
# for cleartext tests

Просмотреть файл

@ -4,9 +4,9 @@ pub 1024/RSA (Encrypt or Sign) 7bc6709b15c23a4a 2017-07-20 [SC]
e95a3cbf583aa80a2ccc53aa7bc6709b15c23a4a
uid key0-uid0
uid key0-uid1
sig 7bc6709b15c23a4a 2017-07-20 key0-uid0
sig 7bc6709b15c23a4a 2017-07-20 key0-uid1
uid key0-uid2
sig 7bc6709b15c23a4a 2017-07-20 key0-uid0
sig 7bc6709b15c23a4a 2017-07-20 key0-uid1
sub 1024/RSA (Encrypt or Sign) 1ed63ee56fadc34d 2017-07-20 [E]
e332b27caf4742a11baa677f1ed63ee56fadc34d
sub 1024/DSA 1d7e8a5393c997a8 2017-07-20 [S] [EXPIRED 2017-11-20]

Двоичные данные
third_party/rnp/src/tests/data/test_fuzz_dump/clusterfuzz-testcase-minimized-fuzz_dump-5757362284265472 поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_fuzz_keyimport/crash_37e8ed57ee47c1991b387fa0506f361f9cd9c663 поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_fuzz_keyimport/leak_11307b70cc609c93fc3a49d37f3a31166df50f44 поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_fuzz_keyimport/timeout_9c10372fe9ebdcdb0b6e275d05f8af4f4e3d6051 поставляемый Normal file

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_key_edge_cases/alice-sig-misc-values.pgp поставляемый Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,12 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEXgS/LxYJKwYBBAHaRw8BAQdAJ/BnDcmcOCED/rW3y1zPHSX6lABI7G19R6mP
hgfIgj+0EUFsaWNlIDxhbGljZUBybnA+iJAEExYIADgWIQRz7cyRGa/I4tu9zeUE
UUCWaf/ePAUCXgS/LwIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAEUUCW
af/ePCSdAP9OWq8uOk5B5LUtPvFnxqGkrZlAHt+tgR271QSggRV3MAEAvtL/ru5o
ss9jx26EqYj2GUgHGtsYqsz8j1y97S5lMQqIewQQEwgAIxYhBK3nrEqPSa2yNPp9
APei/UoD3soZBQJf1LOoBYMAAVGAAAoJEPei/UoD3soZiyEA/0fH6Yhr+/dlHY7G
B74bdzDz2ILpzzy3oJWyO1vnVXQ/APwIaIzQQFJegqUJvWIwXJnkvZnbPujEgCT5
rHi9CFqIgA==
=Wl6/
-----END PGP PUBLIC KEY BLOCK-----

Просмотреть файл

@ -91,8 +91,8 @@ 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);
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;

Просмотреть файл

@ -0,0 +1,3 @@
Text line with 3 trailing CR characters
Another line with CR at the beginning, should not be stripped.
Last line with trailing CR and no LF.

Двоичные данные
third_party/rnp/src/tests/data/test_messages/message-trailing-cr.txt.sig-text поставляемый Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1 +0,0 @@
This is test message to be signed, and/or encrypted, cleartext signed and detached signed. It will use keys from keyrings/1. End of message.

Просмотреть файл

@ -0,0 +1,12 @@
-----BEGIN PGP SIGNATURE-----
Version: LibTMCG 1.3.14
wv8AAAFKBEARCgEU/wAAAAWCW4Qtpv8AAAAChwD/AAAACZAtcnzHaGl3NP8AAAA0
FIAAAAAAIQAKc2VyaWFsbnVtYmVyQGRvdHMudGVzdGRvbWFpbi50ZXN0VEVTVDAw
MDAwMf8AAAAtGmh0dHBzOi8vcG9saWN5LnRlc3Rkb21haW4udGVzdC90aW1lc3Rh
bXBpbmcv/wAAAGqgBAARCgAz/wAAAAUCW4QsOf8AAAAJEC1yfMdoaXc0/wAAABYh
BKD/RZC7YSLt7248VC1yfMdoaXc0AACjhgCZAWMQ7G7Y8ZgA49Om7rP8M6bzpKUA
n11pnt+6XH3ytxMjWIPmIypkSH42/wAAABYhBKD/RZC7YSLt7248VC1yfMdoaXc0
AAAnJwCcC33Agj/STYlb283+HqWQAw/ZIJQAn2lN4+6WHkSc8gm6d2iPfC+3JJGl
=40KQ
-----END PGP SIGNATURE-----

Двоичные данные
third_party/rnp/src/tests/data/test_stream_signatures/source.txt.text.sig поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-expired.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-sig-expired.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-sig-revocation.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-uids-pub-no-expire.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-uids-pub.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-uids-revoked-valid.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-uids-sec.pgp поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rnp/src/tests/data/test_uid_validity/key-uids-with-invalid.pgp поставляемый Normal file

Двоичный файл не отображается.

911
third_party/rnp/src/tests/ffi-key-sig.cpp поставляемый Normal file
Просмотреть файл

@ -0,0 +1,911 @@
/*
* 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_tests.h"
#include "support.h"
TEST_F(rnp_tests, test_ffi_key_signatures)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
// load key
assert_rnp_success(
rnp_input_from_path(&input, "data/test_stream_key_load/ecc-p384-pub.asc"));
assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
// check primary key
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "242A3AA5EA85F44A", &key));
// some edge cases
size_t sigs = 0;
rnp_signature_handle_t sig = NULL;
assert_rnp_failure(rnp_key_get_signature_count(NULL, &sigs));
assert_rnp_failure(rnp_key_get_signature_count(key, NULL));
assert_rnp_failure(rnp_key_get_signature_at(key, 0, &sig));
assert_rnp_failure(rnp_key_get_signature_at(key, 0x10000, &sig));
assert_rnp_failure(rnp_key_get_signature_at(NULL, 0x10000, &sig));
assert_rnp_failure(rnp_key_get_signature_at(NULL, 0, NULL));
// key doesn't have signatures
assert_rnp_success(rnp_key_get_signature_count(key, &sigs));
assert_int_equal(sigs, 0);
// uid must have one signature
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_get_signature_count(uid, &sigs));
assert_int_equal(sigs, 1);
assert_rnp_failure(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
char *type = NULL;
assert_rnp_failure(rnp_signature_get_type(NULL, &type));
assert_rnp_failure(rnp_signature_get_type(sig, NULL));
assert_rnp_success(rnp_signature_get_type(sig, &type));
assert_string_equal(type, "certification (positive)");
rnp_buffer_destroy(type);
uint32_t creation = 0;
assert_rnp_success(rnp_signature_get_creation(sig, &creation));
assert_int_equal(creation, 1549119505);
char *alg = NULL;
assert_rnp_failure(rnp_signature_get_alg(NULL, &alg));
assert_rnp_failure(rnp_signature_get_alg(sig, NULL));
assert_rnp_success(rnp_signature_get_alg(sig, &alg));
assert_string_equal(alg, "ECDSA");
rnp_buffer_destroy(alg);
assert_rnp_success(rnp_signature_get_hash_alg(sig, &alg));
assert_string_equal(alg, "SHA384");
rnp_buffer_destroy(alg);
char *keyid = NULL;
assert_rnp_success(rnp_signature_get_keyid(sig, &keyid));
assert_non_null(keyid);
assert_string_equal(keyid, "242A3AA5EA85F44A");
rnp_buffer_destroy(keyid);
rnp_key_handle_t signer = NULL;
assert_rnp_success(rnp_signature_get_signer(sig, &signer));
assert_non_null(signer);
assert_rnp_success(rnp_key_get_keyid(signer, &keyid));
assert_non_null(keyid);
assert_string_equal(keyid, "242A3AA5EA85F44A");
rnp_buffer_destroy(keyid);
rnp_key_handle_destroy(signer);
assert_int_equal(rnp_signature_is_valid(NULL, 0), RNP_ERROR_NULL_POINTER);
assert_int_equal(rnp_signature_is_valid(sig, 17), RNP_ERROR_BAD_PARAMETERS);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
assert_rnp_success(rnp_signature_handle_destroy(sig));
// subkey must have one signature
rnp_key_handle_t subkey = NULL;
assert_rnp_success(rnp_key_get_subkey_at(key, 0, &subkey));
assert_rnp_success(rnp_key_get_signature_count(subkey, &sigs));
assert_int_equal(sigs, 1);
assert_rnp_success(rnp_key_get_signature_at(subkey, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &type));
assert_string_equal(type, "subkey binding");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_signature_get_creation(sig, &creation));
assert_int_equal(creation, 1549119513);
assert_rnp_success(rnp_signature_get_alg(sig, &alg));
assert_string_equal(alg, "ECDSA");
rnp_buffer_destroy(alg);
assert_rnp_success(rnp_signature_get_hash_alg(sig, &alg));
assert_string_equal(alg, "SHA384");
rnp_buffer_destroy(alg);
assert_rnp_success(rnp_signature_get_keyid(sig, &keyid));
assert_non_null(keyid);
assert_string_equal(keyid, "242A3AA5EA85F44A");
rnp_buffer_destroy(keyid);
assert_rnp_success(rnp_signature_get_signer(sig, &signer));
assert_non_null(signer);
assert_rnp_success(rnp_key_get_keyid(signer, &keyid));
assert_non_null(keyid);
assert_string_equal(keyid, "242A3AA5EA85F44A");
rnp_buffer_destroy(keyid);
rnp_key_handle_destroy(signer);
rnp_key_handle_destroy(subkey);
assert_rnp_success(rnp_signature_handle_destroy(sig));
assert_rnp_success(rnp_uid_handle_destroy(uid));
assert_rnp_success(rnp_key_handle_destroy(key));
// cleanup
rnp_ffi_destroy(ffi);
}
static bool
check_import_sigs(rnp_ffi_t ffi, json_object **jso, json_object **sigarr, const char *sigpath)
{
rnp_input_t input = NULL;
if (rnp_input_from_path(&input, sigpath)) {
return false;
}
bool res = false;
char *sigs = NULL;
*jso = NULL;
if (rnp_import_signatures(ffi, input, 0, &sigs)) {
goto done;
}
if (!sigs) {
goto done;
}
*jso = json_tokener_parse(sigs);
if (!jso) {
goto done;
}
if (!json_object_is_type(*jso, json_type_object)) {
goto done;
}
if (!json_object_object_get_ex(*jso, "sigs", sigarr)) {
goto done;
}
if (!json_object_is_type(*sigarr, json_type_array)) {
goto done;
}
res = true;
done:
if (!res) {
json_object_put(*jso);
*jso = NULL;
}
rnp_input_destroy(input);
rnp_buffer_destroy(sigs);
return res;
}
static bool
check_sig_status(json_object *sig, const char *pub, const char *sec, const char *fp)
{
if (!sig) {
return false;
}
if (!json_object_is_type(sig, json_type_object)) {
return false;
}
json_object *fld = NULL;
if (!json_object_object_get_ex(sig, "public", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), pub) != 0) {
return false;
}
if (!json_object_object_get_ex(sig, "secret", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), sec) != 0) {
return false;
}
if (!fp && json_object_object_get_ex(sig, "signer fingerprint", &fld)) {
return false;
}
if (fp) {
if (!json_object_object_get_ex(sig, "signer fingerprint", &fld)) {
return false;
}
if (strcmp(json_object_get_string(fld), fp) != 0) {
return false;
}
}
return true;
}
TEST_F(rnp_tests, test_ffi_import_signatures)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
char * results = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, &results));
assert_rnp_success(rnp_input_destroy(input));
rnp_buffer_destroy(results);
/* find key and check signature count */
rnp_key_handle_t key_handle = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
size_t sigcount = 0;
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 0);
/* check revocation status */
bool revoked = false;
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_false(revoked);
/* some import edge cases */
assert_rnp_failure(rnp_import_signatures(ffi, NULL, 0, &results));
assert_rnp_failure(rnp_import_signatures(NULL, input, 0, &results));
assert_rnp_failure(rnp_import_signatures(ffi, input, 0x18, &results));
/* import revocation signature */
json_object *jso = NULL;
json_object *jsosigs = NULL;
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-rev.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
json_object *jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(check_sig_status(
jsosig, "new", "unknown key", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
/* key now must become revoked */
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
/* check signature number - it now must be 1 */
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 1);
/* check signature type */
rnp_signature_handle_t sig = NULL;
assert_rnp_success(rnp_key_get_signature_at(key_handle, 0, &sig));
char *type = NULL;
assert_rnp_success(rnp_signature_get_type(sig, &type));
assert_string_equal(type, "key revocation");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
uint32_t screate = 0;
assert_rnp_success(rnp_signature_get_creation(sig, &screate));
assert_int_equal(screate, 1578663151);
rnp_signature_handle_destroy(sig);
/* check key validity */
bool valid = true;
assert_rnp_success(rnp_key_is_valid(key_handle, &valid));
assert_false(valid);
uint32_t till = 0;
assert_rnp_success(rnp_key_valid_till(key_handle, &till));
assert_int_equal(till, 1578663151);
/* check import with NULL results param */
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-rev.pgp"));
assert_rnp_success(rnp_import_signatures(ffi, input, 0, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* import signature again, making sure it is not duplicated */
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-rev.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(check_sig_status(
jsosig, "unchanged", "unknown key", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
/* check signature count, using the same key handle (it must not be changed) */
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 1);
rnp_key_handle_destroy(key_handle);
/* save and reload keyring, making sure signature is saved */
rnp_output_t output = NULL;
assert_rnp_success(rnp_output_to_path(&output, "pubring.gpg"));
assert_rnp_success(rnp_save_keys(ffi, "GPG", output, RNP_LOAD_SAVE_PUBLIC_KEYS));
assert_rnp_success(rnp_output_destroy(output));
assert_rnp_success(rnp_ffi_destroy(ffi));
/* re-init ffi and load keys */
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_input_from_path(&input, "pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* find key and check sig count and revocation status */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 1);
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
assert_rnp_success(rnp_key_is_valid(key_handle, &valid));
assert_false(valid);
assert_rnp_success(rnp_key_valid_till(key_handle, &till));
assert_int_equal(till, 1578663151);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
assert_int_equal(unlink("pubring.gpg"), 0);
/* try to import wrong signature (certification) */
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-cert.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(check_sig_status(jsosig, "none", "none", NULL));
json_object_put(jso);
/* try to import signature for both public and secret key */
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_key_validity/alice-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-sec.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-rev.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(
check_sig_status(jsosig, "new", "new", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
/* import direct-key signature (with revocation key subpacket) */
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-revoker-sig.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(
check_sig_status(jsosig, "new", "new", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 2);
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
assert_rnp_success(rnp_key_get_signature_at(key_handle, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &type));
assert_string_equal(type, "direct");
rnp_buffer_destroy(type);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* load two binary signatures from the file */
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_key_validity/alice-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-sigs.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 2);
jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(check_sig_status(
jsosig, "new", "unknown key", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
jsosig = json_object_array_get_idx(jsosigs, 1);
assert_true(check_sig_status(
jsosig, "new", "unknown key", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 2);
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* load two armored signatures from the single file */
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_key_validity/alice-sec.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_true(
check_import_sigs(ffi, &jso, &jsosigs, "data/test_key_validity/alice-sigs.asc"));
assert_int_equal(json_object_array_length(jsosigs), 2);
jsosig = json_object_array_get_idx(jsosigs, 0);
/* when secret key is loaded then public copy is created automatically */
assert_true(
check_sig_status(jsosig, "new", "new", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
jsosig = json_object_array_get_idx(jsosigs, 1);
assert_true(
check_sig_status(jsosig, "new", "new", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 2);
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* try to import signature from key file - must fail */
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-sec.asc"));
results = NULL;
assert_rnp_failure(rnp_import_signatures(ffi, input, 0, &results));
assert_null(results);
assert_rnp_success(rnp_input_destroy(input));
/* try to import signatures from stream where second is malformed. Nothing should be
* imported. */
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_key_validity/alice-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/alice-sigs-malf.pgp"));
results = NULL;
assert_rnp_failure(rnp_import_signatures(ffi, input, 0, &results));
assert_null(results);
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 0);
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_false(revoked);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_export_revocation)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-sec.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
rnp_key_handle_t key_handle = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
rnp_output_t output = NULL;
assert_rnp_success(rnp_output_to_null(&output));
/* check for failure with wrong parameters */
assert_rnp_failure(rnp_key_export_revocation(
NULL, output, 0, "SHA256", "superseded", "test key revocation"));
assert_rnp_failure(rnp_key_export_revocation(key_handle, NULL, 0, "SHA256", NULL, NULL));
assert_rnp_failure(
rnp_key_export_revocation(key_handle, output, 0x17, "SHA256", NULL, NULL));
assert_rnp_failure(
rnp_key_export_revocation(key_handle, output, 0, "Wrong hash", NULL, NULL));
assert_rnp_failure(
rnp_key_export_revocation(key_handle, output, 0, "SHA256", "Wrong reason code", NULL));
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* check for failure with subkey */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_validity/alice-sub-sec.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "keyid", "DD23CEB7FEBEFF17", &key_handle));
assert_rnp_success(rnp_key_unlock(key_handle, "password"));
assert_rnp_failure(rnp_key_export_revocation(
key_handle, output, 0, "SHA256", "superseded", "test key revocation"));
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* try to export revocation having public key only */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_SECRET));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
assert_rnp_failure(rnp_key_export_revocation(
key_handle, output, 0, "SHA256", "superseded", "test key revocation"));
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* load secret key and export revocation - should succeed with correct password */
assert_rnp_success(rnp_input_from_path(&input, "data/test_key_validity/alice-sec.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_SECRET_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
/* wrong password - must fail */
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "wrong"));
assert_rnp_failure(rnp_key_export_revocation(
key_handle, output, 0, "SHA256", "superseded", "test key revocation"));
/* unlocked key - must succeed */
assert_rnp_success(rnp_key_unlock(key_handle, "password"));
assert_rnp_success(rnp_key_export_revocation(key_handle, output, 0, "SHA256", NULL, NULL));
assert_rnp_success(rnp_output_destroy(output));
assert_rnp_success(rnp_output_to_path(&output, "alice-revocation.pgp"));
/* correct password provider - must succeed */
assert_rnp_success(rnp_key_lock(key_handle));
assert_rnp_success(
rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"));
assert_rnp_success(rnp_key_export_revocation(
key_handle, output, 0, "SHA256", "superseded", "test key revocation"));
/* make sure FFI locks key back */
bool locked = false;
assert_rnp_success(rnp_key_is_locked(key_handle, &locked));
assert_true(locked);
assert_rnp_success(rnp_output_destroy(output));
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* make sure we can successfully import exported revocation */
json_object *jso = NULL;
json_object *jsosigs = NULL;
assert_true(check_import_sigs(ffi, &jso, &jsosigs, "alice-revocation.pgp"));
assert_int_equal(json_object_array_length(jsosigs), 1);
json_object *jsosig = json_object_array_get_idx(jsosigs, 0);
assert_true(
check_sig_status(jsosig, "new", "new", "73edcc9119afc8e2dbbdcde50451409669ffde3c"));
json_object_put(jso);
/* key now must become revoked */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key_handle));
bool revoked = false;
assert_rnp_success(rnp_key_is_revoked(key_handle, &revoked));
assert_true(revoked);
/* check signature number - it now must be 1 */
size_t sigcount = 0;
assert_rnp_success(rnp_key_get_signature_count(key_handle, &sigcount));
assert_int_equal(sigcount, 1);
assert_rnp_success(rnp_key_handle_destroy(key_handle));
/* check signature contents */
pgp_source_t src = {};
assert_rnp_success(init_file_src(&src, "alice-revocation.pgp"));
pgp_signature_t sig = {};
assert_rnp_success(sig.parse(src));
src_close(&src);
assert_int_equal(sig.type(), PGP_SIG_REV_KEY);
assert_true(sig.has_subpkt(PGP_SIG_SUBPKT_REVOCATION_REASON));
assert_true(sig.has_keyfp());
assert_int_equal(sig.revocation_code(), PGP_REVOCATION_SUPERSEDED);
assert_string_equal(sig.revocation_reason().c_str(), "test key revocation");
assert_int_equal(unlink("alice-revocation.pgp"), 0);
assert_rnp_success(rnp_ffi_destroy(ffi));
}
#define KEYSIG_PATH "data/test_key_validity/"
TEST_F(rnp_tests, test_ffi_sig_validity)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
/* Case1:
* Keys: Alice [pub]
* Alice is signed by Basil, but without the Basil's key.
* Result: Alice [valid]
*/
rnp_input_t input = NULL;
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case1/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
bool valid = false;
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_signature_handle_t sig = NULL;
/* signature 0: valid self-signature */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
char *sigtype = NULL;
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 1: valid certification from Basil, but without Basil's key */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_KEY_NOT_FOUND);
/* let's load Basil's key and make sure signature is now validated and valid */
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "basil-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
/* Case2:
* Keys: Alice [pub], Basil [pub]
* Alice is signed by Basil, Basil is signed by Alice, but Alice's self-signature is
* corrupted.
* Result: Alice [invalid], Basil [valid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case2/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* Alice key */
/* we cannot get key by uid since uid is invalid */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
assert_null(key);
/* get it via the fingerprint */
assert_rnp_success(
rnp_locate_key(ffi, "fingerprint", "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C", &key));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
/* signature 0: corrupted self-signature */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
/* signature 1: valid certification from Basil */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
/* Basil key */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Basil <basil@rnp>", &key));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
/* signature 0: valid self-signature */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 1: valid certification from Alice */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
/* Case3:
* Keys: Alice [pub], Basil [pub]
* Alice is signed by Basil, but doesn't have self-signature
* Result: Alice [invalid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case3/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* Alice key */
/* cannot locate it via userid since it is invalid */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
assert_null(key);
/* let's locate it via the fingerprint */
assert_rnp_success(
rnp_locate_key(ffi, "fingerprint", "73EDCC9119AFC8E2DBBDCDE50451409669FFDE3C", &key));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
/* signature 0: valid certification from Basil */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
/* Case4:
* Keys Alice [pub, sub]
* Alice subkey has invalid binding signature
* Result: Alice [valid], Alice sub [invalid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case4/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_key_handle_t sub = NULL;
rnp_key_get_subkey_at(key, 0, &sub);
rnp_key_get_signature_at(sub, 0, &sig);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* Case5:
* Keys Alice [pub, sub], Basil [pub]
* Alice subkey has valid binding signature, but from the key Basil
* Result: Alice [valid], Alice sub [invalid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case5/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_key_get_subkey_at(key, 0, &sub);
rnp_key_get_signature_at(sub, 0, &sig);
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "subkey binding");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* Case6:
* Keys Alice [pub, sub]
* Key Alice has revocation signature by Alice, and subkey doesn't
* Result: Alice [invalid], Alice sub [invalid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case6/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* check revocation signature */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_key_get_signature_at(key, 0, &sig);
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "key revocation");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* check subkey binding */
rnp_key_get_subkey_at(key, 0, &sub);
rnp_key_get_signature_at(sub, 0, &sig);
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "subkey binding");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* Case7:
* Keys Alice [pub, sub]
* Alice subkey has revocation signature by Alice
* Result: Alice [valid], Alice sub [invalid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case7/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* check subkey revocation signature */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_key_get_subkey_at(key, 0, &sub);
rnp_key_get_signature_at(sub, 0, &sig);
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "subkey revocation");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* check subkey binding */
rnp_key_get_signature_at(sub, 1, &sig);
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "subkey binding");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_key_handle_destroy(sub);
rnp_key_handle_destroy(key);
/* Case8:
* Keys Alice [pub, sub]
* Userid is stripped from the key, but it still has valid subkey binding
* Result: Alice [valid], Alice sub[valid]
*/
/* not interesting for us at the moment */
/* Case9:
* Keys Alice [pub, sub]
* Alice key has two self-signatures, one which expires key and second without key
* expiration.
* Result: Alice [valid], Alice sub[valid]
*/
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "case9/pubring.gpg"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
/* Alice key */
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
/* signature 0: valid certification */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 1: valid certification */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
/* another case: expired certification */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(
rnp_input_from_path(&input, KEYSIG_PATH "alice-expired-claus-cert.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_input_from_path(&input, KEYSIG_PATH "claus-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
/* signature 0: valid certification */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 1: expired claus's certification */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_EXPIRED);
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_ffi_destroy(ffi));
}
TEST_F(rnp_tests, test_ffi_get_signature_type)
{
rnp_ffi_t ffi = NULL;
rnp_input_t input = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
assert_rnp_success(
rnp_input_from_path(&input, "data/test_key_edge_cases/alice-sig-misc-values.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_path(&input, KEYSIG_PATH "basil-pub.asc"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
assert_rnp_success(rnp_input_destroy(input));
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "Alice <alice@rnp>", &key));
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
rnp_signature_handle_t sig = NULL;
/* signature 0: valid self-signature */
assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &sig));
char *sigtype = NULL;
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (positive)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 1: valid signature by Basil */
assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (generic)");
rnp_buffer_destroy(sigtype);
assert_rnp_success(rnp_signature_is_valid(sig, 0));
rnp_signature_handle_destroy(sig);
/* signature 2..7: invalid signatures with misc types */
assert_rnp_success(rnp_uid_get_signature_at(uid, 2, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "standalone");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_VERIFICATION_FAILED);
rnp_signature_handle_destroy(sig);
assert_rnp_success(rnp_uid_get_signature_at(uid, 3, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (persona)");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
assert_rnp_success(rnp_uid_get_signature_at(uid, 4, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification (casual)");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
assert_rnp_success(rnp_uid_get_signature_at(uid, 5, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "primary key binding");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_VERIFICATION_FAILED);
rnp_signature_handle_destroy(sig);
assert_rnp_success(rnp_uid_get_signature_at(uid, 6, &sig));
assert_rnp_success(rnp_signature_get_type(sig, &sigtype));
assert_string_equal(sigtype, "certification revocation");
rnp_buffer_destroy(sigtype);
assert_int_equal(rnp_signature_is_valid(sig, 0), RNP_ERROR_SIGNATURE_INVALID);
rnp_signature_handle_destroy(sig);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
assert_rnp_success(rnp_ffi_destroy(ffi));
}

247
third_party/rnp/src/tests/ffi-uid.cpp поставляемый Normal file
Просмотреть файл

@ -0,0 +1,247 @@
/*
* 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_tests.h"
#include "support.h"
TEST_F(rnp_tests, test_ffi_uid_properties)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
rnp_input_t input = NULL;
assert_rnp_success(rnp_input_from_path(&input, "data/test_uid_validity/key-uids-pub.pgp"));
assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "F6E741D1DF582D90", &key));
assert_non_null(key);
size_t uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 4);
rnp_uid_handle_t uid = NULL;
assert_rnp_failure(rnp_key_get_uid_handle_at(NULL, 0, &uid));
assert_rnp_failure(rnp_key_get_uid_handle_at(key, 0, NULL));
assert_rnp_failure(rnp_key_get_uid_handle_at(key, 100, &uid));
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_non_null(uid);
uint32_t uid_type = 0;
assert_rnp_failure(rnp_uid_get_type(NULL, &uid_type));
assert_rnp_failure(rnp_uid_get_type(uid, NULL));
assert_rnp_success(rnp_uid_get_type(uid, &uid_type));
assert_int_equal(uid_type, RNP_USER_ID);
size_t size = 0;
void * data = NULL;
assert_rnp_failure(rnp_uid_get_data(NULL, &data, &size));
assert_rnp_failure(rnp_uid_get_data(uid, NULL, &size));
assert_rnp_failure(rnp_uid_get_data(uid, &data, NULL));
assert_rnp_success(rnp_uid_get_data(uid, &data, &size));
assert_int_equal(size, 12);
assert_int_equal(memcmp(data, "userid-valid", size), 0);
rnp_buffer_destroy(data);
bool primary = false;
assert_rnp_failure(rnp_uid_is_primary(NULL, &primary));
assert_rnp_failure(rnp_uid_is_primary(uid, NULL));
assert_rnp_success(rnp_uid_is_primary(uid, &primary));
assert_true(primary);
rnp_uid_handle_destroy(uid);
assert_rnp_success(rnp_key_get_uid_handle_at(key, 1, &uid));
assert_rnp_success(rnp_uid_get_data(uid, &data, &size));
assert_int_equal(size, 14);
assert_int_equal(memcmp(data, "userid-expired", size), 0);
rnp_buffer_destroy(data);
assert_rnp_success(rnp_uid_is_primary(uid, &primary));
assert_false(primary);
rnp_uid_handle_destroy(uid);
assert_rnp_success(rnp_key_get_uid_handle_at(key, 2, &uid));
assert_rnp_success(rnp_uid_get_data(uid, &data, &size));
assert_int_equal(size, 14);
assert_int_equal(memcmp(data, "userid-invalid", size), 0);
rnp_buffer_destroy(data);
assert_rnp_success(rnp_uid_is_primary(uid, &primary));
assert_false(primary);
rnp_uid_handle_destroy(uid);
assert_rnp_success(rnp_key_get_uid_handle_at(key, 3, &uid));
assert_rnp_success(rnp_uid_get_type(uid, &uid_type));
assert_int_equal(uid_type, RNP_USER_ATTR);
assert_rnp_success(rnp_uid_get_data(uid, &data, &size));
assert_int_equal(size, 3038);
rnp_buffer_destroy(data);
assert_rnp_success(rnp_uid_is_primary(uid, &primary));
assert_false(primary);
rnp_uid_handle_destroy(uid);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}
TEST_F(rnp_tests, test_ffi_uid_validity)
{
rnp_ffi_t ffi = NULL;
assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
rnp_input_t input = NULL;
assert_rnp_success(
rnp_input_from_path(&input, "data/test_uid_validity/key-uids-with-invalid.pgp"));
assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
rnp_input_destroy(input);
rnp_key_handle_t key = NULL;
assert_rnp_success(rnp_locate_key(ffi, "keyid", "F6E741D1DF582D90", &key));
assert_non_null(key);
size_t uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 4);
/* userid 0 : valid */
rnp_uid_handle_t uid = NULL;
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
bool valid = false;
assert_rnp_failure(rnp_uid_is_valid(NULL, &valid));
assert_rnp_failure(rnp_uid_is_valid(uid, NULL));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* userid 1 : expired */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 1, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
rnp_uid_handle_destroy(uid);
/* userid 2 : invalid (malformed signature data) */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 2, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
rnp_uid_handle_destroy(uid);
/* userid 3: valid userattr */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 3, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* Try to locate key via all uids */
rnp_key_handle_t newkey = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "userid-valid", &newkey));
assert_non_null(newkey);
rnp_key_handle_destroy(newkey);
newkey = NULL;
assert_rnp_success(rnp_locate_key(ffi, "userid", "userid-expired", &newkey));
assert_null(newkey);
assert_rnp_success(rnp_locate_key(ffi, "userid", "userid-invalid", &newkey));
assert_null(newkey);
/* Now import key with valid signature for the userid 2 */
assert_rnp_success(rnp_input_from_path(&input, "data/test_uid_validity/key-uids-pub.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 4);
/* userid 0 : valid */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* userid 1 : expired */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 1, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
rnp_uid_handle_destroy(uid);
/* userid 2 : valid */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 2, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* userid 3 : valid userattr */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 3, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_true(valid);
rnp_uid_handle_destroy(uid);
/* now we should be able to locate key via userid-invalid */
assert_rnp_success(rnp_locate_key(ffi, "userid", "userid-invalid", &newkey));
assert_non_null(newkey);
rnp_key_handle_destroy(newkey);
/* Now import key with revoked primary userid */
assert_rnp_success(
rnp_input_from_path(&input, "data/test_uid_validity/key-uids-revoked-valid.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
uids = 0;
assert_rnp_success(rnp_key_get_uid_count(key, &uids));
assert_int_equal(uids, 4);
/* userid 0 : invalid since it is revoked */
assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
assert_rnp_success(rnp_uid_is_valid(uid, &valid));
assert_false(valid);
bool primary = true;
assert_rnp_success(rnp_uid_is_primary(uid, &primary));
assert_false(primary);
rnp_uid_handle_destroy(uid);
/* Primary userid now should be userid-invalid - first is revoked, second is expired */
char *uid_str = NULL;
assert_rnp_success(rnp_key_get_primary_uid(key, &uid_str));
assert_non_null(uid_str);
assert_string_equal(uid_str, "userid-invalid");
rnp_buffer_destroy(uid_str);
/* We should not be able to find key via userid-valid */
assert_rnp_success(rnp_locate_key(ffi, "userid", "userid-valid", &newkey));
assert_null(newkey);
rnp_key_handle_destroy(key);
/* Load expired key with single uid: now should be no primary */
assert_rnp_success(rnp_unload_keys(ffi, RNP_KEY_UNLOAD_PUBLIC));
assert_rnp_success(rnp_input_from_path(&input, "data/test_uid_validity/key-expired.pgp"));
assert_rnp_success(rnp_import_keys(ffi, input, RNP_LOAD_SAVE_PUBLIC_KEYS, NULL));
rnp_input_destroy(input);
assert_rnp_success(rnp_locate_key(ffi, "keyid", "4BE147BB22DF1E60", &key));
assert_non_null(key);
uid_str = NULL;
assert_rnp_failure(rnp_key_get_primary_uid(key, &uid_str));
assert_null(uid_str);
rnp_key_handle_destroy(key);
rnp_ffi_destroy(ffi);
}

1103
third_party/rnp/src/tests/ffi.cpp поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

2
third_party/rnp/src/tests/file-utils.cpp поставляемый
Просмотреть файл

@ -29,7 +29,7 @@
TEST_F(rnp_tests, test_rnp_mkstemp)
{
#ifdef _MSC_VER
#ifdef _WIN32
const char tmpl[17] = "test-file.XXXXXX";
char buf[17];
const int size = 20;

42
third_party/rnp/src/tests/fuzz_dump.cpp поставляемый Normal file
Просмотреть файл

@ -0,0 +1,42 @@
/*
* 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_tests.h"
#include "support.h"
extern "C" int dump_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
#define DATA_PATH "data/test_fuzz_dump/"
TEST_F(rnp_tests, test_fuzz_dump)
{
auto data =
file_to_vec(DATA_PATH "clusterfuzz-testcase-minimized-fuzz_dump-5757362284265472");
time_t start = time(NULL);
assert_int_equal(dump_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
assert_true(time(NULL) - start <= 1800);
}

Просмотреть файл

@ -39,4 +39,13 @@ TEST_F(rnp_tests, test_fuzz_keyimport)
data = file_to_vec(DATA_PATH "crash_e932261875271ccf497715de56adf7caf30ca8a7");
assert_int_equal(keyimport_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
data = file_to_vec(DATA_PATH "crash_37e8ed57ee47c1991b387fa0506f361f9cd9c663");
assert_int_equal(keyimport_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
data = file_to_vec(DATA_PATH "leak_11307b70cc609c93fc3a49d37f3a31166df50f44");
assert_int_equal(keyimport_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
data = file_to_vec(DATA_PATH "timeout_9c10372fe9ebdcdb0b6e275d05f8af4f4e3d6051");
assert_int_equal(keyimport_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
}

44
third_party/rnp/src/tests/fuzz_verify_detached.cpp поставляемый Normal file
Просмотреть файл

@ -0,0 +1,44 @@
/*
* 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_tests.h"
#include "support.h"
#include <librepgp/stream-write.h>
extern "C" int verify_detached_LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
#define DATA_PATH "data/test_fuzz_verify_detached/"
TEST_F(rnp_tests, test_fuzz_verify_detached)
{
auto data = file_to_vec(
DATA_PATH "clusterfuzz-testcase-minimized-fuzz_verify_detached-5092660526972928");
assert_int_equal(verify_detached_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
data = file_to_vec(DATA_PATH "outofmemory-23094cb781b2cf6d1749ebac8bd0576e51440498-z");
assert_int_equal(verify_detached_LLVMFuzzerTestOneInput(data.data(), data.size()), 0);
}

259
third_party/rnp/src/tests/generatekey.cpp поставляемый
Просмотреть файл

@ -188,12 +188,12 @@ TEST_F(rnp_tests, rnpkeys_generatekey_testSignature)
}
cli_rnp_end(&rnp);
assert_int_equal(unlink("dummyfile.dat.pgp"), 0);
unlink("dummyfile.verify");
assert_int_equal(rnp_unlink("dummyfile.dat.pgp"), 0);
rnp_unlink("dummyfile.verify");
}
}
}
assert_int_equal(unlink("dummyfile.dat"), 0);
assert_int_equal(rnp_unlink("dummyfile.dat"), 0);
}
TEST_F(rnp_tests, rnpkeys_generatekey_testEncryption)
@ -258,11 +258,11 @@ TEST_F(rnp_tests, rnpkeys_generatekey_testEncryption)
/* Ensure plaintext recovered */
std::string decrypt = file_to_str("dummyfile.decrypt");
assert_true(decrypt == memToEncrypt);
assert_int_equal(unlink("dummyfile.dat.pgp"), 0);
assert_int_equal(unlink("dummyfile.decrypt"), 0);
assert_int_equal(rnp_unlink("dummyfile.dat.pgp"), 0);
assert_int_equal(rnp_unlink("dummyfile.decrypt"), 0);
}
}
assert_int_equal(unlink("dummyfile.dat"), 0);
assert_int_equal(rnp_unlink("dummyfile.dat"), 0);
}
TEST_F(rnp_tests, rnpkeys_generatekey_verifySupportedHashAlg)
@ -364,15 +364,15 @@ TEST_F(rnp_tests, rnpkeys_generatekey_verifykeyHomeDirOption)
assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_GPG, NULL, NULL));
/* Pubring and secring should not exist yet */
assert_false(path_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_file_exists(".rnp/secring.gpg", NULL));
assert_false(path_rnp_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_rnp_file_exists(".rnp/secring.gpg", NULL));
/* Ensure the key was generated. */
assert_true(generate_test_key(RNP_KEYSTORE_GPG, NULL, "SHA256", NULL));
/* Pubring and secring should now exist */
assert_true(path_file_exists(".rnp/pubring.gpg", NULL));
assert_true(path_file_exists(".rnp/secring.gpg", NULL));
assert_true(path_rnp_file_exists(".rnp/pubring.gpg", NULL));
assert_true(path_rnp_file_exists(".rnp/secring.gpg", NULL));
/* Loading keyrings and checking whether they have correct key */
assert_true(cli_rnp_load_keyrings(&rnp, true));
@ -401,15 +401,15 @@ TEST_F(rnp_tests, rnpkeys_generatekey_verifykeyHomeDirOption)
assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_GPG, newhome.c_str(), NULL));
/* Pubring and secring should not exist yet */
assert_false(path_file_exists(newhome.c_str(), "pubring.gpg", NULL));
assert_false(path_file_exists(newhome.c_str(), "secring.gpg", NULL));
assert_false(path_rnp_file_exists(newhome.c_str(), "pubring.gpg", NULL));
assert_false(path_rnp_file_exists(newhome.c_str(), "secring.gpg", NULL));
/* Ensure the key was generated. */
assert_true(generate_test_key(RNP_KEYSTORE_GPG, "newhomekey", "SHA256", newhome.c_str()));
/* Pubring and secring should now exist */
assert_true(path_file_exists(newhome.c_str(), "pubring.gpg", NULL));
assert_true(path_file_exists(newhome.c_str(), "secring.gpg", NULL));
assert_true(path_rnp_file_exists(newhome.c_str(), "pubring.gpg", NULL));
assert_true(path_rnp_file_exists(newhome.c_str(), "secring.gpg", NULL));
/* Loading keyrings and checking whether they have correct key */
assert_true(cli_rnp_load_keyrings(&rnp, true));
@ -438,17 +438,17 @@ TEST_F(rnp_tests, rnpkeys_generatekey_verifykeyKBXHomeDirOption)
/* Initialize the rnp structure. */
assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_KBX, NULL, NULL));
/* Pubring and secring should not exist yet */
assert_false(path_file_exists(".rnp/pubring.kbx", NULL));
assert_false(path_file_exists(".rnp/secring.kbx", NULL));
assert_false(path_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_file_exists(".rnp/secring.gpg", NULL));
assert_false(path_rnp_file_exists(".rnp/pubring.kbx", NULL));
assert_false(path_rnp_file_exists(".rnp/secring.kbx", NULL));
assert_false(path_rnp_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_rnp_file_exists(".rnp/secring.gpg", NULL));
/* Ensure the key was generated. */
assert_true(generate_test_key(RNP_KEYSTORE_KBX, NULL, "SHA256", NULL));
/* Pubring and secring should now exist, but only for the KBX */
assert_true(path_file_exists(".rnp/pubring.kbx", NULL));
assert_true(path_file_exists(".rnp/secring.kbx", NULL));
assert_false(path_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_file_exists(".rnp/secring.gpg", NULL));
assert_true(path_rnp_file_exists(".rnp/pubring.kbx", NULL));
assert_true(path_rnp_file_exists(".rnp/secring.kbx", NULL));
assert_false(path_rnp_file_exists(".rnp/pubring.gpg", NULL));
assert_false(path_rnp_file_exists(".rnp/secring.gpg", NULL));
/* Loading keyrings and checking whether they have correct key */
assert_true(cli_rnp_load_keyrings(&rnp, true));
@ -471,18 +471,18 @@ TEST_F(rnp_tests, rnpkeys_generatekey_verifykeyKBXHomeDirOption)
/* Initialize the rnp structure. */
assert_true(setup_cli_rnp_common(&rnp, RNP_KEYSTORE_KBX, newhome, NULL));
/* Pubring and secring should not exist yet */
assert_false(path_file_exists(newhome, "pubring.kbx", NULL));
assert_false(path_file_exists(newhome, "secring.kbx", NULL));
assert_false(path_file_exists(newhome, "pubring.gpg", NULL));
assert_false(path_file_exists(newhome, "secring.gpg", NULL));
assert_false(path_rnp_file_exists(newhome, "pubring.kbx", NULL));
assert_false(path_rnp_file_exists(newhome, "secring.kbx", NULL));
assert_false(path_rnp_file_exists(newhome, "pubring.gpg", NULL));
assert_false(path_rnp_file_exists(newhome, "secring.gpg", NULL));
/* Ensure the key was generated. */
assert_true(generate_test_key(RNP_KEYSTORE_KBX, "newhomekey", "SHA256", newhome));
/* Pubring and secring should now exist, but only for the KBX */
assert_true(path_file_exists(newhome, "pubring.kbx", NULL));
assert_true(path_file_exists(newhome, "secring.kbx", NULL));
assert_false(path_file_exists(newhome, "pubring.gpg", NULL));
assert_false(path_file_exists(newhome, "secring.gpg", NULL));
assert_true(path_rnp_file_exists(newhome, "pubring.kbx", NULL));
assert_true(path_rnp_file_exists(newhome, "secring.kbx", NULL));
assert_false(path_rnp_file_exists(newhome, "pubring.gpg", NULL));
assert_false(path_rnp_file_exists(newhome, "secring.gpg", NULL));
/* Loading keyrings and checking whether they have correct key */
assert_true(cli_rnp_load_keyrings(&rnp, true));
keycount = 0;
@ -934,36 +934,38 @@ TEST_F(rnp_tests, test_generated_key_sigs)
assert_true(rnp_key_store_add_key(pubring, &pub));
assert_true(rnp_key_store_add_key(secring, &sec));
// retrieve back from our rings (for later)
primary_pub = rnp_key_store_get_key_by_grip(pubring, pgp_key_get_grip(&pub));
primary_sec = rnp_key_store_get_key_by_grip(secring, pgp_key_get_grip(&pub));
primary_pub = rnp_key_store_get_key_by_grip(pubring, pub.grip());
primary_sec = rnp_key_store_get_key_by_grip(secring, pub.grip());
assert_non_null(primary_pub);
assert_non_null(primary_sec);
assert_true(primary_pub->valid);
assert_true(primary_pub->validated);
assert_true(primary_sec->valid);
assert_true(primary_sec->validated);
assert_true(primary_pub->valid());
assert_true(primary_pub->validated());
assert_false(primary_pub->expired());
assert_true(primary_sec->valid());
assert_true(primary_sec->validated());
assert_false(primary_sec->expired());
// check packet and subsig counts
assert_int_equal(3, pgp_key_get_rawpacket_count(&pub));
assert_int_equal(3, pgp_key_get_rawpacket_count(&sec));
assert_int_equal(1, pgp_key_get_subsig_count(&pub));
assert_int_equal(1, pgp_key_get_subsig_count(&sec));
psig = &pgp_key_get_subsig(&pub, 0)->sig;
ssig = &pgp_key_get_subsig(&sec, 0)->sig;
assert_int_equal(3, pub.rawpkt_count());
assert_int_equal(3, sec.rawpkt_count());
assert_int_equal(1, pub.sig_count());
assert_int_equal(1, sec.sig_count());
psig = &pub.get_sig(0).sig;
ssig = &sec.get_sig(0).sig;
// make sure our sig MPI is not NULL
assert_int_not_equal(psig->material_len, 0);
assert_int_not_equal(ssig->material_len, 0);
// make sure we're targeting the right packet
assert_int_equal(PGP_PKT_SIGNATURE, pgp_key_get_subsig(&pub, 0)->rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, pgp_key_get_subsig(&sec, 0)->rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, pub.get_sig(0).rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, sec.get_sig(0).rawpkt.tag);
// validate the userid self-sig
psiginfo.sig = psig;
psiginfo.signer = &pub;
assert_rnp_success(signature_check_certification(
&psiginfo, pgp_key_get_pkt(&pub), &pgp_key_get_userid(&pub, 0)->pkt));
assert_true(psig->keyfp() == pgp_key_get_fp(&pub));
assert_rnp_success(
signature_check_certification(&psiginfo, &pub.pkt(), &pub.get_uid(0).pkt));
assert_true(psig->keyfp() == pub.fp());
// check subpackets and their contents
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR);
assert_non_null(subpkt);
@ -971,8 +973,8 @@ TEST_F(rnp_tests, test_generated_key_sigs)
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false);
assert_non_null(subpkt);
assert_false(subpkt->hashed);
assert_int_equal(
0, memcmp(subpkt->fields.issuer, pgp_key_get_keyid(&pub).data(), PGP_KEY_ID_SIZE));
assert_int_equal(0,
memcmp(subpkt->fields.issuer, pub.keyid().data(), PGP_KEY_ID_SIZE));
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_CREATION_TIME);
assert_non_null(subpkt);
assert_true(subpkt->hashed);
@ -980,18 +982,18 @@ TEST_F(rnp_tests, test_generated_key_sigs)
ssiginfo.sig = ssig;
ssiginfo.signer = &sec;
assert_rnp_success(signature_check_certification(
&ssiginfo, pgp_key_get_pkt(&sec), &pgp_key_get_userid(&sec, 0)->pkt));
assert_true(ssig->keyfp() == pgp_key_get_fp(&sec));
assert_rnp_success(
signature_check_certification(&ssiginfo, &sec.pkt(), &sec.get_uid(0).pkt));
assert_true(ssig->keyfp() == sec.fp());
// modify a hashed portion of the sig packets
psig->hashed_data[32] ^= 0xff;
ssig->hashed_data[32] ^= 0xff;
// ensure validation fails
assert_rnp_failure(signature_check_certification(
&psiginfo, pgp_key_get_pkt(&pub), &pgp_key_get_userid(&pub, 0)->pkt));
assert_rnp_failure(signature_check_certification(
&ssiginfo, pgp_key_get_pkt(&sec), &pgp_key_get_userid(&sec, 0)->pkt));
assert_rnp_failure(
signature_check_certification(&psiginfo, &pub.pkt(), &pub.get_uid(0).pkt));
assert_rnp_failure(
signature_check_certification(&ssiginfo, &sec.pkt(), &sec.get_uid(0).pkt));
// restore the original data
psig->hashed_data[32] ^= 0xff;
ssig->hashed_data[32] ^= 0xff;
@ -1002,49 +1004,46 @@ TEST_F(rnp_tests, test_generated_key_sigs)
uid.uid_len = 4;
memcpy(uid.uid, "fake", 4);
assert_rnp_failure(
signature_check_certification(&psiginfo, pgp_key_get_pkt(&pub), &uid));
assert_rnp_failure(
signature_check_certification(&ssiginfo, pgp_key_get_pkt(&sec), &uid));
assert_rnp_failure(signature_check_certification(&psiginfo, &pub.pkt(), &uid));
assert_rnp_failure(signature_check_certification(&ssiginfo, &sec.pkt(), &uid));
// validate via an alternative method
// primary_pub + pubring
primary_pub->valid = false;
primary_pub->validated = false;
pgp_key_validate(primary_pub, pubring);
assert_true(primary_pub->valid);
assert_true(primary_pub->validated);
primary_pub->validate(*pubring);
assert_true(primary_pub->valid());
assert_true(primary_pub->validated());
assert_false(primary_pub->expired());
// primary_sec + pubring
primary_sec->valid = false;
primary_sec->validated = false;
pgp_key_validate(primary_sec, pubring);
assert_true(primary_sec->valid);
assert_true(primary_sec->validated);
primary_sec->validate(*pubring);
assert_true(primary_sec->valid());
assert_true(primary_sec->validated());
assert_false(primary_sec->expired());
// primary_pub + secring
primary_pub->valid = primary_pub->validated = false;
pgp_key_validate(primary_pub, secring);
assert_true(primary_pub->valid);
assert_true(primary_pub->validated);
primary_pub->validate(*secring);
assert_true(primary_pub->valid());
assert_true(primary_pub->validated());
assert_false(primary_pub->expired());
// primary_sec + secring
primary_sec->valid = primary_sec->validated = false;
pgp_key_validate(primary_sec, secring);
assert_true(primary_sec->valid);
assert_true(primary_sec->validated);
primary_sec->validate(*secring);
assert_true(primary_sec->valid());
assert_true(primary_sec->validated());
assert_false(primary_sec->expired());
// modify a hashed portion of the sig packet, offset may change in future
pgp_subsig_t *sig = pgp_key_get_subsig(primary_pub, 0);
assert_non_null(sig);
sig->sig.hashed_data[10] ^= 0xff;
sig->validated = false;
pgp_subsig_t &sig = primary_pub->get_sig(0);
sig.sig.hashed_data[10] ^= 0xff;
sig.validity.validated = false;
// ensure validation fails
pgp_key_validate(primary_pub, pubring);
assert_false(primary_pub->valid);
assert_true(primary_pub->validated);
primary_pub->validate(*pubring);
assert_false(primary_pub->valid());
assert_true(primary_pub->validated());
assert_false(primary_pub->expired());
// restore the original data
sig->sig.hashed_data[10] ^= 0xff;
sig->validated = false;
pgp_key_validate(primary_pub, pubring);
assert_true(primary_pub->valid);
assert_true(primary_pub->validated);
sig.sig.hashed_data[10] ^= 0xff;
sig.validity.validated = false;
primary_pub->validate(*pubring);
assert_true(primary_pub->valid());
assert_true(primary_pub->validated());
assert_false(primary_pub->expired());
}
// sub
@ -1066,30 +1065,31 @@ TEST_F(rnp_tests, test_generated_key_sigs)
// generate
assert_true(pgp_generate_subkey(
&desc, true, primary_sec, primary_pub, &sec, &pub, NULL, PGP_KEY_STORE_GPG));
assert_true(pub.valid);
assert_true(pub.validated);
assert_true(sec.valid);
assert_true(sec.validated);
assert_true(pub.valid());
assert_true(pub.validated());
assert_false(pub.expired());
assert_true(sec.valid());
assert_true(sec.validated());
assert_false(sec.expired());
// check packet and subsig counts
assert_int_equal(2, pgp_key_get_rawpacket_count(&pub));
assert_int_equal(2, pgp_key_get_rawpacket_count(&sec));
assert_int_equal(1, pgp_key_get_subsig_count(&pub));
assert_int_equal(1, pgp_key_get_subsig_count(&sec));
psig = &pgp_key_get_subsig(&pub, 0)->sig;
ssig = &pgp_key_get_subsig(&sec, 0)->sig;
assert_int_equal(2, pub.rawpkt_count());
assert_int_equal(2, sec.rawpkt_count());
assert_int_equal(1, pub.sig_count());
assert_int_equal(1, sec.sig_count());
psig = &pub.get_sig(0).sig;
ssig = &sec.get_sig(0).sig;
// make sure our sig MPI is not NULL
assert_int_not_equal(psig->material_len, 0);
assert_int_not_equal(ssig->material_len, 0);
// make sure we're targeting the right packet
assert_int_equal(PGP_PKT_SIGNATURE, pgp_key_get_subsig(&pub, 0)->rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, pgp_key_get_subsig(&sec, 0)->rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, pub.get_sig(0).rawpkt.tag);
assert_int_equal(PGP_PKT_SIGNATURE, sec.get_sig(0).rawpkt.tag);
// validate the binding sig
psiginfo.sig = psig;
psiginfo.signer = primary_pub;
assert_rnp_success(
signature_check_binding(&psiginfo, pgp_key_get_pkt(primary_pub), &pub));
assert_true(psig->keyfp() == pgp_key_get_fp(primary_pub));
assert_rnp_success(signature_check_binding(&psiginfo, &primary_pub->pkt(), &pub));
assert_true(psig->keyfp() == primary_pub->fp());
// check subpackets and their contents
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_ISSUER_FPR);
assert_non_null(subpkt);
@ -1097,10 +1097,8 @@ TEST_F(rnp_tests, test_generated_key_sigs)
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_ISSUER_KEY_ID, false);
assert_non_null(subpkt);
assert_false(subpkt->hashed);
assert_int_equal(0,
memcmp(subpkt->fields.issuer,
pgp_key_get_keyid(primary_pub).data(),
PGP_KEY_ID_SIZE));
assert_int_equal(
0, memcmp(subpkt->fields.issuer, primary_pub->keyid().data(), PGP_KEY_ID_SIZE));
subpkt = psig->get_subpkt(PGP_SIG_SUBPKT_CREATION_TIME);
assert_non_null(subpkt);
assert_true(subpkt->hashed);
@ -1108,18 +1106,15 @@ TEST_F(rnp_tests, test_generated_key_sigs)
ssiginfo.sig = ssig;
ssiginfo.signer = primary_pub;
assert_rnp_success(
signature_check_binding(&ssiginfo, pgp_key_get_pkt(primary_pub), &sec));
assert_true(ssig->keyfp() == pgp_key_get_fp(primary_sec));
assert_rnp_success(signature_check_binding(&ssiginfo, &primary_pub->pkt(), &sec));
assert_true(ssig->keyfp() == primary_sec->fp());
// modify a hashed portion of the sig packets
psig->hashed_data[10] ^= 0xff;
ssig->hashed_data[10] ^= 0xff;
// ensure validation fails
assert_rnp_failure(
signature_check_binding(&psiginfo, pgp_key_get_pkt(primary_pub), &pub));
assert_rnp_failure(
signature_check_binding(&ssiginfo, pgp_key_get_pkt(primary_pub), &sec));
assert_rnp_failure(signature_check_binding(&psiginfo, &primary_pub->pkt(), &pub));
assert_rnp_failure(signature_check_binding(&ssiginfo, &primary_pub->pkt(), &sec));
// restore the original data
psig->hashed_data[10] ^= 0xff;
ssig->hashed_data[10] ^= 0xff;
@ -1128,26 +1123,26 @@ TEST_F(rnp_tests, test_generated_key_sigs)
assert_true(rnp_key_store_add_key(pubring, &pub));
assert_true(rnp_key_store_add_key(secring, &sec));
// retrieve back from our rings
sub_pub = rnp_key_store_get_key_by_grip(pubring, pgp_key_get_grip(&pub));
sub_sec = rnp_key_store_get_key_by_grip(secring, pgp_key_get_grip(&pub));
sub_pub = rnp_key_store_get_key_by_grip(pubring, pub.grip());
sub_sec = rnp_key_store_get_key_by_grip(secring, pub.grip());
assert_non_null(sub_pub);
assert_non_null(sub_sec);
assert_true(sub_pub->valid);
assert_true(sub_pub->validated);
assert_true(sub_sec->valid);
assert_true(sub_sec->validated);
assert_true(sub_pub->valid());
assert_true(sub_pub->validated());
assert_false(sub_pub->expired());
assert_true(sub_sec->valid());
assert_true(sub_sec->validated());
assert_false(sub_sec->expired());
// validate via an alternative method
sub_pub->valid = false;
sub_pub->validated = false;
pgp_key_validate(sub_pub, pubring);
assert_true(sub_pub->valid);
assert_true(sub_pub->validated);
sub_sec->valid = false;
sub_sec->validated = false;
pgp_key_validate(sub_sec, pubring);
assert_true(sub_sec->valid);
assert_true(sub_sec->validated);
sub_pub->validate(*pubring);
assert_true(sub_pub->valid());
assert_true(sub_pub->validated());
assert_false(sub_pub->expired());
sub_sec->validate(*pubring);
assert_true(sub_sec->valid());
assert_true(sub_sec->validated());
assert_false(sub_sec->expired());
}
delete pubring;

5
third_party/rnp/src/tests/issues/1171.cpp поставляемый
Просмотреть файл

@ -60,9 +60,8 @@ TEST_F(rnp_tests, test_issue_1171_key_import_and_remove)
assert_int_equal(bits, 256);
/* directly use rnp_key_store_get_key_by_grip() which caused crash */
pgp_key_t *subkey =
rnp_key_store_get_key_by_grip(ffi->pubring, pgp_key_get_grip(key->pub));
assert_int_equal(pgp_key_get_bits(subkey), 256);
pgp_key_t *subkey = rnp_key_store_get_key_by_grip(ffi->pubring, key->pub->grip());
assert_int_equal(subkey->material().bits(), 256);
assert_rnp_success(rnp_key_handle_destroy(key));
assert_rnp_success(

66
third_party/rnp/src/tests/key-add-userid.cpp поставляемый
Просмотреть файл

@ -59,11 +59,11 @@ TEST_F(rnp_tests, test_key_add_userid)
// unlock the key
pgp_password_provider_t pprov = {.callback = string_copy_password_callback,
.userdata = (void *) "password"};
assert_true(pgp_key_unlock(key, &pprov));
assert_true(key->unlock(pprov));
// save the counts for a few items
unsigned uidc = pgp_key_get_userid_count(key);
unsigned subsigc = pgp_key_get_subsig_count(key);
unsigned uidc = key->uid_count();
unsigned subsigc = key->sig_count();
// add a userid
@ -72,56 +72,52 @@ TEST_F(rnp_tests, test_key_add_userid)
selfsig.key_flags = 0xAB;
selfsig.key_expiration = 123456789;
selfsig.primary = 1;
assert_true(
pgp_key_add_userid_certified(key, pgp_key_get_pkt(key), PGP_HASH_SHA1, &selfsig));
assert_true(pgp_key_add_userid_certified(key, &key->pkt(), PGP_HASH_SHA1, &selfsig));
// make sure this userid has been marked as primary
assert_int_equal(pgp_key_get_userid_count(key) - 1, key->uid0);
assert_int_equal(key->uid_count() - 1, key->get_primary_uid());
// make sure key expiration and flags are set
assert_int_equal(123456789, pgp_key_get_expiration(key));
assert_int_equal(0xAB, pgp_key_get_flags(key));
assert_int_equal(123456789, key->expiration());
assert_int_equal(0xAB, key->flags());
// try to add the same userid (should fail)
rnp_selfsig_cert_info_t dup_selfsig = {};
memcpy(dup_selfsig.userid, "added1", 7);
assert_false(
pgp_key_add_userid_certified(key, pgp_key_get_pkt(key), PGP_HASH_SHA1, &dup_selfsig));
assert_false(pgp_key_add_userid_certified(key, &key->pkt(), PGP_HASH_SHA1, &dup_selfsig));
// try to add another primary userid (should fail)
rnp_selfsig_cert_info_t selfsig2 = {};
memcpy(selfsig2.userid, "added2", 7);
selfsig2.primary = 1;
assert_false(
pgp_key_add_userid_certified(key, pgp_key_get_pkt(key), PGP_HASH_SHA1, &selfsig2));
assert_false(pgp_key_add_userid_certified(key, &key->pkt(), PGP_HASH_SHA1, &selfsig2));
memcpy(selfsig2.userid, "added2", 7);
selfsig2.key_flags = 0xCD;
selfsig2.primary = 0;
// actually add another userid
assert_true(
pgp_key_add_userid_certified(key, pgp_key_get_pkt(key), PGP_HASH_SHA1, &selfsig2));
assert_true(pgp_key_add_userid_certified(key, &key->pkt(), PGP_HASH_SHA1, &selfsig2));
// confirm that the counts have increased as expected
assert_int_equal(pgp_key_get_userid_count(key), uidc + 2);
assert_int_equal(pgp_key_get_subsig_count(key), subsigc + 2);
assert_int_equal(key->uid_count(), uidc + 2);
assert_int_equal(key->sig_count(), subsigc + 2);
// make sure key expiration and flags are now updated
assert_int_equal(0, pgp_key_get_expiration(key));
assert_int_equal(0xCD, pgp_key_get_flags(key));
assert_int_equal(0, key->expiration());
assert_int_equal(0xCD, key->flags());
// check the userids array
// added1
assert_true(pgp_key_get_userid(key, uidc)->str == "added1");
assert_int_equal(uidc, pgp_key_get_subsig(key, subsigc)->uid);
assert_int_equal(0xAB, pgp_key_get_subsig(key, subsigc)->key_flags);
assert_true(key->get_uid(uidc).str == "added1");
assert_int_equal(uidc, key->get_sig(subsigc).uid);
assert_int_equal(0xAB, key->get_sig(subsigc).key_flags);
// added2
assert_true(pgp_key_get_userid(key, uidc + 1)->str == "added2");
assert_int_equal(uidc + 1, pgp_key_get_subsig(key, subsigc + 1)->uid);
assert_int_equal(0xCD, pgp_key_get_subsig(key, subsigc + 1)->key_flags);
assert_true(key->get_uid(uidc + 1).str == "added2");
assert_int_equal(uidc + 1, key->get_sig(subsigc + 1).uid);
assert_int_equal(0xCD, key->get_sig(subsigc + 1).key_flags);
// save the raw packets for the key (to reload later)
assert_rnp_success(init_mem_dest(&dst, NULL, 0));
pgp_key_write_packets(key, &dst);
key->write(dst);
// cleanup
delete ks;
key = NULL;
@ -137,22 +133,22 @@ TEST_F(rnp_tests, test_key_add_userid)
assert_non_null(key = rnp_tests_get_key_by_id(ks, keyids[0], NULL));
// confirm that the counts have increased as expected
assert_int_equal(pgp_key_get_userid_count(key), uidc + 2);
assert_int_equal(pgp_key_get_subsig_count(key), subsigc + 2);
assert_int_equal(key->uid_count(), uidc + 2);
assert_int_equal(key->sig_count(), subsigc + 2);
// make sure correct key expiration and flags are set
assert_int_equal(0, pgp_key_get_expiration(key));
assert_int_equal(0xCD, pgp_key_get_flags(key));
assert_int_equal(0, key->expiration());
assert_int_equal(0xCD, key->flags());
// check the userids array
// added1
assert_true(pgp_key_get_userid(key, uidc)->str == "added1");
assert_int_equal(uidc, pgp_key_get_subsig(key, subsigc)->uid);
assert_int_equal(0xAB, pgp_key_get_subsig(key, subsigc)->key_flags);
assert_true(key->get_uid(uidc).str == "added1");
assert_int_equal(uidc, key->get_sig(subsigc).uid);
assert_int_equal(0xAB, key->get_sig(subsigc).key_flags);
// added2
assert_true(pgp_key_get_userid(key, uidc + 1)->str == "added2");
assert_int_equal(uidc + 1, pgp_key_get_subsig(key, subsigc + 1)->uid);
assert_int_equal(0xCD, pgp_key_get_subsig(key, subsigc + 1)->key_flags);
assert_true(key->get_uid(uidc + 1).str == "added2");
assert_int_equal(uidc + 1, key->get_sig(subsigc + 1).uid);
assert_int_equal(0xCD, key->get_sig(subsigc + 1).key_flags);
// cleanup
delete ks;

162
third_party/rnp/src/tests/key-protect.cpp поставляемый
Просмотреть файл

@ -31,12 +31,6 @@
#include "support.h"
#include "crypto/hash.h"
static bool
mpi_empty(const pgp_mpi_t *val)
{
return val->len == 0;
}
/* This test loads a .gpg keyring and tests protect/unprotect functionality.
* There is also some lock/unlock testing in here, since the two are
* somewhat related.
@ -68,8 +62,8 @@ TEST_F(rnp_tests, test_key_protect_load_pgp)
assert_non_null(key);
// all keys in this keyring are encrypted and thus should be both protected and
// locked initially
assert_true(pgp_key_is_protected(key));
assert_true(pgp_key_is_locked(key));
assert_true(key->is_protected());
assert_true(key->is_locked());
}
pgp_key_t *tmp = NULL;
@ -82,58 +76,58 @@ TEST_F(rnp_tests, test_key_protect_load_pgp)
}
// confirm that this key is indeed RSA
assert_int_equal(pgp_key_get_alg(key), PGP_PKA_RSA);
assert_int_equal(key->alg(), PGP_PKA_RSA);
// confirm key material is currently all NULL (in other words, the key is locked)
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.d));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.p));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.q));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.u));
assert_true(mpi_empty(key->material().rsa.d));
assert_true(mpi_empty(key->material().rsa.p));
assert_true(mpi_empty(key->material().rsa.q));
assert_true(mpi_empty(key->material().rsa.u));
// try to unprotect with a failing password provider
pgp_password_provider_t pprov = {.callback = failing_password_callback, .userdata = NULL};
assert_false(pgp_key_unprotect(key, &pprov));
assert_false(key->unprotect(pprov));
// try to unprotect with an incorrect password
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "badpass"};
assert_false(pgp_key_unprotect(key, &pprov));
assert_false(key->unprotect(pprov));
// unprotect with the correct password
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "password"};
assert_true(pgp_key_unprotect(key, &pprov));
assert_false(pgp_key_is_protected(key));
assert_true(key->unprotect(pprov));
assert_false(key->is_protected());
// should still be locked
assert_true(pgp_key_is_locked(key));
assert_true(key->is_locked());
// confirm secret key material is still NULL
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.d));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.p));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.q));
assert_true(mpi_empty(&pgp_key_get_material(key)->rsa.u));
assert_true(mpi_empty(key->material().rsa.d));
assert_true(mpi_empty(key->material().rsa.p));
assert_true(mpi_empty(key->material().rsa.q));
assert_true(mpi_empty(key->material().rsa.u));
// unlock (no password required since the key is not protected)
pprov = {.callback = asserting_password_callback, .userdata = NULL};
assert_true(pgp_key_unlock(key, &pprov));
assert_false(pgp_key_is_locked(key));
assert_true(key->unlock(pprov));
assert_false(key->is_locked());
// secret key material should be available
assert_false(mpi_empty(&pgp_key_get_material(key)->rsa.d));
assert_false(mpi_empty(&pgp_key_get_material(key)->rsa.p));
assert_false(mpi_empty(&pgp_key_get_material(key)->rsa.q));
assert_false(mpi_empty(&pgp_key_get_material(key)->rsa.u));
assert_false(mpi_empty(key->material().rsa.d));
assert_false(mpi_empty(key->material().rsa.p));
assert_false(mpi_empty(key->material().rsa.q));
assert_false(mpi_empty(key->material().rsa.u));
// save the secret MPIs for some later comparisons
pgp_mpi_t d = pgp_key_get_material(key)->rsa.d;
pgp_mpi_t p = pgp_key_get_material(key)->rsa.p;
pgp_mpi_t q = pgp_key_get_material(key)->rsa.q;
pgp_mpi_t u = pgp_key_get_material(key)->rsa.u;
pgp_mpi_t d = key->material().rsa.d;
pgp_mpi_t p = key->material().rsa.p;
pgp_mpi_t q = key->material().rsa.q;
pgp_mpi_t u = key->material().rsa.u;
// confirm that packets[0] is no longer encrypted
{
pgp_source_t memsrc = {};
rnp_key_store_t *ks = new rnp_key_store_t();
pgp_rawpacket_t &pkt = pgp_key_get_rawpacket(key);
pgp_rawpacket_t &pkt = key->rawpkt();
assert_rnp_success(init_mem_src(&memsrc, pkt.raw.data(), pkt.raw.size(), false));
assert_rnp_success(rnp_key_store_pgp_read_from_src(ks, &memsrc));
@ -145,104 +139,86 @@ TEST_F(rnp_tests, test_key_protect_load_pgp)
assert_non_null(reloaded_key);
// should not be locked, nor protected
assert_false(pgp_key_is_locked(reloaded_key));
assert_false(pgp_key_is_protected(reloaded_key));
assert_false(reloaded_key->is_locked());
assert_false(reloaded_key->is_protected());
// secret key material should not be NULL
assert_false(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.d));
assert_false(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.p));
assert_false(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.q));
assert_false(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.u));
assert_false(mpi_empty(reloaded_key->material().rsa.d));
assert_false(mpi_empty(reloaded_key->material().rsa.p));
assert_false(mpi_empty(reloaded_key->material().rsa.q));
assert_false(mpi_empty(reloaded_key->material().rsa.u));
// compare MPIs of the reloaded key, with the unlocked key from earlier
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.d,
&pgp_key_get_material(reloaded_key)->rsa.d));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.p,
&pgp_key_get_material(reloaded_key)->rsa.p));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.q,
&pgp_key_get_material(reloaded_key)->rsa.q));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.u,
&pgp_key_get_material(reloaded_key)->rsa.u));
assert_true(mpi_equal(&key->material().rsa.d, &reloaded_key->material().rsa.d));
assert_true(mpi_equal(&key->material().rsa.p, &reloaded_key->material().rsa.p));
assert_true(mpi_equal(&key->material().rsa.q, &reloaded_key->material().rsa.q));
assert_true(mpi_equal(&key->material().rsa.u, &reloaded_key->material().rsa.u));
// negative test to try to ensure the above is a valid test
assert_false(mpi_equal(&pgp_key_get_material(key)->rsa.d,
&pgp_key_get_material(reloaded_key)->rsa.p));
assert_false(mpi_equal(&key->material().rsa.d, &reloaded_key->material().rsa.p));
// lock it
assert_true(pgp_key_lock(reloaded_key));
assert_true(pgp_key_is_locked(reloaded_key));
assert_true(reloaded_key->lock());
assert_true(reloaded_key->is_locked());
// confirm that secret MPIs are NULL again
assert_true(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.d));
assert_true(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.p));
assert_true(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.q));
assert_true(mpi_empty(&pgp_key_get_material(reloaded_key)->rsa.u));
assert_true(mpi_empty(reloaded_key->material().rsa.d));
assert_true(mpi_empty(reloaded_key->material().rsa.p));
assert_true(mpi_empty(reloaded_key->material().rsa.q));
assert_true(mpi_empty(reloaded_key->material().rsa.u));
// unlock it (no password, since it's not protected)
pgp_password_provider_t pprov = {.callback = asserting_password_callback,
.userdata = NULL};
assert_true(pgp_key_unlock(reloaded_key, &pprov));
assert_false(pgp_key_is_locked(reloaded_key));
assert_true(reloaded_key->unlock(pprov));
assert_false(reloaded_key->is_locked());
// compare MPIs of the reloaded key, with the unlocked key from earlier
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.d,
&pgp_key_get_material(reloaded_key)->rsa.d));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.p,
&pgp_key_get_material(reloaded_key)->rsa.p));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.q,
&pgp_key_get_material(reloaded_key)->rsa.q));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.u,
&pgp_key_get_material(reloaded_key)->rsa.u));
assert_true(mpi_equal(&key->material().rsa.d, &reloaded_key->material().rsa.d));
assert_true(mpi_equal(&key->material().rsa.p, &reloaded_key->material().rsa.p));
assert_true(mpi_equal(&key->material().rsa.q, &reloaded_key->material().rsa.q));
assert_true(mpi_equal(&key->material().rsa.u, &reloaded_key->material().rsa.u));
delete ks;
}
// lock
assert_true(pgp_key_lock(key));
assert_true(key->lock());
// try to protect (will fail when key is locked)
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "newpass"};
assert_false(rnp_key_add_protection(key,
key->format, // same format
NULL, // default protection
&pprov));
assert_false(pgp_key_is_protected(key));
assert_false(key->add_protection(key->format, {}, pprov));
assert_false(key->is_protected());
// unlock
pprov = {.callback = asserting_password_callback, .userdata = NULL};
assert_true(pgp_key_unlock(key, &pprov));
assert_false(pgp_key_is_locked(key));
assert_true(key->unlock(pprov));
assert_false(key->is_locked());
// try to protect with a failing password provider
pprov = {.callback = failing_password_callback, .userdata = NULL};
assert_false(rnp_key_add_protection(key,
key->format, // same format
NULL, // default protection
&pprov));
assert_false(pgp_key_is_protected(key));
assert_false(key->add_protection(key->format, {}, pprov));
assert_false(key->is_protected());
// (re)protect with a new password
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "newpass"};
assert_true(rnp_key_add_protection(key,
key->format, // same format
NULL, // default protection
&pprov));
assert_true(pgp_key_is_protected(key));
assert_true(key->add_protection(key->format, {}, pprov));
assert_true(key->is_protected());
// lock
assert_true(pgp_key_lock(key));
assert_true(pgp_key_is_locked(key));
assert_true(key->lock());
assert_true(key->is_locked());
// try to unlock with old password
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "password"};
assert_false(pgp_key_unlock(key, &pprov));
assert_true(pgp_key_is_locked(key));
assert_false(key->unlock(pprov));
assert_true(key->is_locked());
// unlock with new password
pprov = {.callback = string_copy_password_callback, .userdata = (void *) "newpass"};
assert_true(pgp_key_unlock(key, &pprov));
assert_false(pgp_key_is_locked(key));
assert_true(key->unlock(pprov));
assert_false(key->is_locked());
// compare secret MPIs with those from earlier
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.d, &d));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.p, &p));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.q, &q));
assert_true(mpi_equal(&pgp_key_get_material(key)->rsa.u, &u));
assert_true(mpi_equal(&key->material().rsa.d, &d));
assert_true(mpi_equal(&key->material().rsa.p, &p));
assert_true(mpi_equal(&key->material().rsa.q, &q));
assert_true(mpi_equal(&key->material().rsa.u, &u));
// cleanup
delete key;

108
third_party/rnp/src/tests/key-store-search.cpp поставляемый
Просмотреть файл

@ -24,6 +24,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include <set>
#include "../librekey/key_store_pgp.h"
#include "pgp-key.h"
@ -53,25 +55,30 @@ TEST_F(rnp_tests, test_key_store_search)
for (size_t n = 0; n < testdata[i].count; n++) {
pgp_key_t key;
key.pkt.tag = PGP_PKT_PUBLIC_KEY;
key.pkt.version = PGP_V4;
key.pkt.alg = PGP_PKA_RSA;
key.pkt().tag = PGP_PKT_PUBLIC_KEY;
key.pkt().version = PGP_V4;
key.pkt().alg = PGP_PKA_RSA;
// set the keyid
assert_true(rnp_hex_decode(testdata[i].keyid, key.keyid.data(), key.keyid.size()));
// keys should have different grips otherwise rnp_key_store_add_key will fail here
assert_true(rnp_hex_decode(testdata[i].keyid, key.grip.data(), key.grip.size()));
key.grip[0] = (uint8_t) n;
// and fingerprint
assert_true(rnp_hex_decode(
testdata[i].keyid, key.fingerprint.fingerprint, PGP_FINGERPRINT_SIZE));
key.fingerprint.fingerprint[0] = (uint8_t) n;
key.fingerprint.length = PGP_FINGERPRINT_SIZE;
testdata[i].keyid, (uint8_t *) key.keyid().data(), key.keyid().size()));
// keys should have different grips otherwise rnp_key_store_add_key will fail here
pgp_key_grip_t &grip = (pgp_key_grip_t &) key.grip();
assert_true(rnp_hex_decode(testdata[i].keyid, grip.data(), grip.size()));
grip[0] = (uint8_t) n;
// and fingerprint
pgp_fingerprint_t &fp = (pgp_fingerprint_t &) key.fp();
assert_true(
rnp_hex_decode(testdata[i].keyid, fp.fingerprint, PGP_FINGERPRINT_SIZE));
fp.fingerprint[0] = (uint8_t) n;
fp.length = PGP_FINGERPRINT_SIZE;
// set the userids
pgp_transferable_key_t tkey;
for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) {
pgp_userid_t *userid = pgp_key_add_userid(&key);
assert_non_null(userid);
userid->str = testdata[i].userids[uidn];
pgp_transferable_userid_t *uid =
transferable_key_add_userid(tkey, testdata[i].userids[uidn]);
assert_non_null(uid);
key.add_uid(*uid);
}
// add to the store
assert_true(rnp_key_store_add_key(store, &key));
@ -82,96 +89,71 @@ TEST_F(rnp_tests, test_key_store_search)
for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
pgp_key_id_t keyid = {};
assert_true(rnp_hex_decode(testdata[i].keyid, keyid.data(), keyid.size()));
list seen_keys = NULL;
std::set<pgp_key_t *> seen_keys;
for (pgp_key_t *key = rnp_key_store_get_key_by_id(store, keyid, NULL); key;
key = rnp_key_store_get_key_by_id(store, keyid, key)) {
// check that the keyid actually matches
assert_true(pgp_key_get_keyid(key) == keyid);
assert_true(key->keyid() == keyid);
// check that we have not already encountered this key pointer
assert_null(list_find(seen_keys, &key, sizeof(key)));
assert_int_equal(seen_keys.count(key), 0);
// keep track of what key pointers we have seen
assert_non_null(list_append(&seen_keys, &key, sizeof(key)));
seen_keys.insert(key);
}
assert_int_equal(list_length(seen_keys), testdata[i].count);
list_destroy(&seen_keys);
assert_int_equal(seen_keys.size(), testdata[i].count);
}
// keyid search (by_name)
for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
list seen_keys = NULL;
pgp_key_t *key = NULL;
std::set<pgp_key_t *> seen_keys;
pgp_key_t * key = NULL;
key = rnp_tests_get_key_by_id(store, testdata[i].keyid, NULL);
while (key) {
// check that the keyid actually matches
pgp_key_id_t expected_keyid = {};
assert_true(
rnp_hex_decode(testdata[i].keyid, expected_keyid.data(), expected_keyid.size()));
assert_true(pgp_key_get_keyid(key) == expected_keyid);
assert_true(key->keyid() == expected_keyid);
// check that we have not already encountered this key pointer
assert_null(list_find(seen_keys, &key, sizeof(key)));
assert_int_equal(seen_keys.count(key), 0);
// keep track of what key pointers we have seen
assert_non_null(list_append(&seen_keys, &key, sizeof(key)));
seen_keys.insert(key);
// this only returns false on error, regardless of whether it found a match
key = rnp_tests_get_key_by_id(store, testdata[i].keyid, key);
}
// check the count
assert_int_equal(list_length(seen_keys), testdata[i].count);
// cleanup
list_destroy(&seen_keys);
assert_int_equal(seen_keys.size(), testdata[i].count);
}
// userid search (literal)
for (auto &key : store->keys) {
for (size_t i = 0; i < key.uid_count(); i++) {
key.get_uid(i).valid = true;
}
}
for (size_t i = 0; i < ARRAY_SIZE(testdata); i++) {
for (size_t uidn = 0; testdata[i].userids[uidn]; uidn++) {
list seen_keys = NULL;
pgp_key_t * key = NULL;
const char *userid = testdata[i].userids[uidn];
key = rnp_tests_key_search(store, userid);
std::set<pgp_key_t *> seen_keys;
const std::string userid = testdata[i].userids[uidn];
pgp_key_t * key = rnp_tests_key_search(store, userid);
while (key) {
// check that the userid actually matches
bool found = false;
for (unsigned j = 0; j < pgp_key_get_userid_count(key); j++) {
if (pgp_key_get_userid(key, j)->str == userid) {
for (unsigned j = 0; j < key->uid_count(); j++) {
if (key->get_uid(j).str == userid) {
found = true;
}
}
assert_true(found);
// check that we have not already encountered this key pointer
assert_null(list_find(seen_keys, &key, sizeof(key)));
assert_int_equal(seen_keys.count(key), 0);
// keep track of what key pointers we have seen
assert_non_null(list_append(&seen_keys, &key, sizeof(key)));
seen_keys.insert(key);
key = rnp_tests_get_key_by_id(store, testdata[i].keyid, key);
}
// check the count
assert_int_equal(list_length(seen_keys), testdata[i].count);
// cleanup
list_destroy(&seen_keys);
assert_int_equal(seen_keys.size(), testdata[i].count);
}
}
#ifdef RNP_KEY_STORE_SEARCH_REGEX
// userid search (regex)
{
list seen_keys = NULL;
pgp_key_t * key = NULL;
const char *userid = "user1-.*";
key = rnp_key_store_get_key_by_name(store, userid, NULL);
while (key) {
// check that we have not already encountered this key pointer
assert_null(list_find(seen_keys, &key, sizeof(key)));
// keep track of what key pointers we have seen
assert_non_null(list_append(&seen_keys, &key, sizeof(key)));
key = rnp_key_store_get_key_by_name(store, userid, key);
}
// check the count
assert_int_equal(list_length(seen_keys), 3);
// cleanup
list_destroy(&seen_keys);
}
#endif // RNP_KEY_STORE_SEARCH_REGEX
// cleanup
delete store;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше