From 10f733003e8baf46b765ad4b42feedb1e86bad92 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Tue, 20 Aug 2024 15:18:30 +0300 Subject: [PATCH] (WIP) FFI: Add bunch of rnp_key_signature_set_* functions. --- include/rnp/rnp.h | 123 ++++++++++++++++ src/lib/rnp.cpp | 184 +++++++++++++++++++++++ src/tests/ffi-key-sig.cpp | 298 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 605 insertions(+) diff --git a/include/rnp/rnp.h b/include/rnp/rnp.h index bee839448..260a048cf 100644 --- a/include/rnp/rnp.h +++ b/include/rnp/rnp.h @@ -1616,6 +1616,126 @@ RNP_API rnp_result_t rnp_key_revocation_signature_create(rnp_key_handle_t */ RNP_API rnp_result_t rnp_key_signature_set_hash(rnp_signature_handle_t sig, const char *hash); +/** + * @brief Set the signature creation time. While it is set by default to the current time, + * caller may override it in case of need. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param creation timestamp with the creation time. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_creation(rnp_signature_handle_t sig, + uint32_t ctime); + +/** + * @brief Set the key usage flags, i.e. whether it is usable for signing, encryption, whatever + * else. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param flags key flags, which directly maps to the ones described in the OpenPGP + * specification. See the RNP_KEY_USAGE_* constants. + * Note: RNP will not check whether flags are applicable to the key itself (i.e. + * signing flag for encryption-only key), so it's up to the caller to check this. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_key_flags(rnp_signature_handle_t sig, + uint32_t flags); + +/** + * @brief Set the key expiration time. Makes sense only for self-certification or direct-key + * signatures. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param expiry number of seconds since key creation when it is considered as valid. Zero + * value means that key never expires. + * I.e. if you want key to last for 1 year from now (given that signature + * creation time is set to now), you should calculate the following: + * expiry = now() - rnp_key_get_creation() + 365*24*60*60 + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_key_expiration(rnp_signature_handle_t sig, + uint32_t expiry); + +/** + * @brief Set the key features. Makes sense only for self-signature. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param features or'ed together feature flags (RNP_FEATURE_*). For the list of currently + * supported flags please see the description of rnp_signature_get_features(). + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_features(rnp_signature_handle_t sig, + uint32_t features); + +/** + * @brief Add preferred symmetric algorithm to the signature. Should be subsequently called for + * each algorithm, making first ones of higher priority. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param alg symmetric algorithm name, cannot be NULL. See + * rnp_op_generate_set_protection_cipher() for the list of possible values. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_add_preferred_alg(rnp_signature_handle_t sig, + const char * alg); + +/** + * @brief Add preferred hash algorithm to the signature. Should be subsequently called for each + * algorithm, making first ones of higher priority. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param alg hash algorithm name, cannot be NULL. See rnp_op_generate_set_hash() for the list + * of possible values. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_add_preferred_hash(rnp_signature_handle_t sig, + const char * hash); + +/** + * @brief Add preferred compression algorithm to the signature. Should be subsequently called + * for each algorithm, making first ones of higher priority. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param alg compression algorithm name, cannot be NULL. See + * rnp_op_generate_add_pref_compression() for the list of possible values. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_add_preferred_zalg(rnp_signature_handle_t sig, + const char * zalg); + +/** + * @brief Set whether corresponding user id should be considered as primary. Makes sense only + * for self-certification. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param primary true for primary or false for not. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_primary_uid(rnp_signature_handle_t sig, + bool primary); + +/** + * @brief Set the key server url which is applicable for this key. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param keyserver key server url. If NULL or empty string then key server field in the + * signature will be removed. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_key_server(rnp_signature_handle_t sig, + const char * keyserver); + +/** + * @brief Set the key server preferences flags. + * + * @param sig editable key signature handle, i.e. created with rnp_key_*_signature_create(). + * @param flags or'ed together preferences flags. Currently only single flag is supported - + * RNP_KEY_SERVER_NO_MODIFY. + * @return RNP_SUCCESS or error code if failed. + */ +RNP_API rnp_result_t rnp_key_signature_set_key_server_prefs(rnp_signature_handle_t sig, + uint32_t flags); + /** * @brief Set revocation reason and code for the revocation signature. * See `rnp_key_revoke()` for the details. @@ -3839,6 +3959,9 @@ RNP_API const char *rnp_backend_version(); #define RNP_ALGNAME_SHA3_512 "SHA3-512" #define RNP_ALGNAME_RIPEMD160 "RIPEMD160" #define RNP_ALGNAME_CRC24 "CRC24" +#define RNP_ALGNAME_ZLIB "ZLib" +#define RNP_ALGNAME_BZIP2 "BZip2" +#define RNP_ALGNAME_ZIP "ZIP" /* SHA1 is not considered secured anymore and SHOULD NOT be used to create messages (as per * Appendix C of RFC 4880-bis-02). SHA2 MUST be implemented. diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 10c7aeb8f..35c4b255f 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -6191,6 +6191,190 @@ try { } FFI_GUARD +rnp_result_t +rnp_key_signature_set_creation(rnp_signature_handle_t sig, uint32_t ctime) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_creation(ctime); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_key_flags(rnp_signature_handle_t sig, uint32_t flags) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + uint32_t check = flags; + extract_flag(check, + PGP_KF_SIGN | PGP_KF_CERTIFY | PGP_KF_ENCRYPT_COMMS | PGP_KF_ENCRYPT_STORAGE | + PGP_KF_SPLIT | PGP_KF_AUTH | PGP_KF_SHARED); + if (check) { + FFI_LOG(sig->ffi, "Unknown key flags: %#" PRIx32, check); + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_key_flags(flags & 0xff); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_key_expiration(rnp_signature_handle_t sig, uint32_t expiry) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_key_expiration(expiry); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_features(rnp_signature_handle_t sig, uint32_t features) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + uint32_t flags = features; + extract_flag(flags, RNP_KEY_FEATURE_MDC | RNP_KEY_FEATURE_AEAD | RNP_KEY_FEATURE_V5); + if (flags) { + FFI_LOG(sig->ffi, "Unknown key features: %#" PRIx32, flags); + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_key_features(features & 0xff); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_add_preferred_alg(rnp_signature_handle_t sig, const char *alg) +try { + if (!sig || !alg) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + auto symm_alg = id_str_pair::lookup(symm_alg_map, alg, PGP_SA_UNKNOWN); + if (symm_alg == PGP_SA_UNKNOWN) { + FFI_LOG(sig->ffi, "Unknown symmetric algorithm: %s", alg); + return RNP_ERROR_BAD_PARAMETERS; + } + auto algs = sig->sig->sig.preferred_symm_algs(); + algs.push_back(symm_alg); + sig->sig->sig.set_preferred_symm_algs(algs); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_add_preferred_hash(rnp_signature_handle_t sig, const char *hash) +try { + if (!sig || !hash) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + auto hash_alg = id_str_pair::lookup(hash_alg_map, hash, PGP_HASH_UNKNOWN); + if (hash_alg == PGP_HASH_UNKNOWN) { + FFI_LOG(sig->ffi, "Unknown hash algorithm: %s", hash); + return RNP_ERROR_BAD_PARAMETERS; + } + auto algs = sig->sig->sig.preferred_hash_algs(); + algs.push_back(hash_alg); + sig->sig->sig.set_preferred_hash_algs(algs); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_add_preferred_zalg(rnp_signature_handle_t sig, const char *zalg) +try { + if (!sig || !zalg) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + auto z_alg = id_str_pair::lookup(compress_alg_map, zalg, PGP_C_UNKNOWN); + if (z_alg == PGP_C_UNKNOWN) { + FFI_LOG(sig->ffi, "Unknown compression algorithm: %s", zalg); + return RNP_ERROR_BAD_PARAMETERS; + } + auto algs = sig->sig->sig.preferred_z_algs(); + algs.push_back(z_alg); + sig->sig->sig.set_preferred_z_algs(algs); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_primary_uid(rnp_signature_handle_t sig, bool primary) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_primary_uid(primary); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_key_server(rnp_signature_handle_t sig, const char *keyserver) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + if (!keyserver) { + keyserver = ""; + } + sig->sig->sig.set_key_server(keyserver); + return RNP_SUCCESS; +} +FFI_GUARD + +rnp_result_t +rnp_key_signature_set_key_server_prefs(rnp_signature_handle_t sig, uint32_t flags) +try { + if (!sig) { + return RNP_ERROR_NULL_POINTER; + } + if (!sig->new_sig) { + return RNP_ERROR_BAD_PARAMETERS; + } + uint32_t check = flags; + extract_flag(check, RNP_KEY_SERVER_NO_MODIFY); + if (check) { + FFI_LOG(sig->ffi, "Unknown key server prefs: %#" PRIx32, check); + return RNP_ERROR_BAD_PARAMETERS; + } + sig->sig->sig.set_key_server_prefs(flags & 0xff); + return RNP_SUCCESS; +} +FFI_GUARD + rnp_result_t rnp_key_signature_set_revocation_reason(rnp_signature_handle_t sig, const char * code, diff --git a/src/tests/ffi-key-sig.cpp b/src/tests/ffi-key-sig.cpp index e60f09c53..25533988b 100644 --- a/src/tests/ffi-key-sig.cpp +++ b/src/tests/ffi-key-sig.cpp @@ -2129,3 +2129,301 @@ TEST_F(rnp_tests, test_ffi_create_key_certification_signature) rnp_ffi_destroy(ffi); } + +TEST_F(rnp_tests, test_ffi_key_self_certification_features) +{ + rnp_ffi_t ffi = NULL; + assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG")); + rnp_ffi_set_pass_provider(ffi, ffi_string_password_provider, (void *) "password"); + + assert_true(import_all_keys(ffi, "data/test_stream_key_load/ecc-p256-sec.asc")); + rnp_key_handle_t key = NULL; + assert_rnp_success(rnp_locate_key(ffi, "userid", "ecc-p256", &key)); + uint32_t sig_creation = 0; + assert_rnp_success(rnp_key_get_creation(key, &sig_creation)); + const uint32_t sig_diff = 1000; + sig_creation += sig_diff; + rnp_uid_handle_t uid = NULL; + assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid)); + /* Create key certification with default fields to check later */ + rnp_signature_handle_t newsig = NULL; + assert_rnp_success(rnp_key_certification_create(key, uid, NULL, &newsig)); + assert_rnp_success(rnp_key_signature_sign(newsig)); + rnp_signature_handle_destroy(newsig); + /* Create key certification and set different fields to check later */ + assert_rnp_success(rnp_key_certification_create(key, uid, NULL, &newsig)); + /* Signature creation time */ + assert_rnp_failure(rnp_key_signature_set_creation(NULL, 0)); + assert_rnp_success(rnp_key_signature_set_creation(newsig, sig_creation)); + /* Signature hash algorithm */ + const char *hash = "SHA384"; + assert_rnp_success(rnp_key_signature_set_hash(newsig, hash)); + /* Key flags */ + assert_rnp_failure(rnp_key_signature_set_key_flags(NULL, RNP_KEY_USAGE_CERTIFY)); + assert_rnp_failure(rnp_key_signature_set_key_flags(newsig, 0x100 | RNP_KEY_USAGE_CERTIFY)); + assert_rnp_success(rnp_key_signature_set_key_flags(newsig, RNP_KEY_USAGE_CERTIFY)); + /* Key expiration */ + uint32_t expiry = 50 * 365 * 24 * 60 * 60; + assert_rnp_failure(rnp_key_signature_set_key_expiration(NULL, expiry)); + assert_rnp_success(rnp_key_signature_set_key_expiration(newsig, 100000)); + assert_rnp_success(rnp_key_signature_set_key_expiration(newsig, expiry)); + /* Primary user id */ + assert_rnp_failure(rnp_key_signature_set_primary_uid(NULL, true)); + assert_rnp_success(rnp_key_signature_set_primary_uid(newsig, false)); + assert_rnp_success(rnp_key_signature_set_primary_uid(newsig, true)); + /* Key server */ + const char *key_serv = "https://key-server/"; + assert_rnp_failure(rnp_key_signature_set_key_server(NULL, key_serv)); + assert_rnp_success(rnp_key_signature_set_key_server(newsig, "wrong")); + assert_rnp_success(rnp_key_signature_set_key_server(newsig, NULL)); + assert_rnp_success(rnp_key_signature_set_key_server(newsig, "wrong2")); + assert_rnp_success(rnp_key_signature_set_key_server(newsig, key_serv)); + /* Key server prefs */ + assert_rnp_failure(rnp_key_signature_set_key_server_prefs(NULL, RNP_KEY_SERVER_NO_MODIFY)); + assert_rnp_failure( + rnp_key_signature_set_key_server_prefs(newsig, 0x101 | RNP_KEY_SERVER_NO_MODIFY)); + assert_rnp_success(rnp_key_signature_set_key_server_prefs(newsig, 0)); + assert_rnp_success( + rnp_key_signature_set_key_server_prefs(newsig, RNP_KEY_SERVER_NO_MODIFY)); + /* Key features */ + uint32_t features = RNP_KEY_FEATURE_MDC | RNP_KEY_FEATURE_AEAD | RNP_KEY_FEATURE_V5; + assert_rnp_failure(rnp_key_signature_set_features(NULL, features)); + assert_rnp_failure(rnp_key_signature_set_features(newsig, 0x123)); + assert_rnp_success(rnp_key_signature_set_features(newsig, RNP_KEY_FEATURE_MDC)); + assert_rnp_success(rnp_key_signature_set_features(newsig, features)); + /* Preferred symmetric algorithms */ + assert_rnp_failure(rnp_key_signature_add_preferred_alg(newsig, NULL)); + assert_rnp_failure(rnp_key_signature_add_preferred_alg(NULL, RNP_ALGNAME_AES_256)); + assert_rnp_failure(rnp_key_signature_add_preferred_alg(newsig, RNP_ALGNAME_SHA256)); + assert_rnp_failure(rnp_key_signature_add_preferred_alg(newsig, RNP_ALGNAME_SHA256)); + assert_rnp_success(rnp_key_signature_add_preferred_alg(newsig, RNP_ALGNAME_AES_256)); + assert_rnp_success(rnp_key_signature_add_preferred_alg(newsig, RNP_ALGNAME_CAMELLIA_192)); + assert_rnp_success(rnp_key_signature_add_preferred_alg(newsig, RNP_ALGNAME_IDEA)); + /* Preferred hash algorithms */ + assert_rnp_failure(rnp_key_signature_add_preferred_hash(newsig, NULL)); + assert_rnp_failure(rnp_key_signature_add_preferred_hash(NULL, RNP_ALGNAME_SHA256)); + assert_rnp_failure(rnp_key_signature_add_preferred_hash(newsig, RNP_ALGNAME_AES_256)); + assert_rnp_success(rnp_key_signature_add_preferred_hash(newsig, RNP_ALGNAME_SHA256)); + assert_rnp_success(rnp_key_signature_add_preferred_hash(newsig, RNP_ALGNAME_SHA3_512)); + assert_rnp_success(rnp_key_signature_add_preferred_hash(newsig, RNP_ALGNAME_SM3)); + /* Preferred compression algorithms */ + assert_rnp_failure(rnp_key_signature_add_preferred_zalg(newsig, NULL)); + assert_rnp_failure(rnp_key_signature_add_preferred_zalg(NULL, RNP_ALGNAME_BZIP2)); + assert_rnp_failure(rnp_key_signature_add_preferred_zalg(newsig, RNP_ALGNAME_SHA256)); + assert_rnp_success(rnp_key_signature_add_preferred_zalg(newsig, RNP_ALGNAME_ZLIB)); + assert_rnp_success(rnp_key_signature_add_preferred_zalg(newsig, RNP_ALGNAME_BZIP2)); + /* Sign */ + assert_rnp_success(rnp_key_signature_sign(newsig)); + rnp_signature_handle_destroy(newsig); + /* Check certification parameters */ + size_t sigs = 0; + assert_rnp_success(rnp_uid_get_signature_count(uid, &sigs)); + assert_int_equal(sigs, 3); + /* First signature, available after the load */ + uint32_t check = 0; + bool primary = false; + assert_rnp_success(rnp_uid_get_signature_at(uid, 0, &newsig)); + assert_rnp_success(rnp_signature_is_valid(newsig, 0)); + assert_true(check_sig_hash(newsig, RNP_ALGNAME_SHA256)); + assert_true(check_sig_type(newsig, "certification (positive)")); + assert_rnp_success(rnp_signature_get_creation(newsig, &check)); + assert_int_equal(check, 1549119463); + assert_rnp_success(rnp_signature_get_key_expiration(newsig, &check)); + assert_int_equal(check, 0); + assert_rnp_success(rnp_signature_get_primary_uid(newsig, &primary)); + assert_false(primary); + assert_rnp_success(rnp_signature_get_features(newsig, &check)); + assert_int_equal(check, 3); + assert_rnp_success(rnp_signature_get_key_flags(newsig, &check)); + assert_int_equal(check, RNP_KEY_USAGE_CERTIFY | RNP_KEY_USAGE_SIGN); + assert_rnp_success(rnp_signature_get_key_server_prefs(newsig, &check)); + assert_int_equal(check, RNP_KEY_SERVER_NO_MODIFY); + size_t count = 0; + assert_rnp_success(rnp_signature_get_preferred_alg_count(newsig, &count)); + assert_int_equal(count, 4); + char *alg = NULL; + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 0, &alg)); + assert_string_equal(alg, "AES256"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 1, &alg)); + assert_string_equal(alg, "AES192"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 2, &alg)); + assert_string_equal(alg, "AES128"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 3, &alg)); + assert_string_equal(alg, "TRIPLEDES"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash_count(newsig, &count)); + assert_int_equal(count, 5); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 0, &alg)); + assert_string_equal(alg, "SHA512"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 1, &alg)); + assert_string_equal(alg, "SHA384"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 2, &alg)); + assert_string_equal(alg, "SHA256"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 3, &alg)); + assert_string_equal(alg, "SHA224"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 4, &alg)); + assert_string_equal(alg, "SHA1"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_zalg_count(newsig, &count)); + assert_int_equal(count, 3); + assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 0, &alg)); + assert_string_equal(alg, "ZLIB"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 1, &alg)); + assert_string_equal(alg, "BZip2"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 2, &alg)); + assert_string_equal(alg, "ZIP"); + rnp_buffer_destroy(alg); + rnp_signature_handle_destroy(newsig); + /* First newly added signature with defaults */ + assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &newsig)); + assert_rnp_success(rnp_signature_is_valid(newsig, 0)); + assert_true(check_sig_hash(newsig, DEFAULT_HASH_ALG)); + assert_true(check_sig_type(newsig, "certification (positive)")); + uint32_t now = ::time(NULL); + assert_rnp_failure(rnp_signature_get_creation(NULL, &check)); + assert_rnp_failure(rnp_signature_get_creation(newsig, NULL)); + assert_rnp_success(rnp_signature_get_creation(newsig, &check)); + assert_true(check >= now - 10); + assert_rnp_failure(rnp_signature_get_key_expiration(NULL, &check)); + assert_rnp_failure(rnp_signature_get_key_expiration(newsig, NULL)); + assert_rnp_success(rnp_signature_get_key_expiration(newsig, &check)); + assert_int_equal(check, 0); + assert_rnp_failure(rnp_signature_get_primary_uid(NULL, &primary)); + assert_rnp_failure(rnp_signature_get_primary_uid(newsig, NULL)); + assert_rnp_success(rnp_signature_get_primary_uid(newsig, &primary)); + assert_false(primary); + char *strcheck = NULL; + assert_rnp_failure(rnp_signature_get_key_server(NULL, &strcheck)); + assert_rnp_failure(rnp_signature_get_key_server(newsig, NULL)); + assert_rnp_success(rnp_signature_get_key_server(newsig, &strcheck)); + assert_string_equal(strcheck, ""); + rnp_buffer_destroy(strcheck); + assert_rnp_failure(rnp_signature_get_features(NULL, &check)); + assert_rnp_failure(rnp_signature_get_features(newsig, NULL)); + assert_rnp_success(rnp_signature_get_features(newsig, &check)); + assert_int_equal(check, 0); + assert_rnp_failure(rnp_signature_get_key_flags(NULL, &check)); + assert_rnp_failure(rnp_signature_get_key_flags(newsig, NULL)); + assert_rnp_success(rnp_signature_get_features(newsig, &check)); + assert_int_equal(check, 0); + assert_rnp_failure(rnp_signature_get_key_server_prefs(NULL, &check)); + assert_rnp_failure(rnp_signature_get_key_server_prefs(newsig, NULL)); + assert_rnp_success(rnp_signature_get_key_server_prefs(newsig, &check)); + assert_int_equal(check, 0); + assert_rnp_failure(rnp_signature_get_preferred_alg_count(NULL, &count)); + assert_rnp_failure(rnp_signature_get_preferred_alg_count(newsig, NULL)); + assert_rnp_success(rnp_signature_get_preferred_alg_count(newsig, &count)); + assert_int_equal(count, 0); + assert_rnp_failure(rnp_signature_get_preferred_alg(NULL, 0, &alg)); + assert_rnp_failure(rnp_signature_get_preferred_alg(newsig, 0, NULL)); + assert_rnp_failure(rnp_signature_get_preferred_alg(newsig, 0, &alg)); + assert_rnp_failure(rnp_signature_get_preferred_hash_count(NULL, &count)); + assert_rnp_failure(rnp_signature_get_preferred_hash_count(newsig, NULL)); + assert_rnp_success(rnp_signature_get_preferred_hash_count(newsig, &count)); + assert_int_equal(count, 0); + assert_rnp_failure(rnp_signature_get_preferred_hash(NULL, 0, &alg)); + assert_rnp_failure(rnp_signature_get_preferred_hash(newsig, 0, NULL)); + assert_rnp_failure(rnp_signature_get_preferred_hash(newsig, 0, &alg)); + assert_rnp_failure(rnp_signature_get_preferred_zalg_count(NULL, &count)); + assert_rnp_failure(rnp_signature_get_preferred_zalg_count(newsig, NULL)); + assert_rnp_success(rnp_signature_get_preferred_zalg_count(newsig, &count)); + assert_int_equal(count, 0); + assert_rnp_failure(rnp_signature_get_preferred_zalg(NULL, 0, &alg)); + assert_rnp_failure(rnp_signature_get_preferred_zalg(newsig, 0, NULL)); + assert_rnp_failure(rnp_signature_get_preferred_zalg(newsig, 0, &alg)); + rnp_signature_handle_destroy(newsig); + /* Second newly added signature with customized parameters */ + assert_rnp_success(rnp_uid_get_signature_at(uid, 2, &newsig)); + assert_rnp_success(rnp_signature_is_valid(newsig, 0)); + assert_true(check_sig_type(newsig, "certification (positive)")); + assert_rnp_success(rnp_signature_get_creation(newsig, &check)); + assert_int_equal(check, sig_creation); + assert_true(check_sig_hash(newsig, hash)); + assert_rnp_success(rnp_signature_get_key_expiration(newsig, &check)); + assert_int_equal(check, expiry); + assert_rnp_success(rnp_signature_get_primary_uid(newsig, &primary)); + assert_true(primary); + assert_rnp_success(rnp_signature_get_key_server(newsig, &strcheck)); + assert_string_equal(strcheck, key_serv); + rnp_buffer_destroy(strcheck); + assert_rnp_success(rnp_signature_get_key_server_prefs(newsig, &check)); + assert_int_equal(check, RNP_KEY_SERVER_NO_MODIFY); + assert_rnp_success(rnp_signature_get_features(newsig, &check)); + assert_int_equal(check, features); + assert_rnp_success(rnp_signature_get_key_flags(newsig, &check)); + assert_int_equal(check, RNP_KEY_USAGE_CERTIFY); + assert_rnp_success(rnp_signature_get_preferred_alg_count(newsig, &count)); + assert_int_equal(count, 3); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 0, &alg)); + assert_string_equal(alg, "AES256"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 1, &alg)); + assert_string_equal(alg, "CAMELLIA192"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_alg(newsig, 2, &alg)); + assert_string_equal(alg, "IDEA"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash_count(newsig, &count)); + assert_int_equal(count, 3); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 0, &alg)); + assert_string_equal(alg, "SHA256"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 1, &alg)); + assert_string_equal(alg, "SHA3-512"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_hash(newsig, 2, &alg)); + assert_string_equal(alg, "SM3"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_zalg_count(newsig, &count)); + assert_int_equal(count, 2); + assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 0, &alg)); + assert_string_equal(alg, "ZLIB"); + rnp_buffer_destroy(alg); + assert_rnp_success(rnp_signature_get_preferred_zalg(newsig, 1, &alg)); + assert_string_equal(alg, "BZip2"); + rnp_buffer_destroy(alg); + rnp_signature_handle_destroy(newsig); + rnp_uid_handle_destroy(uid); + /* Export key and make sure data is saved */ + auto keydata = export_key(key, true); + rnp_key_handle_destroy(key); + rnp_ffi_t newffi = NULL; + assert_rnp_success(rnp_ffi_create(&newffi, "GPG", "GPG")); + assert_true(import_all_keys(newffi, keydata.data(), keydata.size())); + assert_rnp_success(rnp_locate_key(newffi, "userid", "ecc-p256", &key)); + 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, 3); + assert_rnp_success(rnp_uid_get_signature_at(uid, 1, &newsig)); + assert_rnp_success(rnp_signature_is_valid(newsig, 0)); + assert_true(check_sig_hash(newsig, DEFAULT_HASH_ALG)); + assert_true(check_sig_type(newsig, "certification (positive)")); + assert_rnp_success(rnp_signature_get_creation(newsig, &check)); + assert_true(check >= now - 20); + rnp_signature_handle_destroy(newsig); + + assert_rnp_success(rnp_uid_get_signature_at(uid, 2, &newsig)); + assert_rnp_success(rnp_signature_is_valid(newsig, 0)); + assert_true(check_sig_hash(newsig, hash)); + assert_true(check_sig_type(newsig, "certification (positive)")); + assert_rnp_success(rnp_signature_get_key_server(newsig, &strcheck)); + assert_string_equal(strcheck, key_serv); + assert_rnp_success(rnp_signature_get_key_flags(newsig, &check)); + assert_int_equal(check, RNP_KEY_USAGE_CERTIFY); + rnp_buffer_destroy(strcheck); + rnp_signature_handle_destroy(newsig); + rnp_uid_handle_destroy(uid); + rnp_key_handle_destroy(key); + rnp_ffi_destroy(newffi); + + rnp_ffi_destroy(ffi); +}