From ac46b5164c8e36efa8aa29966c90016d42b23197 Mon Sep 17 00:00:00 2001 From: Nickolay Olshevsky Date: Wed, 1 May 2024 11:45:05 +0300 Subject: [PATCH] Use pgp::KeyMaterial instead of pgp_key_material_t. --- src/lib/crypto.cpp | 278 +------- src/lib/crypto.h | 12 - src/lib/crypto/dsa.h | 11 + src/lib/crypto/ec.h | 36 + src/lib/crypto/ecdh.cpp | 2 +- src/lib/crypto/ecdh.h | 7 +- src/lib/crypto/elgamal.h | 11 + src/lib/crypto/rsa.h | 14 + src/lib/crypto/signatures.cpp | 265 +------ src/lib/crypto/signatures.h | 5 +- src/lib/fingerprint.cpp | 12 +- src/lib/pgp-key.cpp | 403 +---------- src/lib/pgp-key.h | 23 +- src/lib/rnp.cpp | 120 ++-- src/lib/types.h | 35 +- src/librekey/g23_sexp.hpp | 2 +- src/librekey/key_store_g10.cpp | 262 ++++--- src/librepgp/stream-dump.cpp | 379 +++++----- src/librepgp/stream-key.cpp | 501 +------------- src/librepgp/stream-key.h | 9 +- src/librepgp/stream-parse.cpp | 95 +-- src/librepgp/stream-write.cpp | 111 +-- src/tests/cipher.cpp | 649 ++++++++++-------- src/tests/cli_tests.py | 2 +- .../data/test_key_validity/case5/generate.cpp | 2 +- src/tests/key-protect.cpp | 82 ++- src/tests/key-unlock.cpp | 13 +- src/tests/load-pgp.cpp | 6 +- 28 files changed, 1056 insertions(+), 2291 deletions(-) diff --git a/src/lib/crypto.cpp b/src/lib/crypto.cpp index a6f4a0ff40..a9a33b6968 100644 --- a/src/lib/crypto.cpp +++ b/src/lib/crypto.cpp @@ -95,135 +95,18 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, #endif seckey.creation_time = crypto.ctx->time(); seckey.alg = crypto.key_alg; - seckey.material.alg = crypto.key_alg; + seckey.material = pgp::KeyMaterial::create(crypto.key_alg); + if (!seckey.material) { + RNP_LOG("Unsupported key algorithm: %d", crypto.key_alg); + return false; + } seckey.tag = primary ? PGP_PKT_SECRET_KEY : PGP_PKT_SECRET_SUBKEY; - switch (seckey.alg) { - case PGP_PKA_RSA: - if (rsa_generate(&crypto.ctx->rng, &seckey.material.rsa, crypto.rsa.modulus_bit_len)) { - RNP_LOG("failed to generate RSA key"); - return false; - } - break; - case PGP_PKA_DSA: - if (dsa_generate(&crypto.ctx->rng, - &seckey.material.dsa, - crypto.dsa.p_bitlen, - crypto.dsa.q_bitlen)) { - RNP_LOG("failed to generate DSA key"); - return false; - } - break; - case PGP_PKA_EDDSA: - if (eddsa_generate(&crypto.ctx->rng, &seckey.material.ec)) { - RNP_LOG("failed to generate EDDSA key"); - return false; - } - break; - case PGP_PKA_ECDH: - if (!ecdh_set_params(&seckey.material.ec, crypto.ecc.curve)) { - RNP_LOG("Unsupported curve [ID=%d]", crypto.ecc.curve); - return false; - } - if (crypto.ecc.curve == PGP_CURVE_25519) { - if (x25519_generate(&crypto.ctx->rng, &seckey.material.ec)) { - RNP_LOG("failed to generate x25519 key"); - return false; - } - seckey.material.ec.curve = crypto.ecc.curve; - break; - } - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - if (!curve_supported(crypto.ecc.curve)) { - RNP_LOG("EC generate: curve %d is not supported.", (int) crypto.ecc.curve); - return false; - } - if (ec_generate(&crypto.ctx->rng, &seckey.material.ec, seckey.alg, crypto.ecc.curve)) { - RNP_LOG("failed to generate EC key"); - return false; - } - seckey.material.ec.curve = crypto.ecc.curve; - break; - case PGP_PKA_ELGAMAL: - if (elgamal_generate( - &crypto.ctx->rng, &seckey.material.eg, crypto.elgamal.key_bitlen)) { - RNP_LOG("failed to generate ElGamal key"); - return false; - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - if (generate_ed25519_native(&crypto.ctx->rng, - seckey.material.ed25519.priv, - seckey.material.ed25519.pub) != RNP_SUCCESS) { - RNP_LOG("failed to generate ED25519 key"); - return false; - } - break; - case PGP_PKA_X25519: - if (generate_x25519_native(&crypto.ctx->rng, - seckey.material.x25519.priv, - seckey.material.x25519.pub) != RNP_SUCCESS) { - RNP_LOG("failed to generate X25519 key"); - return false; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - if (pgp_kyber_ecdh_composite_key_t::gen_keypair( - &crypto.ctx->rng, &seckey.material.kyber_ecdh, seckey.alg)) { - RNP_LOG("failed to generate MLKEM-ECDH-composite key for PK alg %d", seckey.alg); - return false; - } - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - if (pgp_dilithium_exdsa_composite_key_t::gen_keypair( - &crypto.ctx->rng, &seckey.material.dilithium_exdsa, seckey.alg)) { - RNP_LOG("failed to generate mldsa-ecdsa/eddsa-composite key for PK alg %d", - seckey.alg); - return false; - } - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - if (pgp_sphincsplus_generate(&crypto.ctx->rng, - &seckey.material.sphincsplus, - crypto.sphincsplus.param, - seckey.alg)) { - RNP_LOG("failed to generate SLH-DSA key for PK alg %d", seckey.alg); - return false; - } - break; -#endif - default: - RNP_LOG("key generation not implemented for PK alg: %d", seckey.alg); + if (!seckey.material->generate(crypto)) { return false; } + seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; - seckey.material.secret = true; - seckey.material.validity.mark_valid(); /* fill the sec_data/sec_len */ if (encrypt_secret_key(&seckey, NULL, crypto.ctx->rng)) { RNP_LOG("failed to fill sec_data"); @@ -231,150 +114,3 @@ pgp_generate_seckey(const rnp_keygen_crypto_params_t &crypto, } return true; } - -bool -key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2) -{ - if (key1->alg != key2->alg) { - return false; - } - - switch (key1->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return (key1->rsa.n == key2->rsa.n) && (key1->rsa.e == key2->rsa.e); - case PGP_PKA_DSA: - return (key1->dsa.p == key2->dsa.p) && (key1->dsa.q == key2->dsa.q) && - (key1->dsa.g == key2->dsa.g) && (key1->dsa.y == key2->dsa.y); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return (key1->eg.p == key2->eg.p) && (key1->eg.g == key2->eg.g) && - (key1->eg.y == key2->eg.y); - case PGP_PKA_EDDSA: - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - return (key1->ec.curve == key2->ec.curve) && (key1->ec.p == key2->ec.p); -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return (key1->ed25519.pub == key2->ed25519.pub); - case PGP_PKA_X25519: - return (key1->x25519.pub == key2->x25519.pub); -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return (key1->kyber_ecdh.pub == key2->kyber_ecdh.pub); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return (key1->dilithium_exdsa.pub == key2->dilithium_exdsa.pub); - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return (key1->sphincsplus.pub == key2->sphincsplus.pub); -#endif - default: - RNP_LOG("unknown public key algorithm: %d", (int) key1->alg); - return false; - } -} - -rnp_result_t -validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng) -{ -#ifdef FUZZERS_ENABLED - /* do not timeout on large keys during fuzzing */ - return RNP_SUCCESS; -#else - switch (material->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return rsa_validate_key(rng, &material->rsa, material->secret); - case PGP_PKA_DSA: - return dsa_validate_key(rng, &material->dsa, material->secret); - case PGP_PKA_EDDSA: - return eddsa_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_ECDH: - if (!curve_supported(material->ec.curve)) { - /* allow to import key if curve is not supported */ - RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); - return RNP_SUCCESS; - } - return ecdh_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_ECDSA: - if (!curve_supported(material->ec.curve)) { - /* allow to import key if curve is not supported */ - RNP_LOG("ECDH validate: curve %d is not supported.", (int) material->ec.curve); - return RNP_SUCCESS; - } - return ecdsa_validate_key(rng, &material->ec, material->secret); - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - return sm2_validate_key(rng, &material->ec, material->secret); -#else - RNP_LOG("SM2 key validation is not available."); - return RNP_ERROR_NOT_IMPLEMENTED; -#endif - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return elgamal_validate_key(&material->eg, material->secret) ? RNP_SUCCESS : - RNP_ERROR_GENERIC; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return ed25519_validate_key_native(rng, &material->ed25519, material->secret); - case PGP_PKA_X25519: - return x25519_validate_key_native(rng, &material->x25519, material->secret); -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return kyber_ecdh_validate_key(rng, &material->kyber_ecdh, material->secret); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return dilithium_exdsa_validate_key(rng, &material->dilithium_exdsa, material->secret); - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return sphincsplus_validate_key(rng, &material->sphincsplus, material->secret); -#endif - default: - RNP_LOG("unknown public key algorithm: %d", (int) material->alg); - } - - return RNP_ERROR_BAD_PARAMETERS; -#endif -} diff --git a/src/lib/crypto.h b/src/lib/crypto.h index 4fd1f81d89..47346f0f06 100644 --- a/src/lib/crypto.h +++ b/src/lib/crypto.h @@ -104,16 +104,4 @@ bool pgp_generate_subkey(rnp_keygen_subkey_desc_t & desc, const pgp_password_provider_t &password_provider, pgp_key_store_format_t secformat); -/** - * @brief Check two key material for equality. Only public part is checked, so this can be - * called on public/secret key material - * - * @param key1 first key material - * @param key2 second key material - * @return true if both key materials are equal or false otherwise - */ -bool key_material_equal(const pgp_key_material_t *key1, const pgp_key_material_t *key2); - -rnp_result_t validate_pgp_key_material(const pgp_key_material_t *material, rnp::RNG *rng); - #endif /* CRYPTO_H_ */ diff --git a/src/lib/crypto/dsa.h b/src/lib/crypto/dsa.h index 52eaae3bb7..fe6d795cac 100644 --- a/src/lib/crypto/dsa.h +++ b/src/lib/crypto/dsa.h @@ -43,6 +43,17 @@ typedef struct pgp_dsa_key_t { pgp::mpi y; /* secret mpi */ pgp::mpi x; + + void + clear_secret() + { + x.forget(); + } + + ~pgp_dsa_key_t() + { + clear_secret(); + } } pgp_dsa_key_t; typedef struct pgp_dsa_signature_t { diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index 2b85844007..d96508dc87 100644 --- a/src/lib/crypto/ec.h +++ b/src/lib/crypto/ec.h @@ -35,6 +35,7 @@ #include #include "crypto/rng.h" #include "crypto/mpi.h" +#include "crypto/mem.h" #include #define MAX_CURVE_BIT_SIZE 521 // secp521r1 @@ -83,6 +84,17 @@ typedef struct pgp_ec_key_t { /* ecdh params */ pgp_hash_alg_t kdf_hash_alg; /* Hash used by kdf */ pgp_symm_alg_t key_wrap_alg; /* Symmetric algorithm used to wrap KEK*/ + + void + clear_secret() + { + x.forget(); + } + + ~pgp_ec_key_t() + { + clear_secret(); + } } pgp_ec_key_t; typedef struct pgp_ec_signature_t { @@ -94,6 +106,18 @@ typedef struct pgp_ec_signature_t { typedef struct pgp_ed25519_key_t { std::vector pub; // \ native encoding std::vector priv; // / + + void + clear_secret() + { + secure_clear(priv.data(), priv.size()); + priv.resize(0); + } + + ~pgp_ed25519_key_t() + { + clear_secret(); + } } pgp_ed25519_key_t; typedef struct pgp_ed25519_signature_t { @@ -103,6 +127,18 @@ typedef struct pgp_ed25519_signature_t { typedef struct pgp_x25519_key_t { std::vector pub; // \ native encoding std::vector priv; // / + + void + clear_secret() + { + secure_clear(priv.data(), priv.size()); + priv.resize(0); + } + + ~pgp_x25519_key_t() + { + clear_secret(); + } } pgp_x25519_key_t; typedef struct pgp_x25519_encrypted_t { diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index 024a759e0d..206e352a97 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -302,7 +302,7 @@ ecdh_decrypt_pkcs5(uint8_t * out, const pgp_ec_key_t * key, const pgp_fingerprint_t & fingerprint) { - if (!out_len || !in || !key || !key->x.bytes()) { + if (!out || !out_len || !in || !key || !key->x.bytes()) { return RNP_ERROR_BAD_PARAMETERS; } diff --git a/src/lib/crypto/ecdh.h b/src/lib/crypto/ecdh.h index 1ac35ccf79..ef9a00d7f4 100644 --- a/src/lib/crypto/ecdh.h +++ b/src/lib/crypto/ecdh.h @@ -41,9 +41,10 @@ typedef struct pgp_fingerprint_t pgp_fingerprint_t; typedef struct pgp_ecdh_encrypted_t { - pgp::mpi p; - uint8_t m[ECDH_WRAPPED_KEY_SIZE]; - size_t mlen; + pgp::mpi p; + uint8_t m[ECDH_WRAPPED_KEY_SIZE]; + size_t mlen; + const pgp_fingerprint_t *fp; } pgp_ecdh_encrypted_t; rnp_result_t ecdh_validate_key(rnp::RNG *rng, const pgp_ec_key_t *key, bool secret); diff --git a/src/lib/crypto/elgamal.h b/src/lib/crypto/elgamal.h index ce35a958a4..369022fc26 100644 --- a/src/lib/crypto/elgamal.h +++ b/src/lib/crypto/elgamal.h @@ -37,6 +37,17 @@ typedef struct pgp_eg_key_t { pgp::mpi y; /* secret mpi */ pgp::mpi x; + + void + clear_secret() + { + x.forget(); + } + + ~pgp_eg_key_t() + { + clear_secret(); + } } pgp_eg_key_t; typedef struct pgp_eg_signature_t { diff --git a/src/lib/crypto/rsa.h b/src/lib/crypto/rsa.h index 998742812e..9f8583cee1 100644 --- a/src/lib/crypto/rsa.h +++ b/src/lib/crypto/rsa.h @@ -44,6 +44,20 @@ typedef struct pgp_rsa_key_t { pgp::mpi p; pgp::mpi q; pgp::mpi u; + + void + clear_secret() + { + d.forget(); + p.forget(); + q.forget(); + u.forget(); + } + + ~pgp_rsa_key_t() + { + clear_secret(); + } } pgp_rsa_key_t; typedef struct pgp_rsa_signature_t { diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 1735c59572..71b623d089 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -42,11 +42,9 @@ * @param hdr literal packet header for attached signatures or NULL otherwise. * @return RNP_SUCCESS on success or some error otherwise */ -static void +static rnp::secure_vector signature_hash_finish(const pgp_signature_t & sig, rnp::Hash & hash, - uint8_t * hbuf, - size_t & hlen, const pgp_literal_hdr_t *hdr) { hash.add(sig.hashed_data, sig.hashed_len); @@ -86,7 +84,9 @@ signature_hash_finish(const pgp_signature_t & sig, default: break; } - hlen = hash.finish(hbuf); + rnp::secure_vector res(hash.size()); + hash.finish(res.data()); + return res; } std::unique_ptr @@ -100,46 +100,27 @@ signature_init(const pgp_key_pkt_t &key, const pgp_signature_t &sig) } #endif - if (key.material.alg == PGP_PKA_SM2) { -#if defined(ENABLE_SM2) - rnp_result_t r = sm2_compute_za(key.material.ec, *hash); - if (r != RNP_SUCCESS) { - RNP_LOG("failed to compute SM2 ZA field"); - throw rnp::rnp_exception(r); - } -#else - RNP_LOG("SM2 ZA computation not available"); - throw rnp::rnp_exception(RNP_ERROR_NOT_IMPLEMENTED); -#endif + if (key.material->alg() == PGP_PKA_SM2) { + auto &sm2 = dynamic_cast(*key.material); + sm2.compute_za(*hash); } return hash; } void signature_calculate(pgp_signature_t & sig, - pgp_key_material_t & seckey, + pgp::KeyMaterial & seckey, rnp::Hash & hash, rnp::SecurityContext & ctx, const pgp_literal_hdr_t *hdr) { - uint8_t hval[PGP_MAX_HASH_SIZE]; - size_t hlen = 0; - rnp_result_t ret = RNP_ERROR_GENERIC; - const pgp_hash_alg_t hash_alg = hash.alg(); - /* Finalize hash first, since function is required to do this */ - try { - signature_hash_finish(sig, hash, hval, hlen, hdr); - } catch (const std::exception &e) { - RNP_LOG("Failed to finalize hash: %s", e.what()); - throw; - } - - if (!seckey.secret) { + auto hval = signature_hash_finish(sig, hash, hdr); + if (!seckey.secret()) { RNP_LOG("Secret key is required."); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - if (sig.palg != seckey.alg) { + if (sig.palg != seckey.alg()) { RNP_LOG("Signature and secret key do not agree on algorithm type."); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } @@ -150,131 +131,31 @@ signature_calculate(pgp_signature_t & sig, throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - /* copy left 16 bits to signature */ - memcpy(sig.lbits, hval, 2); + /* Copy left 16 bits to signature */ + memcpy(sig.lbits, hval.data(), 2); - /* sign */ pgp_signature_material_t material = {}; - switch (sig.palg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - ret = rsa_sign_pkcs1(&ctx.rng, &material.rsa, sig.halg, hval, hlen, &seckey.rsa); - if (ret) { - RNP_LOG("rsa signing failed"); - } - break; - case PGP_PKA_EDDSA: - ret = eddsa_sign(&ctx.rng, &material.ecc, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("eddsa signing failed"); - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - ret = - ed25519_sign_native(&ctx.rng, material.ed25519.sig, seckey.ed25519.priv, hval, hlen); - if (ret) { - RNP_LOG("ed25519 signing failed"); - } - break; -#endif - case PGP_PKA_DSA: - ret = dsa_sign(&ctx.rng, &material.dsa, hval, hlen, &seckey.dsa); - if (ret != RNP_SUCCESS) { - RNP_LOG("DSA signing failed"); - } - break; - /* - * ECDH is signed with ECDSA. This must be changed when ECDH will support - * X25519, but I need to check how it should be done exactly. - */ - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: { - const ec_curve_desc_t *curve = get_curve_desc(seckey.ec.curve); - if (!curve) { - RNP_LOG("Unknown curve"); - ret = RNP_ERROR_BAD_PARAMETERS; - break; - } - if (!curve_supported(seckey.ec.curve)) { - RNP_LOG("EC sign: curve %s is not supported.", curve->pgp_name); - ret = RNP_ERROR_NOT_SUPPORTED; - break; - } - /* "-2" because ECDSA on P-521 must work with SHA-512 digest */ - if (BITS_TO_BYTES(curve->bitlen) - 2 > hlen) { - RNP_LOG("Message hash too small"); - ret = RNP_ERROR_BAD_PARAMETERS; - break; - } - - if (sig.palg == PGP_PKA_SM2) { -#if defined(ENABLE_SM2) - ret = sm2_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("SM2 signing failed"); - } -#else - RNP_LOG("SM2 signing is not available."); - ret = RNP_ERROR_NOT_IMPLEMENTED; -#endif - break; - } + /* Some algos require used hash algorithm for signing */ + material.halg = sig.halg; + /* Sign */ + auto ret = seckey.sign(ctx, material, hval); - ret = ecdsa_sign(&ctx.rng, &material.ecc, hash_alg, hval, hlen, &seckey.ec); - if (ret) { - RNP_LOG("ECDSA signing failed"); - } - break; - } -#if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - ret = seckey.dilithium_exdsa.priv.sign( - &ctx.rng, &material.dilithium_exdsa, hash_alg, hval, hlen); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - ret = seckey.sphincsplus.priv.sign(&ctx.rng, &material.sphincsplus, hval, hlen); - break; -#endif - default: - RNP_LOG("Unsupported algorithm %d", sig.palg); - break; - } if (ret) { throw rnp::rnp_exception(ret); } - try { - sig.write_material(material); - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - throw; - } + sig.write_material(material); } rnp_result_t signature_validate(const pgp_signature_t & sig, - const pgp_key_material_t & key, + const pgp::KeyMaterial & key, rnp::Hash & hash, const rnp::SecurityContext &ctx, const pgp_literal_hdr_t * hdr) { - if (sig.palg != key.alg) { - RNP_LOG("Signature and key do not agree on algorithm type: %d vs %d", - (int) sig.palg, - (int) key.alg); + if (sig.palg != key.alg()) { + RNP_LOG( + "Signature and key do not agree on algorithm type: %d vs %d", sig.palg, key.alg()); return RNP_ERROR_BAD_PARAMETERS; } @@ -289,18 +170,7 @@ signature_validate(const pgp_signature_t & sig, #if defined(ENABLE_PQC) /* check that hash matches key requirements */ - bool hash_alg_valid = false; - switch (key.alg) { - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hash_alg_valid = key.sphincsplus.pub.validate_signature_hash_requirements(hash.alg()); - break; - default: - hash_alg_valid = true; - break; - } - if (!hash_alg_valid) { + if (!key.sig_hash_allowed(hash.alg())) { RNP_LOG("Signature invalid since hash algorithm requirements are not met for the " "given key."); return RNP_ERROR_SIGNATURE_INVALID; @@ -308,94 +178,19 @@ signature_validate(const pgp_signature_t & sig, #endif /* Finalize hash */ - uint8_t hval[PGP_MAX_HASH_SIZE]; - size_t hlen = 0; - try { - signature_hash_finish(sig, hash, hval, hlen, hdr); - } catch (const std::exception &e) { - RNP_LOG("Failed to finalize signature hash."); - return RNP_ERROR_GENERIC; - } + auto hval = signature_hash_finish(sig, hash, hdr); /* compare lbits */ - if (memcmp(hval, sig.lbits, 2)) { + if (memcmp(hval.data(), sig.lbits, 2)) { RNP_LOG("wrong lbits"); return RNP_ERROR_SIGNATURE_INVALID; } /* validate signature */ pgp_signature_material_t material = {}; - try { - sig.parse_material(material); - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - return RNP_ERROR_OUT_OF_MEMORY; - } - rnp_result_t ret = RNP_ERROR_GENERIC; - switch (sig.palg) { - case PGP_PKA_DSA: - ret = dsa_verify(&material.dsa, hval, hlen, &key.dsa); - break; - case PGP_PKA_EDDSA: - ret = eddsa_verify(&material.ecc, hval, hlen, &key.ec); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - ret = ed25519_verify_native(material.ed25519.sig, key.ed25519.pub, hval, hlen); - break; -#endif - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - ret = sm2_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); -#else - RNP_LOG("SM2 verification is not available."); - ret = RNP_ERROR_NOT_IMPLEMENTED; -#endif - break; - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - ret = rsa_verify_pkcs1(&material.rsa, sig.halg, hval, hlen, &key.rsa); - break; - case PGP_PKA_RSA_ENCRYPT_ONLY: - RNP_LOG("RSA encrypt-only signature considered as invalid."); - ret = RNP_ERROR_SIGNATURE_INVALID; - break; - case PGP_PKA_ECDSA: - if (!curve_supported(key.ec.curve)) { - RNP_LOG("ECDSA verify: curve %d is not supported.", (int) key.ec.curve); - ret = RNP_ERROR_NOT_SUPPORTED; - break; - } - ret = ecdsa_verify(&material.ecc, hash.alg(), hval, hlen, &key.ec); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - RNP_LOG("ElGamal are considered as invalid."); - ret = RNP_ERROR_SIGNATURE_INVALID; - break; -#if defined(ENABLE_PQC) - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - ret = - key.dilithium_exdsa.pub.verify(&material.dilithium_exdsa, hash.alg(), hval, hlen); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - ret = key.sphincsplus.pub.verify(&material.sphincsplus, hval, hlen); - break; -#endif - default: - RNP_LOG("Unknown algorithm"); - ret = RNP_ERROR_BAD_PARAMETERS; - } - return ret; + /* We check whether material could be parsed during the signature parsing */ + sig.parse_material(material); + material.halg = sig.halg; + + return key.verify(ctx, material, hval); } diff --git a/src/lib/crypto/signatures.h b/src/lib/crypto/signatures.h index 3cba7cc4ff..58c1735f2d 100644 --- a/src/lib/crypto/signatures.h +++ b/src/lib/crypto/signatures.h @@ -28,6 +28,7 @@ #define RNP_SIGNATURES_H_ #include "crypto/hash.hpp" +#include "key_material.hpp" /** * @brief Initialize a signature computation. @@ -48,7 +49,7 @@ std::unique_ptr signature_init(const pgp_key_pkt_t & key, * @param hdr literal packet header for attached document signatures or NULL otherwise. */ void signature_calculate(pgp_signature_t & sig, - pgp_key_material_t & seckey, + pgp::KeyMaterial & seckey, rnp::Hash & hash, rnp::SecurityContext & ctx, const pgp_literal_hdr_t *hdr = NULL); @@ -66,7 +67,7 @@ void signature_calculate(pgp_signature_t & sig, * @return RNP_SUCCESS if signature was successfully validated or error code otherwise. */ rnp_result_t signature_validate(const pgp_signature_t & sig, - const pgp_key_material_t & key, + const pgp::KeyMaterial & key, rnp::Hash & hash, const rnp::SecurityContext &ctx, const pgp_literal_hdr_t * hdr = NULL); diff --git a/src/lib/fingerprint.cpp b/src/lib/fingerprint.cpp index bc5c9cfec3..a4bf355409 100644 --- a/src/lib/fingerprint.cpp +++ b/src/lib/fingerprint.cpp @@ -47,9 +47,10 @@ try { RNP_LOG("bad algorithm"); return RNP_ERROR_NOT_SUPPORTED; } - auto hash = rnp::Hash::create(PGP_HASH_MD5); - hash->add(key.material.rsa.n); - hash->add(key.material.rsa.e); + auto &rsa = dynamic_cast(*key.material); + auto hash = rnp::Hash::create(PGP_HASH_MD5); + hash->add(rsa.n()); + hash->add(rsa.e()); fp.length = hash->finish(fp.fingerprint); return RNP_SUCCESS; } @@ -91,8 +92,9 @@ pgp_keyid(pgp_key_id_t &keyid, const pgp_key_pkt_t &key) RNP_LOG("bad algorithm"); return RNP_ERROR_NOT_SUPPORTED; } - size_t n = key.material.rsa.n.bytes(); - (void) memcpy(keyid.data(), key.material.rsa.n.mpi + n - keyid.size(), keyid.size()); + auto & rsa = dynamic_cast(*key.material); + size_t n = rsa.n().bytes(); + (void) memcpy(keyid.data(), rsa.n().mpi + n - keyid.size(), keyid.size()); return RNP_SUCCESS; } case PGP_V4: diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 83f792ece9..ab8f1ad61e 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -478,48 +478,6 @@ find_suitable_key(pgp_op_t op, pgp_key_t *key, rnp::KeyProvider *key_provider, b return subkey; } -pgp_hash_alg_t -pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey) -{ -#if defined(ENABLE_PQC) - switch (pubkey->alg) { - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return sphincsplus_default_hash_alg(pubkey->alg, - pubkey->material.sphincsplus.pub.param()); - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return dilithium_default_hash_alg(); - default: - break; - } -#endif - - if ((pubkey->alg != PGP_PKA_DSA) && (pubkey->alg != PGP_PKA_ECDSA)) { - return hash; - } - - pgp_hash_alg_t hash_min; - if (pubkey->alg == PGP_PKA_ECDSA) { - hash_min = ecdsa_get_min_hash(pubkey->material.ec.curve); - } else { - hash_min = dsa_get_min_hash(pubkey->material.dsa.q.bits()); - } - - if (rnp::Hash::size(hash) < rnp::Hash::size(hash_min)) { - return hash_min; - } - return hash; -} - static void bytevec_append_uniq(std::vector &vec, uint8_t val) { @@ -790,13 +748,13 @@ pgp_revoke_t::pgp_revoke_t(pgp_subsig_t &sig) pgp_key_t::pgp_key_t(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) { - if (!is_key_pkt(pkt_.tag) || !pkt_.material.alg) { + if (!is_key_pkt(pkt_.tag) || !pkt_.material->alg()) { throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } - if (pgp_keyid(keyid_, pkt_) || pgp_fingerprint(fingerprint_, pkt_) || - !pkt_.material.get_grip(grip_)) { + if (pgp_keyid(keyid_, pkt_) || pgp_fingerprint(fingerprint_, pkt_)) { throw rnp::rnp_exception(RNP_ERROR_GENERIC); } + grip_ = pkt_.material->grip(); /* parse secret key if not encrypted */ if (is_secret_key_pkt(pkt_.tag)) { @@ -806,7 +764,7 @@ pgp_key_t::pgp_key_t(const pgp_key_pkt_t &keypkt) : pkt_(keypkt) throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); } /* decryption resets validity */ - pkt_.material.validity = keypkt.material.validity; + pkt_.material->set_validity(keypkt.material->validity()); } /* add rawpacket */ rawpkt_ = pgp_rawpacket_t(pkt_); @@ -1234,10 +1192,22 @@ pgp_key_t::set_pkt(const pgp_key_pkt_t &pkt) pkt_ = pkt; } -pgp_key_material_t & +const pgp::KeyMaterial & +pgp_key_t::material() const +{ + if (!pkt_.material) { + throw rnp::rnp_exception(RNP_ERROR_NULL_POINTER); + } + return *pkt_.material; +} + +pgp::KeyMaterial & pgp_key_t::material() { - return pkt_.material; + if (!pkt_.material) { + throw rnp::rnp_exception(RNP_ERROR_NULL_POINTER); + } + return *pkt_.material; } pgp_pubkey_alg_t @@ -1249,21 +1219,7 @@ pgp_key_t::alg() const pgp_curve_t pgp_key_t::curve() const { - switch (alg()) { - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return pkt_.material.ec.curve; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return PGP_CURVE_ED25519; - case PGP_PKA_X25519: - return PGP_CURVE_25519; -#endif - default: - return PGP_CURVE_UNKNOWN; - } + return material().curve(); } pgp_version_t @@ -1281,7 +1237,7 @@ pgp_key_t::type() const bool pgp_key_t::encrypted() const { - return is_secret() && !pkt().material.secret; + return is_secret() && !material().secret(); } uint8_t @@ -1609,11 +1565,8 @@ pgp_key_t::unlock(const pgp_password_provider_t &provider, pgp_op_t op) return false; } - // this shouldn't really be necessary, but just in case - forget_secret_key_fields(&pkt_.material); - // copy the decrypted mpis into the pgp_key_t - pkt_.material = decrypted_seckey->material; - pkt_.material.secret = true; + // move the decrypted mpis into the pgp_key_t + pkt_.material = std::move(decrypted_seckey->material); delete decrypted_seckey; return true; } @@ -1632,7 +1585,7 @@ pgp_key_t::lock() return true; } - forget_secret_key_fields(&pkt_.material); + material().clear_secret(); return true; } @@ -1662,7 +1615,7 @@ pgp_key_t::protect(pgp_key_pkt_t & decrypted, return false; } bool ownpkt = &decrypted == &pkt_; - if (!decrypted.material.secret) { + if (!decrypted.material->secret()) { RNP_LOG("Decrypted secret key must be provided"); return false; } @@ -1723,7 +1676,7 @@ pgp_key_t::unprotect(const pgp_password_provider_t &password_provider, } pkt_ = std::move(*decrypted_seckey); /* current logic is that unprotected key should be additionally unlocked */ - forget_secret_key_fields(&pkt_.material); + material().clear_secret(); delete decrypted_seckey; return true; } @@ -2079,7 +2032,7 @@ pgp_key_t::validate_sig(pgp_signature_info_t & sinfo, /* Validate signature itself */ if (sinfo.signer_valid || valid_at(sinfo.sig->creation())) { - sinfo.valid = !signature_validate(*sinfo.sig, pkt_.material, hash, ctx, hdr); + sinfo.valid = !signature_validate(*sinfo.sig, *pkt_.material, hash, ctx, hdr); } else { sinfo.valid = false; RNP_LOG("invalid or untrusted key"); @@ -2453,7 +2406,7 @@ pgp_key_t::sign_init(rnp::RNG & rng, pgp_version_t version) const { sig.version = version; - sig.halg = pgp_hash_adjust_alg_to_key(hash, &pkt_); + sig.halg = pkt_.material->adjust_hash(hash); sig.palg = alg(); sig.set_keyfp(fp()); sig.set_creation(creation); @@ -2477,7 +2430,7 @@ pgp_key_t::sign_cert(const pgp_key_pkt_t & key, { sig.fill_hashed_data(); auto hash = signature_hash_certification(sig, key, uid); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2487,7 +2440,7 @@ pgp_key_t::sign_direct(const pgp_key_pkt_t & key, { sig.fill_hashed_data(); auto hash = signature_hash_direct(sig, key); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2498,7 +2451,7 @@ pgp_key_t::sign_binding(const pgp_key_pkt_t & key, sig.fill_hashed_data(); auto hash = is_primary() ? signature_hash_binding(sig, pkt(), key) : signature_hash_binding(sig, key, pkt()); - signature_calculate(sig, pkt_.material, *hash, ctx); + signature_calculate(sig, *pkt_.material, *hash, ctx); } void @@ -2882,9 +2835,9 @@ pgp_key_t::merge(const pgp_key_t &src) if (is_secret() && !is_locked()) { /* we may do thing below only because key material is opaque structure without * pointers! */ - tmpkey.pkt().material = pkt().material; + tmpkey.pkt().material = pkt().material->clone(); } else if (src.is_secret() && !src.is_locked()) { - tmpkey.pkt().material = src.pkt().material; + tmpkey.pkt().material = src.pkt().material->clone(); } /* copy validity status */ tmpkey.validity_ = validity_; @@ -2938,9 +2891,9 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) if (is_secret() && !is_locked()) { /* we may do thing below only because key material is opaque structure without * pointers! */ - tmpkey.pkt().material = pkt().material; + tmpkey.pkt().material = pkt().material->clone(); } else if (src.is_secret() && !src.is_locked()) { - tmpkey.pkt().material = src.pkt().material; + tmpkey.pkt().material = src.pkt().material->clone(); } /* copy validity status */ tmpkey.validity_ = validity_; @@ -2949,291 +2902,3 @@ pgp_key_t::merge(const pgp_key_t &src, pgp_key_t *primary) *this = std::move(tmpkey); return true; } - -pgp_curve_t -pgp_key_material_t::curve() const -{ - switch (alg) { - case PGP_PKA_ECDH: - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_EDDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SM2: - return ec.curve; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - return PGP_CURVE_ED25519; - case PGP_PKA_X25519: - return PGP_CURVE_25519; -#endif - default: - return PGP_CURVE_UNKNOWN; - } -} - -size_t -pgp_key_material_t::bits() const -{ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return 8 * rsa.n.bytes(); - case PGP_PKA_DSA: - return 8 * dsa.p.bytes(); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return 8 * eg.y.bytes(); - case PGP_PKA_ECDH: - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - FALLTHROUGH_STATEMENT; - case PGP_PKA_EDDSA: - FALLTHROUGH_STATEMENT; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - FALLTHROUGH_STATEMENT; - case PGP_PKA_X25519: - FALLTHROUGH_STATEMENT; -#endif - case PGP_PKA_SM2: { - /* handle ecc cases */ - const ec_curve_desc_t *curve_desc = get_curve_desc(curve()); - return curve_desc ? curve_desc->bitlen : 0; - } -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return 8 * kyber_ecdh.pub.get_encoded().size(); /* public key length */ - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - return 8 * dilithium_exdsa.pub.get_encoded().size(); /* public key length*/ - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - return 8 * sphincsplus.pub.get_encoded().size(); /* public key length */ -#endif - default: - RNP_LOG("Unknown public key alg: %d", (int) alg); - return 0; - } -} - -size_t -pgp_key_material_t::qbits() const -{ - if (alg != PGP_PKA_DSA) { - return 0; - } - return 8 * dsa.q.bytes(); -} - -void -pgp_key_material_t::validate(rnp::SecurityContext &ctx, bool reset) -{ - if (!reset && validity.validated) { - return; - } - validity.reset(); - validity.valid = !validate_pgp_key_material(this, &ctx.rng); - validity.validated = true; -} - -bool -pgp_key_material_t::valid() const -{ - return validity.validated && validity.valid; -} - -namespace { -void -grip_hash_mpi(rnp::Hash &hash, const pgp::mpi &val, const char name, bool lzero = true) -{ - size_t len = val.bytes(); - size_t idx = 0; - for (idx = 0; (idx < len) && !val.mpi[idx]; idx++) - ; - - if (name) { - size_t hlen = idx >= len ? 0 : len - idx; - if ((len > idx) && lzero && (val.mpi[idx] & 0x80)) { - hlen++; - } - - char buf[26] = {0}; - snprintf(buf, sizeof(buf), "(1:%c%zu:", name, hlen); - hash.add(buf, strlen(buf)); - } - - if (idx < len) { - /* gcrypt prepends mpis with zero if higher bit is set */ - if (lzero && (val.mpi[idx] & 0x80)) { - uint8_t zero = 0; - hash.add(&zero, 1); - } - hash.add(val.mpi + idx, len - idx); - } - if (name) { - hash.add(")", 1); - } -} - -void -grip_hash_ecc_hex(rnp::Hash &hash, const char *hex, char name) -{ - pgp::mpi mpi = {}; - mpi.len = rnp::hex_decode(hex, mpi.mpi, sizeof(mpi.mpi)); - if (!mpi.len) { - RNP_LOG("wrong hex mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - - /* libgcrypt doesn't add leading zero when hashes ecc mpis */ - return grip_hash_mpi(hash, mpi, name, false); -} - -void -grip_hash_ec(rnp::Hash &hash, const pgp_ec_key_t &key) -{ - const ec_curve_desc_t *desc = get_curve_desc(key.curve); - if (!desc) { - RNP_LOG("unknown curve %d", (int) key.curve); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - - /* build uncompressed point from gx and gy */ - pgp::mpi g = {}; - g.mpi[0] = 0x04; - g.len = 1; - size_t len = rnp::hex_decode(desc->gx, g.mpi + g.len, sizeof(g.mpi) - g.len); - if (!len) { - RNP_LOG("wrong x mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len += len; - len = rnp::hex_decode(desc->gy, g.mpi + g.len, sizeof(g.mpi) - g.len); - if (!len) { - RNP_LOG("wrong y mpi"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len += len; - - /* p, a, b, g, n, q */ - grip_hash_ecc_hex(hash, desc->p, 'p'); - grip_hash_ecc_hex(hash, desc->a, 'a'); - grip_hash_ecc_hex(hash, desc->b, 'b'); - grip_hash_mpi(hash, g, 'g', false); - grip_hash_ecc_hex(hash, desc->n, 'n'); - - if ((key.curve == PGP_CURVE_ED25519) || (key.curve == PGP_CURVE_25519)) { - if (g.len < 1) { - RNP_LOG("wrong 25519 p"); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - g.len = key.p.len - 1; - memcpy(g.mpi, key.p.mpi + 1, g.len); - grip_hash_mpi(hash, g, 'q', false); - } else { - grip_hash_mpi(hash, key.p, 'q', false); - } -} -} // namespace - -/* keygrip is subjectKeyHash from pkcs#15 for RSA. */ -bool -pgp_key_material_t::get_grip(pgp_key_grip_t &grip) const -{ - try { - auto hash = rnp::Hash::create(PGP_HASH_SHA1); - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - case PGP_PKA_RSA_ENCRYPT_ONLY: - grip_hash_mpi(*hash, rsa.n, '\0'); - break; - case PGP_PKA_DSA: - grip_hash_mpi(*hash, dsa.p, 'p'); - grip_hash_mpi(*hash, dsa.q, 'q'); - grip_hash_mpi(*hash, dsa.g, 'g'); - grip_hash_mpi(*hash, dsa.y, 'y'); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - grip_hash_mpi(*hash, eg.p, 'p'); - grip_hash_mpi(*hash, eg.g, 'g'); - grip_hash_mpi(*hash, eg.y, 'y'); - break; - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - grip_hash_ec(*hash, ec); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - // TODO: if GnuPG would ever support v6, check whether this works correctly. - case PGP_PKA_ED25519: - hash->add(ed25519.pub); - break; - case PGP_PKA_X25519: - hash->add(x25519.pub); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - hash->add(kyber_ecdh.pub.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - hash->add(dilithium_exdsa.pub.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hash->add(sphincsplus.pub.get_encoded()); - break; -#endif - default: - RNP_LOG("unsupported public-key algorithm %d", (int) alg); - return false; - } - return hash->finish(grip.data()) == grip.size(); - } catch (const std::exception &e) { - RNP_LOG("Grip calculation failed: %s", e.what()); - return false; - } -} diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index 62e94e113d..51ed91d8c5 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -211,11 +211,11 @@ struct pgp_key_t { size_t revoker_count() const; const pgp_fingerprint_t &get_revoker(size_t idx) const; - const pgp_key_pkt_t &pkt() const; - pgp_key_pkt_t & pkt(); - void set_pkt(const pgp_key_pkt_t &pkt); - - pgp_key_material_t &material(); + const pgp_key_pkt_t & pkt() const; + pgp_key_pkt_t & pkt(); + void set_pkt(const pgp_key_pkt_t &pkt); + const pgp::KeyMaterial &material() const; + pgp::KeyMaterial & material(); pgp_pubkey_alg_t alg() const; pgp_curve_t curve() const; @@ -689,17 +689,4 @@ pgp_key_t *find_suitable_key(pgp_op_t op, rnp::KeyProvider *key_provider, bool no_primary = false); -/* - * Picks up hash algorithm according to domain parameters set - * in `pubkey' and user provided hash. That's mostly because DSA - * and ECDSA needs special treatment. - * - * @param hash set by the caller - * @param pubkey initialized public key - * - * @returns hash algorithm that must be use for operation (mostly - signing with secure key which corresponds to 'pubkey') - */ -pgp_hash_alg_t pgp_hash_adjust_alg_to_key(pgp_hash_alg_t hash, const pgp_key_pkt_t *pubkey); - #endif // RNP_PACKET_KEY_H diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index 7b7b96183b..ae20cdae4e 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -4160,7 +4160,8 @@ try { (seckey->curve() != PGP_CURVE_25519)) { return RNP_ERROR_BAD_PARAMETERS; } - *result = x25519_bits_tweaked(seckey->material().ec); + auto &material = dynamic_cast(seckey->material()); + *result = material.x25519_bits_tweaked(); return RNP_SUCCESS; } FFI_GUARD @@ -4176,7 +4177,8 @@ try { (seckey->curve() != PGP_CURVE_25519)) { return RNP_ERROR_BAD_PARAMETERS; } - if (!x25519_tweak_bits(seckey->pkt().material.ec)) { + auto &material = dynamic_cast(seckey->material()); + if (!material.x25519_tweak_bits()) { FFI_LOG(key->ffi, "Failed to tweak 25519 key bits."); return RNP_ERROR_BAD_STATE; } @@ -6846,8 +6848,8 @@ try { return RNP_ERROR_BAD_PARAMETERS; } - return get_map_value( - sphincsplus_params_map, key->material().sphincsplus.pub.param(), param); + auto &material = dynamic_cast(key->material()); + return get_map_value(sphincsplus_params_map, material.pub().param(), param); } FFI_GUARD #endif @@ -6875,11 +6877,11 @@ try { return RNP_ERROR_NULL_POINTER; } pgp_key_t *key = get_key_prefer_public(handle); - size_t _qbits = key->material().qbits(); - if (!_qbits) { + auto material = dynamic_cast(&key->material()); + if (!material) { return RNP_ERROR_BAD_PARAMETERS; } - *qbits = _qbits; + *qbits = material->qbits(); return RNP_SUCCESS; } FFI_GUARD @@ -7692,25 +7694,46 @@ add_json_mpis(json_object *jso, ...) } static rnp_result_t -add_json_public_mpis(json_object *jso, pgp_key_t *key) +add_json_mpis(json_object *jso, pgp_key_t *key, bool secret = false) { - const pgp_key_material_t &km = key->material(); - switch (km.alg) { + auto &km = key->material(); + switch (km.alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return add_json_mpis(jso, "n", &km.rsa.n, "e", &km.rsa.e, NULL); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return add_json_mpis(jso, "p", &km.eg.p, "g", &km.eg.g, "y", &km.eg.y, NULL); - case PGP_PKA_DSA: + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "n", &rsa.n(), "e", &rsa.e(), NULL); + } return add_json_mpis( - jso, "p", &km.dsa.p, "q", &km.dsa.q, "g", &km.dsa.g, "y", &km.dsa.y, NULL); + jso, "d", &rsa.d(), "p", &rsa.p(), "q", &rsa.q(), "u", &rsa.u(), NULL); + } + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "p", &eg.p(), "g", &eg.g(), "y", &eg.y(), NULL); + } + return add_json_mpis(jso, "x", &eg.x(), NULL); + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(km); + if (!secret) { + return add_json_mpis( + jso, "p", &dsa.p(), "q", &dsa.q(), "g", &dsa.g(), "y", &dsa.y(), NULL); + } + return add_json_mpis(jso, "x", &dsa.x(), NULL); + } case PGP_PKA_ECDH: case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return add_json_mpis(jso, "point", &km.ec.p, NULL); + case PGP_PKA_SM2: { + auto &ec = dynamic_cast(km); + if (!secret) { + return add_json_mpis(jso, "point", &ec.p(), NULL); + } + return add_json_mpis(jso, "x", &ec.x(), NULL); + } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: @@ -7750,50 +7773,6 @@ add_json_public_mpis(json_object *jso, pgp_key_t *key) return RNP_SUCCESS; } -static rnp_result_t -add_json_secret_mpis(json_object *jso, pgp_key_t *key) -{ - const pgp_key_material_t &km = key->material(); - switch (key->alg()) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return add_json_mpis( - jso, "d", &km.rsa.d, "p", &km.rsa.p, "q", &km.rsa.q, "u", &km.rsa.u, NULL); - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return add_json_mpis(jso, "x", &km.eg.x, NULL); - case PGP_PKA_DSA: - return add_json_mpis(jso, "x", &km.dsa.x, NULL); - case PGP_PKA_ECDH: - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return add_json_mpis(jso, "x", &km.ec.x, NULL); -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - case PGP_PKA_X25519: - return RNP_SUCCESS; /* TODO */ -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - return RNP_SUCCESS; /* TODO */ -#endif - default: - return RNP_ERROR_NOT_SUPPORTED; - } - return RNP_SUCCESS; -} - static rnp_result_t add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) { @@ -8029,13 +8008,16 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) // curve / alg-specific items switch (key->alg()) { case PGP_PKA_ECDH: { - const char *hash_name = - id_str_pair::lookup(hash_alg_map, key->material().ec.kdf_hash_alg, NULL); + auto ecdh = dynamic_cast(&key->material()); + if (!ecdh) { + return RNP_ERROR_BAD_PARAMETERS; + } + const char *hash_name = id_str_pair::lookup(hash_alg_map, ecdh->kdf_hash_alg(), NULL); if (!hash_name) { return RNP_ERROR_BAD_PARAMETERS; } const char *cipher_name = - id_str_pair::lookup(symm_alg_map, key->material().ec.key_wrap_alg, NULL); + id_str_pair::lookup(symm_alg_map, ecdh->key_wrap_alg(), NULL); if (!cipher_name) { return RNP_ERROR_BAD_PARAMETERS; } @@ -8049,7 +8031,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) case PGP_PKA_EDDSA: case PGP_PKA_SM2: { const char *curve_name = NULL; - if (!curve_type_to_str(key->material().ec.curve, &curve_name)) { + if (!curve_type_to_str(key->material().curve(), &curve_name)) { return RNP_ERROR_BAD_PARAMETERS; } if (!json_add(jso, "curve", curve_name)) { @@ -8182,7 +8164,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } rnp_result_t tmpret; - if ((tmpret = add_json_public_mpis(jsompis, key))) { + if ((tmpret = add_json_mpis(jsompis, key))) { return tmpret; } } @@ -8203,7 +8185,7 @@ key_to_json(json_object *jso, rnp_key_handle_t handle, uint32_t flags) return RNP_ERROR_OUT_OF_MEMORY; } rnp_result_t tmpret; - if ((tmpret = add_json_secret_mpis(jsompis, handle->sec))) { + if ((tmpret = add_json_mpis(jsompis, handle->sec, true))) { return tmpret; } } diff --git a/src/lib/types.h b/src/lib/types.h index a7eac3a121..dc38aab0af 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -164,40 +164,6 @@ typedef struct pgp_validity_t { void reset(); } pgp_validity_t; -/** - * Type to keep public/secret key mpis without any openpgp-dependent data. - */ -typedef struct pgp_key_material_t { - pgp_pubkey_alg_t alg; /* algorithm of the key */ - bool secret; /* secret part of the key material is populated */ - pgp_validity_t validity; /* key material validation status */ - - union { - pgp_rsa_key_t rsa; - pgp_dsa_key_t dsa; - pgp_eg_key_t eg; - pgp_ec_key_t ec; - }; -#if defined(ENABLE_CRYPTO_REFRESH) - pgp_ed25519_key_t ed25519; /* non-trivial type, cannot be in a union */ - pgp_x25519_key_t x25519; /* non-trivial type, cannot be in a union */ -#endif -#if defined(ENABLE_PQC) - pgp_kyber_ecdh_key_t kyber_ecdh; /* non-trivial type, cannot be in a union */ - pgp_dilithium_exdsa_key_t dilithium_exdsa; /* non-trivial type, cannot be in a union */ - pgp_sphincsplus_key_t sphincsplus; /* non-trivial type, cannot be in a union */ -#endif - - pgp_curve_t curve() - const; /* return curve for EC algorithms, PGP_CURVE_UNKNOWN otherwise */ - size_t bits() const; - size_t qbits() const; - void validate(rnp::SecurityContext &ctx, bool reset = true); - bool valid() const; - - bool get_grip(pgp_key_grip_t &grip) const; -} pgp_key_material_t; - /** * Type to keep signature without any openpgp-dependent data. */ @@ -216,6 +182,7 @@ typedef struct pgp_signature_material_t { dilithium_exdsa; // non-trivial type cannot be member in union pgp_sphincsplus_signature_t sphincsplus; // non-trivial type cannot be member in union #endif + pgp_hash_alg_t halg; } pgp_signature_material_t; /** diff --git a/src/librekey/g23_sexp.hpp b/src/librekey/g23_sexp.hpp index 0fb5c5144a..f7b0222260 100644 --- a/src/librekey/g23_sexp.hpp +++ b/src/librekey/g23_sexp.hpp @@ -53,7 +53,7 @@ class gnupg_sexp_t : public sexp::sexp_list_t { void add(unsigned u); p_gnupg_sexp add_sub(); void add_mpi(const std::string &name, const pgp::mpi &val); - void add_curve(const std::string &name, const pgp_ec_key_t &key); + void add_curve(const std::string &name, pgp_curve_t curve); void add_pubkey(const pgp_key_pkt_t &key); void add_seckey(const pgp_key_pkt_t &key); void add_protected_seckey(pgp_key_pkt_t & seckey, diff --git a/src/librekey/key_store_g10.cpp b/src/librekey/key_store_g10.cpp index aa0292e2ff..51e695d391 100644 --- a/src/librekey/key_store_g10.cpp +++ b/src/librekey/key_store_g10.cpp @@ -347,9 +347,9 @@ gnupg_sexp_t::add_mpi(const std::string &name, const pgp::mpi &mpi) } void -gnupg_sexp_t::add_curve(const std::string &name, const pgp_ec_key_t &key) +gnupg_sexp_t::add_curve(const std::string &name, pgp_curve_t kcurve) { - const char *curve = id_str_pair::lookup(g10_curve_names, key.curve, NULL); + const char *curve = id_str_pair::lookup(g10_curve_names, kcurve, NULL); if (!curve) { RNP_LOG("unknown curve"); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -359,13 +359,13 @@ gnupg_sexp_t::add_curve(const std::string &name, const pgp_ec_key_t &key) psub_s_exp->add(name); psub_s_exp->add(curve); - if ((key.curve != PGP_CURVE_ED25519) && (key.curve != PGP_CURVE_25519)) { + if ((kcurve != PGP_CURVE_ED25519) && (kcurve != PGP_CURVE_25519)) { return; } psub_s_exp = add_sub(); psub_s_exp->add("flags"); - psub_s_exp->add((key.curve == PGP_CURVE_ED25519) ? "eddsa" : "djb-tweak"); + psub_s_exp->add((kcurve == PGP_CURVE_ED25519) ? "eddsa" : "djb-tweak"); } static bool @@ -373,47 +373,50 @@ parse_pubkey(pgp_key_pkt_t &pubkey, const sexp_list_t *s_exp, pgp_pubkey_alg_t a { pubkey.version = PGP_V4; pubkey.alg = alg; - pubkey.material.alg = alg; switch (alg) { - case PGP_PKA_DSA: - if (!read_mpi(s_exp, "p", pubkey.material.dsa.p) || - !read_mpi(s_exp, "q", pubkey.material.dsa.q) || - !read_mpi(s_exp, "g", pubkey.material.dsa.g) || - !read_mpi(s_exp, "y", pubkey.material.dsa.y)) { + case PGP_PKA_DSA: { + pgp_dsa_key_t dsa{}; + if (!read_mpi(s_exp, "p", dsa.p) || !read_mpi(s_exp, "q", dsa.q) || + !read_mpi(s_exp, "g", dsa.g) || !read_mpi(s_exp, "y", dsa.y)) { return false; } + pubkey.material = pgp::KeyMaterial::create(dsa); break; - + } case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!read_mpi(s_exp, "n", pubkey.material.rsa.n) || - !read_mpi(s_exp, "e", pubkey.material.rsa.e)) { + case PGP_PKA_RSA_SIGN_ONLY: { + pgp_rsa_key_t rsa{}; + if (!read_mpi(s_exp, "n", rsa.n) || !read_mpi(s_exp, "e", rsa.e)) { return false; } + pubkey.material = pgp::KeyMaterial::create(alg, rsa); break; - + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!read_mpi(s_exp, "p", pubkey.material.eg.p) || - !read_mpi(s_exp, "g", pubkey.material.eg.g) || - !read_mpi(s_exp, "y", pubkey.material.eg.y)) { + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + pgp_eg_key_t eg{}; + if (!read_mpi(s_exp, "p", eg.p) || !read_mpi(s_exp, "g", eg.g) || + !read_mpi(s_exp, "y", eg.y)) { return false; } + pubkey.material = pgp::KeyMaterial::create(alg, eg); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: - if (!read_curve(s_exp, "curve", pubkey.material.ec) || - !read_mpi(s_exp, "q", pubkey.material.ec.p)) { + case PGP_PKA_EDDSA: { + pgp_ec_key_t ec{}; + if (!read_curve(s_exp, "curve", ec) || !read_mpi(s_exp, "q", ec.p)) { return false; } - if (pubkey.material.ec.curve == PGP_CURVE_ED25519) { + if (ec.curve == PGP_CURVE_ED25519) { /* need to adjust it here since 'ecc' key type defaults to ECDSA */ pubkey.alg = PGP_PKA_EDDSA; - pubkey.material.alg = PGP_PKA_EDDSA; } + pubkey.material = pgp::KeyMaterial::create(pubkey.alg, ec); break; + } default: RNP_LOG("Unsupported public key algorithm: %d", (int) alg); return false; @@ -423,44 +426,62 @@ parse_pubkey(pgp_key_pkt_t &pubkey, const sexp_list_t *s_exp, pgp_pubkey_alg_t a } static bool -parse_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *s_exp, pgp_pubkey_alg_t alg) +parse_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *s_exp) { - switch (alg) { - case PGP_PKA_DSA: - if (!read_mpi(s_exp, "x", seckey.material.dsa.x)) { + switch (seckey.alg) { + case PGP_PKA_DSA: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "x", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!read_mpi(s_exp, "d", seckey.material.rsa.d) || - !read_mpi(s_exp, "p", seckey.material.rsa.p) || - !read_mpi(s_exp, "q", seckey.material.rsa.q) || - !read_mpi(s_exp, "u", seckey.material.rsa.u)) { + case PGP_PKA_RSA_SIGN_ONLY: { + pgp::mpi d, p, q, u; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "d", d) || !read_mpi(s_exp, "p", p) || + !read_mpi(s_exp, "q", q) || !read_mpi(s_exp, "u", u)) { return false; } - break; + key->set_secret(d, p, q, u); + d.forget(); + p.forget(); + q.forget(); + u.forget(); + return true; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!read_mpi(s_exp, "x", seckey.material.eg.x)) { + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "x", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: - if (!read_mpi(s_exp, "d", seckey.material.ec.x)) { + case PGP_PKA_EDDSA: { + pgp::mpi x; + auto key = dynamic_cast(seckey.material.get()); + if (!key || !read_mpi(s_exp, "d", x)) { return false; } - break; + key->set_secret(x); + x.forget(); + return true; + } default: - RNP_LOG("Unsupported public key algorithm: %d", (int) alg); + RNP_LOG("Unsupported public key algorithm: %d", (int) seckey.alg); return false; } - - seckey.material.secret = true; - return true; } static bool @@ -654,7 +675,7 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha // we're all done if no password was provided (decryption not requested) if (!password) { - seckey.material.secret = false; + seckey.material->clear_secret(); return true; } @@ -705,7 +726,7 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha protected_at_data->get_string().size()); } // parse MPIs - if (!parse_seckey(seckey, decrypted_s_exp.sexp_list_at(0), seckey.alg)) { + if (!parse_seckey(seckey, decrypted_s_exp.sexp_list_at(0))) { RNP_LOG("failed to parse seckey"); return false; } @@ -744,15 +765,15 @@ parse_protected_seckey(pgp_key_pkt_t &seckey, const sexp_list_t *list, const cha return false; } } - seckey.material.secret = true; return true; } static bool -g23_parse_seckey(pgp_key_pkt_t &seckey, - const uint8_t *data, - size_t data_len, - const char * password) +g23_parse_seckey(pgp_key_pkt_t & seckey, + const uint8_t * data, + size_t data_len, + const char * password, + pgp_pubkey_alg_t pubalg = PGP_PKA_NOTHING) { gnupg_extended_private_key_t g23_extended_key; @@ -805,19 +826,22 @@ g23_parse_seckey(pgp_key_pkt_t &seckey, return false; } - auto & alg_bt = alg_s_exp->sexp_string_at(0)->get_string(); - pgp_pubkey_alg_t alg = static_cast( - id_str_pair::lookup(g10_alg_aliases, (const char *) alg_bt.data(), PGP_PKA_NOTHING)); - if (alg == PGP_PKA_NOTHING) { - RNP_LOG( - "Unsupported algorithm: '%.*s'", (int) alg_bt.size(), (const char *) alg_bt.data()); - return false; - } - bool ret = false; - if (!parse_pubkey(seckey, alg_s_exp, alg)) { - RNP_LOG("failed to parse pubkey"); - goto done; + auto alg = pubalg; + if (alg == PGP_PKA_NOTHING) { + auto &alg_bt = alg_s_exp->sexp_string_at(0)->get_string(); + auto alg_st = (const char *) alg_bt.data(); + alg = static_cast( + id_str_pair::lookup(g10_alg_aliases, alg_st, PGP_PKA_NOTHING)); + if (alg == PGP_PKA_NOTHING) { + RNP_LOG("Unsupported algorithm: '%.*s'", (int) alg_bt.size(), alg_st); + return false; + } + /* Parse pubkey only if it was not parsed before */ + if (!parse_pubkey(seckey, alg_s_exp, alg)) { + RNP_LOG("failed to parse pubkey"); + goto done; + } } if (is_protected) { @@ -828,7 +852,7 @@ g23_parse_seckey(pgp_key_pkt_t &seckey, seckey.sec_protection.s2k.usage = PGP_S2KU_NONE; seckey.sec_protection.symm_alg = PGP_SA_PLAINTEXT; seckey.sec_protection.s2k.hash_alg = PGP_HASH_UNKNOWN; - if (!parse_seckey(seckey, alg_s_exp, alg)) { + if (!parse_seckey(seckey, alg_s_exp)) { RNP_LOG("failed to parse seckey"); goto done; } @@ -850,13 +874,9 @@ g10_decrypt_seckey(const pgp_rawpacket_t &raw, return NULL; } auto seckey = std::unique_ptr(new pgp_key_pkt_t(pubkey, false)); - if (!g23_parse_seckey(*seckey, raw.raw.data(), raw.raw.size(), password)) { - return NULL; + if (!g23_parse_seckey(*seckey, raw.raw.data(), raw.raw.size(), password, pubkey.alg)) { + return nullptr; } - /* g10 has the same 'ecc' algo for ECDSA/ECDH/EDDSA. Probably should be better place to fix - * this. */ - seckey->alg = pubkey.alg; - seckey->material.alg = pubkey.material.alg; return seckey.release(); } @@ -865,31 +885,43 @@ copy_secret_fields(pgp_key_pkt_t &dst, const pgp_key_pkt_t &src) { switch (src.alg) { case PGP_PKA_DSA: - dst.material.dsa.x = src.material.dsa.x; + if (src.material->secret()) { + auto &dsasrc = dynamic_cast(*src.material); + auto &dsadst = dynamic_cast(*dst.material); + dsadst.set_secret(dsasrc.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; + if (src.material->secret()) { + auto &rsasrc = dynamic_cast(*src.material); + auto &rsadst = dynamic_cast(*dst.material); + rsadst.set_secret(rsasrc.d(), rsasrc.p(), rsasrc.q(), rsasrc.u()); + } break; case PGP_PKA_ELGAMAL: case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst.material.eg.x = src.material.eg.x; + if (src.material->secret()) { + auto &egsrc = dynamic_cast(*src.material); + auto &egdst = dynamic_cast(*dst.material); + egdst.set_secret(egsrc.x()); + } break; case PGP_PKA_ECDSA: case PGP_PKA_ECDH: case PGP_PKA_EDDSA: - dst.material.ec.x = src.material.ec.x; + if (src.material->secret()) { + auto &ecsrc = dynamic_cast(*src.material); + auto &ecdst = dynamic_cast(*dst.material); + ecdst.set_secret(ecsrc.x()); + } break; default: 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; return true; @@ -910,11 +942,8 @@ KeyStore::load_g10(pgp_source_t &src, const KeyProvider *key_provider) /* copy public key fields if any */ pgp_key_t key; if (key_provider) { - pgp_key_grip_t grip{}; - if (!seckey.material.get_grip(grip)) { - return false; - } - auto pubkey = + pgp_key_grip_t grip = seckey.material->grip(); + auto pubkey = key_provider->request_key(*rnp::KeySearch::create(grip), PGP_OP_MERGE_INFO); if (!pubkey) { return false; @@ -973,33 +1002,41 @@ void gnupg_sexp_t::add_pubkey(const pgp_key_pkt_t &key) { switch (key.alg) { - case PGP_PKA_DSA: + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*key.material); add("dsa"); - add_mpi("p", key.material.dsa.p); - add_mpi("q", key.material.dsa.q); - add_mpi("g", key.material.dsa.g); - add_mpi("y", key.material.dsa.y); + add_mpi("p", dsa.p()); + add_mpi("q", dsa.q()); + add_mpi("g", dsa.g()); + add_mpi("y", dsa.y()); break; + } case PGP_PKA_RSA_SIGN_ONLY: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA: + case PGP_PKA_RSA: { + auto &rsa = dynamic_cast(*key.material); add("rsa"); - add_mpi("n", key.material.rsa.n); - add_mpi("e", key.material.rsa.e); + add_mpi("n", rsa.n()); + add_mpi("e", rsa.e()); break; - case PGP_PKA_ELGAMAL: + } + case PGP_PKA_ELGAMAL: { + auto &eg = dynamic_cast(*key.material); add("elg"); - add_mpi("p", key.material.eg.p); - add_mpi("g", key.material.eg.g); - add_mpi("y", key.material.eg.y); + add_mpi("p", eg.p()); + add_mpi("g", eg.g()); + add_mpi("y", eg.y()); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: - case PGP_PKA_EDDSA: + case PGP_PKA_EDDSA: { + auto &ec = dynamic_cast(*key.material); add("ecc"); - add_curve("curve", key.material.ec); - add_mpi("q", key.material.ec.p); + add_curve("curve", ec.curve()); + add_mpi("q", ec.p()); break; + } default: RNP_LOG("Unsupported public key algorithm: %d", (int) key.alg); throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); @@ -1010,24 +1047,31 @@ void gnupg_sexp_t::add_seckey(const pgp_key_pkt_t &key) { switch (key.alg) { - case PGP_PKA_DSA: - add_mpi("x", key.material.dsa.x); + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*key.material); + add_mpi("x", dsa.x()); break; + } case PGP_PKA_RSA_SIGN_ONLY: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA: - add_mpi("d", key.material.rsa.d); - add_mpi("p", key.material.rsa.p); - add_mpi("q", key.material.rsa.q); - add_mpi("u", key.material.rsa.u); + case PGP_PKA_RSA: { + auto &rsa = dynamic_cast(*key.material); + add_mpi("d", rsa.d()); + add_mpi("p", rsa.p()); + add_mpi("q", rsa.q()); + add_mpi("u", rsa.u()); break; - case PGP_PKA_ELGAMAL: - add_mpi("x", key.material.eg.x); + } + case PGP_PKA_ELGAMAL: { + auto &eg = dynamic_cast(*key.material); + add_mpi("x", eg.x()); break; + } case PGP_PKA_ECDSA: case PGP_PKA_ECDH: case PGP_PKA_EDDSA: { - add_mpi("d", key.material.ec.x); + auto &ec = dynamic_cast(*key.material); + add_mpi("d", ec.x()); break; } default: diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index ad9157d254..7b075ac9f8 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -880,82 +880,70 @@ stream_dump_signature(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) return ret; } -static rnp_result_t -stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +static void +stream_dump_key_material(rnp_dump_ctx_t & ctx, + const pgp::KeyMaterial *material, + pgp_dest_t * dst) { - pgp_key_pkt_t key; - rnp_result_t ret; - pgp_fingerprint_t keyfp = {}; - - try { - ret = key.parse(*src); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); - ret = RNP_ERROR_GENERIC; - /* LCOV_EXCL_END */ - } - if (ret) { - return ret; - } - - dst_printf(dst, "%s packet\n", id_str_pair::lookup(key_type_map, key.tag, "Unknown")); - indent_dest_increase(dst); - - dst_printf(dst, "version: %d\n", (int) key.version); - dst_print_time(dst, "creation time", key.creation_time); - if (key.version < PGP_V4) { - dst_printf(dst, "v3 validity days: %d\n", (int) key.v3_days); - } - dst_print_palg(dst, NULL, key.alg); - if (key.version == PGP_V5) { - dst_printf(dst, "v5 public key material length: %" PRIu32 "\n", key.v5_pub_len); + if (!material) { + return; } - dst_printf(dst, "public key material:\n"); - indent_dest_increase(dst); - - switch (key.alg) { + switch (material->alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - dst_print_mpi(dst, "rsa n", key.material.rsa.n, ctx->dump_mpi); - dst_print_mpi(dst, "rsa e", key.material.rsa.e, ctx->dump_mpi); - break; - case PGP_PKA_DSA: - dst_print_mpi(dst, "dsa p", key.material.dsa.p, ctx->dump_mpi); - dst_print_mpi(dst, "dsa q", key.material.dsa.q, ctx->dump_mpi); - dst_print_mpi(dst, "dsa g", key.material.dsa.g, ctx->dump_mpi); - dst_print_mpi(dst, "dsa y", key.material.dsa.y, ctx->dump_mpi); - break; + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + dst_print_mpi(dst, "rsa n", rsa.n(), ctx.dump_mpi); + dst_print_mpi(dst, "rsa e", rsa.e(), ctx.dump_mpi); + return; + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + dst_print_mpi(dst, "dsa p", dsa.p(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa q", dsa.q(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa g", dsa.g(), ctx.dump_mpi); + dst_print_mpi(dst, "dsa y", dsa.y(), ctx.dump_mpi); + return; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst_print_mpi(dst, "eg p", key.material.eg.p, ctx->dump_mpi); - dst_print_mpi(dst, "eg g", key.material.eg.g, ctx->dump_mpi); - dst_print_mpi(dst, "eg y", key.material.eg.y, ctx->dump_mpi); - break; + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + dst_print_mpi(dst, "eg p", eg.p(), ctx.dump_mpi); + dst_print_mpi(dst, "eg g", eg.g(), ctx.dump_mpi); + dst_print_mpi(dst, "eg y", eg.y(), ctx.dump_mpi); + return; + } case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: case PGP_PKA_SM2: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - dst_print_mpi(dst, "ecc p", key.material.ec.p, ctx->dump_mpi); + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + dst_print_mpi(dst, "ecc p", ec.p(), ctx.dump_mpi); dst_printf(dst, "ecc curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); - break; + return; } case PGP_PKA_ECDH: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - dst_print_mpi(dst, "ecdh p", key.material.ec.p, ctx->dump_mpi); + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + /* Common EC fields */ + dst_print_mpi(dst, "ecdh p", ec.p(), ctx.dump_mpi); dst_printf(dst, "ecdh curve: %s\n", cdesc ? cdesc->pgp_name : "unknown"); - dst_print_halg(dst, "ecdh hash algorithm", key.material.ec.kdf_hash_alg); - dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) key.material.ec.key_wrap_alg); - break; + /* ECDH-only fields */ + dst_print_halg(dst, "ecdh hash algorithm", ec.kdf_hash_alg()); + dst_printf(dst, "ecdh key wrap algorithm: %d\n", (int) ec.key_wrap_alg()); + return; } #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - dst_print_vec(dst, "ed25519", key.material.ed25519.pub, ctx->dump_mpi); - break; - case PGP_PKA_X25519: - dst_print_vec(dst, "x25519", key.material.x25519.pub, ctx->dump_mpi); - break; + case PGP_PKA_ED25519: { + auto &ed25519 = dynamic_cast(*material); + dst_print_vec(dst, "ed25519", ed25519.pub(), ctx.dump_mpi); + return; + } + case PGP_PKA_X25519: { + auto &x25519 = dynamic_cast(*material); + dst_print_vec(dst, "x25519", x25519.pub(), ctx.dump_mpi); + return; + } #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: @@ -967,12 +955,12 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - dst_print_vec(dst, - "mlkem-ecdh encoded pubkey", - key.material.kyber_ecdh.pub.get_encoded(), - ctx->dump_mpi); - break; + case PGP_PKA_KYBER1024_BP384: { + auto &kyber = dynamic_cast(*material); + dst_print_vec( + dst, "mlkem-ecdh encoded pubkey", kyber.pub().get_encoded(), ctx.dump_mpi); + return; + } case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; @@ -982,24 +970,61 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: + case PGP_PKA_DILITHIUM5_BP384: { + auto &dilithium = dynamic_cast(*material); dst_print_vec(dst, "mldsa-ecdsa/eddsa encodced pubkey", - key.material.dilithium_exdsa.pub.get_encoded(), - ctx->dump_mpi); - break; + dilithium.pub().get_encoded(), + ctx.dump_mpi); + return; + } case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - dst_print_vec(dst, - "slhdsa encoded pubkey", - key.material.sphincsplus.pub.get_encoded(), - ctx->dump_mpi); - break; + case PGP_PKA_SPHINCSPLUS_SHAKE: { + auto &sphincs = dynamic_cast(*material); + dst_print_vec(dst, "slhdsa encoded pubkey", sphincs.pub().get_encoded(), ctx.dump_mpi); + return; + } #endif default: dst_printf(dst, "unknown public key algorithm\n"); } +} + +static rnp_result_t +stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + pgp_fingerprint_t keyfp = {}; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + /* LCOV_EXCL_START */ + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + /* LCOV_EXCL_END */ + } + if (ret) { + return ret; + } + + dst_printf(dst, "%s packet\n", id_str_pair::lookup(key_type_map, key.tag, "Unknown")); + indent_dest_increase(dst); + + dst_printf(dst, "version: %d\n", (int) key.version); + dst_print_time(dst, "creation time", key.creation_time); + if (key.version < PGP_V4) { + dst_printf(dst, "v3 validity days: %d\n", (int) key.v3_days); + } + dst_print_palg(dst, NULL, key.alg); + if (key.version == PGP_V5) { + dst_printf(dst, "v5 public key material length: %" PRIu32 "\n", key.v5_pub_len); + } + dst_printf(dst, "public key material:\n"); + indent_dest_increase(dst); + stream_dump_key_material(*ctx, key.material.get(), dst); indent_dest_decrease(dst); if (is_secret_key_pkt(key.tag)) { @@ -1051,8 +1076,8 @@ stream_dump_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) } if (ctx->dump_grips) { - pgp_key_grip_t grip; - if (key.material.get_grip(grip)) { + if (key.material) { + pgp_key_grip_t grip = key.material->grip(); dst_print_hex(dst, "grip", grip.data(), grip.size(), false); } else { dst_printf(dst, "grip: failed to calculate\n"); @@ -2047,107 +2072,77 @@ stream_dump_signature_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object * return stream_dump_signature_pkt_json(ctx, &sig, pkt); } -static rnp_result_t -stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +static bool +stream_dump_key_material_json(rnp_dump_ctx_t & ctx, + const pgp::KeyMaterial *material, + json_object * jso) { - pgp_key_pkt_t key; - rnp_result_t ret; - json_object * material = NULL; - - try { - ret = key.parse(*src); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); - ret = RNP_ERROR_GENERIC; - /* LCOV_EXCL_END */ - } - if (ret) { - return ret; - } - - if (!json_add(pkt, "version", (int) key.version)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!json_add(pkt, "creation time", (uint64_t) key.creation_time)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if ((key.version < PGP_V4) && !json_add(pkt, "v3 days", (int) key.v3_days)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!obj_add_intstr_json(pkt, "algorithm", key.alg, pubkey_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if ((key.version == PGP_V5) && - !json_add(pkt, "v5 public key material length", (int) key.v5_pub_len)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - - material = json_object_new_object(); - if (!material || !json_add(pkt, "material", material)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (!material) { + return false; // LCOV_EXCL_LINE } - - switch (key.alg) { + switch (material->alg()) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!obj_add_mpi_json(material, "n", key.material.rsa.n, ctx->dump_mpi) || - !obj_add_mpi_json(material, "e", key.material.rsa.e, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "n", rsa.n(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "e", rsa.e(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; - case PGP_PKA_DSA: - if (!obj_add_mpi_json(material, "p", key.material.dsa.p, ctx->dump_mpi) || - !obj_add_mpi_json(material, "q", key.material.dsa.q, ctx->dump_mpi) || - !obj_add_mpi_json(material, "g", key.material.dsa.g, ctx->dump_mpi) || - !obj_add_mpi_json(material, "y", key.material.dsa.y, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + return true; + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "p", dsa.p(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "q", dsa.q(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "g", dsa.g(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "y", dsa.y(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; + return true; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!obj_add_mpi_json(material, "p", key.material.eg.p, ctx->dump_mpi) || - !obj_add_mpi_json(material, "g", key.material.eg.g, ctx->dump_mpi) || - !obj_add_mpi_json(material, "y", key.material.eg.y, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + if (!obj_add_mpi_json(jso, "p", eg.p(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "g", eg.g(), ctx.dump_mpi) || + !obj_add_mpi_json(jso, "y", eg.y(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - break; + return true; + } case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: - case PGP_PKA_SM2: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - if (!obj_add_mpi_json(material, "p", key.material.ec.p, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - if (!json_add(material, "curve", cdesc ? cdesc->pgp_name : "unknown")) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE - } - break; - } + case PGP_PKA_SM2: case PGP_PKA_ECDH: { - const ec_curve_desc_t *cdesc = get_curve_desc(key.material.ec.curve); - if (!obj_add_mpi_json(material, "p", key.material.ec.p, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + auto &ec = dynamic_cast(*material); + auto cdesc = get_curve_desc(ec.curve()); + /* Common EC fields */ + if (!obj_add_mpi_json(jso, "p", ec.p(), ctx.dump_mpi)) { + return false; // LCOV_EXCL_LINE } - if (!json_add(material, "curve", cdesc ? cdesc->pgp_name : "unknown")) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (!json_add(jso, "curve", cdesc ? cdesc->pgp_name : "unknown")) { + return false; // LCOV_EXCL_LINE } - if (!obj_add_intstr_json( - material, "hash algorithm", key.material.ec.kdf_hash_alg, hash_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (material->alg() != PGP_PKA_ECDH) { + return true; + } + /* ECDH-only fields */ + auto &ecdh = dynamic_cast(*material); + if (!obj_add_intstr_json(jso, "hash algorithm", ecdh.kdf_hash_alg(), hash_alg_map)) { + return false; // LCOV_EXCL_LINE } if (!obj_add_intstr_json( - material, "key wrap algorithm", key.material.ec.key_wrap_alg, symm_alg_map)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + jso, "key wrap algorithm", ecdh.key_wrap_alg(), symm_alg_map)) { + return false; // LCOV_EXCL_LINE } - break; + return true; } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: /* TODO */ - break; + return true; #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: @@ -2161,7 +2156,7 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER1024_BP384: // TODO - break; + return true; case PGP_PKA_DILITHIUM3_ED25519: FALLTHROUGH_STATEMENT; // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; @@ -2173,15 +2168,60 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM5_BP384: /* TODO */ - break; + return true; case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; case PGP_PKA_SPHINCSPLUS_SHAKE: /* TODO */ - break; + return true; #endif default: - break; + return false; + } +} + +static rnp_result_t +stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) +{ + pgp_key_pkt_t key; + rnp_result_t ret; + json_object * material = NULL; + + try { + ret = key.parse(*src); + } catch (const std::exception &e) { + /* LCOV_EXCL_START */ + RNP_LOG("%s", e.what()); + ret = RNP_ERROR_GENERIC; + /* LCOV_EXCL_END */ + } + if (ret) { + return ret; + } + + if (!json_add(pkt, "version", (int) key.version)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!json_add(pkt, "creation time", (uint64_t) key.creation_time)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if ((key.version < PGP_V4) && !json_add(pkt, "v3 days", (int) key.v3_days)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!obj_add_intstr_json(pkt, "algorithm", key.alg, pubkey_alg_map)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if ((key.version == PGP_V5) && + !json_add(pkt, "v5 public key material length", (int) key.v5_pub_len)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + + material = json_object_new_object(); + if (!material || !json_add(pkt, "material", material)) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + if (!stream_dump_key_material_json(*ctx, key.material.get(), material)) { + return RNP_ERROR_OUT_OF_MEMORY; } if (is_secret_key_pkt(key.tag)) { @@ -2217,10 +2257,13 @@ stream_dump_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - pgp_key_grip_t grip; - if (!key.material.get_grip(grip) || - !json_add_hex(pkt, "grip", grip.data(), grip.size())) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + if (key.material) { + pgp_key_grip_t grip = key.material->grip(); + if (!json_add_hex(pkt, "grip", grip.data(), grip.size())) { + return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + } + } else { + return RNP_ERROR_BAD_PARAMETERS; // LCOV_EXCL_LINE } } return RNP_SUCCESS; diff --git a/src/librepgp/stream-key.cpp b/src/librepgp/stream-key.cpp index ae31cf9ca6..5e9a9b6d87 100644 --- a/src/librepgp/stream-key.cpp +++ b/src/librepgp/stream-key.cpp @@ -597,129 +597,18 @@ parse_secret_key_mpis(pgp_key_pkt_t &key, const uint8_t *mpis, size_t len) /* parse mpis depending on algorithm */ pgp_packet_body_t body(mpis, len); -#if defined(ENABLE_CRYPTO_REFRESH) || defined(ENABLE_PQC) - std::vector tmpbuf; -#endif - - switch (key.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!body.get(key.material.rsa.d) || !body.get(key.material.rsa.p) || - !body.get(key.material.rsa.q) || !body.get(key.material.rsa.u)) { - RNP_LOG("failed to parse rsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_DSA: - if (!body.get(key.material.dsa.x)) { - RNP_LOG("failed to parse dsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_EDDSA: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - if (!body.get(key.material.ec.x)) { - RNP_LOG("failed to parse ecc secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!body.get(key.material.eg.x)) { - RNP_LOG("failed to parse eg secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_ED25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse Ed25519 secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.ed25519.priv = tmpbuf; - break; - } - case PGP_PKA_X25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse X25519 secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.x25519.priv = tmpbuf; - break; - } -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - tmpbuf.resize(pgp_kyber_ecdh_composite_private_key_t::encoded_size(key.alg)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mkem-ecdh secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.kyber_ecdh.priv = - pgp_kyber_ecdh_composite_private_key_t(tmpbuf.data(), tmpbuf.size(), key.alg); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - tmpbuf.resize(pgp_dilithium_exdsa_composite_private_key_t::encoded_size(key.alg)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mldsa-ecdsa/eddsa secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.dilithium_exdsa.priv = pgp_dilithium_exdsa_composite_private_key_t( - tmpbuf.data(), tmpbuf.size(), key.alg); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: { - uint8_t param; - if (!body.get(param)) { - RNP_LOG("failed to parse SLH-DSA secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - tmpbuf.resize(sphincsplus_privkey_size((sphincsplus_parameter_t) param)); - if (!body.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse SLH-DSA secret key data"); - return RNP_ERROR_BAD_FORMAT; - } - key.material.sphincsplus.priv = - pgp_sphincsplus_private_key_t(tmpbuf, (sphincsplus_parameter_t) param, key.alg); - break; - } -#endif - default: + if (!key.material) { RNP_LOG("unknown pk alg : %d", (int) key.alg); return RNP_ERROR_BAD_PARAMETERS; } + if (!key.material->parse_secret(body)) { + return RNP_ERROR_BAD_FORMAT; + } if (body.left()) { RNP_LOG("extra data in sec key"); return RNP_ERROR_BAD_FORMAT; } - key.material.secret = true; return RNP_SUCCESS; } catch (const std::exception &e) { RNP_LOG("%s", e.what()); @@ -737,7 +626,7 @@ decrypt_secret_key(pgp_key_pkt_t *key, const char *password) return RNP_ERROR_BAD_PARAMETERS; } /* mark material as not validated as it may be valid for public part */ - key->material.validity.reset(); + key->material->reset_validity(); /* check whether data is not encrypted */ if (!key->sec_protection.s2k.usage) { @@ -816,72 +705,7 @@ static void write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) { /* add mpis */ - switch (key.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - body.add(key.material.rsa.d); - body.add(key.material.rsa.p); - body.add(key.material.rsa.q); - body.add(key.material.rsa.u); - break; - case PGP_PKA_DSA: - body.add(key.material.dsa.x); - break; - case PGP_PKA_EDDSA: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - body.add(key.material.ec.x); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - body.add(key.material.eg.x); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - body.add(key.material.ed25519.priv); - break; - case PGP_PKA_X25519: - body.add(key.material.x25519.priv); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - body.add(key.material.kyber_ecdh.priv.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - body.add(key.material.dilithium_exdsa.priv.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - body.add_byte((uint8_t) key.material.sphincsplus.priv.param()); - body.add(key.material.sphincsplus.priv.get_encoded()); - break; -#endif - default: - RNP_LOG("unknown pk alg : %d", (int) key.alg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } + key.material->write_secret(body); #if defined(ENABLE_CRYPTO_REFRESH) if (key.version == PGP_V6 && key.sec_protection.s2k.usage == PGP_S2KU_NONE) { @@ -914,7 +738,7 @@ write_secret_key_mpis(pgp_packet_body_t &body, pgp_key_pkt_t &key) rnp_result_t encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) { - if (!is_secret_key_pkt(key->tag) || !key->material.secret) { + if (!is_secret_key_pkt(key->tag) || !key->material->secret()) { return RNP_ERROR_BAD_PARAMETERS; } if (key->sec_protection.s2k.usage && @@ -984,7 +808,7 @@ encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) memcpy(key->sec_data, body.data(), body.size()); key->sec_len = body.size(); /* cleanup cleartext fields */ - forget_secret_key_fields(&key->material); + key->material->clear_secret(); return RNP_SUCCESS; } catch (const std::exception &e) { RNP_LOG("%s", e.what()); @@ -992,83 +816,6 @@ encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng) } } -void -forget_secret_key_fields(pgp_key_material_t *key) -{ - if (!key || !key->secret) { - return; - } - - switch (key->alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - key->rsa.d.forget(); - key->rsa.p.forget(); - key->rsa.q.forget(); - key->rsa.u.forget(); - break; - case PGP_PKA_DSA: - key->dsa.x.forget(); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - key->eg.x.forget(); - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - key->ec.x.forget(); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - secure_clear(key->ed25519.priv.data(), key->ed25519.priv.size()); - key->ed25519.priv.clear(); - break; - case PGP_PKA_X25519: - secure_clear(key->x25519.priv.data(), key->x25519.priv.size()); - key->x25519.priv.clear(); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - key->kyber_ecdh.priv.secure_clear(); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - key->dilithium_exdsa.priv.secure_clear(); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - key->sphincsplus.priv.secure_clear(); - break; -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) key->alg); - } - - key->secret = false; -} - pgp_userid_pkt_t::pgp_userid_pkt_t(const pgp_userid_pkt_t &src) { tag = src.tag; @@ -1211,9 +958,11 @@ pgp_key_pkt_t::pgp_key_pkt_t(const pgp_key_pkt_t &src, bool pubonly) } memcpy(hashed_data, src.hashed_data, hashed_len); } - material = src.material; + material = src.material ? src.material->clone() : nullptr; if (pubonly) { - forget_secret_key_fields(&material); + if (material) { + material->clear_secret(); + } sec_len = 0; v5_s2k_len = 0; v5_sec_len = 0; @@ -1245,8 +994,7 @@ pgp_key_pkt_t::pgp_key_pkt_t(pgp_key_pkt_t &&src) hashed_len = src.hashed_len; hashed_data = src.hashed_data; src.hashed_data = NULL; - material = src.material; - forget_secret_key_fields(&src.material); + material = std::move(src.material); sec_len = src.sec_len; v5_s2k_len = src.v5_s2k_len; v5_sec_len = src.v5_sec_len; @@ -1270,8 +1018,7 @@ pgp_key_pkt_t::operator=(pgp_key_pkt_t &&src) free(hashed_data); hashed_data = src.hashed_data; src.hashed_data = NULL; - material = src.material; - forget_secret_key_fields(&src.material); + material = std::move(src.material); secure_clear(sec_data, sec_len); free(sec_data); sec_len = src.sec_len; @@ -1303,7 +1050,7 @@ pgp_key_pkt_t::operator=(const pgp_key_pkt_t &src) } memcpy(hashed_data, src.hashed_data, hashed_len); } - material = src.material; + material = src.material ? src.material->clone() : nullptr; secure_clear(sec_data, sec_len); free(sec_data); sec_data = NULL; @@ -1323,7 +1070,6 @@ pgp_key_pkt_t::operator=(const pgp_key_pkt_t &src) pgp_key_pkt_t::~pgp_key_pkt_t() { - forget_secret_key_fields(&material); free(hashed_data); secure_clear(sec_data, sec_len); free(sec_data); @@ -1488,7 +1234,11 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_ERROR_BAD_FORMAT; } alg = (pgp_pubkey_alg_t) analg; - material.alg = (pgp_pubkey_alg_t) analg; + material = pgp::KeyMaterial::create(alg); + if (!material) { + RNP_LOG("unknown key algorithm: %d", (int) alg); + return RNP_ERROR_BAD_FORMAT; + } switch (version) { case PGP_V2: case PGP_V3: @@ -1516,131 +1266,10 @@ pgp_key_pkt_t::parse(pgp_source_t &src) } /* algorithm specific fields */ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!pkt.get(material.rsa.n) || !pkt.get(material.rsa.e)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_DSA: - if (!pkt.get(material.dsa.p) || !pkt.get(material.dsa.q) || !pkt.get(material.dsa.g) || - !pkt.get(material.dsa.y)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!pkt.get(material.eg.p) || !pkt.get(material.eg.g) || !pkt.get(material.eg.y)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { - return RNP_ERROR_BAD_FORMAT; - } - break; - case PGP_PKA_ECDH: { - if (!pkt.get(material.ec.curve) || !pkt.get(material.ec.p)) { - return RNP_ERROR_BAD_FORMAT; - } - /* read KDF parameters. At the moment should be 0x03 0x01 halg ealg */ - uint8_t len = 0, halg = 0, walg = 0; - if (!pkt.get(len) || (len != 3)) { - return RNP_ERROR_BAD_FORMAT; - } - if (!pkt.get(len) || (len != 1)) { - return RNP_ERROR_BAD_FORMAT; - } - if (!pkt.get(halg) || !pkt.get(walg)) { - return RNP_ERROR_BAD_FORMAT; - } - material.ec.kdf_hash_alg = (pgp_hash_alg_t) halg; - material.ec.key_wrap_alg = (pgp_symm_alg_t) walg; - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_ED25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse Ed25519 public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.ed25519.pub = tmpbuf; - break; - } - case PGP_PKA_X25519: { - const ec_curve_desc_t *ec_desc = get_curve_desc(PGP_CURVE_25519); - tmpbuf.resize(BITS_TO_BYTES(ec_desc->bitlen)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse X25519 public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.x25519.pub = tmpbuf; - break; - } -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - tmpbuf.resize(pgp_kyber_ecdh_composite_public_key_t::encoded_size(alg)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mlkem-ecdh public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.kyber_ecdh.pub = pgp_kyber_ecdh_composite_public_key_t(tmpbuf, alg); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - tmpbuf.resize(pgp_dilithium_exdsa_composite_public_key_t::encoded_size(alg)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse mldsa-ecdsa/eddsa public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.dilithium_exdsa.pub = pgp_dilithium_exdsa_composite_public_key_t(tmpbuf, alg); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: { - uint8_t param; - if (!pkt.get(param)) { - RNP_LOG("failed to parse SLH-DSA public key data"); - return RNP_ERROR_BAD_FORMAT; - } - tmpbuf.resize(sphincsplus_pubkey_size((sphincsplus_parameter_t) param)); - if (!pkt.get(tmpbuf.data(), tmpbuf.size())) { - RNP_LOG("failed to parse SLH-DSA public key data"); - return RNP_ERROR_BAD_FORMAT; - } - material.sphincsplus.pub = - pgp_sphincsplus_public_key_t(tmpbuf, (sphincsplus_parameter_t) param, alg); - break; - } -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) alg); + if (!material->parse(pkt)) { return RNP_ERROR_BAD_FORMAT; } + /* fill hashed data used for signatures */ if (!(hashed_data = (uint8_t *) malloc(pkt.size() - pkt.left()))) { RNP_LOG("allocation failed"); @@ -1763,88 +1392,6 @@ pgp_key_pkt_t::parse(pgp_source_t &src) return RNP_SUCCESS; } -void -pgp_key_pkt_t::make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody) -{ - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - hbody.add(material.rsa.n); - hbody.add(material.rsa.e); - break; - case PGP_PKA_DSA: - hbody.add(material.dsa.p); - hbody.add(material.dsa.q); - hbody.add(material.dsa.g); - hbody.add(material.dsa.y); - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - hbody.add(material.eg.p); - hbody.add(material.eg.g); - hbody.add(material.eg.y); - break; - case PGP_PKA_ECDSA: - case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - hbody.add(material.ec.curve); - hbody.add(material.ec.p); - break; - case PGP_PKA_ECDH: - hbody.add(material.ec.curve); - hbody.add(material.ec.p); - hbody.add_byte(3); - hbody.add_byte(1); - hbody.add_byte(material.ec.kdf_hash_alg); - hbody.add_byte(material.ec.key_wrap_alg); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - hbody.add(material.ed25519.pub); - break; - case PGP_PKA_X25519: - hbody.add(material.x25519.pub); - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - hbody.add(material.kyber_ecdh.pub.get_encoded()); - break; - case PGP_PKA_DILITHIUM3_ED25519: - FALLTHROUGH_STATEMENT; - // TODO: add case PGP_PKA_DILITHIUM5_ED448: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM3_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - hbody.add(material.dilithium_exdsa.pub.get_encoded()); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - hbody.add_byte((uint8_t) material.sphincsplus.pub.param()); - hbody.add(material.sphincsplus.pub.get_encoded()); - break; -#endif - default: - RNP_LOG("unknown key algorithm: %d", (int) alg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } -} - void pgp_key_pkt_t::fill_hashed_data() { @@ -1868,7 +1415,7 @@ pgp_key_pkt_t::fill_hashed_data() /* Algorithm specific fields */ pgp_packet_body_t alg_spec_fields(PGP_PKT_RESERVED); - make_alg_spec_fields_for_public_key(alg_spec_fields); + material->write(alg_spec_fields); #if defined(ENABLE_CRYPTO_REFRESH) if (version == PGP_V6) { hbody.add_uint32(alg_spec_fields.size()); @@ -1904,7 +1451,7 @@ pgp_key_pkt_t::equals(const pgp_key_pkt_t &key, bool pubonly) const noexcept return false; } /* check key material */ - return key_material_equal(&material, &key.material); + return material->equals(*key.material); } pgp_transferable_subkey_t::pgp_transferable_subkey_t(const pgp_transferable_subkey_t &src, diff --git a/src/librepgp/stream-key.h b/src/librepgp/stream-key.h index 708c196705..24f5ff1f76 100644 --- a/src/librepgp/stream-key.h +++ b/src/librepgp/stream-key.h @@ -34,6 +34,7 @@ #include "stream-common.h" #include "stream-sig.h" #include "stream-packet.h" +#include "key_material.hpp" /** Struct to hold a key packet. May contain public or private key/subkey */ typedef struct pgp_key_pkt_t { @@ -47,7 +48,7 @@ typedef struct pgp_key_pkt_t { uint8_t *hashed_data; /* key's hashed data used for signature calculation */ size_t hashed_len; - pgp_key_material_t material; + std::unique_ptr material; /* secret key data, if available. sec_len == 0, sec_data == NULL for public key/subkey */ pgp_key_protection_t sec_protection; @@ -58,7 +59,7 @@ typedef struct pgp_key_pkt_t { pgp_key_pkt_t() : tag(PGP_PKT_RESERVED), version(PGP_VUNKNOWN), creation_time(0), alg(PGP_PKA_NOTHING), - v3_days(0), v5_pub_len(0), hashed_data(NULL), hashed_len(0), material({}), + v3_days(0), v5_pub_len(0), hashed_data(NULL), hashed_len(0), material(nullptr), sec_protection({}), sec_data(NULL), sec_len(0), v5_s2k_len(0), v5_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); @@ -74,8 +75,6 @@ typedef struct pgp_key_pkt_t { bool equals(const pgp_key_pkt_t &key, bool pubonly = false) const noexcept; private: - /* create the contents of the algorithm specific public key fields in a separate packet */ - void make_alg_spec_fields_for_public_key(pgp_packet_body_t &hbody); void make_s2k_params(pgp_packet_body_t &hbody); uint8_t s2k_specifier_len(pgp_s2k_specifier_t specifier); } pgp_key_pkt_t; @@ -147,6 +146,4 @@ rnp_result_t decrypt_secret_key(pgp_key_pkt_t *key, const char *password); rnp_result_t encrypt_secret_key(pgp_key_pkt_t *key, const char *password, rnp::RNG &rng); -void forget_secret_key_fields(pgp_key_material_t *key); - #endif diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index b597624d48..74ee59a45b 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1619,95 +1619,14 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, rnp::secure_array decbuf; /* Decrypting session key value */ - rnp_result_t err; - bool res = false; - auto & keymaterial = seckey.material(); - size_t declen = 0; - switch (sesskey.alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - err = rsa_decrypt_pkcs1( - &ctx.rng, decbuf.data(), &declen, &encmaterial.rsa, &keymaterial.rsa); - if (err) { - RNP_LOG("RSA decryption failure"); - return false; - } - break; - case PGP_PKA_SM2: -#if defined(ENABLE_SM2) - declen = decbuf.size(); - err = sm2_decrypt(decbuf.data(), &declen, &encmaterial.sm2, &keymaterial.ec); - if (err != RNP_SUCCESS) { - RNP_LOG("SM2 decryption failure, error %x", (int) err); - return false; - } - break; -#else - RNP_LOG("SM2 decryption is not available."); - return false; -#endif - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { - const rnp_result_t ret = elgamal_decrypt_pkcs1( - &ctx.rng, decbuf.data(), &declen, &encmaterial.eg, &keymaterial.eg); - if (ret) { - RNP_LOG("ElGamal decryption failure [%X]", ret); - return false; - } - break; - } - case PGP_PKA_ECDH: { - if (!curve_supported(keymaterial.ec.curve)) { - RNP_LOG("ECDH decrypt: curve %d is not supported.", (int) keymaterial.ec.curve); - return false; - } - if ((keymaterial.ec.curve == PGP_CURVE_25519) && - !x25519_bits_tweaked(keymaterial.ec)) { - RNP_LOG("Warning: bits of 25519 secret key are not tweaked."); - } - declen = decbuf.size(); - err = ecdh_decrypt_pkcs5( - decbuf.data(), &declen, &encmaterial.ecdh, &keymaterial.ec, seckey.fp()); - if (err) { - RNP_LOG("ECDH decryption error %u", err); - return false; - } - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: - declen = decbuf.size(); - err = x25519_native_decrypt( - &ctx.rng, keymaterial.x25519, &encmaterial.x25519, decbuf.data(), &declen); - if (err) { - RNP_LOG("X25519 decryption error %u", err); - return false; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: { - declen = decbuf.size(); - err = keymaterial.kyber_ecdh.priv.decrypt( - &ctx.rng, decbuf.data(), &declen, &encmaterial.kyber_ecdh); - if (err) { - RNP_LOG("ML-KEM + ECC decryption failure"); - return false; - } - break; + bool res = false; + size_t declen = decbuf.size(); + + if (sesskey.alg == PGP_PKA_ECDH) { + encmaterial.ecdh.fp = &seckey.fp(); } -#endif - default: - RNP_LOG("unsupported public key algorithm %d\n", seckey.alg()); + auto err = seckey.pkt().material->decrypt(ctx, decbuf.data(), declen, encmaterial); + if (err) { return false; } diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index 9b72438473..fbbd0c2114 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -675,102 +675,12 @@ encrypted_add_recipient(pgp_write_handler_t *handler, pgp_encrypted_material_t material; - switch (userkey->alg()) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: { - ret = rsa_encrypt_pkcs1(&handler->ctx->ctx->rng, - &material.rsa, - enckey.data(), - enckey_len, - &userkey->material().rsa); - if (ret) { - RNP_LOG("rsa_encrypt_pkcs1 failed"); - return ret; - } - break; - } - case PGP_PKA_SM2: { -#if defined(ENABLE_SM2) - ret = sm2_encrypt(&handler->ctx->ctx->rng, - &material.sm2, - enckey.data(), - enckey_len, - PGP_HASH_SM3, - &userkey->material().ec); - if (ret) { - RNP_LOG("sm2_encrypt failed"); - return ret; - } - break; -#else - RNP_LOG("sm2_encrypt is not available"); - return RNP_ERROR_NOT_IMPLEMENTED; -#endif + if (userkey->alg() == PGP_PKA_ECDH) { + material.ecdh.fp = &userkey->fp(); } - case PGP_PKA_ECDH: { - if (!curve_supported(userkey->material().ec.curve)) { - RNP_LOG("ECDH encrypt: curve %d is not supported.", - (int) userkey->material().ec.curve); - return RNP_ERROR_NOT_SUPPORTED; - } - ret = ecdh_encrypt_pkcs5(&handler->ctx->ctx->rng, - &material.ecdh, - enckey.data(), - enckey_len, - &userkey->material().ec, - userkey->fp()); - if (ret) { - RNP_LOG("ECDH encryption failed %d", ret); - return ret; - } - break; - } - case PGP_PKA_ELGAMAL: { - ret = elgamal_encrypt_pkcs1(&handler->ctx->ctx->rng, - &material.eg, - enckey.data(), - enckey_len, - &userkey->material().eg); - if (ret) { - RNP_LOG("pgp_elgamal_public_encrypt failed"); - return ret; - } - break; - } -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: - ret = x25519_native_encrypt(&handler->ctx->ctx->rng, - userkey->material().x25519.pub, - enckey.data(), - enckey_len, - &material.x25519); - if (ret) { - RNP_LOG("x25519 encryption failed"); - return ret; - } - break; -#endif -#if defined(ENABLE_PQC) - case PGP_PKA_KYBER768_X25519: - FALLTHROUGH_STATEMENT; - // TODO add case PGP_PKA_KYBER1024_X448: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_P256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_P384: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER768_BP256: - FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - ret = userkey->material().kyber_ecdh.pub.encrypt( - &handler->ctx->ctx->rng, &material.kyber_ecdh, enckey.data(), enckey_len); - if (ret) { - RNP_LOG("ML-KEM + ECC Encrypt failed"); - return ret; - } - break; -#endif - default: - RNP_LOG("unsupported alg: %d", (int) userkey->alg()); + ret = userkey->pkt().material->encrypt( + *handler->ctx->ctx, material, enckey.data(), enckey_len); + if (ret) { return ret; } @@ -1364,7 +1274,8 @@ signed_fill_signature(pgp_dest_signed_param_t ¶m, } /* calculate the signature */ auto hdr = param.has_lhdr ? ¶m.lhdr : NULL; - signature_calculate(sig, signer.key->material(), *listh->clone(), *param.ctx->ctx, hdr); + signature_calculate( + sig, *signer.key->pkt().material, *listh->clone(), *param.ctx->ctx, hdr); } static rnp_result_t @@ -1498,13 +1409,13 @@ signed_add_signer(pgp_dest_signed_param_t *param, rnp_signer_info_t *signer, boo { pgp_dest_signer_info_t sinfo = {}; - if (!signer->key->is_secret()) { + if (!signer->key->pkt().material || !signer->key->is_secret()) { RNP_LOG("secret key required for signing"); return RNP_ERROR_BAD_PARAMETERS; } /* validate signing key material if didn't before */ - signer->key->pkt().material.validate(*param->ctx->ctx, false); - if (!signer->key->pkt().material.valid()) { + signer->key->pkt().material->validate(*param->ctx->ctx, false); + if (!signer->key->pkt().material->valid()) { RNP_LOG("attempt to sign to the key with invalid material"); return RNP_ERROR_NO_SUITABLE_KEY; } @@ -1515,7 +1426,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, &signer->key->pkt()); + sinfo.halg = signer->key->material().adjust_hash(signer->halg); try { param->hashes.add_alg(sinfo.halg); } catch (const std::exception &e) { diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 616133da13..3b39d2e8c9 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -115,10 +115,8 @@ TEST_F(rnp_tests, cipher_test_success) TEST_F(rnp_tests, pkcs1_rsa_test_success) { - uint8_t ptext[1024 / 8] = {'a', 'b', 'c', 0}; - uint8_t dec[1024 / 8]; - pgp_rsa_encrypted_t enc; - size_t dec_size; + uint8_t ptext[1024 / 8] = {'a', 'b', 'c', 0}; + uint8_t dec[1024 / 8]; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_RSA; @@ -127,92 +125,91 @@ TEST_F(rnp_tests, pkcs1_rsa_test_success) key_desc.ctx = &global_ctx; pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const pgp_rsa_key_t *key_rsa = &seckey.material.rsa; - assert_rnp_success(rsa_encrypt_pkcs1(&global_ctx.rng, &enc, ptext, 3, key_rsa)); - assert_int_equal(enc.m.len, 1024 / 8); + pgp_encrypted_material_t enc; + assert_rnp_success(seckey.material->encrypt(global_ctx, enc, ptext, 3)); + assert_int_equal(enc.rsa.m.len, 1024 / 8); memset(dec, 0, sizeof(dec)); - dec_size = 0; - assert_rnp_success(rsa_decrypt_pkcs1(&global_ctx.rng, dec, &dec_size, &enc, key_rsa)); + size_t dec_size = 0; + assert_rnp_success(seckey.material->decrypt(global_ctx, dec, dec_size, enc)); assert_true(bin_eq_hex(dec, 3, "616263")); assert_int_equal(dec_size, 3); } TEST_F(rnp_tests, rnp_test_eddsa) { - rnp::SecurityContext ctx; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_EDDSA; key_desc.hash_alg = PGP_HASH_SHA256; - key_desc.ctx = &ctx; + key_desc.ctx = &global_ctx; pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const uint8_t hash[32] = {0}; - pgp_ec_signature_t sig = {{{0}}}; - - assert_rnp_success( - eddsa_sign(&global_ctx.rng, &sig, hash, sizeof(hash), &seckey.material.ec)); + rnp::secure_vector hash(32); + pgp_signature_material_t sig = {}; - assert_rnp_success(eddsa_verify(&sig, hash, sizeof(hash), &seckey.material.ec)); + assert_rnp_success(seckey.material->sign(global_ctx, sig, hash)); + assert_rnp_success(seckey.material->verify(global_ctx, sig, hash)); // cut one byte off hash -> invalid sig - assert_rnp_failure(eddsa_verify(&sig, hash, sizeof(hash) - 1, &seckey.material.ec)); + rnp::secure_vector hash_cut(31); + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash_cut)); // swap r/s -> invalid sig - pgp::mpi tmp = sig.r; - sig.r = sig.s; - sig.s = tmp; - assert_rnp_failure(eddsa_verify(&sig, hash, sizeof(hash), &seckey.material.ec)); + pgp::mpi tmp = sig.ecc.r; + sig.ecc.r = sig.ecc.s; + sig.ecc.s = tmp; + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash)); } TEST_F(rnp_tests, rnp_test_x25519) { rnp_keygen_crypto_params_t key_desc = {}; - pgp_key_pkt_t seckey; - pgp_ecdh_encrypted_t enc = {}; - uint8_t in[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - uint8_t out[16] = {}; - size_t outlen = 0; - pgp_fingerprint_t fp = {}; - key_desc.key_alg = PGP_PKA_ECDH; key_desc.hash_alg = PGP_HASH_SHA256; key_desc.ctx = &global_ctx; key_desc.ecc.curve = PGP_CURVE_25519; + pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); /* check for length and correctly tweaked bits */ - assert_int_equal(seckey.material.ec.x.len, 32); - assert_int_equal(seckey.material.ec.x.mpi[31] & 7, 0); - assert_int_equal(seckey.material.ec.x.mpi[0] & 128, 0); - assert_int_equal(seckey.material.ec.x.mpi[0] & 64, 64); + auto &ec = dynamic_cast(*seckey.material); + assert_int_equal(ec.x().len, 32); + assert_int_equal(ec.x().mpi[31] & 7, 0); + assert_int_equal(ec.x().mpi[0] & 128, 0); + assert_int_equal(ec.x().mpi[0] & 64, 64); + /* encrypt */ + pgp_fingerprint_t fp = {}; assert_rnp_success(pgp_fingerprint(fp, seckey)); - assert_rnp_success( - ecdh_encrypt_pkcs5(&global_ctx.rng, &enc, in, sizeof(in), &seckey.material.ec, fp)); - assert_true(enc.mlen > 16); - assert_true((enc.p.mpi[0] == 0x40) && (enc.p.len == 33)); - outlen = sizeof(out); - assert_rnp_success(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); - assert_true(outlen == 16); - assert_true(memcmp(in, out, 16) == 0); - + uint8_t in[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + pgp_encrypted_material_t enc = {}; + enc.ecdh.fp = &fp; + assert_rnp_success(seckey.material->encrypt(global_ctx, enc, in, sizeof(in))); + assert_true(enc.ecdh.mlen > 16); + assert_int_equal(enc.ecdh.p.mpi[0], 0x40); + assert_int_equal(enc.ecdh.p.len, 33); + /* decrypt */ + uint8_t out[16] = {}; + size_t outlen = sizeof(out); + assert_rnp_success(seckey.material->decrypt(global_ctx, out, outlen, enc)); + assert_int_equal(outlen, 16); + assert_int_equal(memcmp(in, out, 16), 0); /* negative cases */ - enc.p.mpi[16] ^= 0xff; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[16] ^= 0xff; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.p.mpi[16] ^= 0xff; - enc.p.mpi[0] = 0x04; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[16] ^= 0xff; + enc.ecdh.p.mpi[0] = 0x04; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.p.mpi[0] = 0x40; - enc.mlen--; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.p.mpi[0] = 0x40; + enc.ecdh.mlen--; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); - enc.mlen += 2; - assert_rnp_failure(ecdh_decrypt_pkcs5(out, &outlen, &enc, &seckey.material.ec, fp)); + enc.ecdh.mlen += 2; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, outlen, enc)); } static void @@ -239,7 +236,6 @@ TEST_F(rnp_tests, raw_elgamal_random_key_test_success) TEST_F(rnp_tests, ecdsa_signverify_success) { - uint8_t message[64]; const pgp_hash_alg_t hash_alg = PGP_HASH_SHA512; struct curve { @@ -250,9 +246,9 @@ TEST_F(rnp_tests, ecdsa_signverify_success) for (size_t i = 0; i < ARRAY_SIZE(curves); i++) { // Generate test data. Mainly to make valgrind not to complain about uninitialized data - global_ctx.rng.get(message, sizeof(message)); + rnp::secure_vector hash(rnp::Hash::size(hash_alg)); + global_ctx.rng.get(hash.data(), hash.size()); - pgp_ec_signature_t sig = {{{0}}}; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_ECDSA; key_desc.hash_alg = hash_alg; @@ -265,20 +261,17 @@ TEST_F(rnp_tests, ecdsa_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_ec_key_t *key1 = &seckey1.material.ec; - const pgp_ec_key_t *key2 = &seckey2.material.ec; - - assert_rnp_success( - ecdsa_sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message), key1)); - - assert_rnp_success(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key1)); + pgp_signature_material_t sig = {}; + sig.halg = hash_alg; + assert_rnp_success(seckey1.material->sign(global_ctx, sig, hash)); + assert_rnp_success(seckey1.material->verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key2)); + assert_rnp_failure(seckey2.material->verify(global_ctx, sig, hash)); // Fails because message won't verify - message[0] = ~message[0]; - assert_rnp_failure(ecdsa_verify(&sig, hash_alg, message, sizeof(message), key1)); + hash[0] = ~hash[0]; + assert_rnp_failure(seckey1.material->verify(global_ctx, sig, hash)); } } @@ -290,11 +283,8 @@ TEST_F(rnp_tests, ecdh_roundtrip) } curves[] = { {PGP_CURVE_NIST_P_256, 32}, {PGP_CURVE_NIST_P_384, 48}, {PGP_CURVE_NIST_P_521, 66}}; - pgp_ecdh_encrypted_t enc; - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); + uint8_t in[32] = {1, 2, 3}; + size_t in_len = sizeof(in_len); for (size_t i = 0; i < ARRAY_SIZE(curves); i++) { rnp_keygen_crypto_params_t key_desc; @@ -309,28 +299,46 @@ TEST_F(rnp_tests, ecdh_roundtrip) pgp_fingerprint_t ecdh_key1_fpr = {}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - assert_rnp_success(ecdh_encrypt_pkcs5(&global_ctx.rng, - &enc, - plaintext, - plaintext_len, - &ecdh_key1.material.ec, - ecdh_key1_fpr)); + pgp_encrypted_material_t enc = {}; + enc.ecdh.fp = &ecdh_key1_fpr; + assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in, in_len)); - assert_rnp_success(ecdh_decrypt_pkcs5( - result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr)); + uint8_t res[40] = {0}; + size_t res_len = sizeof(res); + assert_rnp_success(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc)); - assert_int_equal(plaintext_len, result_len); - assert_int_equal(memcmp(plaintext, result, result_len), 0); + assert_int_equal(in_len, res_len); + assert_int_equal(memcmp(in, res, res_len), 0); } } +namespace pgp { +class ECDHTestKeyMaterial : public ECDHKeyMaterial { + public: + ECDHTestKeyMaterial(const ECDHKeyMaterial &src) : ECDHKeyMaterial(src) + { + } + + void + set_key_wrap_alg(pgp_symm_alg_t alg) + { + key_.key_wrap_alg = alg; + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; +} // namespace pgp + TEST_F(rnp_tests, ecdh_decryptionNegativeCases) { - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); - pgp_ecdh_encrypted_t enc; + uint8_t in[32] = {1, 2, 3, 4}; + size_t in_len = sizeof(in); + uint8_t res[36] = {0}; + size_t res_len = sizeof(res); rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_ECDH; @@ -344,74 +352,58 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) pgp_fingerprint_t ecdh_key1_fpr = {}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - assert_rnp_success(ecdh_encrypt_pkcs5( - &global_ctx.rng, &enc, plaintext, plaintext_len, &ecdh_key1.material.ec, ecdh_key1_fpr)); + pgp_encrypted_material_t enc; + enc.ecdh.fp = &ecdh_key1_fpr; + assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in, in_len)); - assert_int_equal(ecdh_decrypt_pkcs5(NULL, 0, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, nullptr, res_len, enc), RNP_ERROR_BAD_PARAMETERS); - assert_int_equal(ecdh_decrypt_pkcs5(result, &result_len, &enc, NULL, ecdh_key1_fpr), - RNP_ERROR_BAD_PARAMETERS); - - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, NULL, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_BAD_PARAMETERS); - - size_t mlen = enc.mlen; - enc.mlen = 0; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_GENERIC); + size_t mlen = enc.ecdh.mlen; + enc.ecdh.mlen = 0; + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc), + RNP_ERROR_GENERIC); - enc.mlen = mlen - 1; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_GENERIC); + enc.ecdh.mlen = mlen - 1; + assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, res_len, enc), + RNP_ERROR_GENERIC); - int key_wrapping_alg = ecdh_key1.material.ec.key_wrap_alg; - ecdh_key1.material.ec.key_wrap_alg = PGP_SA_IDEA; - assert_int_equal( - ecdh_decrypt_pkcs5(result, &result_len, &enc, &ecdh_key1.material.ec, ecdh_key1_fpr), - RNP_ERROR_NOT_SUPPORTED); - ecdh_key1.material.ec.key_wrap_alg = (pgp_symm_alg_t) key_wrapping_alg; + pgp::ECDHTestKeyMaterial key1_mod( + dynamic_cast(*ecdh_key1.material)); + key1_mod.set_key_wrap_alg(PGP_SA_IDEA); + assert_int_equal(key1_mod.decrypt(global_ctx, res, res_len, enc), RNP_ERROR_NOT_SUPPORTED); } #if defined(ENABLE_SM2) TEST_F(rnp_tests, sm2_roundtrip) { - uint8_t key[27] = {0}; - uint8_t decrypted[27]; - size_t decrypted_size; - rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_SM2; key_desc.hash_alg = PGP_HASH_SM3; key_desc.ecc.curve = PGP_CURVE_SM2_P_256; key_desc.ctx = &global_ctx; + uint8_t key[27] = {0}; global_ctx.rng.get(key, sizeof(key)); pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); - const pgp_ec_key_t *eckey = &seckey.material.ec; + auto &eckey = *seckey.material; - pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; - pgp_sm2_encrypted_t enc; - rnp_result_t ret; + pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; + pgp_encrypted_material_t enc; for (size_t i = 0; i < ARRAY_SIZE(hashes); ++i) { - ret = sm2_encrypt(&global_ctx.rng, &enc, key, sizeof(key), hashes[i], eckey); + auto ret = eckey.encrypt(global_ctx, enc, key, sizeof(key)); assert_int_equal(ret, RNP_SUCCESS); - memset(decrypted, 0, sizeof(decrypted)); - decrypted_size = sizeof(decrypted); - ret = sm2_decrypt(decrypted, &decrypted_size, &enc, eckey); + uint8_t dec[32] = {0}; + size_t dec_size = sizeof(dec); + ret = eckey.decrypt(global_ctx, dec, dec_size, enc); assert_int_equal(ret, RNP_SUCCESS); - assert_int_equal(decrypted_size, sizeof(key)); - for (size_t i = 0; i < decrypted_size; ++i) { - assert_int_equal(key[i], decrypted[i]); - } + assert_int_equal(dec_size, sizeof(key)); + assert_int_equal(memcmp(key, dec, dec_size), 0); } } #endif @@ -507,10 +499,6 @@ TEST_F(rnp_tests, sm2_sha256_signature_test) TEST_F(rnp_tests, test_dsa_roundtrip) { - uint8_t message[PGP_MAX_HASH_SIZE]; - pgp_key_pkt_t seckey; - pgp_dsa_signature_t sig; - struct key_params { size_t p; size_t q; @@ -531,10 +519,10 @@ TEST_F(rnp_tests, test_dsa_roundtrip) {1024, 256, PGP_HASH_SHA256}, }; + uint8_t message[PGP_MAX_HASH_SIZE]; global_ctx.rng.get(message, sizeof(message)); for (size_t i = 0; i < ARRAY_SIZE(keys); i++) { - sig = {}; rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = PGP_PKA_DSA; key_desc.hash_alg = keys[i].h; @@ -542,6 +530,7 @@ TEST_F(rnp_tests, test_dsa_roundtrip) key_desc.dsa.q_bitlen = keys[i].q; key_desc.ctx = &global_ctx; + pgp_key_pkt_t seckey; assert_true(pgp_generate_seckey(key_desc, seckey, true)); // try to prevent timeouts in travis-ci printf("p: %zu q: %zu h: %s\n", @@ -550,20 +539,21 @@ TEST_F(rnp_tests, test_dsa_roundtrip) rnp::Hash::name(key_desc.hash_alg)); fflush(stdout); - pgp_dsa_key_t *key1 = &seckey.material.dsa; + auto &key = *seckey.material; - size_t h_size = rnp::Hash::size(keys[i].h); - assert_int_equal(dsa_sign(&global_ctx.rng, &sig, message, h_size, key1), RNP_SUCCESS); - assert_int_equal(dsa_verify(&sig, message, h_size, key1), RNP_SUCCESS); + size_t h_size = rnp::Hash::size(keys[i].h); + rnp::secure_vector hash(message, message + h_size); + pgp_signature_material_t sig = {}; + assert_rnp_success(key.sign(global_ctx, sig, hash)); + assert_rnp_success(key.verify(global_ctx, sig, hash)); } } TEST_F(rnp_tests, test_dsa_verify_negative) { - uint8_t message[PGP_MAX_HASH_SIZE]; - pgp_key_pkt_t sec_key1; - pgp_key_pkt_t sec_key2; - pgp_dsa_signature_t sig = {}; + uint8_t message[PGP_MAX_HASH_SIZE]; + pgp_key_pkt_t sec_key1; + pgp_key_pkt_t sec_key2; struct key_params { size_t p; @@ -588,16 +578,18 @@ TEST_F(rnp_tests, test_dsa_verify_negative) rnp::Hash::name(key_desc.hash_alg)); assert_true(pgp_generate_seckey(key_desc, sec_key2, true)); - pgp_dsa_key_t *key1 = &sec_key1.material.dsa; - pgp_dsa_key_t *key2 = &sec_key2.material.dsa; + auto &key1 = *sec_key1.material; + auto &key2 = *sec_key2.material; - size_t h_size = rnp::Hash::size(key.h); - assert_int_equal(dsa_sign(&global_ctx.rng, &sig, message, h_size, key1), RNP_SUCCESS); + size_t h_size = rnp::Hash::size(key.h); + rnp::secure_vector hash(message, message + h_size); + pgp_signature_material_t sig = {}; + assert_rnp_success(key1.sign(global_ctx, sig, hash)); // wrong key used - assert_int_equal(dsa_verify(&sig, message, h_size, key2), RNP_ERROR_SIGNATURE_INVALID); + assert_int_equal(key2.verify(global_ctx, sig, hash), RNP_ERROR_SIGNATURE_INVALID); // different message - message[0] = ~message[0]; - assert_int_equal(dsa_verify(&sig, message, h_size, key1), RNP_ERROR_SIGNATURE_INVALID); + hash[0] = ~hash[0]; + assert_int_equal(key1.verify(global_ctx, sig, hash), RNP_ERROR_SIGNATURE_INVALID); } #if defined(ENABLE_PQC) @@ -609,14 +601,13 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) PGP_PKA_KYBER768_BP256, PGP_PKA_KYBER1024_BP384}; - pgp_kyber_ecdh_encrypted_t enc; - uint8_t plaintext[32] = {0}; - size_t plaintext_len = sizeof(plaintext); - uint8_t result[32] = {0}; - size_t result_len = sizeof(result); + uint8_t in[32] = {0}; + size_t in_len = sizeof(in); + uint8_t res[36] = {0}; + size_t res_len = sizeof(res); - for (size_t i = 0; i < plaintext_len; i++) { - plaintext[i] = i; // assures that we do not have a special case with all-zeroes + for (size_t i = 0; i < in_len; i++) { + in[i] = i; // assures that we do not have a special case with all-zeroes } for (size_t i = 0; i < ARRAY_SIZE(algs); i++) { @@ -628,17 +619,12 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) pgp_key_pkt_t key_pkt; assert_true(pgp_generate_seckey(key_desc, key_pkt, true)); - pgp_fingerprint_t key_fpr = {}; - assert_rnp_success(pgp_fingerprint(key_fpr, key_pkt)); - - pgp_key_t key(key_pkt); - assert_rnp_success(key_pkt.material.kyber_ecdh.pub.encrypt( - &global_ctx.rng, &enc, plaintext, plaintext_len)); - assert_rnp_success(key_pkt.material.kyber_ecdh.priv.decrypt( - &global_ctx.rng, result, &result_len, &enc)); + pgp_encrypted_material_t enc; + assert_rnp_success(key_pkt.material->encrypt(global_ctx, enc, in, in_len)); + assert_rnp_success(key_pkt.material->decrypt(global_ctx, res, res_len, enc)); - assert_int_equal(plaintext_len, result_len); - assert_int_equal(memcmp(plaintext, result, result_len), 0); + assert_int_equal(in_len, res_len); + assert_int_equal(memcmp(in, res, res_len), 0); } } @@ -657,8 +643,7 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) // Generate test data. Mainly to make valgrind not to complain about uninitialized data global_ctx.rng.get(message, sizeof(message)); - pgp_dilithium_exdsa_signature_t sig; - rnp_keygen_crypto_params_t key_desc; + rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = algs[i]; key_desc.hash_alg = hash_alg; key_desc.ctx = &global_ctx; @@ -669,16 +654,17 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_dilithium_exdsa_key_t *key1 = &seckey1.material.dilithium_exdsa; - const pgp_dilithium_exdsa_key_t *key2 = &seckey2.material.dilithium_exdsa; - - assert_rnp_success( - key1->priv.sign(&global_ctx.rng, &sig, hash_alg, message, sizeof(message))); + auto &key1 = *seckey1.material; + auto &key2 = *seckey2.material; - assert_rnp_success(key1->pub.verify(&sig, hash_alg, message, sizeof(message))); + pgp_signature_material_t sig; + sig.halg = hash_alg; + rnp::secure_vector hash(message, message + sizeof(message)); + assert_rnp_success(key1.sign(global_ctx, sig, hash)); + assert_rnp_success(key1.verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(key2->pub.verify(&sig, hash_alg, message, sizeof(message))); + assert_rnp_failure(key2.verify(global_ctx, sig, hash)); } } @@ -699,8 +685,7 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) // data global_ctx.rng.get(message, sizeof(message)); - pgp_sphincsplus_signature_t sig; - rnp_keygen_crypto_params_t key_desc; + rnp_keygen_crypto_params_t key_desc; key_desc.key_alg = algs[i]; key_desc.sphincsplus.param = params[j]; key_desc.ctx = &global_ctx; @@ -711,16 +696,15 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) assert_true(pgp_generate_seckey(key_desc, seckey1, true)); assert_true(pgp_generate_seckey(key_desc, seckey2, true)); - const pgp_sphincsplus_key_t *key1 = &seckey1.material.sphincsplus; - const pgp_sphincsplus_key_t *key2 = &seckey2.material.sphincsplus; - - assert_rnp_success( - key1->priv.sign(&global_ctx.rng, &sig, message, sizeof(message))); - - assert_rnp_success(key1->pub.verify(&sig, message, sizeof(message))); + auto & key1 = *seckey1.material; + auto & key2 = *seckey2.material; + rnp::secure_vector hash(message, message + sizeof(message)); + pgp_signature_material_t sig; + assert_rnp_success(key1.sign(global_ctx, sig, hash)); + assert_rnp_success(key1.verify(global_ctx, sig, hash)); // Fails because of different key used - assert_rnp_failure(key2->pub.verify(&sig, message, sizeof(message))); + assert_rnp_failure(key2.verify(global_ctx, sig, hash)); } } } @@ -796,155 +780,274 @@ read_key_pkt(pgp_key_pkt_t *key, const char *path) return res; } +namespace pgp { +class RSATestKeyMaterial : public RSAKeyMaterial { + public: + RSATestKeyMaterial(const RSAKeyMaterial &src) : RSAKeyMaterial(src) + { + } + + pgp_rsa_key_t & + rsa() + { + return key_; + } +}; + +class DSATestKeyMaterial : public DSAKeyMaterial { + public: + DSATestKeyMaterial(const DSAKeyMaterial &src) : DSAKeyMaterial(src) + { + } + + pgp_dsa_key_t & + dsa() + { + return key_; + } +}; + +class EGTestKeyMaterial : public EGKeyMaterial { + public: + EGTestKeyMaterial(const EGKeyMaterial &src) : EGKeyMaterial(src) + { + } + + pgp_eg_key_t & + eg() + { + return key_; + } +}; + +class ECDSATestKeyMaterial : public ECDSAKeyMaterial { + public: + ECDSATestKeyMaterial(const ECDSAKeyMaterial &src) : ECDSAKeyMaterial(src) + { + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; + +class EDDSATestKeyMaterial : public EDDSAKeyMaterial { + public: + EDDSATestKeyMaterial(const EDDSAKeyMaterial &src) : EDDSAKeyMaterial(src) + { + } + + pgp_ec_key_t & + ec() + { + return key_; + } +}; + +} // namespace pgp + #define KEYS "data/test_validate_key_material/" TEST_F(rnp_tests, test_validate_key_material) { pgp_key_pkt_t key; - rnp::RNG & rng = global_ctx.rng; /* RSA key and subkey */ assert_true(read_key_pkt(&key, KEYS "rsa-pub.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] |= 1; - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::RSATestKeyMaterial rkey(dynamic_cast(*key.material)); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] |= 1; + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-sub.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.n.mpi[key.material.rsa.n.len - 1] |= 1; - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] &= ~1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().n.mpi[rkey.rsa().n.len - 1] |= 1; + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] &= ~1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-sec.pgp")); - key.material.validate(global_ctx); - assert_true(key.material.validity.valid); - assert_true(key.material.validity.validated); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + assert_true(key.material->validity().valid); + assert_true(key.material->validity().validated); assert_rnp_success(decrypt_secret_key(&key, NULL)); /* make sure validity is reset after decryption */ - assert_false(key.material.validity.valid); - assert_false(key.material.validity.validated); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] += 1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] -= 1; - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] -= 2; - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] -= 2; - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); + assert_false(key.material->validity().valid); + assert_false(key.material->validity().validated); + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] += 1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] -= 1; + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] -= 2; + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] -= 2; + rkey.validate(global_ctx); + assert_true(rkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "rsa-ssb.pgp")); assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] += 1; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.e.mpi[key.material.rsa.e.len - 1] -= 1; - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.p.len - 1] -= 2; - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.rsa.p.mpi[key.material.rsa.q.len - 1] -= 2; - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + rkey = pgp::RSATestKeyMaterial(dynamic_cast(*key.material)); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] += 1; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().e.mpi[rkey.rsa().e.len - 1] -= 1; + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().p.mpi[rkey.rsa().p.len - 1] -= 2; + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] += 2; + rkey.validate(global_ctx); + assert_false(rkey.valid()); + rkey.rsa().q.mpi[rkey.rsa().q.len - 1] -= 2; + rkey.validate(global_ctx); + assert_true(rkey.valid()); key = pgp_key_pkt_t(); /* DSA-ElGamal key */ assert_true(read_key_pkt(&key, KEYS "dsa-sec.pgp")); - key.material.dsa.q.mpi[key.material.dsa.q.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.q.mpi[key.material.dsa.q.len - 1] -= 2; + pgp::DSATestKeyMaterial dkey(dynamic_cast(*key.material)); + dkey.dsa().q.mpi[dkey.dsa().q.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().q.mpi[dkey.dsa().q.len - 1] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.y.mpi[key.material.dsa.y.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.y.mpi[key.material.dsa.y.len - 1] -= 2; - key.material.dsa.p.mpi[key.material.dsa.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.dsa.p.mpi[key.material.dsa.p.len - 1] -= 2; + assert_true(key.material->secret()); + key.material->validate(global_ctx); + assert_true(key.material->valid()); + dkey = pgp::DSATestKeyMaterial(dynamic_cast(*key.material)); + dkey.dsa().y.mpi[dkey.dsa().y.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().y.mpi[dkey.dsa().y.len - 1] -= 2; + dkey.dsa().p.mpi[dkey.dsa().p.len - 1] += 2; + dkey.validate(global_ctx); + assert_false(dkey.valid()); + dkey.dsa().p.mpi[dkey.dsa().p.len - 1] -= 2; /* since Botan calculates y from x on key load we do not check x vs y */ - key.material.dsa.x = key.material.dsa.q; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + dkey.dsa().x = dkey.dsa().q; + dkey.validate(global_ctx); + assert_false(dkey.valid()); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "eg-sec.pgp")); - key.material.eg.p.mpi[key.material.eg.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] -= 2; + pgp::EGTestKeyMaterial gkey(dynamic_cast(*key.material)); + gkey.eg().p.mpi[gkey.eg().p.len - 1] += 2; + gkey.validate(global_ctx); + assert_false(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.eg.p.mpi[key.material.eg.p.len - 1] -= 2; + assert_true(key.material->secret()); + gkey = pgp::EGTestKeyMaterial(dynamic_cast(*key.material)); + gkey.validate(global_ctx); + assert_true(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] += 2; + gkey.validate(global_ctx); + assert_false(gkey.valid()); + gkey.eg().p.mpi[gkey.eg().p.len - 1] -= 2; /* since Botan calculates y from x on key load we do not check x vs y */ - key.material.eg.x = key.material.eg.p; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + gkey.eg().x = gkey.eg().p; + gkey.validate(global_ctx); + assert_false(gkey.valid()); key = pgp_key_pkt_t(); /* ElGamal key with small subgroup */ assert_true(read_key_pkt(&key, KEYS "eg-sec-small-group.pgp")); - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_false(key.material->valid()); assert_rnp_success(decrypt_secret_key(&key, NULL)); key = pgp_key_pkt_t(); assert_true(read_key_pkt(&key, KEYS "eg-sec-small-group-enc.pgp")); - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); + key.material->validate(global_ctx); + assert_false(key.material->valid()); assert_rnp_success(decrypt_secret_key(&key, "password")); key = pgp_key_pkt_t(); /* ECDSA key */ assert_true(read_key_pkt(&key, KEYS "ecdsa-p256-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; - key.material.ec.p.mpi[10] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[10] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::ECDSATestKeyMaterial ekey(dynamic_cast(*key.material)); + ekey.validate(global_ctx); + assert_true(ekey.valid()); + ekey.ec().p.mpi[0] += 2; + ekey.validate(global_ctx); + assert_false(ekey.valid()); + ekey.ec().p.mpi[0] -= 2; + ekey.ec().p.mpi[10] += 2; + ekey.validate(global_ctx); + assert_false(ekey.valid()); + ekey.ec().p.mpi[10] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); + assert_true(key.material->secret()); key = pgp_key_pkt_t(); /* ECDH key */ assert_true(read_key_pkt(&key, KEYS "ecdh-p256-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; - key.material.ec.p.mpi[10] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[10] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::ECDHTestKeyMaterial ehkey(dynamic_cast(*key.material)); + ehkey.ec().p.mpi[0] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[0] -= 2; + ehkey.ec().p.mpi[10] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[10] -= 2; assert_rnp_success(decrypt_secret_key(&key, NULL)); - assert_true(key.material.secret); + assert_true(key.material->secret()); key = pgp_key_pkt_t(); /* EDDSA key, just test for header since any value can be secret key */ assert_true(read_key_pkt(&key, KEYS "ed25519-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + pgp::EDDSATestKeyMaterial edkey(dynamic_cast(*key.material)); + edkey.ec().p.mpi[0] += 2; + edkey.validate(global_ctx); + assert_false(edkey.valid()); + edkey.ec().p.mpi[0] -= 2; key = pgp_key_pkt_t(); /* x25519 key, same as the previous - botan calculates pub key from the secret one */ assert_true(read_key_pkt(&key, KEYS "x25519-sec.pgp")); - assert_rnp_success(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] += 2; - assert_rnp_failure(validate_pgp_key_material(&key.material, &rng)); - key.material.ec.p.mpi[0] -= 2; + key.material->validate(global_ctx); + assert_true(key.material->valid()); + ehkey = pgp::ECDHTestKeyMaterial(dynamic_cast(*key.material)); + ehkey.ec().p.mpi[0] += 2; + ehkey.validate(global_ctx); + assert_false(ehkey.valid()); + ehkey.ec().p.mpi[0] -= 2; key = pgp_key_pkt_t(); } diff --git a/src/tests/cli_tests.py b/src/tests/cli_tests.py index ebea4a7517..f3f2a22408 100755 --- a/src/tests/cli_tests.py +++ b/src/tests/cli_tests.py @@ -2490,7 +2490,7 @@ def test_rnp_autocrypt_key_import(self): def test_rnp_list_packets(self): KEY_P256 = data_path('test_list_packets/ecc-p256-pub.asc') - # List packets in humand-readable format + # List packets in human-readable format params = ['--list-packets', KEY_P256] ret, out, _ = run_proc(RNP, params) self.assertEqual(ret, 0, PKT_LIST_FAILED) diff --git a/src/tests/data/test_key_validity/case5/generate.cpp b/src/tests/data/test_key_validity/case5/generate.cpp index 6ec92cd470..3b185aec7a 100644 --- a/src/tests/data/test_key_validity/case5/generate.cpp +++ b/src/tests/data/test_key_validity/case5/generate.cpp @@ -94,7 +94,7 @@ main(int argc, char **argv) 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->halg = tskey.key.material->adjust_hash(binding->halg); binding->palg = tskey.key.alg; binding->set_keyfp(keyfp); diff --git a/src/tests/key-protect.cpp b/src/tests/key-protect.cpp index d22960d838..30e4c67c0d 100644 --- a/src/tests/key-protect.cpp +++ b/src/tests/key-protect.cpp @@ -30,6 +30,22 @@ #include "support.h" #include "crypto.h" +bool +rsa_sec_empty(const pgp::KeyMaterial &key) +{ + auto &rsa = dynamic_cast(key); + return mpi_empty(rsa.d()) && mpi_empty(rsa.p()) && mpi_empty(rsa.q()) && + mpi_empty(rsa.u()); +} + +bool +rsa_sec_filled(const pgp::KeyMaterial &key) +{ + auto &rsa = dynamic_cast(key); + return !mpi_empty(rsa.d()) && !mpi_empty(rsa.p()) && !mpi_empty(rsa.q()) && + !mpi_empty(rsa.u()); +} + /* 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. @@ -77,10 +93,7 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) 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(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)); + assert_true(rsa_sec_empty(key->material())); // try to unprotect with a failing password provider pgp_password_provider_t pprov(failing_password_callback); @@ -99,10 +112,7 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_true(key->is_locked()); // confirm secret key material is still NULL - 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)); + assert_true(rsa_sec_empty(key->material())); // unlock (no password required since the key is not protected) pprov = {asserting_password_callback}; @@ -110,16 +120,14 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(key->is_locked()); // secret key material should be available - 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)); + assert_true(rsa_sec_filled(key->material())); // save the secret MPIs for some later comparisons - pgp::mpi d = key->material().rsa.d; - pgp::mpi p = key->material().rsa.p; - pgp::mpi q = key->material().rsa.q; - pgp::mpi u = key->material().rsa.u; + auto &rsa = dynamic_cast(key->material()); + auto d = rsa.d(); + auto p = rsa.p(); + auto q = rsa.q(); + auto u = rsa.u(); // confirm that packets[0] is no longer encrypted { @@ -140,36 +148,35 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(reloaded_key->is_locked()); assert_false(reloaded_key->is_protected()); // secret key material should not be NULL - 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)); + auto &rsar = dynamic_cast(reloaded_key->material()); + assert_false(mpi_empty(rsar.d())); + assert_false(mpi_empty(rsar.p())); + assert_false(mpi_empty(rsar.q())); + assert_false(mpi_empty(rsar.u())); // compare MPIs of the reloaded key, with the unlocked key from earlier - assert_true(key->material().rsa.d == reloaded_key->material().rsa.d); - assert_true(key->material().rsa.p == reloaded_key->material().rsa.p); - assert_true(key->material().rsa.q == reloaded_key->material().rsa.q); - assert_true(key->material().rsa.u == reloaded_key->material().rsa.u); + assert_true(rsa.d() == rsar.d()); + assert_true(rsa.p() == rsar.p()); + assert_true(rsa.q() == rsar.q()); + assert_true(rsa.u() == rsar.u()); // negative test to try to ensure the above is a valid test - assert_false(key->material().rsa.d == reloaded_key->material().rsa.p); + assert_false(rsa.d() == rsar.p()); // lock it assert_true(reloaded_key->lock()); assert_true(reloaded_key->is_locked()); // confirm that secret MPIs are NULL again - 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)); + assert_true(rsa_sec_empty(reloaded_key->material())); // unlock it (no password, since it's not protected) pgp_password_provider_t pprov(asserting_password_callback); 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(key->material().rsa.d == reloaded_key->material().rsa.d); - assert_true(key->material().rsa.p == reloaded_key->material().rsa.p); - assert_true(key->material().rsa.q == reloaded_key->material().rsa.q); - assert_true(key->material().rsa.u == reloaded_key->material().rsa.u); + auto &rsar2 = dynamic_cast(reloaded_key->material()); + assert_true(rsa.d() == rsar2.d()); + assert_true(rsa.p() == rsar2.p()); + assert_true(rsa.q() == rsar2.q()); + assert_true(rsa.u() == rsar2.u()); delete ks; } @@ -212,10 +219,11 @@ TEST_F(rnp_tests, test_key_protect_load_pgp) assert_false(key->is_locked()); // compare secret MPIs with those from earlier - assert_true(key->material().rsa.d == d); - assert_true(key->material().rsa.p == p); - assert_true(key->material().rsa.q == q); - assert_true(key->material().rsa.u == u); + auto &rsa2 = dynamic_cast(key->material()); + assert_true(rsa2.d() == d); + assert_true(rsa2.p() == p); + assert_true(rsa2.q() == q); + assert_true(rsa2.u() == u); // cleanup delete key; diff --git a/src/tests/key-unlock.cpp b/src/tests/key-unlock.cpp index 53ccb94687..fc58fd9eb9 100644 --- a/src/tests/key-unlock.cpp +++ b/src/tests/key-unlock.cpp @@ -31,6 +31,9 @@ #include "support.h" #include +bool rsa_sec_empty(const pgp::KeyMaterial &key); +bool rsa_sec_filled(const pgp::KeyMaterial &key); + TEST_F(rnp_tests, test_key_unlock_pgp) { cli_rnp_t rnp = {}; @@ -86,10 +89,7 @@ TEST_F(rnp_tests, test_key_unlock_pgp) rnp_buffer_destroy(alg); // confirm the secret MPIs are NULL - assert_true(mpi_empty(key->sec->material().rsa.d)); - assert_true(mpi_empty(key->sec->material().rsa.p)); - assert_true(mpi_empty(key->sec->material().rsa.q)); - assert_true(mpi_empty(key->sec->material().rsa.u)); + assert_true(rsa_sec_empty(key->sec->material())); // try to unlock with a failing password provider provider.callback = failing_password_callback; @@ -114,10 +114,7 @@ TEST_F(rnp_tests, test_key_unlock_pgp) assert_false(locked); // confirm the secret MPIs are now filled in - assert_false(mpi_empty(key->sec->material().rsa.d)); - assert_false(mpi_empty(key->sec->material().rsa.p)); - assert_false(mpi_empty(key->sec->material().rsa.q)); - assert_false(mpi_empty(key->sec->material().rsa.u)); + assert_true(rsa_sec_filled(key->sec->material())); // now the signing key is unlocked, confirm that no password is required for signing assert_rnp_success( diff --git a/src/tests/load-pgp.cpp b/src/tests/load-pgp.cpp index 07292ae746..888ddbcc28 100644 --- a/src/tests/load-pgp.cpp +++ b/src/tests/load-pgp.cpp @@ -705,7 +705,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_KEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* subkey 1 */ keycp = pgp_key_t(*skey1, true); @@ -717,7 +717,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* subkey 2 */ keycp = pgp_key_t(*skey2, true); @@ -729,7 +729,7 @@ TEST_F(rnp_tests, test_load_public_from_secret) assert_int_equal(keycp.rawpkt().tag, PGP_PKT_PUBLIC_SUBKEY); assert_null(keycp.pkt().sec_data); assert_int_equal(keycp.pkt().sec_len, 0); - assert_false(keycp.pkt().material.secret); + assert_false(keycp.pkt().material->secret()); pubstore->add_key(keycp); /* save pubring */ assert_true(pubstore->write());