diff --git a/.cirrus.yml b/.cirrus.yml index 8f0d736585..a32ffcd00a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -23,7 +23,7 @@ # POSSIBILITY OF SUCH DAMAGE. freebsd_instance: - image: freebsd-13-2-release-amd64 + image: freebsd-13-4-release-amd64 task: name: build diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 606bc5bae4..001d7ef520 100755 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -370,6 +370,8 @@ add_library(librnp-obj OBJECT pass-provider.cpp sig_subpacket.cpp key_material.cpp + enc_material.cpp + sig_material.cpp keygen.cpp pgp-key.cpp rnp.cpp diff --git a/src/lib/crypto/dsa.h b/src/lib/crypto/dsa.h index ee2c37016a..6bdcb2a674 100644 --- a/src/lib/crypto/dsa.h +++ b/src/lib/crypto/dsa.h @@ -40,18 +40,18 @@ namespace dsa { class Signature { public: - pgp::mpi r; - pgp::mpi s; + mpi r; + mpi s; }; class Key { public: - pgp::mpi p{}; - pgp::mpi q{}; - pgp::mpi g{}; - pgp::mpi y{}; + mpi p{}; + mpi q{}; + mpi g{}; + mpi y{}; /* secret mpi */ - pgp::mpi x{}; + mpi x{}; void clear_secret() diff --git a/src/lib/crypto/dsa_ossl.cpp b/src/lib/crypto/dsa_ossl.cpp index 33367bbdc4..3d1b56945a 100644 --- a/src/lib/crypto/dsa_ossl.cpp +++ b/src/lib/crypto/dsa_ossl.cpp @@ -245,7 +245,7 @@ Key::verify(const Signature &sig, const rnp::secure_bytes &hash) const RNP_LOG("Failed to initialize verify: %lu", ERR_peek_last_error()); return RNP_ERROR_GENERIC; } - pgp::mpi sigbuf; + mpi sigbuf; if (!encode_sig(sigbuf.mpi, &sigbuf.len, sig)) { return RNP_ERROR_GENERIC; } diff --git a/src/lib/crypto/ec.h b/src/lib/crypto/ec.h index eba765ff43..71cd8e92db 100644 --- a/src/lib/crypto/ec.h +++ b/src/lib/crypto/ec.h @@ -106,16 +106,16 @@ class Curve { class Signature { public: - pgp::mpi r; - pgp::mpi s; + mpi r; + mpi s; }; class Key { public: pgp_curve_t curve; - pgp::mpi p; + mpi p; /* secret mpi */ - pgp::mpi x; + mpi x; /* 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*/ diff --git a/src/lib/crypto/ec_ossl.cpp b/src/lib/crypto/ec_ossl.cpp index fa6bbb42be..3c9b3ba9c1 100644 --- a/src/lib/crypto/ec_ossl.cpp +++ b/src/lib/crypto/ec_ossl.cpp @@ -101,7 +101,7 @@ generate_pkey(const pgp_pubkey_alg_t alg_id, const pgp_curve_t curve) } static bool -write_raw_seckey(const rnp::ossl::evp::PKey &pkey, pgp::ec::Key &key) +write_raw_seckey(const rnp::ossl::evp::PKey &pkey, ec::Key &key) { /* EdDSA and X25519 keys are saved in a different way */ static_assert(sizeof(key.x.mpi) > 32, "mpi is too small."); @@ -123,7 +123,7 @@ write_raw_seckey(const rnp::ossl::evp::PKey &pkey, pgp::ec::Key &key) } static bool -write_seckey(rnp::ossl::evp::PKey &pkey, pgp::mpi &key) +write_seckey(rnp::ossl::evp::PKey &pkey, mpi &key) { #if defined(CRYPTO_BACKEND_OPENSSL3) rnp::bn x; @@ -173,7 +173,7 @@ Key::generate(rnp::RNG &rng, const pgp_pubkey_alg_t alg_id, const pgp_curve_t cu } static rnp::ossl::evp::PKey -load_raw_key(const pgp::mpi &keyp, const pgp::mpi *keyx, int nid) +load_raw_key(const mpi &keyp, const mpi *keyx, int nid) { if (!keyx) { /* as per RFC, EdDSA & 25519 keys must use 0x40 byte for encoding */ @@ -219,7 +219,7 @@ load_raw_key(const pgp::mpi &keyp, const pgp::mpi *keyx, int nid) #if defined(CRYPTO_BACKEND_OPENSSL3) static rnp::ossl::Param -build_params(const pgp::mpi &p, const pgp::mpi *x, const char *curve) +build_params(const mpi &p, const mpi *x, const char *curve) { rnp::ossl::ParamBld bld(OSSL_PARAM_BLD_new()); if (!bld) { @@ -235,7 +235,7 @@ build_params(const pgp::mpi &p, const pgp::mpi *x, const char *curve) } static rnp::ossl::evp::PKey -load_key_openssl3(const pgp::mpi &keyp, const pgp::mpi *keyx, const Curve &curv_desc) +load_key_openssl3(const mpi &keyp, const mpi *keyx, const Curve &curv_desc) { auto params = build_params(keyp, keyx, curv_desc.openssl_name); if (!params) { @@ -266,7 +266,7 @@ load_key_openssl3(const pgp::mpi &keyp, const pgp::mpi *keyx, const Curve &curv_ #endif rnp::ossl::evp::PKey -load_key(const pgp::mpi &keyp, const pgp::mpi *keyx, pgp_curve_t curve) +load_key(const mpi &keyp, const mpi *keyx, pgp_curve_t curve) { auto curv_desc = Curve::get(curve); if (!curv_desc) { @@ -394,7 +394,7 @@ validate_key(const Key &key, bool secret) } bool -write_pubkey(const rnp::ossl::evp::PKey &pkey, pgp::mpi &mpi, pgp_curve_t curve) +write_pubkey(const rnp::ossl::evp::PKey &pkey, mpi &mpi, pgp_curve_t curve) { if (is_raw_key(curve)) { /* EdDSA and X25519 keys are saved in a different way */ diff --git a/src/lib/crypto/ec_ossl.h b/src/lib/crypto/ec_ossl.h index 9b7f956672..c98086a524 100644 --- a/src/lib/crypto/ec_ossl.h +++ b/src/lib/crypto/ec_ossl.h @@ -35,13 +35,13 @@ namespace pgp { namespace ec { -rnp::ossl::evp::PKey load_key(const pgp::mpi &keyp, const pgp::mpi *keyx, pgp_curve_t curve); +rnp::ossl::evp::PKey load_key(const mpi &keyp, const mpi *keyx, pgp_curve_t curve); -rnp_result_t validate_key(const pgp::ec::Key &key, bool secret); +rnp_result_t validate_key(const ec::Key &key, bool secret); rnp::ossl::evp::PKey generate_pkey(const pgp_pubkey_alg_t alg_id, const pgp_curve_t curve); -bool write_pubkey(const rnp::ossl::evp::PKey &key, pgp::mpi &mpi, pgp_curve_t curve); +bool write_pubkey(const rnp::ossl::evp::PKey &key, mpi &mpi, pgp_curve_t curve); } // namespace ec } // namespace pgp diff --git a/src/lib/crypto/ecdh.cpp b/src/lib/crypto/ecdh.cpp index 11e009eaea..67280bcb26 100644 --- a/src/lib/crypto/ecdh.cpp +++ b/src/lib/crypto/ecdh.cpp @@ -163,11 +163,7 @@ validate_key(rnp::RNG &rng, const ec::Key &key, bool secret) } rnp_result_t -encrypt_pkcs5(rnp::RNG & rng, - Encrypted & out, - const rnp::secure_bytes & in, - const ec::Key & key, - const std::vector &fp) +encrypt_pkcs5(rnp::RNG &rng, Encrypted &out, const rnp::secure_bytes &in, const ec::Key &key) { if (in.size() > MAX_SESSION_KEY_SIZE) { return RNP_ERROR_BAD_PARAMETERS; @@ -193,7 +189,7 @@ encrypt_pkcs5(rnp::RNG & rng, // See 13.5 of RFC 4880 for definition of other_info size const size_t kek_len = pgp_key_size(key.key_wrap_alg); auto other_info = - kdf_other_info_serialize(*curve_desc, fp, key.kdf_hash_alg, key.key_wrap_alg); + kdf_other_info_serialize(*curve_desc, out.fp, key.kdf_hash_alg, key.key_wrap_alg); assert(other_info.size() == curve_desc->OID.size() + 46); rnp::botan::Privkey eph_prv_key; @@ -253,10 +249,7 @@ encrypt_pkcs5(rnp::RNG & rng, } rnp_result_t -decrypt_pkcs5(rnp::secure_bytes & out, - const Encrypted & in, - const ec::Key & key, - const std::vector &fp) +decrypt_pkcs5(rnp::secure_bytes &out, const Encrypted &in, const ec::Key &key) { if (!key.x.bytes()) { return RNP_ERROR_BAD_PARAMETERS; @@ -277,7 +270,7 @@ decrypt_pkcs5(rnp::secure_bytes & out, } // See 13.5 of RFC 4880 for definition of other_info_size - auto other_info = kdf_other_info_serialize(*curve_desc, fp, kdf_hash, wrap_alg); + auto other_info = kdf_other_info_serialize(*curve_desc, in.fp, kdf_hash, wrap_alg); assert(other_info.size() == curve_desc->OID.size() + 46); rnp::botan::Privkey prv_key; diff --git a/src/lib/crypto/ecdh.h b/src/lib/crypto/ecdh.h index 63d409e7dd..032b8059f9 100644 --- a/src/lib/crypto/ecdh.h +++ b/src/lib/crypto/ecdh.h @@ -70,7 +70,6 @@ bool set_params(ec::Key &key, pgp_curve_t curve_id); * as specified in RFC 3394 * @param in data to be encrypted * @param key public key to be used for encryption - * @param fp fingerprint of the encrypting key * * @return RNP_SUCCESS on success and output parameters are populated * @return RNP_ERROR_NOT_SUPPORTED unknown curve @@ -78,11 +77,10 @@ bool set_params(ec::Key &key, pgp_curve_t curve_id); * @return RNP_ERROR_SHORT_BUFFER `wrapped_key_len' to small to store result * @return RNP_ERROR_GENERIC implementation error */ -rnp_result_t encrypt_pkcs5(rnp::RNG & rng, - Encrypted & out, - const rnp::secure_bytes & in, - const ec::Key & key, - const std::vector &fp); +rnp_result_t encrypt_pkcs5(rnp::RNG & rng, + Encrypted & out, + const rnp::secure_bytes &in, + const ec::Key & key); /* * Decrypts session key with a KEK agreed during ECDH as specified in @@ -104,10 +102,7 @@ rnp_result_t encrypt_pkcs5(rnp::RNG & rng, * @return RNP_ERROR_SHORT_BUFFER `session_key_len' to small to store result * @return RNP_ERROR_GENERIC decryption failed or implementation error */ -rnp_result_t decrypt_pkcs5(rnp::secure_bytes & out, - const Encrypted & in, - const ec::Key & key, - const std::vector &fp); +rnp_result_t decrypt_pkcs5(rnp::secure_bytes &out, const Encrypted &in, const ec::Key &key); } // namespace ecdh } // namespace pgp diff --git a/src/lib/crypto/ecdh_ossl.cpp b/src/lib/crypto/ecdh_ossl.cpp index a57e232261..fcebf6a0a2 100644 --- a/src/lib/crypto/ecdh_ossl.cpp +++ b/src/lib/crypto/ecdh_ossl.cpp @@ -248,11 +248,7 @@ ecdh_kek_len(pgp_symm_alg_t wrap_alg) } rnp_result_t -encrypt_pkcs5(rnp::RNG & rng, - Encrypted & out, - const rnp::secure_bytes & in, - const ec::Key & key, - const std::vector &fp) +encrypt_pkcs5(rnp::RNG &rng, Encrypted &out, const rnp::secure_bytes &in, const ec::Key &key) { if (in.size() > MAX_SESSION_KEY_SIZE) { return RNP_ERROR_BAD_PARAMETERS; @@ -298,7 +294,7 @@ encrypt_pkcs5(rnp::RNG & rng, } /* here we got x value in sec, deriving kek */ rnp::secure_bytes kek(keklen, 0); - auto ret = derive_kek(sec, key, fp, kek); + auto ret = derive_kek(sec, key, out.fp, kek); if (ret) { /* LCOV_EXCL_START */ RNP_LOG("Failed to derive KEK."); @@ -329,10 +325,7 @@ encrypt_pkcs5(rnp::RNG & rng, } rnp_result_t -decrypt_pkcs5(rnp::secure_bytes & out, - const Encrypted & in, - const ec::Key & key, - const std::vector &fp) +decrypt_pkcs5(rnp::secure_bytes &out, const Encrypted &in, const ec::Key &key) { if (!key.x.bytes()) { return RNP_ERROR_BAD_PARAMETERS; @@ -368,7 +361,7 @@ decrypt_pkcs5(rnp::secure_bytes & out, } /* here we got x value in sec, deriving kek */ rnp::secure_bytes kek(keklen, 0); - auto ret = derive_kek(sec, key, fp, kek); + auto ret = derive_kek(sec, key, in.fp, kek); if (ret) { /* LCOV_EXCL_START */ RNP_LOG("Failed to derive KEK."); diff --git a/src/lib/crypto/ecdh_utils.cpp b/src/lib/crypto/ecdh_utils.cpp index f36cbde513..5861dfe938 100644 --- a/src/lib/crypto/ecdh_utils.cpp +++ b/src/lib/crypto/ecdh_utils.cpp @@ -53,7 +53,7 @@ static const struct ecdh_params_t { // returns size of data written to other_info std::vector -kdf_other_info_serialize(const pgp::ec::Curve & curve, +kdf_other_info_serialize(const ec::Curve & curve, const std::vector &fp, const pgp_hash_alg_t kdf_hash, const pgp_symm_alg_t wrap_alg) @@ -117,7 +117,7 @@ unpad_pkcs7(rnp::secure_bytes &buf) } bool -set_params(pgp::ec::Key &key, pgp_curve_t curve_id) +set_params(ec::Key &key, pgp_curve_t curve_id) { for (size_t i = 0; i < ARRAY_SIZE(ecdh_params); i++) { if (ecdh_params[i].curve == curve_id) { diff --git a/src/lib/crypto/ecdh_utils.h b/src/lib/crypto/ecdh_utils.h index c038313855..447dbfcaec 100644 --- a/src/lib/crypto/ecdh_utils.h +++ b/src/lib/crypto/ecdh_utils.h @@ -35,7 +35,7 @@ namespace pgp { namespace ecdh { -std::vector kdf_other_info_serialize(const pgp::ec::Curve & curve, +std::vector kdf_other_info_serialize(const ec::Curve & curve, const std::vector &fp, const pgp_hash_alg_t kdf_hash, const pgp_symm_alg_t wrap_alg); diff --git a/src/lib/crypto/ecdsa.cpp b/src/lib/crypto/ecdsa.cpp index fddd800250..e103f5c591 100644 --- a/src/lib/crypto/ecdsa.cpp +++ b/src/lib/crypto/ecdsa.cpp @@ -34,9 +34,9 @@ namespace pgp { namespace ecdsa { static bool -load_public_key(rnp::botan::Pubkey &pubkey, const pgp::ec::Key &keydata) +load_public_key(rnp::botan::Pubkey &pubkey, const ec::Key &keydata) { - auto curve = pgp::ec::Curve::get(keydata.curve); + auto curve = ec::Curve::get(keydata.curve); if (!curve) { RNP_LOG("unknown curve"); return false; @@ -62,9 +62,9 @@ load_public_key(rnp::botan::Pubkey &pubkey, const pgp::ec::Key &keydata) } static bool -load_secret_key(rnp::botan::Privkey &seckey, const pgp::ec::Key &keydata) +load_secret_key(rnp::botan::Privkey &seckey, const ec::Key &keydata) { - auto curve = pgp::ec::Curve::get(keydata.curve); + auto curve = ec::Curve::get(keydata.curve); if (!curve) { return false; } @@ -82,7 +82,7 @@ load_secret_key(rnp::botan::Privkey &seckey, const pgp::ec::Key &keydata) } rnp_result_t -validate_key(rnp::RNG &rng, const pgp::ec::Key &key, bool secret) +validate_key(rnp::RNG &rng, const ec::Key &key, bool secret) { rnp::botan::Pubkey bpkey; if (!load_public_key(bpkey, key) || botan_pubkey_check_key(bpkey.get(), rng.handle(), 0)) { @@ -131,12 +131,12 @@ padding_str_for(pgp_hash_alg_t hash_alg) rnp_result_t sign(rnp::RNG & rng, - pgp::ec::Signature & sig, + ec::Signature & sig, pgp_hash_alg_t hash_alg, const rnp::secure_bytes &hash, - const pgp::ec::Key & key) + const ec::Key & key) { - auto curve = pgp::ec::Curve::get(key.curve); + auto curve = ec::Curve::get(key.curve); if (!curve) { return RNP_ERROR_BAD_PARAMETERS; } @@ -172,12 +172,12 @@ sign(rnp::RNG & rng, } rnp_result_t -verify(const pgp::ec::Signature &sig, - pgp_hash_alg_t hash_alg, - const rnp::secure_bytes & hash, - const pgp::ec::Key & key) +verify(const ec::Signature & sig, + pgp_hash_alg_t hash_alg, + const rnp::secure_bytes &hash, + const ec::Key & key) { - auto curve = pgp::ec::Curve::get(key.curve); + auto curve = ec::Curve::get(key.curve); if (!curve) { RNP_LOG("unknown curve"); return RNP_ERROR_BAD_PARAMETERS; diff --git a/src/lib/crypto/eddsa.cpp b/src/lib/crypto/eddsa.cpp index d59bae7415..71ddbf7745 100644 --- a/src/lib/crypto/eddsa.cpp +++ b/src/lib/crypto/eddsa.cpp @@ -35,7 +35,7 @@ namespace pgp { namespace eddsa { static bool -load_public_key(rnp::botan::Pubkey &pubkey, const pgp::ec::Key &keydata) +load_public_key(rnp::botan::Pubkey &pubkey, const ec::Key &keydata) { if (keydata.curve != PGP_CURVE_ED25519) { return false; @@ -53,7 +53,7 @@ load_public_key(rnp::botan::Pubkey &pubkey, const pgp::ec::Key &keydata) } static bool -load_secret_key(rnp::botan::Privkey &seckey, const pgp::ec::Key &keydata) +load_secret_key(rnp::botan::Privkey &seckey, const ec::Key &keydata) { if (keydata.curve != PGP_CURVE_ED25519) { return false; @@ -72,7 +72,7 @@ load_secret_key(rnp::botan::Privkey &seckey, const pgp::ec::Key &keydata) } rnp_result_t -validate_key(rnp::RNG &rng, const pgp::ec::Key &key, bool secret) +validate_key(rnp::RNG &rng, const ec::Key &key, bool secret) { rnp::botan::Pubkey bpkey; if (!load_public_key(bpkey, key) || botan_pubkey_check_key(bpkey.get(), rng.handle(), 0)) { @@ -92,7 +92,7 @@ validate_key(rnp::RNG &rng, const pgp::ec::Key &key, bool secret) } rnp_result_t -generate(rnp::RNG &rng, pgp::ec::Key &key) +generate(rnp::RNG &rng, ec::Key &key) { rnp::botan::Privkey eddsa; if (botan_privkey_create(&eddsa.get(), "Ed25519", NULL, rng.handle())) { @@ -115,7 +115,7 @@ generate(rnp::RNG &rng, pgp::ec::Key &key) } rnp_result_t -verify(const pgp::ec::Signature &sig, const rnp::secure_bytes &hash, const pgp::ec::Key &key) +verify(const ec::Signature &sig, const rnp::secure_bytes &hash, const ec::Key &key) { // Unexpected size for Ed25519 signature if ((sig.r.bytes() > 32) || (sig.s.bytes() > 32)) { @@ -144,10 +144,7 @@ verify(const pgp::ec::Signature &sig, const rnp::secure_bytes &hash, const pgp:: } rnp_result_t -sign(rnp::RNG & rng, - pgp::ec::Signature & sig, - const rnp::secure_bytes &hash, - const pgp::ec::Key & key) +sign(rnp::RNG &rng, ec::Signature &sig, const rnp::secure_bytes &hash, const ec::Key &key) { rnp::botan::Privkey eddsa; if (!load_secret_key(eddsa, key)) { diff --git a/src/lib/crypto/eddsa_ossl.cpp b/src/lib/crypto/eddsa_ossl.cpp index 2754145218..150f877a8b 100644 --- a/src/lib/crypto/eddsa_ossl.cpp +++ b/src/lib/crypto/eddsa_ossl.cpp @@ -40,7 +40,7 @@ namespace pgp { namespace eddsa { rnp_result_t -validate_key(rnp::RNG &rng, const pgp::ec::Key &key, bool secret) +validate_key(rnp::RNG &rng, const ec::Key &key, bool secret) { /* Not implemented in the OpenSSL, so just do basic size checks. */ if ((key.p.bytes() != 33) || (key.p.mpi[0] != 0x40)) { @@ -53,7 +53,7 @@ validate_key(rnp::RNG &rng, const pgp::ec::Key &key, bool secret) } rnp_result_t -generate(rnp::RNG &rng, pgp::ec::Key &key) +generate(rnp::RNG &rng, ec::Key &key) { rnp_result_t ret = key.generate(rng, PGP_PKA_EDDSA, PGP_CURVE_ED25519); if (!ret) { @@ -63,7 +63,7 @@ generate(rnp::RNG &rng, pgp::ec::Key &key) } rnp_result_t -verify(const pgp::ec::Signature &sig, const rnp::secure_bytes &hash, const pgp::ec::Key &key) +verify(const ec::Signature &sig, const rnp::secure_bytes &hash, const ec::Key &key) { if ((sig.r.bytes() > 32) || (sig.s.bytes() > 32)) { RNP_LOG("Invalid EdDSA signature."); @@ -74,7 +74,7 @@ verify(const pgp::ec::Signature &sig, const rnp::secure_bytes &hash, const pgp:: return RNP_ERROR_BAD_PARAMETERS; } - auto evpkey = pgp::ec::load_key(key.p, NULL, PGP_CURVE_ED25519); + auto evpkey = ec::load_key(key.p, NULL, PGP_CURVE_ED25519); if (!evpkey) { RNP_LOG("Failed to load key"); return RNP_ERROR_BAD_PARAMETERS; @@ -103,16 +103,13 @@ verify(const pgp::ec::Signature &sig, const rnp::secure_bytes &hash, const pgp:: } rnp_result_t -sign(rnp::RNG & rng, - pgp::ec::Signature & sig, - const rnp::secure_bytes &hash, - const pgp::ec::Key & key) +sign(rnp::RNG &rng, ec::Signature &sig, const rnp::secure_bytes &hash, const ec::Key &key) { if (!key.x.bytes()) { RNP_LOG("private key not set"); return RNP_ERROR_BAD_PARAMETERS; } - auto evpkey = pgp::ec::load_key(key.p, &key.x, PGP_CURVE_ED25519); + auto evpkey = ec::load_key(key.p, &key.x, PGP_CURVE_ED25519); if (!evpkey) { RNP_LOG("Failed to load private key: %lu", ERR_peek_last_error()); return RNP_ERROR_BAD_PARAMETERS; diff --git a/src/lib/crypto/elgamal.h b/src/lib/crypto/elgamal.h index 56878b636a..a4f372985c 100644 --- a/src/lib/crypto/elgamal.h +++ b/src/lib/crypto/elgamal.h @@ -39,23 +39,23 @@ class Signature { public: /* This is kept only for packet reading. Implementation MUST * not create elgamal signatures */ - pgp::mpi r; - pgp::mpi s; + mpi r; + mpi s; }; class Encrypted { public: - pgp::mpi g; - pgp::mpi m; + mpi g; + mpi m; }; class Key { public: - pgp::mpi p; - pgp::mpi g; - pgp::mpi y; + mpi p; + mpi g; + mpi y; /* secret mpi */ - pgp::mpi x; + mpi x; void clear_secret() diff --git a/src/lib/crypto/elgamal_ossl.cpp b/src/lib/crypto/elgamal_ossl.cpp index 60f2834b26..aa7f43d5bd 100644 --- a/src/lib/crypto/elgamal_ossl.cpp +++ b/src/lib/crypto/elgamal_ossl.cpp @@ -306,8 +306,8 @@ Key::decrypt_pkcs1(rnp::RNG &rng, rnp::secure_bytes &out, const Encrypted &in) c return RNP_ERROR_GENERIC; /* LCOV_EXCL_END */ } - pgp::mpi mm = {}; - bool res = m.mpi(mm); + mpi mm = {}; + bool res = m.mpi(mm); assert(res); if (!res) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE diff --git a/src/lib/crypto/signatures.cpp b/src/lib/crypto/signatures.cpp index 252d39cf3d..be89dc6d39 100644 --- a/src/lib/crypto/signatures.cpp +++ b/src/lib/crypto/signatures.cpp @@ -25,6 +25,7 @@ */ #include +#include #include "crypto/signatures.h" #include "librepgp/stream-packet.h" #include "librepgp/stream-sig.h" @@ -134,16 +135,17 @@ signature_calculate(pgp_signature_t & sig, /* Copy left 16 bits to signature */ std::copy(hval.begin(), hval.begin() + 2, sig.lbits.begin()); - pgp_signature_material_t material = {}; /* Some algos require used hash algorithm for signing */ - material.halg = sig.halg; + auto material = pgp::SigMaterial::create(sig.palg, sig.halg); + if (!material) { + throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); + } /* Sign */ - auto ret = seckey.sign(ctx, material, hval); - + auto ret = seckey.sign(ctx, *material, hval); if (ret) { throw rnp::rnp_exception(ret); } - sig.write_material(material); + sig.write_material(*material); } rnp_result_t @@ -187,10 +189,8 @@ signature_validate(const pgp_signature_t & sig, } /* validate signature */ - pgp_signature_material_t material = {}; /* 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); + auto material = sig.parse_material(); + assert(material); + return key.verify(ctx, *material, hval); } diff --git a/src/lib/enc_material.cpp b/src/lib/enc_material.cpp new file mode 100644 index 0000000000..1730265053 --- /dev/null +++ b/src/lib/enc_material.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "enc_material.hpp" +#include "librepgp/stream-packet.h" +#include "logging.h" + +namespace pgp { + +std::unique_ptr +EncMaterial::create(pgp_pubkey_alg_t alg) +{ + switch (alg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_ENCRYPT_ONLY: + return std::unique_ptr(new RSAEncMaterial()); + case PGP_PKA_ELGAMAL: + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return std::unique_ptr(new EGEncMaterial()); + case PGP_PKA_SM2: + return std::unique_ptr(new SM2EncMaterial()); + case PGP_PKA_ECDH: + return std::unique_ptr(new ECDHEncMaterial()); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_X25519: + return std::unique_ptr(new X25519EncMaterial()); +#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 std::unique_ptr(new MlkemEcdhEncMaterial(alg)); +#endif + default: + RNP_LOG("unknown pk alg %d", alg); + return nullptr; + } +} + +bool +RSAEncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(enc.m); +} + +void +RSAEncMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(enc.m); +} + +bool +EGEncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(enc.g) && pkt.get(enc.m); +} + +void +EGEncMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(enc.g); + pkt.add(enc.m); +} + +bool +SM2EncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(enc.m); +} + +void +SM2EncMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(enc.m); +} + +bool +ECDHEncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + uint8_t sz = 0; + /* ECDH ephemeral point and m size */ + if (!pkt.get(enc.p) || !pkt.get(sz)) { + return false; + } + /* ECDH m */ + if (sz > ECDH_WRAPPED_KEY_SIZE) { + RNP_LOG("wrong ecdh m len"); + return false; + } + enc.m.resize(sz); + if (!pkt.get(enc.m.data(), sz)) { + return false; + } + return true; +} + +void +ECDHEncMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(enc.p); + pkt.add_byte((uint8_t) enc.m.size()); + pkt.add(enc.m); +} + +#if defined(ENABLE_CRYPTO_REFRESH) +bool +X25519EncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + enc.eph_key.resize(32); + if (!pkt.get(enc.eph_key.data(), enc.eph_key.size())) { + RNP_LOG("failed to parse X25519 PKESK (eph. pubkey)"); + return false; + } + uint8_t sess_len = 0; + if (!pkt.get(sess_len) || !sess_len) { + RNP_LOG("failed to parse X25519 PKESK (enc sesskey length)"); + return false; + } + /* get plaintext salg if PKESKv3 */ + if (version == PGP_PKSK_V3) { + uint8_t bt = 0; + if (!pkt.get(bt)) { + RNP_LOG("failed to get salg"); + return RNP_ERROR_BAD_FORMAT; + } + sess_len--; + salg = (pgp_symm_alg_t) bt; + } + enc.enc_sess_key.resize(sess_len); + if (!pkt.get(enc.enc_sess_key.data(), sess_len)) { + RNP_LOG("failed to parse X25519 PKESK (enc sesskey)"); + return false; + } + return true; +} + +void +X25519EncMaterial::write(pgp_packet_body_t &pkt) const +{ + uint8_t inc = ((version == PGP_PKSK_V3) ? 1 : 0); + pkt.add(enc.eph_key); + pkt.add_byte(static_cast(enc.enc_sess_key.size() + inc)); + if (version == PGP_PKSK_V3) { + pkt.add_byte(salg); /* added as plaintext */ + } + pkt.add(enc.enc_sess_key); +} +#endif + +#if defined(ENABLE_PQC) +bool +MlkemEcdhEncMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + /* Calculate ciphertext size */ + auto csize = + kyber_ciphertext_size(pgp_kyber_ecdh_composite_key_t::pk_alg_to_kyber_id(alg_)) + + pgp_kyber_ecdh_composite_key_t::ecdh_curve_ephemeral_size( + pgp_kyber_ecdh_composite_key_t::pk_alg_to_curve_id(alg_)); + enc.composite_ciphertext.resize(csize); + /* Read composite ciphertext */ + if (!pkt.get(enc.composite_ciphertext.data(), enc.composite_ciphertext.size())) { + RNP_LOG("failed to get kyber-ecdh ciphertext"); + return false; + } + uint8_t wrapped_key_len = 0; + if (!pkt.get(wrapped_key_len) || !wrapped_key_len) { + RNP_LOG("failed to get kyber-ecdh wrapped session key length"); + return false; + } + /* get plaintext salg if PKESKv3 */ + if (version == PGP_PKSK_V3) { + uint8_t balg = 0; + if (!pkt.get(balg)) { + RNP_LOG("failed to get salg"); + return RNP_ERROR_BAD_FORMAT; + } + salg = (pgp_symm_alg_t) balg; + wrapped_key_len--; + } + enc.wrapped_sesskey.resize(wrapped_key_len); + if (!pkt.get(enc.wrapped_sesskey.data(), enc.wrapped_sesskey.size())) { + RNP_LOG("failed to get kyber-ecdh session key"); + return false; + } + return true; +} + +void +MlkemEcdhEncMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(enc.composite_ciphertext); + uint8_t inc = ((version == PGP_PKSK_V3) ? 1 : 0); + pkt.add_byte(static_cast(enc.wrapped_sesskey.size()) + inc); + if (version == PGP_PKSK_V3) { + pkt.add_byte(salg); /* added as plaintext */ + } + pkt.add(enc.wrapped_sesskey); +} +#endif + +} // namespace pgp diff --git a/src/lib/enc_material.hpp b/src/lib/enc_material.hpp new file mode 100644 index 0000000000..7caab1eca4 --- /dev/null +++ b/src/lib/enc_material.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_ENC_MATERIAL_HPP_ +#define RNP_ENC_MATERIAL_HPP_ + +#include "types.h" +#include "defaults.h" + +typedef struct pgp_packet_body_t pgp_packet_body_t; + +namespace pgp { + +class EncMaterial { + public: +#if defined(ENABLE_CRYPTO_REFRESH) + pgp_pkesk_version_t version = PGP_PKSK_V3; + pgp_symm_alg_t salg = PGP_SA_UNKNOWN; +#endif + virtual ~EncMaterial(){}; + + virtual bool parse(pgp_packet_body_t &pkt) noexcept = 0; + virtual void write(pgp_packet_body_t &pkt) const = 0; + + static std::unique_ptr create(pgp_pubkey_alg_t alg); +}; + +class RSAEncMaterial : public EncMaterial { + public: + rsa::Encrypted enc; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class EGEncMaterial : public EncMaterial { + public: + eg::Encrypted enc; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class SM2EncMaterial : public EncMaterial { + public: + sm2::Encrypted enc; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class ECDHEncMaterial : public EncMaterial { + public: + ecdh::Encrypted enc; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +#if defined(ENABLE_CRYPTO_REFRESH) +class X25519EncMaterial : public EncMaterial { + public: + pgp_x25519_encrypted_t enc; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; +#endif + +#if defined(ENABLE_PQC) +class MlkemEcdhEncMaterial : public EncMaterial { + pgp_pubkey_alg_t alg_; + + public: + pgp_kyber_ecdh_encrypted_t enc; + + MlkemEcdhEncMaterial(pgp_pubkey_alg_t alg) : alg_(alg) + { + } + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; +#endif + +} // namespace pgp + +#endif // RNP_ENC_MATERIAL_HPP_ diff --git a/src/lib/key_material.cpp b/src/lib/key_material.cpp index b5cfc7aafb..a7a51870e6 100644 --- a/src/lib/key_material.cpp +++ b/src/lib/key_material.cpp @@ -260,12 +260,6 @@ KeyMaterial::valid() const return validity_.validated && validity_.valid; } -bool -KeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - return alg_ == value.alg_; -} - void KeyMaterial::validate(rnp::SecurityContext &ctx, bool reset) { @@ -322,33 +316,33 @@ KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -KeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +KeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { return RNP_ERROR_NOT_SUPPORTED; } rnp_result_t -KeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +KeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { return RNP_ERROR_NOT_SUPPORTED; } rnp_result_t -KeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +KeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { return RNP_ERROR_NOT_SUPPORTED; } rnp_result_t -KeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +KeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { return RNP_ERROR_NOT_SUPPORTED; } @@ -495,16 +489,6 @@ RSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !key_.validate(ctx.rng, secret_); } -bool -RSAKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return (key->key_.n == key_.n) && (key->key_.e == key_.e); -} - void RSAKeyMaterial::clear_secret() noexcept { @@ -562,39 +546,55 @@ RSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -RSAKeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +RSAKeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { - return key_.encrypt_pkcs1(ctx.rng, out.rsa, data); + auto rsa = dynamic_cast(&out); + if (!rsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.encrypt_pkcs1(ctx.rng, rsa->enc, data); } rnp_result_t -RSAKeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +RSAKeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { - return key_.decrypt_pkcs1(ctx.rng, out, in.rsa); + auto rsa = dynamic_cast(&in); + if (!rsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.decrypt_pkcs1(ctx.rng, out, rsa->enc); } rnp_result_t -RSAKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +RSAKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { if (alg() == PGP_PKA_RSA_ENCRYPT_ONLY) { RNP_LOG("RSA encrypt-only signature considered as invalid."); return RNP_ERROR_SIGNATURE_INVALID; } - return key_.verify_pkcs1(sig.rsa, sig.halg, hash); + auto rsa = dynamic_cast(&sig); + if (!rsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.verify_pkcs1(rsa->sig, rsa->halg, hash); } rnp_result_t -RSAKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +RSAKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return key_.sign_pkcs1(ctx.rng, sig.rsa, sig.halg, hash); + auto rsa = dynamic_cast(&sig); + if (!rsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.sign_pkcs1(ctx.rng, rsa->sig, rsa->halg, hash); } void @@ -670,17 +670,6 @@ DSAKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !key_.validate(ctx.rng, secret_); } -bool -DSAKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return (key->key_.p == key_.p) && (key->key_.q == key_.q) && (key->key_.g == key_.g) && - (key->key_.y == key_.y); -} - void DSAKeyMaterial::clear_secret() noexcept { @@ -733,19 +722,27 @@ DSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -DSAKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +DSAKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { - return key_.verify(sig.dsa, hash); + auto dsa = dynamic_cast(&sig); + if (!dsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.verify(dsa->sig, hash); } rnp_result_t -DSAKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +DSAKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return key_.sign(ctx.rng, sig.dsa, hash); + auto dsa = dynamic_cast(&sig); + if (!dsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.sign(ctx.rng, dsa->sig, hash); } pgp_hash_alg_t @@ -827,16 +824,6 @@ EGKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return key_.validate(secret_); } -bool -EGKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return (key->key_.p == key_.p) && (key->key_.g == key_.g) && (key->key_.y == key_.y); -} - void EGKeyMaterial::clear_secret() noexcept { @@ -892,25 +879,33 @@ EGKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -EGKeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +EGKeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { - return key_.encrypt_pkcs1(ctx.rng, out.eg, data); + auto eg = dynamic_cast(&out); + if (!eg) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.encrypt_pkcs1(ctx.rng, eg->enc, data); } rnp_result_t -EGKeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +EGKeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { - return key_.decrypt_pkcs1(ctx.rng, out, in.eg); + auto eg = dynamic_cast(&in); + if (!eg) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.decrypt_pkcs1(ctx.rng, out, eg->enc); } rnp_result_t -EGKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +EGKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { RNP_LOG("ElGamal signatures are considered as invalid."); return RNP_ERROR_SIGNATURE_INVALID; @@ -959,16 +954,6 @@ ECKeyMaterial::grip_update(rnp::Hash &hash) const grip_hash_ec(hash, key_); } -bool -ECKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return (key->key_.curve == key_.curve) && (key->key_.p == key_.p); -} - void ECKeyMaterial::clear_secret() noexcept { @@ -1096,27 +1081,35 @@ ECDSAKeyMaterial::clone() } rnp_result_t -ECDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +ECDSAKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { if (!ec::Curve::is_supported(key_.curve)) { RNP_LOG("Curve %d is not supported.", key_.curve); return RNP_ERROR_NOT_SUPPORTED; } - return ecdsa::verify(sig.ecc, sig.halg, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ecdsa::verify(ec->sig, ec->halg, hash, key_); } rnp_result_t -ECDSAKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +ECDSAKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { auto ret = check_curve(hash.size()); if (ret) { return ret; } - return ecdsa::sign(ctx.rng, sig.ecc, sig.halg, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ecdsa::sign(ctx.rng, ec->sig, ec->halg, hash, key_); } pgp_hash_alg_t @@ -1201,21 +1194,25 @@ ECDHKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -ECDHKeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +ECDHKeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { if (!ec::Curve::is_supported(key_.curve)) { RNP_LOG("ECDH encrypt: curve %d is not supported.", key_.curve); return RNP_ERROR_NOT_SUPPORTED; } - return ecdh::encrypt_pkcs5(ctx.rng, out.ecdh, data, key_, out.ecdh.fp); + auto ecdh = dynamic_cast(&out); + if (!ecdh) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ecdh::encrypt_pkcs5(ctx.rng, ecdh->enc, data, key_); } rnp_result_t -ECDHKeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +ECDHKeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { if (!ec::Curve::is_supported(key_.curve)) { RNP_LOG("ECDH decrypt: curve %d is not supported.", key_.curve); @@ -1224,7 +1221,11 @@ ECDHKeyMaterial::decrypt(rnp::SecurityContext & ctx, if ((key_.curve == PGP_CURVE_25519) && !x25519_bits_tweaked()) { RNP_LOG("Warning: bits of 25519 secret key are not tweaked."); } - return ecdh::decrypt_pkcs5(out, in.ecdh, key_, in.ecdh.fp); + auto ecdh = dynamic_cast(&in); + if (!ecdh) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ecdh::decrypt_pkcs5(out, ecdh->enc, key_); } pgp_hash_alg_t @@ -1274,26 +1275,34 @@ EDDSAKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -EDDSAKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +EDDSAKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { - return eddsa::verify(sig.ecc, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return eddsa::verify(ec->sig, hash, key_); } rnp_result_t -EDDSAKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +EDDSAKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return eddsa::sign(ctx.rng, sig.ecc, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return eddsa::sign(ctx.rng, ec->sig, hash, key_); } bool SM2KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) { #if defined(ENABLE_SM2) - return !pgp::sm2::validate_key(ctx.rng, key_, secret_); + return !sm2::validate_key(ctx.rng, key_, secret_); #else RNP_LOG("SM2 key validation is not available."); return false; @@ -1307,12 +1316,16 @@ SM2KeyMaterial::clone() } rnp_result_t -SM2KeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +SM2KeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { #if defined(ENABLE_SM2) - return pgp::sm2::encrypt(ctx.rng, out.sm2, data, PGP_HASH_SM3, key_); + auto sm2 = dynamic_cast(&out); + if (!sm2) { + return RNP_ERROR_BAD_PARAMETERS; + } + return sm2::encrypt(ctx.rng, sm2->enc, data, PGP_HASH_SM3, key_); #else RNP_LOG("sm2_encrypt is not available"); return RNP_ERROR_NOT_IMPLEMENTED; @@ -1320,12 +1333,16 @@ SM2KeyMaterial::encrypt(rnp::SecurityContext & ctx, } rnp_result_t -SM2KeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +SM2KeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { #if defined(ENABLE_SM2) - return pgp::sm2::decrypt(out, in.sm2, key_); + auto sm2 = dynamic_cast(&in); + if (!sm2) { + return RNP_ERROR_BAD_PARAMETERS; + } + return sm2::decrypt(out, sm2->enc, key_); #else RNP_LOG("SM2 decryption is not available."); return RNP_ERROR_NOT_IMPLEMENTED; @@ -1333,12 +1350,16 @@ SM2KeyMaterial::decrypt(rnp::SecurityContext & ctx, } rnp_result_t -SM2KeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +SM2KeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { #if defined(ENABLE_SM2) - return pgp::sm2::verify(sig.ecc, sig.halg, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return sm2::verify(ec->sig, ec->halg, hash, key_); #else RNP_LOG("SM2 verification is not available."); return RNP_ERROR_NOT_IMPLEMENTED; @@ -1346,16 +1367,20 @@ SM2KeyMaterial::verify(const rnp::SecurityContext & ctx, } rnp_result_t -SM2KeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +SM2KeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { #if defined(ENABLE_SM2) auto ret = check_curve(hash.size()); if (ret) { return ret; } - return pgp::sm2::sign(ctx.rng, sig.ecc, sig.halg, hash, key_); + auto ec = dynamic_cast(&sig); + if (!ec) { + return RNP_ERROR_BAD_PARAMETERS; + } + return sm2::sign(ctx.rng, ec->sig, ec->halg, hash, key_); #else RNP_LOG("SM2 signing is not available."); return RNP_ERROR_NOT_IMPLEMENTED; @@ -1366,7 +1391,7 @@ void SM2KeyMaterial::compute_za(rnp::Hash &hash) const { #if defined(ENABLE_SM2) - auto res = pgp::sm2::compute_za(key_, hash); + auto res = sm2::compute_za(key_, hash); if (res) { RNP_LOG("failed to compute SM2 ZA field"); throw rnp::rnp_exception(res); @@ -1397,16 +1422,6 @@ Ed25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !ed25519_validate_key_native(&ctx.rng, &key_, secret_); } -bool -Ed25519KeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return key->key_.pub == key_.pub; -} - void Ed25519KeyMaterial::clear_secret() noexcept { @@ -1418,7 +1433,7 @@ bool Ed25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept { secret_ = false; - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_ED25519); + auto ec_desc = ec::Curve::get(PGP_CURVE_ED25519); std::vector buf(ec_desc->bytes()); if (!pkt.get(buf.data(), buf.size())) { RNP_LOG("failed to parse Ed25519 public key data"); @@ -1431,7 +1446,7 @@ Ed25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept bool Ed25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept { - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_ED25519); + auto ec_desc = ec::Curve::get(PGP_CURVE_ED25519); std::vector buf(ec_desc->bytes()); if (!pkt.get(buf.data(), buf.size())) { RNP_LOG("failed to parse Ed25519 secret key data"); @@ -1465,19 +1480,28 @@ Ed25519KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -Ed25519KeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +Ed25519KeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { - return ed25519_verify_native(sig.ed25519.sig, key_.pub, hash.data(), hash.size()); + auto ed25519 = dynamic_cast(&sig); + if (!ed25519) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ed25519_verify_native(ed25519->sig.sig, key_.pub, hash.data(), hash.size()); } rnp_result_t -Ed25519KeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +Ed25519KeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return ed25519_sign_native(&ctx.rng, sig.ed25519.sig, key_.priv, hash.data(), hash.size()); + auto ed25519 = dynamic_cast(&sig); + if (!ed25519) { + return RNP_ERROR_BAD_PARAMETERS; + } + return ed25519_sign_native( + &ctx.rng, ed25519->sig.sig, key_.priv, hash.data(), hash.size()); } size_t @@ -1523,16 +1547,6 @@ X25519KeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !x25519_validate_key_native(&ctx.rng, &key_, secret_); } -bool -X25519KeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return key->key_.pub == key_.pub; -} - void X25519KeyMaterial::clear_secret() noexcept { @@ -1544,7 +1558,7 @@ bool X25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept { secret_ = false; - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_25519); + auto ec_desc = ec::Curve::get(PGP_CURVE_25519); std::vector buf(ec_desc->bytes()); if (!pkt.get(buf.data(), buf.size())) { RNP_LOG("failed to parse X25519 public key data"); @@ -1557,7 +1571,7 @@ X25519KeyMaterial::parse(pgp_packet_body_t &pkt) noexcept bool X25519KeyMaterial::parse_secret(pgp_packet_body_t &pkt) noexcept { - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_25519); + auto ec_desc = ec::Curve::get(PGP_CURVE_25519); std::vector buf(ec_desc->bytes()); if (!pkt.get(buf.data(), buf.size())) { RNP_LOG("failed to parse X25519 secret key data"); @@ -1591,21 +1605,29 @@ X25519KeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -X25519KeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +X25519KeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { - return x25519_native_encrypt(&ctx.rng, key_.pub, data.data(), data.size(), &out.x25519); + auto x25519 = dynamic_cast(&out); + if (!x25519) { + return RNP_ERROR_BAD_PARAMETERS; + } + return x25519_native_encrypt(&ctx.rng, key_.pub, data.data(), data.size(), &x25519->enc); } rnp_result_t -X25519KeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +X25519KeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { + auto x25519 = dynamic_cast(&in); + if (!x25519) { + return RNP_ERROR_BAD_PARAMETERS; + } out.resize(PGP_MPINT_SIZE); size_t out_size = out.size(); - auto ret = x25519_native_decrypt(&ctx.rng, key_, &in.x25519, out.data(), &out_size); + auto ret = x25519_native_decrypt(&ctx.rng, key_, &x25519->enc, out.data(), &out_size); if (!ret) { out.resize(out_size); } @@ -1656,16 +1678,6 @@ MlkemEcdhKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !kyber_ecdh_validate_key(&ctx.rng, &key_, secret_); } -bool -MlkemEcdhKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return key->key_.pub == key_.pub; -} - void MlkemEcdhKeyMaterial::clear_secret() noexcept { @@ -1722,21 +1734,29 @@ MlkemEcdhKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶m } rnp_result_t -MlkemEcdhKeyMaterial::encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const +MlkemEcdhKeyMaterial::encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const { - return key_.pub.encrypt(&ctx.rng, &out.kyber_ecdh, data.data(), data.size()); + auto mlkem = dynamic_cast(&out); + if (!mlkem) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.pub.encrypt(&ctx.rng, &mlkem->enc, data.data(), data.size()); } rnp_result_t -MlkemEcdhKeyMaterial::decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const +MlkemEcdhKeyMaterial::decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const { + auto mlkem = dynamic_cast(&in); + if (!mlkem) { + return RNP_ERROR_BAD_PARAMETERS; + } out.resize(PGP_MPINT_SIZE); size_t out_size = out.size(); - auto ret = key_.priv.decrypt(&ctx.rng, out.data(), &out_size, &in.kyber_ecdh); + auto ret = key_.priv.decrypt(&ctx.rng, out.data(), &out_size, &mlkem->enc); if (!ret) { out.resize(out_size); } @@ -1779,16 +1799,6 @@ DilithiumEccKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset return !dilithium_exdsa_validate_key(&ctx.rng, &key_, secret_); } -bool -DilithiumEccKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return key->key_.pub == key_.pub; -} - void DilithiumEccKeyMaterial::clear_secret() noexcept { @@ -1845,19 +1855,28 @@ DilithiumEccKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams &pa } rnp_result_t -DilithiumEccKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +DilithiumEccKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { - return key_.pub.verify(&sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); + auto dilithium = dynamic_cast(&sig); + if (!dilithium) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.pub.verify(&dilithium->sig, dilithium->halg, hash.data(), hash.size()); } rnp_result_t -DilithiumEccKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +DilithiumEccKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return key_.priv.sign(&ctx.rng, &sig.dilithium_exdsa, sig.halg, hash.data(), hash.size()); + auto dilithium = dynamic_cast(&sig); + if (!dilithium) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.priv.sign( + &ctx.rng, &dilithium->sig, dilithium->halg, hash.data(), hash.size()); } pgp_hash_alg_t @@ -1902,16 +1921,6 @@ SlhdsaKeyMaterial::validate_material(rnp::SecurityContext &ctx, bool reset) return !sphincsplus_validate_key(&ctx.rng, &key_, secret_); } -bool -SlhdsaKeyMaterial::equals(const KeyMaterial &value) const noexcept -{ - auto key = dynamic_cast(&value); - if (!key || !KeyMaterial::equals(value)) { - return false; - } - return key->key_.pub == key_.pub; -} - void SlhdsaKeyMaterial::clear_secret() noexcept { @@ -1988,19 +1997,27 @@ SlhdsaKeyMaterial::generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) } rnp_result_t -SlhdsaKeyMaterial::verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +SlhdsaKeyMaterial::verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const { - return key_.pub.verify(&sig.sphincsplus, hash.data(), hash.size()); + auto slhdsa = dynamic_cast(&sig); + if (!slhdsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.pub.verify(&slhdsa->sig, hash.data(), hash.size()); } rnp_result_t -SlhdsaKeyMaterial::sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const +SlhdsaKeyMaterial::sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const { - return key_.priv.sign(&ctx.rng, &sig.sphincsplus, hash.data(), hash.size()); + auto slhdsa = dynamic_cast(&sig); + if (!slhdsa) { + return RNP_ERROR_BAD_PARAMETERS; + } + return key_.priv.sign(&ctx.rng, &slhdsa->sig, hash.data(), hash.size()); } pgp_hash_alg_t diff --git a/src/lib/key_material.hpp b/src/lib/key_material.hpp index 67628e4b3f..a9357808cd 100644 --- a/src/lib/key_material.hpp +++ b/src/lib/key_material.hpp @@ -29,10 +29,10 @@ #include "types.h" #include "defaults.h" +#include "enc_material.hpp" +#include "sig_material.hpp" -typedef struct pgp_packet_body_t pgp_packet_body_t; -typedef struct pgp_encrypted_material_t pgp_encrypted_material_t; -typedef struct pgp_signature_material_t pgp_signature_material_t; +typedef struct pgp_packet_body_t pgp_packet_body_t; namespace pgp { @@ -200,25 +200,24 @@ class KeyMaterial { void set_validity(const pgp_validity_t &val); void reset_validity(); bool valid() const; - virtual bool equals(const KeyMaterial &value) const noexcept; virtual void clear_secret() noexcept; virtual bool parse(pgp_packet_body_t &pkt) noexcept = 0; virtual bool parse_secret(pgp_packet_body_t &pkt) noexcept = 0; virtual void write(pgp_packet_body_t &pkt) const = 0; virtual void write_secret(pgp_packet_body_t &pkt) const = 0; virtual bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms); - virtual rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const; - virtual rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const; - virtual rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const; - virtual rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const; + virtual rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const; + virtual rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const; + virtual rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const; + virtual rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const; /* Pick up hash algorithm, used for signing, to be compatible with key material. */ virtual pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const; @@ -247,25 +246,24 @@ class RSAKeyMaterial : public KeyMaterial { : KeyMaterial(kalg, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; void set_secret(const mpi &d, const mpi &p, const mpi &q, const mpi &u); size_t bits() const noexcept override; @@ -291,19 +289,18 @@ class DSAKeyMaterial : public KeyMaterial { : KeyMaterial(PGP_PKA_DSA, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; void set_secret(const mpi &x); size_t bits() const noexcept override; @@ -329,22 +326,21 @@ class EGKeyMaterial : public KeyMaterial { : KeyMaterial(kalg, secret), key_(key){}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; void set_secret(const mpi &x); size_t bits() const noexcept override; @@ -367,7 +363,6 @@ class ECKeyMaterial : public KeyMaterial { ECKeyMaterial(pgp_pubkey_alg_t kalg, const ec::Key &key, bool secret = false) : KeyMaterial(kalg, secret), key_(key){}; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; @@ -392,12 +387,12 @@ class ECDSAKeyMaterial : public ECKeyMaterial { : ECKeyMaterial(PGP_PKA_ECDSA, key, secret){}; std::unique_ptr clone() override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; }; @@ -414,12 +409,12 @@ class ECDHKeyMaterial : public ECKeyMaterial { bool parse(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; pgp_hash_alg_t kdf_hash_alg() const noexcept; pgp_symm_alg_t key_wrap_alg() const noexcept; @@ -438,12 +433,12 @@ class EDDSAKeyMaterial : public ECKeyMaterial { std::unique_ptr clone() override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; }; class SM2KeyMaterial : public ECKeyMaterial { @@ -456,18 +451,18 @@ class SM2KeyMaterial : public ECKeyMaterial { : ECKeyMaterial(PGP_PKA_SM2, key, secret){}; std::unique_ptr clone() override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; void compute_za(rnp::Hash &hash) const; }; @@ -483,19 +478,18 @@ class Ed25519KeyMaterial : public KeyMaterial { Ed25519KeyMaterial() : KeyMaterial(PGP_PKA_ED25519), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; size_t bits() const noexcept override; pgp_curve_t curve() const noexcept override; @@ -514,19 +508,18 @@ class X25519KeyMaterial : public KeyMaterial { X25519KeyMaterial() : KeyMaterial(PGP_PKA_X25519), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; size_t bits() const noexcept override; pgp_curve_t curve() const noexcept override; @@ -547,19 +540,18 @@ class MlkemEcdhKeyMaterial : public KeyMaterial { MlkemEcdhKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t encrypt(rnp::SecurityContext & ctx, - pgp_encrypted_material_t &out, - const rnp::secure_bytes & data) const override; - rnp_result_t decrypt(rnp::SecurityContext & ctx, - rnp::secure_bytes & out, - const pgp_encrypted_material_t &in) const override; + rnp_result_t encrypt(rnp::SecurityContext & ctx, + EncMaterial & out, + const rnp::secure_bytes &data) const override; + rnp_result_t decrypt(rnp::SecurityContext &ctx, + rnp::secure_bytes & out, + const EncMaterial & in) const override; size_t bits() const noexcept override; const pgp_kyber_ecdh_composite_public_key_t & pub() const noexcept; @@ -579,19 +571,18 @@ class DilithiumEccKeyMaterial : public KeyMaterial { /** @brief Check two key material for equality. Only public part is checked, so this may be * called on public/secret key material */ - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; size_t bits() const noexcept override; @@ -610,19 +601,18 @@ class SlhdsaKeyMaterial : public KeyMaterial { SlhdsaKeyMaterial(pgp_pubkey_alg_t kalg) : KeyMaterial(kalg), key_{} {}; std::unique_ptr clone() override; - bool equals(const KeyMaterial &value) const noexcept override; void clear_secret() noexcept override; bool parse(pgp_packet_body_t &pkt) noexcept override; bool parse_secret(pgp_packet_body_t &pkt) noexcept override; void write(pgp_packet_body_t &pkt) const override; void write_secret(pgp_packet_body_t &pkt) const override; bool generate(rnp::SecurityContext &ctx, const KeyParams ¶ms) override; - rnp_result_t verify(const rnp::SecurityContext & ctx, - const pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; - rnp_result_t sign(rnp::SecurityContext & ctx, - pgp_signature_material_t &sig, - const rnp::secure_bytes & hash) const override; + rnp_result_t verify(const rnp::SecurityContext &ctx, + const SigMaterial & sig, + const rnp::secure_bytes & hash) const override; + rnp_result_t sign(rnp::SecurityContext & ctx, + SigMaterial & sig, + const rnp::secure_bytes &hash) const override; pgp_hash_alg_t adjust_hash(pgp_hash_alg_t hash) const override; bool sig_hash_allowed(pgp_hash_alg_t hash) const override; size_t bits() const noexcept override; diff --git a/src/lib/logging.h b/src/lib/logging.h index 5f5f46835a..3a0a2fa4ef 100644 --- a/src/lib/logging.h +++ b/src/lib/logging.h @@ -58,7 +58,8 @@ class LogStop { }; } // namespace rnp -#define __SOURCE_PATH_FILE__ (__FILE__ + SOURCE_PATH_SIZE + 3 /* remove "src" */) +/* remove "src" */ +#define __SOURCE_PATH_FILE__ (&(__FILE__[SOURCE_PATH_SIZE + 3])) #define RNP_LOG_FD(fd, ...) \ do { \ diff --git a/src/lib/rnp.cpp b/src/lib/rnp.cpp index fe75f95737..cc245bb364 100644 --- a/src/lib/rnp.cpp +++ b/src/lib/rnp.cpp @@ -8174,29 +8174,32 @@ add_json_mpis(json_object *jso, pgp_key_t *key, bool secret = false) static rnp_result_t add_json_sig_mpis(json_object *jso, const pgp_signature_t *sig) { - pgp_signature_material_t material = {}; - try { - if (!sig->parse_material(material)) { - return RNP_ERROR_BAD_PARAMETERS; - } - } catch (const std::exception &e) { - RNP_LOG("%s", e.what()); - return RNP_ERROR_OUT_OF_MEMORY; + auto material = sig->parse_material(); + if (!material) { + return RNP_ERROR_NOT_SUPPORTED; } switch (sig->palg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - return add_json_mpis(jso, "sig", &material.rsa.s, NULL); + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + return add_json_mpis(jso, "sig", &rsa.sig.s, NULL); + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - return add_json_mpis(jso, "r", &material.eg.r, "s", &material.eg.s, NULL); - case PGP_PKA_DSA: - return add_json_mpis(jso, "r", &material.dsa.r, "s", &material.dsa.s, NULL); + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + return add_json_mpis(jso, "r", &eg.sig.r, "s", &eg.sig.s, NULL); + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + return add_json_mpis(jso, "r", &dsa.sig.r, "s", &dsa.sig.s, NULL); + } case PGP_PKA_ECDSA: case PGP_PKA_EDDSA: - case PGP_PKA_SM2: - return add_json_mpis(jso, "r", &material.ecc.r, "s", &material.ecc.s, NULL); + case PGP_PKA_SM2: { + auto &ec = dynamic_cast(*material); + return add_json_mpis(jso, "r", &ec.sig.r, "s", &ec.sig.s, NULL); + } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: diff --git a/src/lib/sig_material.cpp b/src/lib/sig_material.cpp new file mode 100644 index 0000000000..8e339610e6 --- /dev/null +++ b/src/lib/sig_material.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "sig_material.hpp" +#include "librepgp/stream-packet.h" +#include "logging.h" + +namespace pgp { + +std::unique_ptr +SigMaterial::create(pgp_pubkey_alg_t palg, pgp_hash_alg_t halg) +{ + switch (palg) { + case PGP_PKA_RSA: + case PGP_PKA_RSA_SIGN_ONLY: + return std::unique_ptr(new RSASigMaterial(halg)); + case PGP_PKA_DSA: + return std::unique_ptr(new DSASigMaterial(halg)); + case PGP_PKA_EDDSA: + case PGP_PKA_ECDSA: + case PGP_PKA_SM2: + case PGP_PKA_ECDH: + return std::unique_ptr(new ECSigMaterial(halg)); + case PGP_PKA_ELGAMAL: /* we support reading it but will not validate */ + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: + return std::unique_ptr(new EGSigMaterial(halg)); +#if defined(ENABLE_CRYPTO_REFRESH) + case PGP_PKA_ED25519: { + return std::unique_ptr(new Ed25519SigMaterial(halg)); + } +#endif +#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: + return std::unique_ptr(new DilithiumSigMaterial(palg, halg)); + case PGP_PKA_SPHINCSPLUS_SHA2: + FALLTHROUGH_STATEMENT; + case PGP_PKA_SPHINCSPLUS_SHAKE: + return std::unique_ptr(new SlhdsaSigMaterial(halg)); +#endif + default: + RNP_LOG("Unknown pk algorithm : %d", (int) palg); + return nullptr; + } +} + +bool +RSASigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(sig.s); +} + +void +RSASigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(sig.s); +} + +bool +DSASigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(sig.r) && pkt.get(sig.s); +} + +void +DSASigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(sig.r); + pkt.add(sig.s); +} + +bool +EGSigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(sig.r) && pkt.get(sig.s); +} + +void +EGSigMaterial::write(pgp_packet_body_t &pkt) const +{ + /* we support writing it but will not generate */ + pkt.add(sig.r); + pkt.add(sig.s); +} + +bool +ECSigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + return pkt.get(sig.r) && pkt.get(sig.s); +} + +void +ECSigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(sig.r); + pkt.add(sig.s); +} + +#if defined(ENABLE_CRYPTO_REFRESH) +bool +Ed25519SigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_25519); + if (!pkt.get(sig.sig, 2 * ec_desc->bytes())) { + RNP_LOG("failed to parse ED25519 signature data"); + return false; + } + return true; +} + +void +Ed25519SigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(sig.sig); +} +#endif + +#if defined(ENABLE_PQC) +bool +DilithiumSigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + if (!pkt.get(sig.sig, pgp_dilithium_exdsa_signature_t::composite_signature_size(palg))) { + RNP_LOG("failed to get mldsa-ecdsa/eddsa signature"); + return false; + } + return true; +} + +void +DilithiumSigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add(sig.sig); +} + +bool +SlhdsaSigMaterial::parse(pgp_packet_body_t &pkt) noexcept +{ + uint8_t param = 0; + if (!pkt.get(param)) { + RNP_LOG("failed to parse SLH-DSA signature data"); + return false; + } + auto sig_size = sphincsplus_signature_size((sphincsplus_parameter_t) param); + if (!sig_size) { + RNP_LOG("invalid SLH-DSA param value"); + return false; + } + sig.param = (sphincsplus_parameter_t) param; + if (!pkt.get(sig.sig, sig_size)) { + RNP_LOG("failed to parse SLH-DSA signature data"); + return false; + } + return true; +} + +void +SlhdsaSigMaterial::write(pgp_packet_body_t &pkt) const +{ + pkt.add_byte((uint8_t) sig.param); + pkt.add(sig.sig); +} +#endif + +} // namespace pgp diff --git a/src/lib/sig_material.hpp b/src/lib/sig_material.hpp new file mode 100644 index 0000000000..74347277a3 --- /dev/null +++ b/src/lib/sig_material.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024 [Ribose Inc](https://www.ribose.com). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RNP_SIG_MATERIAL_HPP_ +#define RNP_SIG_MATERIAL_HPP_ + +#include "types.h" +#include "defaults.h" + +typedef struct pgp_packet_body_t pgp_packet_body_t; + +namespace pgp { + +class SigMaterial { + public: + pgp_hash_alg_t halg; + SigMaterial(pgp_hash_alg_t ahalg) : halg(ahalg){}; + virtual ~SigMaterial(){}; + + virtual bool parse(pgp_packet_body_t &pkt) noexcept = 0; + virtual void write(pgp_packet_body_t &pkt) const = 0; + + static std::unique_ptr create(pgp_pubkey_alg_t alg, pgp_hash_alg_t halg); +}; + +class RSASigMaterial : public SigMaterial { + public: + rsa::Signature sig; + RSASigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class DSASigMaterial : public SigMaterial { + public: + dsa::Signature sig; + DSASigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class EGSigMaterial : public SigMaterial { + public: + eg::Signature sig; + EGSigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class ECSigMaterial : public SigMaterial { + public: + ec::Signature sig; + ECSigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +#if defined(ENABLE_CRYPTO_REFRESH) +class Ed25519SigMaterial : public SigMaterial { + public: + pgp_ed25519_signature_t sig; + Ed25519SigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; +#endif + +#if defined(ENABLE_PQC) +class DilithiumSigMaterial : public SigMaterial { + public: + pgp_pubkey_alg_t palg; + pgp_dilithium_exdsa_signature_t sig; + + DilithiumSigMaterial(pgp_pubkey_alg_t apalg, pgp_hash_alg_t ahalg) + : SigMaterial(ahalg), palg(apalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; + +class SlhdsaSigMaterial : public SigMaterial { + public: + pgp_sphincsplus_signature_t sig; + SlhdsaSigMaterial(pgp_hash_alg_t ahalg) : SigMaterial(ahalg){}; + + bool parse(pgp_packet_body_t &pkt) noexcept override; + void write(pgp_packet_body_t &pkt) const override; +}; +#endif +} // namespace pgp + +#endif // RNP_SIG_MATERIAL_HPP_ diff --git a/src/lib/types.h b/src/lib/types.h index 0cc618a4c1..571789a0e9 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -166,44 +166,6 @@ typedef struct pgp_validity_t { void reset(); } pgp_validity_t; -/** - * Type to keep signature without any openpgp-dependent data. - */ -typedef struct pgp_signature_material_t { - union { - pgp::rsa::Signature rsa; - pgp::dsa::Signature dsa; - pgp::ec::Signature ecc; - pgp::eg::Signature eg; - }; -#if defined(ENABLE_CRYPTO_REFRESH) - pgp_ed25519_signature_t ed25519; // non-trivial type cannot be member in union -#endif -#if defined(ENABLE_PQC) - pgp_dilithium_exdsa_signature_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; - -/** - * Type to keep pk-encrypted data without any openpgp-dependent data. - */ -typedef struct pgp_encrypted_material_t { - /* Temporary: will be replaced by class */ - pgp::rsa::Encrypted rsa; - pgp::eg::Encrypted eg; - pgp::sm2::Encrypted sm2; - pgp::ecdh::Encrypted ecdh; -#if defined(ENABLE_CRYPTO_REFRESH) - pgp_x25519_encrypted_t x25519; // non-trivial type cannot be member in union -#endif -#if defined(ENABLE_PQC) - pgp_kyber_ecdh_encrypted_t kyber_ecdh; // non-trivial type cannot be member in union -#endif -} pgp_encrypted_material_t; - typedef struct pgp_s2k_t { pgp_s2k_usage_t usage{}; diff --git a/src/librepgp/stream-dump.cpp b/src/librepgp/stream-dump.cpp index c51820e2de..3a2ad60d81 100644 --- a/src/librepgp/stream-dump.cpp +++ b/src/librepgp/stream-dump.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include #else @@ -572,9 +573,9 @@ dst_hexdump(pgp_dest_t *dst, const std::vector &data) static rnp_result_t stream_dump_packets_raw(rnp_dump_ctx_t *ctx, pgp_source_t * src, pgp_dest_t * dst); -static void stream_dump_signature_pkt(rnp_dump_ctx_t * ctx, - pgp_signature_t *sig, - pgp_dest_t * dst); +static void stream_dump_signature_pkt(rnp_dump_ctx_t * ctx, + const pgp_signature_t &sig, + pgp_dest_t * dst); /* Todo: move dumper to pgp::pkt or pgp namespace */ using namespace pgp; @@ -734,7 +735,7 @@ signature_dump_subpacket(rnp_dump_ctx_t *ctx, pgp_dest_t *dst, const pkt::sigsub auto &sub = dynamic_cast(subpkt); dst_printf(dst, "%s:\n", sname); pgp_signature_t sig(*sub.signature()); - stream_dump_signature_pkt(ctx, &sig, dst); + stream_dump_signature_pkt(ctx, sig, dst); break; } case pkt::sigsub::Type::IssuerFingerprint: { @@ -757,14 +758,14 @@ signature_dump_subpacket(rnp_dump_ctx_t *ctx, pgp_dest_t *dst, const pkt::sigsub } static void -signature_dump_subpackets(rnp_dump_ctx_t * ctx, - pgp_dest_t * dst, - pgp_signature_t *sig, - bool hashed) +signature_dump_subpackets(rnp_dump_ctx_t * ctx, + pgp_dest_t * dst, + const pgp_signature_t &sig, + bool hashed) { bool empty = true; - for (auto &subpkt : sig->subpkts) { + for (auto &subpkt : sig.subpkts) { if (subpkt->hashed() != hashed) { continue; } @@ -787,20 +788,20 @@ signature_dump_subpackets(rnp_dump_ctx_t * ctx, } static void -stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t *dst) +stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, const pgp_signature_t &sig, pgp_dest_t *dst) { indent_dest_increase(dst); - dst_printf(dst, "version: %d\n", (int) sig->version); - dst_print_sig_type(dst, "type", sig->type()); - if (sig->version < PGP_V4) { - dst_print_time(dst, "creation time", sig->creation_time); - dst_print_keyid(dst, "signing key id", sig->signer); + dst_printf(dst, "version: %d\n", (int) sig.version); + dst_print_sig_type(dst, "type", sig.type()); + if (sig.version < PGP_V4) { + dst_print_time(dst, "creation time", sig.creation_time); + dst_print_keyid(dst, "signing key id", sig.signer); } - dst_print_palg(dst, NULL, sig->palg); - dst_print_halg(dst, NULL, sig->halg); + dst_print_palg(dst, NULL, sig.palg); + dst_print_halg(dst, NULL, sig.halg); - if (sig->version >= PGP_V4) { + if (sig.version >= PGP_V4) { dst_printf(dst, "hashed subpackets:\n"); indent_dest_increase(dst); signature_dump_subpackets(ctx, dst, sig, true); @@ -812,45 +813,58 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t indent_dest_decrease(dst); } - dst_print_hex(dst, "lbits", sig->lbits.data(), sig->lbits.size(), false); + dst_print_hex(dst, "lbits", sig.lbits.data(), sig.lbits.size(), false); dst_printf(dst, "signature material:\n"); indent_dest_increase(dst); - pgp_signature_material_t material = {}; - try { - sig->parse_material(material); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); + auto material = sig.parse_material(); + assert(material); + /* LCOV_EXCL_START */ + if (!material) { + indent_dest_decrease(dst); + indent_dest_decrease(dst); return; - /* LCOV_EXCL_END */ } - switch (sig->palg) { + /* LCOV_EXCL_END */ + switch (sig.palg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - dst_print_mpi(dst, "rsa s", material.rsa.s, ctx->dump_mpi); + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material); + dst_print_mpi(dst, "rsa s", rsa.sig.s, ctx->dump_mpi); break; - case PGP_PKA_DSA: - dst_print_mpi(dst, "dsa r", material.dsa.r, ctx->dump_mpi); - dst_print_mpi(dst, "dsa s", material.dsa.s, ctx->dump_mpi); + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*material); + dst_print_mpi(dst, "dsa r", dsa.sig.r, ctx->dump_mpi); + dst_print_mpi(dst, "dsa s", dsa.sig.s, ctx->dump_mpi); break; + } case PGP_PKA_EDDSA: case PGP_PKA_ECDSA: case PGP_PKA_SM2: - case PGP_PKA_ECDH: - dst_print_mpi(dst, "ecc r", material.ecc.r, ctx->dump_mpi); - dst_print_mpi(dst, "ecc s", material.ecc.s, ctx->dump_mpi); + case PGP_PKA_ECDH: { + auto &ec = dynamic_cast(*material); + dst_print_mpi(dst, "ecc r", ec.sig.r, ctx->dump_mpi); + dst_print_mpi(dst, "ecc s", ec.sig.s, ctx->dump_mpi); break; + } + /* Wasn't able to find ElGamal sig artifacts so let's ignore this for coverage */ + /* LCOV_EXCL_START */ case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst_print_mpi(dst, "eg r", material.eg.r, ctx->dump_mpi); - dst_print_mpi(dst, "eg s", material.eg.s, ctx->dump_mpi); + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material); + dst_print_mpi(dst, "eg r", eg.sig.r, ctx->dump_mpi); + dst_print_mpi(dst, "eg s", eg.sig.s, ctx->dump_mpi); break; + } + /* LCOV_EXCL_END */ #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - dst_print_vec(dst, "ed25519 sig", material.ed25519.sig, ctx->dump_mpi); + case PGP_PKA_ED25519: { + auto &ed = dynamic_cast(*material); + dst_print_vec(dst, "ed25519 sig", ed.sig.sig, ctx->dump_mpi); break; + } #endif #if defined(ENABLE_PQC) case PGP_PKA_DILITHIUM3_ED25519: @@ -862,15 +876,18 @@ stream_dump_signature_pkt(rnp_dump_ctx_t *ctx, pgp_signature_t *sig, pgp_dest_t FALLTHROUGH_STATEMENT; case PGP_PKA_DILITHIUM3_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_DILITHIUM5_BP384: - dst_print_vec( - dst, "mldsa-ecdsa/eddsa sig", material.dilithium_exdsa.sig, ctx->dump_mpi); + case PGP_PKA_DILITHIUM5_BP384: { + auto &dilithium = dynamic_cast(*material); + dst_print_vec(dst, "mldsa-ecdsa/eddsa sig", dilithium.sig.sig, ctx->dump_mpi); break; + } case PGP_PKA_SPHINCSPLUS_SHA2: FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - dst_print_vec(dst, "slhdsa sig", material.sphincsplus.sig, ctx->dump_mpi); + case PGP_PKA_SPHINCSPLUS_SHAKE: { + auto &slhdsa = dynamic_cast(*material); + dst_print_vec(dst, "slhdsa sig", slhdsa.sig.sig, ctx->dump_mpi); break; + } #endif default: dst_printf(dst, "unknown algorithm\n"); @@ -900,7 +917,7 @@ stream_dump_signature(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) indent_dest_decrease(dst); return ret; } - stream_dump_signature_pkt(ctx, &sig, dst); + stream_dump_signature_pkt(ctx, sig, dst); return ret; } @@ -1161,21 +1178,15 @@ stream_dump_userid(pgp_source_t *src, pgp_dest_t *dst) static rnp_result_t stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *dst) { - pgp_pk_sesskey_t pkey; - pgp_encrypted_material_t material; - rnp_result_t ret; - - try { - ret = pkey.parse(*src); - if (!pkey.parse_material(material)) { - ret = RNP_ERROR_BAD_FORMAT; - } - } catch (const std::exception &e) { - ret = RNP_ERROR_GENERIC; - } + pgp_pk_sesskey_t pkey; + auto ret = pkey.parse(*src); if (ret) { return ret; } + auto material = pkey.parse_material(); + if (!material) { + return RNP_ERROR_BAD_FORMAT; + } dst_printf(dst, "Public-key encrypted session key packet\n"); indent_dest_increase(dst); @@ -1197,32 +1208,40 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d switch (pkey.alg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - dst_print_mpi(dst, "rsa m", material.rsa.m, ctx->dump_mpi); + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*material).enc; + dst_print_mpi(dst, "rsa m", rsa.m, ctx->dump_mpi); break; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - dst_print_mpi(dst, "eg g", material.eg.g, ctx->dump_mpi); - dst_print_mpi(dst, "eg m", material.eg.m, ctx->dump_mpi); + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*material).enc; + dst_print_mpi(dst, "eg g", eg.g, ctx->dump_mpi); + dst_print_mpi(dst, "eg m", eg.m, ctx->dump_mpi); break; - case PGP_PKA_SM2: - dst_print_mpi(dst, "sm2 m", material.sm2.m, ctx->dump_mpi); + } + case PGP_PKA_SM2: { + auto &sm2 = dynamic_cast(*material).enc; + dst_print_mpi(dst, "sm2 m", sm2.m, ctx->dump_mpi); break; - case PGP_PKA_ECDH: - dst_print_mpi(dst, "ecdh p", material.ecdh.p, ctx->dump_mpi); + } + case PGP_PKA_ECDH: { + auto &ecdh = dynamic_cast(*material).enc; + dst_print_mpi(dst, "ecdh p", ecdh.p, ctx->dump_mpi); if (ctx->dump_mpi) { - dst_print_hex(dst, "ecdh m", material.ecdh.m.data(), material.ecdh.m.size(), true); + dst_print_hex(dst, "ecdh m", ecdh.m.data(), ecdh.m.size(), true); } else { - dst_printf(dst, "ecdh m: %zu bytes\n", material.ecdh.m.size()); + dst_printf(dst, "ecdh m: %zu bytes\n", ecdh.m.size()); } break; + } #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: - dst_print_vec( - dst, "x25519 ephemeral public key", material.x25519.eph_key, ctx->dump_mpi); - dst_print_vec( - dst, "x25519 encrypted session key", material.x25519.enc_sess_key, ctx->dump_mpi); + case PGP_PKA_X25519: { + auto &x25519 = dynamic_cast(*material).enc; + dst_print_vec(dst, "x25519 ephemeral public key", x25519.eph_key, ctx->dump_mpi); + dst_print_vec(dst, "x25519 encrypted session key", x25519.enc_sess_key, ctx->dump_mpi); break; + } #endif #if defined(ENABLE_PQC) case PGP_PKA_KYBER768_X25519: @@ -1234,16 +1253,14 @@ stream_dump_pk_session_key(rnp_dump_ctx_t *ctx, pgp_source_t *src, pgp_dest_t *d FALLTHROUGH_STATEMENT; case PGP_PKA_KYBER768_BP256: FALLTHROUGH_STATEMENT; - case PGP_PKA_KYBER1024_BP384: - dst_print_vec(dst, - "mlkem-ecdh composite ciphertext", - material.kyber_ecdh.composite_ciphertext, - ctx->dump_mpi); - dst_print_vec(dst, - "mlkem-ecdh wrapped session key", - material.kyber_ecdh.wrapped_sesskey, - ctx->dump_mpi); + case PGP_PKA_KYBER1024_BP384: { + auto &mlkem = dynamic_cast(*material).enc; + dst_print_vec( + dst, "mlkem-ecdh composite ciphertext", mlkem.composite_ciphertext, ctx->dump_mpi); + dst_print_vec( + dst, "mlkem-ecdh wrapped session key", mlkem.wrapped_sesskey, ctx->dump_mpi); break; + } #endif default: dst_printf(dst, "unknown public key algorithm\n"); @@ -1776,7 +1793,7 @@ obj_add_s2k_json(json_object *obj, pgp_s2k_t *s2k) } static rnp_result_t stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, - const pgp_signature_t *sig, + const pgp_signature_t &sig, json_object * pkt); static bool @@ -1909,10 +1926,10 @@ signature_dump_subpacket_json(rnp_dump_ctx_t * ctx, case pkt::sigsub::Type::EmbeddedSignature: { auto & sub = dynamic_cast(subpkt); json_object *sig = json_object_new_object(); - if (!sig || !json_add(obj, "signature", sig)) { + if (!sub.signature() || !sig || !json_add(obj, "signature", sig)) { return false; // LCOV_EXCL_LINE } - return !stream_dump_signature_pkt_json(ctx, sub.signature(), sig); + return !stream_dump_signature_pkt_json(ctx, *sub.signature(), sig); } case pkt::sigsub::Type::IssuerFingerprint: { auto &sub = dynamic_cast(subpkt); @@ -1939,7 +1956,7 @@ signature_dump_subpacket_json(rnp_dump_ctx_t * ctx, } static json_object * -signature_dump_subpackets_json(rnp_dump_ctx_t *ctx, const pgp_signature_t *sig) +signature_dump_subpackets_json(rnp_dump_ctx_t *ctx, const pgp_signature_t &sig) { json_object *res = json_object_new_array(); if (!res) { @@ -1947,7 +1964,7 @@ signature_dump_subpackets_json(rnp_dump_ctx_t *ctx, const pgp_signature_t *sig) } rnp::JSONObject reswrap(res); - for (auto &subpkt : sig->subpkts) { + for (auto &subpkt : sig.subpkts) { json_object *jso_subpkt = json_object_new_object(); if (json_object_array_add(res, jso_subpkt)) { json_object_put(jso_subpkt); @@ -1981,42 +1998,41 @@ signature_dump_subpackets_json(rnp_dump_ctx_t *ctx, const pgp_signature_t *sig) static rnp_result_t stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, - const pgp_signature_t *sig, + const pgp_signature_t &sig, json_object * pkt) { - json_object * material = NULL; - pgp_signature_material_t sigmaterial = {}; + json_object *material = NULL; - if (!json_add(pkt, "version", (int) sig->version)) { + if (!json_add(pkt, "version", (int) sig.version)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (!obj_add_intstr_json(pkt, "type", sig->type(), sig_type_map)) { + if (!obj_add_intstr_json(pkt, "type", sig.type(), sig_type_map)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (sig->version < PGP_V4) { - if (!json_add(pkt, "creation time", (uint64_t) sig->creation_time)) { + if (sig.version < PGP_V4) { + if (!json_add(pkt, "creation time", (uint64_t) sig.creation_time)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (!json_add(pkt, "signer", sig->signer)) { + if (!json_add(pkt, "signer", sig.signer)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } } - if (!obj_add_intstr_json(pkt, "algorithm", sig->palg, pubkey_alg_map)) { + if (!obj_add_intstr_json(pkt, "algorithm", sig.palg, pubkey_alg_map)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (!obj_add_intstr_json(pkt, "hash algorithm", sig->halg, hash_alg_map)) { + if (!obj_add_intstr_json(pkt, "hash algorithm", sig.halg, hash_alg_map)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (sig->version >= PGP_V4) { + if (sig.version >= PGP_V4) { json_object *subpkts = signature_dump_subpackets_json(ctx, sig); if (!subpkts || !json_add(pkt, "subpackets", subpkts)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } } - if (!json_add_hex(pkt, "lbits", sig->lbits.data(), sig->lbits.size())) { + if (!json_add_hex(pkt, "lbits", sig.lbits.data(), sig.lbits.size())) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } @@ -2025,44 +2041,51 @@ stream_dump_signature_pkt_json(rnp_dump_ctx_t * ctx, return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - try { - sig->parse_material(sigmaterial); - } catch (const std::exception &e) { - /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); - return RNP_ERROR_OUT_OF_MEMORY; - /* LCOV_EXCL_END */ + auto sigmaterial = sig.parse_material(); + if (!sigmaterial) { + return RNP_ERROR_BAD_PARAMETERS; } - switch (sig->palg) { + switch (sig.palg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!obj_add_mpi_json(material, "s", sigmaterial.rsa.s, ctx->dump_mpi)) { + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*sigmaterial); + if (!obj_add_mpi_json(material, "s", rsa.sig.s, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; - case PGP_PKA_DSA: - if (!obj_add_mpi_json(material, "r", sigmaterial.dsa.r, ctx->dump_mpi) || - !obj_add_mpi_json(material, "s", sigmaterial.dsa.s, ctx->dump_mpi)) { + } + case PGP_PKA_DSA: { + auto &dsa = dynamic_cast(*sigmaterial); + if (!obj_add_mpi_json(material, "r", dsa.sig.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", dsa.sig.s, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; + } case PGP_PKA_EDDSA: case PGP_PKA_ECDSA: case PGP_PKA_SM2: - case PGP_PKA_ECDH: - if (!obj_add_mpi_json(material, "r", sigmaterial.ecc.r, ctx->dump_mpi) || - !obj_add_mpi_json(material, "s", sigmaterial.ecc.s, ctx->dump_mpi)) { + case PGP_PKA_ECDH: { + auto &ec = dynamic_cast(*sigmaterial); + if (!obj_add_mpi_json(material, "r", ec.sig.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", ec.sig.s, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; + } + /* Wasn't able to find ElGamal sig artifacts so let's ignore this for coverage */ + /* LCOV_EXCL_START */ case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!obj_add_mpi_json(material, "r", sigmaterial.eg.r, ctx->dump_mpi) || - !obj_add_mpi_json(material, "s", sigmaterial.eg.s, ctx->dump_mpi)) { - return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*sigmaterial); + if (!obj_add_mpi_json(material, "r", eg.sig.r, ctx->dump_mpi) || + !obj_add_mpi_json(material, "s", eg.sig.s, ctx->dump_mpi)) { + return RNP_ERROR_OUT_OF_MEMORY; } break; + } + /* LCOV_EXCL_END */ #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: /* TODO */ @@ -2109,7 +2132,7 @@ stream_dump_signature_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object * if (ret) { return ret; } - return stream_dump_signature_pkt_json(ctx, &sig, pkt); + return stream_dump_signature_pkt_json(ctx, sig, pkt); } static bool @@ -2343,21 +2366,15 @@ stream_dump_userid_json(pgp_source_t *src, json_object *pkt) static rnp_result_t stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_object *pkt) { - pgp_pk_sesskey_t pkey; - pgp_encrypted_material_t pkmaterial; - rnp_result_t ret; - - try { - ret = pkey.parse(*src); - if (!pkey.parse_material(pkmaterial)) { - ret = RNP_ERROR_BAD_FORMAT; - } - } catch (const std::exception &e) { - ret = RNP_ERROR_GENERIC; // LCOV_EXCL_LINE - } + pgp_pk_sesskey_t pkey; + auto ret = pkey.parse(*src); if (ret) { return ret; } + auto pkmaterial = pkey.parse_material(); + if (!pkmaterial) { + return RNP_ERROR_BAD_FORMAT; + } if (!json_add(pkt, "version", (int) pkey.version) || !json_add(pkt, "keyid", pkey.key_id) || @@ -2373,32 +2390,40 @@ stream_dump_pk_session_key_json(rnp_dump_ctx_t *ctx, pgp_source_t *src, json_obj switch (pkey.alg) { case PGP_PKA_RSA: case PGP_PKA_RSA_ENCRYPT_ONLY: - case PGP_PKA_RSA_SIGN_ONLY: - if (!obj_add_mpi_json(material, "m", pkmaterial.rsa.m, ctx->dump_mpi)) { + case PGP_PKA_RSA_SIGN_ONLY: { + auto &rsa = dynamic_cast(*pkmaterial).enc; + if (!obj_add_mpi_json(material, "m", rsa.m, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; + } case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!obj_add_mpi_json(material, "g", pkmaterial.eg.g, ctx->dump_mpi) || - !obj_add_mpi_json(material, "m", pkmaterial.eg.m, ctx->dump_mpi)) { + case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: { + auto &eg = dynamic_cast(*pkmaterial).enc; + if (!obj_add_mpi_json(material, "g", eg.g, ctx->dump_mpi) || + !obj_add_mpi_json(material, "m", eg.m, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; - case PGP_PKA_SM2: - if (!obj_add_mpi_json(material, "m", pkmaterial.sm2.m, ctx->dump_mpi)) { + } + case PGP_PKA_SM2: { + auto &sm2 = dynamic_cast(*pkmaterial).enc; + if (!obj_add_mpi_json(material, "m", sm2.m, ctx->dump_mpi)) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; - case PGP_PKA_ECDH: - if (!obj_add_mpi_json(material, "p", pkmaterial.ecdh.p, ctx->dump_mpi) || - !json_add(material, "m.bytes", (int) pkmaterial.ecdh.m.size())) { + } + case PGP_PKA_ECDH: { + auto &ecdh = dynamic_cast(*pkmaterial).enc; + if (!obj_add_mpi_json(material, "p", ecdh.p, ctx->dump_mpi) || + !json_add(material, "m.bytes", (int) ecdh.m.size())) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } - if (ctx->dump_mpi && !json_add_hex(material, "m", pkmaterial.ecdh.m)) { + if (ctx->dump_mpi && !json_add_hex(material, "m", ecdh.m.data(), ecdh.m.size())) { return RNP_ERROR_OUT_OF_MEMORY; // LCOV_EXCL_LINE } break; + } #if defined(ENABLE_CRYPTO_REFRESH) case PGP_PKA_ED25519: case PGP_PKA_X25519: diff --git a/src/librepgp/stream-packet.cpp b/src/librepgp/stream-packet.cpp index 384249d726..4137b50057 100644 --- a/src/librepgp/stream-packet.cpp +++ b/src/librepgp/stream-packet.cpp @@ -1184,211 +1184,39 @@ pgp_pk_sesskey_t::parse(pgp_source_t &src) /* we cannot fail here */ pkt.get(material_buf.data(), material_buf.size()); /* check whether it can be parsed */ - pgp_encrypted_material_t material = {}; - if (!parse_material(material)) { + if (!parse_material()) { return RNP_ERROR_BAD_FORMAT; } return RNP_SUCCESS; } -bool -pgp_pk_sesskey_t::parse_material(pgp_encrypted_material_t &material) +std::unique_ptr +pgp_pk_sesskey_t::parse_material() const { - pgp_packet_body_t pkt(material_buf.data(), material_buf.size()); - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - /* RSA m */ - if (!pkt.get(material.rsa.m)) { - RNP_LOG("failed to get rsa m"); - return false; - } - break; - case PGP_PKA_ELGAMAL: - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - /* ElGamal g, m */ - if (!pkt.get(material.eg.g) || !pkt.get(material.eg.m)) { - RNP_LOG("failed to get elgamal mpis"); - return false; - } - break; - case PGP_PKA_SM2: - /* SM2 m */ - if (!pkt.get(material.sm2.m)) { - RNP_LOG("failed to get sm2 m"); - return false; - } - break; - case PGP_PKA_ECDH: { - /* ECDH ephemeral point */ - if (!pkt.get(material.ecdh.p)) { - RNP_LOG("failed to get ecdh p"); - return false; - } - /* ECDH m */ - uint8_t bt = 0; - if (!pkt.get(bt)) { - RNP_LOG("failed to get ecdh m len"); - return false; - } - if (bt > ECDH_WRAPPED_KEY_SIZE) { - RNP_LOG("wrong ecdh m len"); - return false; - } - material.ecdh.m.resize(bt); - if (!pkt.get(material.ecdh.m, bt)) { - RNP_LOG("failed to get ecdh m len"); - return false; - } - break; + auto enc = pgp::EncMaterial::create(alg); + if (!enc) { + return nullptr; } #if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: { - uint8_t bt = 0; - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_25519); - material.x25519.eph_key.resize(ec_desc->bytes()); - if (!pkt.get(material.x25519.eph_key.data(), material.x25519.eph_key.size())) { - RNP_LOG("failed to parse X25519 PKESK (eph. pubkey)"); - return false; - } - uint8_t enc_sesskey_len; - if (!pkt.get(enc_sesskey_len)) { - RNP_LOG("failed to parse X25519 PKESK (enc sesskey length)"); - return false; - } - /* get plaintext salg if PKESKv3 */ - if ((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { - if (!pkt.get(bt)) { - RNP_LOG("failed to get salg"); - return RNP_ERROR_BAD_FORMAT; - } - enc_sesskey_len -= 1; - salg = (pgp_symm_alg_t) bt; - } - material.x25519.enc_sess_key.resize(enc_sesskey_len); - if (!pkt.get(material.x25519.enc_sess_key.data(), enc_sesskey_len)) { - RNP_LOG("failed to parse X25519 PKESK (enc sesskey)"); - return false; - } - break; - } + enc->version = version; #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: { - uint8_t wrapped_key_len = 0; - uint8_t bt = 0; - material.kyber_ecdh.composite_ciphertext.resize( - pgp_kyber_ecdh_encrypted_t::composite_ciphertext_size(alg)); - if (!pkt.get(material.kyber_ecdh.composite_ciphertext.data(), - material.kyber_ecdh.composite_ciphertext.size())) { - RNP_LOG("failed to get kyber-ecdh ciphertext"); - return false; - } - if (!pkt.get(wrapped_key_len)) { - RNP_LOG("failed to get kyber-ecdh wrapped session key length"); - return false; - } - /* get plaintext salg if PKESKv3 */ - if ((version == PGP_PKSK_V3) && !do_encrypt_pkesk_v3_alg_id(alg)) { - if (!pkt.get(bt)) { - RNP_LOG("failed to get salg"); - return RNP_ERROR_BAD_FORMAT; - } - salg = (pgp_symm_alg_t) bt; - wrapped_key_len--; - } - material.kyber_ecdh.wrapped_sesskey.resize(wrapped_key_len); - if (!pkt.get(material.kyber_ecdh.wrapped_sesskey.data(), - material.kyber_ecdh.wrapped_sesskey.size())) { - RNP_LOG("failed to get kyber-ecdh session key"); - return false; - } - break; - } -#endif - default: - RNP_LOG("unknown pk alg %d", (int) alg); - return false; + pgp_packet_body_t pkt(material_buf); + if (!enc->parse(pkt)) { + return nullptr; } - if (pkt.left()) { - RNP_LOG("extra %d bytes in pk packet", (int) pkt.left()); - return false; + RNP_LOG("extra %zu bytes in pk packet", pkt.left()); + return nullptr; } - return true; + return enc; } void -pgp_pk_sesskey_t::write_material(const pgp_encrypted_material_t &material) +pgp_pk_sesskey_t::write_material(const pgp::EncMaterial &material) { pgp_packet_body_t pktbody(PGP_PKT_PK_SESSION_KEY); - - switch (alg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_ENCRYPT_ONLY: - pktbody.add(material.rsa.m); - break; - case PGP_PKA_SM2: - pktbody.add(material.sm2.m); - break; - case PGP_PKA_ECDH: - pktbody.add(material.ecdh.p); - pktbody.add_byte(material.ecdh.m.size()); - pktbody.add(material.ecdh.m); - break; - case PGP_PKA_ELGAMAL: - pktbody.add(material.eg.g); - pktbody.add(material.eg.m); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_X25519: { - uint8_t enc_sesskey_length_offset = ((version == PGP_PKSK_V3) ? 1 : 0); - pktbody.add(material.x25519.eph_key); - pktbody.add_byte(static_cast(material.x25519.enc_sess_key.size() + - enc_sesskey_length_offset)); - if (version == PGP_PKSK_V3) { - pktbody.add_byte(salg); /* added as plaintext */ - } - pktbody.add(material.x25519.enc_sess_key); - 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: { - pktbody.add(material.kyber_ecdh.composite_ciphertext); - uint8_t opt_salg_length = (version == PGP_PKSK_V3) ? 1 : 0; - pktbody.add_byte(static_cast(material.kyber_ecdh.wrapped_sesskey.size()) + - opt_salg_length); - if (version == PGP_PKSK_V3) { - pktbody.add_byte(salg); /* added as plaintext */ - } - pktbody.add(material.kyber_ecdh.wrapped_sesskey); - break; - } -#endif - default: - RNP_LOG("Unknown pk alg: %d", (int) alg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } - material_buf = {pktbody.data(), pktbody.data() + pktbody.size()}; + material.write(pktbody); + material_buf.assign(pktbody.data(), pktbody.data() + pktbody.size()); } void diff --git a/src/librepgp/stream-packet.h b/src/librepgp/stream-packet.h index 25445d27cb..92bc5a337d 100644 --- a/src/librepgp/stream-packet.h +++ b/src/librepgp/stream-packet.h @@ -32,6 +32,7 @@ #include #include "types.h" #include "stream-common.h" +#include "enc_material.hpp" /* maximum size of the 'small' packet */ #define PGP_MAX_PKT_SIZE 0x100000 @@ -186,15 +187,14 @@ typedef struct pgp_pk_sesskey_t { rnp_result_t parse(pgp_source_t &src); /** * @brief Parse encrypted material which is stored in packet in raw. - * @param material on success parsed material will be stored here. - * @return true on success or false otherwise. May also throw an exception. + * @return Parsed material or nullptr. May also throw an exception. */ - bool parse_material(pgp_encrypted_material_t &material); + std::unique_ptr parse_material() const; /** * @brief Write encrypted material to the material_buf. * @param material populated encrypted material. */ - void write_material(const pgp_encrypted_material_t &material); + void write_material(const pgp::EncMaterial &material); } pgp_pk_sesskey_t; /** pkp_sk_sesskey_t */ diff --git a/src/librepgp/stream-parse.cpp b/src/librepgp/stream-parse.cpp index 97d929a23e..eaff5dca77 100644 --- a/src/librepgp/stream-parse.cpp +++ b/src/librepgp/stream-parse.cpp @@ -1569,19 +1569,14 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, pgp_key_t & seckey, rnp::SecurityContext & ctx) { - pgp_encrypted_material_t encmaterial; - try { - if (!sesskey.parse_material(encmaterial) || !seckey.material()) { - return false; - } - seckey.material()->validate(ctx, false); - if (!seckey.material()->valid()) { - RNP_LOG("Attempt to decrypt using the key with invalid material."); - return false; - } - } catch (const std::exception &e) { + auto encmaterial = sesskey.parse_material(); + if (!encmaterial || !seckey.material()) { + return false; + } + seckey.material()->validate(ctx, false); + if (!seckey.material()->valid()) { /* LCOV_EXCL_START */ - RNP_LOG("%s", e.what()); + RNP_LOG("Attempt to decrypt using the key with invalid material."); return false; /* LCOV_EXCL_END */ } @@ -1599,6 +1594,8 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #endif #if defined(ENABLE_CRYPTO_REFRESH) || defined(ENABLE_PQC) + /* If AES is forced then salg must be stored plaintext in material */ + sesskey.salg = encmaterial->salg; /* check that AES is used when mandated by the standard */ if (!check_enforce_aes_v3_pkesk(sesskey.alg, sesskey.salg, sesskey.version)) { RNP_LOG("For the given asymmetric encryption algorithm in the PKESK, only AES is " @@ -1608,11 +1605,13 @@ encrypted_try_key(pgp_source_encrypted_param_t *param, #endif /* Decrypting session key value */ - rnp::secure_bytes decbuf(PGP_MPINT_SIZE, 0); + rnp::secure_bytes decbuf; if (sesskey.alg == PGP_PKA_ECDH) { - encmaterial.ecdh.fp = seckey.fp().vec(); + auto ecdh = dynamic_cast(encmaterial.get()); + assert(ecdh); + ecdh->enc.fp = seckey.fp().vec(); } - auto err = seckey.pkt().material->decrypt(ctx, decbuf, encmaterial); + auto err = seckey.pkt().material->decrypt(ctx, decbuf, *encmaterial); if (err) { return false; } diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index d7935bdbcd..c94142b787 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1018,8 +1018,7 @@ pgp_signature_t::parse(pgp_packet_body_t &pkt) /* we cannot fail here */ pkt.get(material_buf, pkt.left()); /* check whether it can be parsed */ - pgp_signature_material_t material = {}; - if (!parse_material(material)) { + if (!parse_material()) { return RNP_ERROR_BAD_FORMAT; } return RNP_SUCCESS; @@ -1036,103 +1035,22 @@ pgp_signature_t::parse(pgp_source_t &src) return parse(pkt); } -bool -pgp_signature_t::parse_material(pgp_signature_material_t &material) const +std::unique_ptr +pgp_signature_t::parse_material() const { - pgp_packet_body_t pkt(material_buf); - - switch (palg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - if (!pkt.get(material.rsa.s)) { - return false; - } - break; - case PGP_PKA_DSA: - if (!pkt.get(material.dsa.r) || !pkt.get(material.dsa.s)) { - return false; - } - break; - case PGP_PKA_EDDSA: - if (version < PGP_V4) { - RNP_LOG("Warning! v3 EdDSA signature."); - } - FALLTHROUGH_STATEMENT; - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - if (!pkt.get(material.ecc.r) || !pkt.get(material.ecc.s)) { - return false; - } - break; - case PGP_PKA_ELGAMAL: /* we support reading it but will not validate */ - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - if (!pkt.get(material.eg.r) || !pkt.get(material.eg.s)) { - return false; - } - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: { - auto ec_desc = pgp::ec::Curve::get(PGP_CURVE_25519); - material.ed25519.sig.resize(2 * ec_desc->bytes()); - if (!pkt.get(material.ed25519.sig.data(), material.ed25519.sig.size())) { - RNP_LOG("failed to parse ED25519 signature data"); - return false; - } - break; - } -#endif -#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: - material.dilithium_exdsa.sig.resize( - pgp_dilithium_exdsa_signature_t::composite_signature_size(palg)); - if (!pkt.get(material.dilithium_exdsa.sig.data(), - material.dilithium_exdsa.sig.size())) { - RNP_LOG("failed to get mldsa-ecdsa/eddsa signature"); - return false; - } - 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 signature data"); - return false; - } - auto sig_size = sphincsplus_signature_size((sphincsplus_parameter_t) param); - if (!sig_size) { - RNP_LOG("invalid SLH-DSA param value"); - return false; - } - material.sphincsplus.param = (sphincsplus_parameter_t) param; - material.sphincsplus.sig.resize(sig_size); - if (!pkt.get(material.sphincsplus.sig.data(), sig_size)) { - RNP_LOG("failed to parse SLH-DSA signature data"); - return false; - } - break; + auto sig = pgp::SigMaterial::create(palg, halg); + if (!sig) { + return nullptr; } -#endif - default: - RNP_LOG("Unknown pk algorithm : %d", (int) palg); - return false; + pgp_packet_body_t pkt(material_buf); + if (!sig->parse(pkt)) { + return nullptr; } - if (pkt.left()) { - RNP_LOG("extra %d bytes in signature packet", (int) pkt.left()); - return false; + RNP_LOG("extra %zu bytes in pk packet", pkt.left()); + return nullptr; } - return true; + return sig; } void @@ -1179,59 +1097,10 @@ pgp_signature_t::write(bool hdr) const } void -pgp_signature_t::write_material(const pgp_signature_material_t &material) +pgp_signature_t::write_material(const pgp::SigMaterial &material) { pgp_packet_body_t pktbody(PGP_PKT_SIGNATURE); - switch (palg) { - case PGP_PKA_RSA: - case PGP_PKA_RSA_SIGN_ONLY: - pktbody.add(material.rsa.s); - break; - case PGP_PKA_DSA: - pktbody.add(material.dsa.r); - pktbody.add(material.dsa.s); - break; - case PGP_PKA_EDDSA: - case PGP_PKA_ECDSA: - case PGP_PKA_SM2: - case PGP_PKA_ECDH: - pktbody.add(material.ecc.r); - pktbody.add(material.ecc.s); - break; - case PGP_PKA_ELGAMAL: /* we support writing it but will not generate */ - case PGP_PKA_ELGAMAL_ENCRYPT_OR_SIGN: - pktbody.add(material.eg.r); - pktbody.add(material.eg.s); - break; -#if defined(ENABLE_CRYPTO_REFRESH) - case PGP_PKA_ED25519: - pktbody.add(material.ed25519.sig); - break; -#endif -#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: - pktbody.add(material.dilithium_exdsa.sig); - break; - case PGP_PKA_SPHINCSPLUS_SHA2: - FALLTHROUGH_STATEMENT; - case PGP_PKA_SPHINCSPLUS_SHAKE: - pktbody.add_byte((uint8_t) material.sphincsplus.param); - pktbody.add(material.sphincsplus.sig); - break; -#endif - default: - RNP_LOG("Unknown pk algorithm : %d", (int) palg); - throw rnp::rnp_exception(RNP_ERROR_BAD_PARAMETERS); - } + material.write(pktbody); material_buf.assign(pktbody.data(), pktbody.data() + pktbody.size()); } diff --git a/src/librepgp/stream-sig.h b/src/librepgp/stream-sig.h index 1cecaa779e..5400841ead 100644 --- a/src/librepgp/stream-sig.h +++ b/src/librepgp/stream-sig.h @@ -34,6 +34,7 @@ #include "stream-common.h" #include "stream-packet.h" #include "sig_subpacket.hpp" +#include "sig_material.hpp" typedef struct pgp_signature_t { private: @@ -407,7 +408,7 @@ typedef struct pgp_signature_t { * @param material on success parsed material will be stored here. * @return true on success or false otherwise. May also throw an exception. */ - bool parse_material(pgp_signature_material_t &material) const; + std::unique_ptr parse_material() const; /** * @brief Write signature to the destination. May throw an exception. @@ -420,7 +421,7 @@ typedef struct pgp_signature_t { * * @param material populated signature material. */ - void write_material(const pgp_signature_material_t &material); + void write_material(const pgp::SigMaterial &material); /** * @brief Fill signature's hashed data. This includes all the fields from signature which diff --git a/src/librepgp/stream-write.cpp b/src/librepgp/stream-write.cpp index b8423af23e..7af51807b7 100644 --- a/src/librepgp/stream-write.cpp +++ b/src/librepgp/stream-write.cpp @@ -574,12 +574,11 @@ encrypted_dst_close(pgp_dest_t *dst, bool discard) } static rnp_result_t -encrypted_add_recipient(pgp_write_handler_t *handler, - pgp_dest_t * dst, - pgp_key_t * userkey, - const uint8_t * key, - const size_t keylen, - pgp_pkesk_version_t pkesk_version) +encrypted_add_recipient(pgp_write_handler_t * handler, + pgp_dest_t * dst, + pgp_key_t * userkey, + const rnp::secure_bytes &key, + pgp_pkesk_version_t pkesk_version) { pgp_dest_encrypted_param_t *param = (pgp_dest_encrypted_param_t *) dst->param; @@ -623,12 +622,12 @@ encrypted_add_recipient(pgp_write_handler_t *handler, #else enckey.push_back(pkey.salg); #endif - enckey.insert(enckey.end(), key, key + keylen); + enckey.insert(enckey.end(), key.begin(), key.end()); if (have_pkesk_checksum(pkey.alg)) { /* Calculate checksum */ rnp::secure_array checksum; - for (size_t i = 0; i < keylen; i++) { + for (size_t i = 0; i < key.size(); i++) { checksum[0] += key[i]; } enckey.push_back(checksum[0] >> 8); @@ -639,19 +638,24 @@ encrypted_add_recipient(pgp_write_handler_t *handler, RNP_LOG_U8VEC("Session Key: %s", std::vector(enckey.begin(), enckey.end())); #endif - pgp_encrypted_material_t material; - + auto material = pgp::EncMaterial::create(pkey.alg); +#if defined(ENABLE_CRYPTO_REFRESH) + material->version = pkey.version; + material->salg = pkey.salg; +#endif if (userkey->alg() == PGP_PKA_ECDH) { - material.ecdh.fp = userkey->fp().vec(); + auto ecdh = dynamic_cast(material.get()); + assert(ecdh); + ecdh->enc.fp = userkey->fp().vec(); } - auto ret = userkey->pkt().material->encrypt(*handler->ctx->ctx, material, enckey); + auto ret = userkey->pkt().material->encrypt(*handler->ctx->ctx, *material, enckey); if (ret) { return ret; } /* Writing symmetric key encrypted session key packet */ try { - pkey.write_material(material); + pkey.write_material(*material); pkey.write(*param->pkt.origdst); return param->pkt.origdst->werr; } catch (const std::exception &e) { @@ -987,7 +991,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr dst->close = encrypted_dst_close; dst->type = PGP_STREAM_ENCRYPTED; - rnp::secure_array enckey; /* content encryption key */ + rnp::secure_bytes enckey(keylen, 0); /* content encryption key */ if (!pkeycount && !skeycount) { RNP_LOG("no recipients"); ret = RNP_ERROR_BAD_PARAMETERS; @@ -1019,8 +1023,7 @@ init_encrypted_dst(pgp_write_handler_t *handler, pgp_dest_t *dst, pgp_dest_t *wr param->ctx->aalg = DEFAULT_AEAD_ALG; } #endif - ret = encrypted_add_recipient( - handler, dst, recipient, enckey.data(), keylen, pkesk_version); + ret = encrypted_add_recipient(handler, dst, recipient, enckey, pkesk_version); if (ret) { goto finish; } diff --git a/src/tests/cipher.cpp b/src/tests/cipher.cpp index 428e5b9fa8..ee0e6fcda3 100644 --- a/src/tests/cipher.cpp +++ b/src/tests/cipher.cpp @@ -125,13 +125,55 @@ TEST_F(rnp_tests, pkcs1_rsa_test_success) pgp_key_pkt_t seckey; assert_true(keygen.generate(seckey, true)); - pgp_encrypted_material_t enc; + pgp::RSAEncMaterial enc; + pgp::EGEncMaterial enc2; + assert_rnp_failure(seckey.material->encrypt(global_ctx, enc2, ptext)); assert_rnp_success(seckey.material->encrypt(global_ctx, enc, ptext)); - assert_int_equal(enc.rsa.m.len, 1024 / 8); + assert_int_equal(enc.enc.m.len, 1024 / 8); + assert_rnp_failure(seckey.material->decrypt(global_ctx, dec, enc2)); + assert_true(dec.empty()); assert_rnp_success(seckey.material->decrypt(global_ctx, dec, enc)); assert_int_equal(dec.size(), 3); assert_true(bin_eq_hex(dec.data(), 3, "616263")); + + /* Try signing */ + assert_true(keygen.generate(seckey, true)); + + rnp::secure_bytes hash(32); + global_ctx.rng.get(hash.data(), hash.size()); + pgp::RSASigMaterial sig(PGP_HASH_SHA256); + pgp::DSASigMaterial sig2(PGP_HASH_SHA256); + + assert_rnp_failure(seckey.material->sign(global_ctx, sig2, hash)); + assert_rnp_failure(seckey.material->verify(global_ctx, sig2, hash)); + 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 + rnp::secure_bytes hash_cut(hash.begin(), hash.end() - 1); + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash_cut)); + + // modify sig + sig.sig.s.mpi[0] ^= 0xff; + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash)); +} + +TEST_F(rnp_tests, pkcs1_rsa_test_sign_enc_only) +{ + rnp::KeygenParams keygen(PGP_PKA_RSA_SIGN_ONLY, global_ctx); + auto & rsa = dynamic_cast(keygen.key_params()); + rsa.set_bits(1024); + + pgp_key_pkt_t seckey; + assert_false(keygen.generate(seckey, true)); + + rnp::KeygenParams keygen2(PGP_PKA_RSA_ENCRYPT_ONLY, global_ctx); + auto & rsa2 = dynamic_cast(keygen2.key_params()); + rsa2.set_bits(1024); + + pgp_key_pkt_t seckey2; + assert_false(keygen2.generate(seckey2, true)); } TEST_F(rnp_tests, rnp_test_eddsa) @@ -140,20 +182,30 @@ TEST_F(rnp_tests, rnp_test_eddsa) pgp_key_pkt_t seckey; assert_true(keygen.generate(seckey, true)); - rnp::secure_bytes hash(32); - pgp_signature_material_t sig = {}; + rnp::secure_bytes hash(32); + global_ctx.rng.get(hash.data(), hash.size()); + + pgp::ECSigMaterial sig(PGP_HASH_SHA256); + pgp::RSASigMaterial sig2(PGP_HASH_SHA256); + + assert_rnp_failure(seckey.material->sign(global_ctx, sig2, hash)); + assert_rnp_failure(seckey.material->verify(global_ctx, sig2, hash)); assert_rnp_success(seckey.material->sign(global_ctx, sig, hash)); assert_rnp_success(seckey.material->verify(global_ctx, sig, hash)); + pgp::ECDHEncMaterial enc; + assert_rnp_failure(seckey.material->encrypt(global_ctx, enc, hash)); + assert_rnp_failure(seckey.material->decrypt(global_ctx, hash, enc)); + // cut one byte off hash -> invalid sig rnp::secure_bytes hash_cut(31); assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash_cut)); // swap r/s -> invalid sig - pgp::mpi tmp = sig.ecc.r; - sig.ecc.r = sig.ecc.s; - sig.ecc.s = tmp; + pgp::mpi tmp = sig.sig.r; + sig.sig.r = sig.sig.s; + sig.sig.s = tmp; assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash)); } @@ -175,34 +227,44 @@ TEST_F(rnp_tests, rnp_test_x25519) /* encrypt */ pgp_fingerprint_t fp = {}; assert_rnp_success(pgp_fingerprint(fp, seckey)); - rnp::secure_bytes in({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.vec(); + rnp::secure_bytes in({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); + pgp::ECDHEncMaterial enc; + pgp::SM2EncMaterial enc2; + enc.enc.fp = fp.vec(); + assert_rnp_failure(seckey.material->encrypt(global_ctx, enc2, in)); assert_rnp_success(seckey.material->encrypt(global_ctx, enc, in)); - assert_true(enc.ecdh.m.size() > 16); - assert_int_equal(enc.ecdh.p.mpi[0], 0x40); - assert_int_equal(enc.ecdh.p.len, 33); + assert_true(enc.enc.m.size() > 16); + assert_int_equal(enc.enc.p.mpi[0], 0x40); + assert_int_equal(enc.enc.p.len, 33); /* decrypt */ rnp::secure_bytes out; + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc2)); + assert_true(out.empty()); assert_rnp_success(seckey.material->decrypt(global_ctx, out, enc)); assert_int_equal(out.size(), 16); assert_int_equal(memcmp(in.data(), out.data(), 16), 0); /* negative cases */ - enc.ecdh.p.mpi[16] ^= 0xff; + enc.enc.p.mpi[16] ^= 0xff; assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc)); - enc.ecdh.p.mpi[16] ^= 0xff; - enc.ecdh.p.mpi[0] = 0x04; + enc.enc.p.mpi[16] ^= 0xff; + enc.enc.p.mpi[0] = 0x04; assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc)); - enc.ecdh.p.mpi[0] = 0x40; - uint8_t back = enc.ecdh.m.back(); - enc.ecdh.m.pop_back(); + enc.enc.p.mpi[0] = 0x40; + uint8_t back = enc.enc.m.back(); + enc.enc.m.pop_back(); assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc)); - enc.ecdh.m.push_back(back); - enc.ecdh.m.push_back(0); + enc.enc.m.push_back(back); + enc.enc.m.push_back(0); assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc)); + + rnp::secure_bytes hash(32); + global_ctx.rng.get(hash.data(), hash.size()); + pgp::ECSigMaterial sig(PGP_HASH_SHA256); + assert_rnp_failure(seckey.material->sign(global_ctx, sig, hash)); + assert_rnp_failure(seckey.material->verify(global_ctx, sig, hash)); } static void @@ -253,8 +315,13 @@ TEST_F(rnp_tests, ecdsa_signverify_success) assert_true(keygen.generate(seckey1, true)); assert_true(keygen.generate(seckey2, true)); - pgp_signature_material_t sig = {}; - sig.halg = hash_alg; + rnp::secure_bytes in({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); + rnp::secure_bytes out; + pgp::ECDHEncMaterial enc; + assert_rnp_failure(seckey1.material->encrypt(global_ctx, enc, in)); + assert_rnp_failure(seckey1.material->decrypt(global_ctx, out, enc)); + + pgp::ECSigMaterial sig(hash_alg); assert_rnp_success(seckey1.material->sign(global_ctx, sig, hash)); assert_rnp_success(seckey1.material->verify(global_ctx, sig, hash)); @@ -290,8 +357,13 @@ TEST_F(rnp_tests, ecdh_roundtrip) pgp_fingerprint_t ecdh_key1_fpr{}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - pgp_encrypted_material_t enc{}; - enc.ecdh.fp = ecdh_key1_fpr.vec(); + pgp::ECSigMaterial sig(keygen.hash()); + rnp::secure_bytes hash(rnp::Hash::size(keygen.hash())); + assert_rnp_failure(ecdh_key1.material->sign(global_ctx, sig, hash)); + assert_rnp_failure(ecdh_key1.material->verify(global_ctx, sig, hash)); + + pgp::ECDHEncMaterial enc; + enc.enc.fp = ecdh_key1_fpr.vec(); assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in)); rnp::secure_bytes res; @@ -340,15 +412,15 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) pgp_fingerprint_t ecdh_key1_fpr = {}; assert_rnp_success(pgp_fingerprint(ecdh_key1_fpr, ecdh_key1)); - pgp_encrypted_material_t enc; - enc.ecdh.fp = ecdh_key1_fpr.vec(); + pgp::ECDHEncMaterial enc; + enc.enc.fp = ecdh_key1_fpr.vec(); assert_rnp_success(ecdh_key1.material->encrypt(global_ctx, enc, in)); - auto m = enc.ecdh.m; - enc.ecdh.m.resize(0); + auto m = enc.enc.m; + enc.enc.m.resize(0); assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, enc), RNP_ERROR_GENERIC); - enc.ecdh.m.assign(m.begin(), m.end() - 1); + enc.enc.m.assign(m.begin(), m.end() - 1); assert_int_equal(ecdh_key1.material->decrypt(global_ctx, res, enc), RNP_ERROR_GENERIC); pgp::ECDHTestKeyMaterial key1_mod( @@ -357,7 +429,6 @@ TEST_F(rnp_tests, ecdh_decryptionNegativeCases) assert_int_equal(key1_mod.decrypt(global_ctx, res, enc), RNP_ERROR_NOT_SUPPORTED); } -#if defined(ENABLE_SM2) TEST_F(rnp_tests, sm2_roundtrip) { rnp::KeygenParams keygen(PGP_PKA_SM2, global_ctx); @@ -367,25 +438,26 @@ TEST_F(rnp_tests, sm2_roundtrip) global_ctx.rng.get(key.data(), key.size()); pgp_key_pkt_t seckey; +#if defined(ENABLE_SM2) assert_true(keygen.generate(seckey, true)); - auto &eckey = *seckey.material; - pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; - pgp_encrypted_material_t enc; + pgp_hash_alg_t hashes[] = {PGP_HASH_SM3, PGP_HASH_SHA256, PGP_HASH_SHA512}; + pgp::SM2EncMaterial enc; + pgp::ECDHEncMaterial enc2; for (size_t i = 0; i < ARRAY_SIZE(hashes); ++i) { - auto ret = eckey.encrypt(global_ctx, enc, key); - assert_int_equal(ret, RNP_SUCCESS); - rnp::secure_bytes dec(32, 0); - ret = eckey.decrypt(global_ctx, dec, enc); - assert_int_equal(ret, RNP_SUCCESS); - assert_int_equal(dec.size(), key.size()); + assert_rnp_failure(eckey.encrypt(global_ctx, enc2, key)); + assert_rnp_failure(eckey.decrypt(global_ctx, dec, enc2)); + assert_rnp_success(eckey.encrypt(global_ctx, enc, key)); + assert_rnp_success(eckey.decrypt(global_ctx, dec, enc)); assert_true(dec == key); } -} +#else + assert_false(keygen.generate(seckey, true)); #endif +} #if defined(ENABLE_SM2) TEST_F(rnp_tests, sm2_sm3_signature_test) @@ -512,9 +584,15 @@ TEST_F(rnp_tests, test_dsa_roundtrip) "p: %zu q: %zu h: %s\n", dsa.bits(), dsa.qbits(), rnp::Hash::name(keygen.hash())); fflush(stdout); - auto & key = *seckey.material; - rnp::secure_bytes hash(message, message + rnp::Hash::size(keygen.hash())); - pgp_signature_material_t sig = {}; + rnp::secure_bytes in({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}); + rnp::secure_bytes out; + pgp::EGEncMaterial enc; + assert_rnp_failure(seckey.material->encrypt(global_ctx, enc, in)); + assert_rnp_failure(seckey.material->decrypt(global_ctx, out, enc)); + + auto & key = *seckey.material; + rnp::secure_bytes hash(message, message + rnp::Hash::size(keygen.hash())); + pgp::DSASigMaterial sig(keygen.hash()); assert_rnp_success(key.sign(global_ctx, sig, hash)); assert_rnp_success(key.verify(global_ctx, sig, hash)); } @@ -542,8 +620,8 @@ TEST_F(rnp_tests, test_dsa_verify_negative) auto &key1 = *sec_key1.material; auto &key2 = *sec_key2.material; - rnp::secure_bytes hash(message, message + rnp::Hash::size(keygen.hash())); - pgp_signature_material_t sig = {}; + rnp::secure_bytes hash(message, message + rnp::Hash::size(keygen.hash())); + pgp::DSASigMaterial sig(keygen.hash()); assert_rnp_success(key1.sign(global_ctx, sig, hash)); // wrong key used assert_int_equal(key2.verify(global_ctx, sig, hash), RNP_ERROR_SIGNATURE_INVALID); @@ -575,7 +653,7 @@ TEST_F(rnp_tests, kyber_ecdh_roundtrip) pgp_key_pkt_t key_pkt; assert_true(keygen.generate(key_pkt, true)); - pgp_encrypted_material_t enc; + pgp::MlkemEcdhEncMaterial enc(algs[i]); assert_rnp_success(key_pkt.material->encrypt(global_ctx, enc, in)); assert_rnp_success(key_pkt.material->decrypt(global_ctx, res, enc)); @@ -611,7 +689,7 @@ TEST_F(rnp_tests, dilithium_exdsa_signverify_success) auto &key1 = *seckey1.material; auto &key2 = *seckey2.material; - pgp_signature_material_t sig; + pgp::DilithiumSigMaterial sig(keygen.alg(), keygen.hash()); sig.halg = hash_alg; rnp::secure_bytes hash(message, message + sizeof(message)); assert_rnp_success(key1.sign(global_ctx, sig, hash)); @@ -649,10 +727,10 @@ TEST_F(rnp_tests, sphincsplus_signverify_success) assert_true(keygen.generate(seckey1, true)); assert_true(keygen.generate(seckey2, true)); - auto & key1 = *seckey1.material; - auto & key2 = *seckey2.material; - rnp::secure_bytes hash(message, message + sizeof(message)); - pgp_signature_material_t sig; + auto & key1 = *seckey1.material; + auto & key2 = *seckey2.material; + rnp::secure_bytes hash(message, message + sizeof(message)); + pgp::SlhdsaSigMaterial sig(keygen.hash()); assert_rnp_success(key1.sign(global_ctx, sig, hash)); assert_rnp_success(key1.verify(global_ctx, sig, hash)); diff --git a/src/tests/cli_tests.py b/src/tests/cli_tests.py index 5ac3649255..e58d49767b 100755 --- a/src/tests/cli_tests.py +++ b/src/tests/cli_tests.py @@ -48,6 +48,7 @@ RNP_BLOWFISH = True RNP_CAST5 = True RNP_RIPEMD160 = True +RNP_SM2 = True # Botan may cause AV during OCB decryption in certain cases, see https://github.com/randombit/botan/issues/3812 RNP_BOTAN_OCB_AV = False @@ -880,7 +881,7 @@ def gpg_check_features(): print('GPG_BRAINPOOL: ' + str(GPG_BRAINPOOL)) def rnp_check_features(): - global RNP_TWOFISH, RNP_BRAINPOOL, RNP_AEAD, RNP_AEAD_EAX, RNP_AEAD_OCB, RNP_AEAD_OCB_AES, RNP_IDEA, RNP_BLOWFISH, RNP_CAST5, RNP_RIPEMD160, RNP_PQC + global RNP_TWOFISH, RNP_BRAINPOOL, RNP_AEAD, RNP_AEAD_EAX, RNP_AEAD_OCB, RNP_AEAD_OCB_AES, RNP_IDEA, RNP_BLOWFISH, RNP_CAST5, RNP_RIPEMD160, RNP_PQC, RNP_SM2 global RNP_BOTAN_OCB_AV ret, out, _ = run_proc(RNP, ['--version']) if ret != 0: @@ -907,6 +908,8 @@ def rnp_check_features(): RNP_BLOWFISH = re.match(r'(?s)^.*Encryption:.*BLOWFISH.*', out) is not None RNP_CAST5 = re.match(r'(?s)^.*Encryption:.*CAST5.*', out) is not None RNP_RIPEMD160 = re.match(r'(?s)^.*Hash:.*RIPEMD160.*', out) is not None + # SM2 + RNP_SM2 = re.match(r'(?s)^.*Public key:.*SM2.*', out) is not None # Determine PQC support in general. If present, assume that all PQC schemes are supported. pqc_strs = ['ML-KEM', 'ML-DSA'] RNP_PQC = any([re.match('(?s)^.*Public key:.*' + scheme + '.*', out) is not None for scheme in pqc_strs]) @@ -4475,8 +4478,7 @@ def test_sym_encrypted__rnp_aead_botan_crash(self): def test_aead_chunk_edge_cases(self): if not RNP_AEAD: - print('AEAD is not available for RNP - skipping.') - return + self.skipTest('AEAD is not available for RNP - skipping.') src, dst, enc = reg_workfiles('cleartext', '.txt', '.rnp', '.enc') # Cover lines from src_skip() where > 16 bytes must be skipped random_text(src, 1001) @@ -4870,7 +4872,7 @@ def test_encryption_x25519(self): def test_encryption_aead_defs(self): if not RNP_AEAD or not RNP_BRAINPOOL: - return + self.skipTest('AEAD and/or Brainpool are not supported') # Encrypt with RNP pubkey = data_path(KEY_ALICE_SUB_PUB) src, enc, dec = reg_workfiles('cleartext', '.txt', '.enc', '.dec') @@ -4938,6 +4940,40 @@ def test_aead_eax_botan35_decryption(self): self.assertEqual(ret, 0) clear_workfiles() + def test_sm2_encryption_signing(self): + if not RNP_SM2: + self.skipTest('SM2 is not supported or disabled') + RNPDIR2 = RNPDIR + '2' + os.mkdir(RNPDIR2, 0o700) + # Import public key + ret, _, _ = run_proc(RNPK, ['--homedir', RNPDIR2, '--import', data_path('test_stream_key_load/sm2-pub.asc')]) + self.assertEqual(ret, 0) + # Check listing + ret, out, _ = run_proc(RNPK, ['--homedir', RNPDIR2, '--list-keys']) + self.assertEqual(ret, 0) + self.assertRegex(out, r'(?s)2 keys found.*pub.*256/SM2.*3a143c1695ae14c9.*sm2\-key.*sub.*256/SM2.*75ca025d13c1c512.*') + # Validate signature + ret, _, err = run_proc(RNP, ['--homedir', RNPDIR2, '-v', data_path('test_messages/message.txt.signed-sm2')]) + self.assertEqual(ret, 0) + self.assertRegex(err, r'(?s)Good signature made.*using SM2 key 3a143c1695ae14c9.*') + # Import secret key + ret, _, _ = run_proc(RNPK, ['--homedir', RNPDIR2, '--import', data_path('test_stream_key_load/sm2-sec.asc')]) + self.assertEqual(ret, 0) + # Check listing + ret, out, _ = run_proc(RNPK, ['--homedir', RNPDIR2, '--list-keys', '--secret']) + self.assertEqual(ret, 0) + self.assertRegex(out, r'(?s)2 keys found.*sec.*256/SM2.*3a143c1695ae14c9.*sm2\-key.*ssb.*256/SM2.*75ca025d13c1c512.*') + # Decrypt encrypted file + ret, out, _ = run_proc(RNP, ['--homedir', RNPDIR2, '--password', PASSWORD, '-d', data_path('test_messages/message.txt.enc-sm2')]) + self.assertEqual(ret, 0) + self.assertRegex(out, r'(?s)This is test message to be.*') + # Decrypt and verify file + ret, out, err = run_proc(RNP, ['--homedir', RNPDIR2, '--password', PASSWORD, '-d', data_path('test_messages/message.txt.enc-signed-sm2')]) + self.assertEqual(ret, 0) + self.assertRegex(out, r'(?s)This is test message to be.*') + self.assertRegex(err, r'(?s)Good signature made.*using SM2 key 3a143c1695ae14c9.*') + shutil.rmtree(RNPDIR2, ignore_errors=True) + class Compression(unittest.TestCase): @classmethod def setUpClass(cls): diff --git a/src/tests/data/test_messages/message.txt.enc-signed-sm2 b/src/tests/data/test_messages/message.txt.enc-signed-sm2 new file mode 100644 index 0000000000..71ec49eb0d Binary files /dev/null and b/src/tests/data/test_messages/message.txt.enc-signed-sm2 differ diff --git a/src/tests/data/test_messages/message.txt.enc-sm2 b/src/tests/data/test_messages/message.txt.enc-sm2 new file mode 100644 index 0000000000..095111e244 Binary files /dev/null and b/src/tests/data/test_messages/message.txt.enc-sm2 differ diff --git a/src/tests/data/test_messages/message.txt.signed-sm2 b/src/tests/data/test_messages/message.txt.signed-sm2 new file mode 100644 index 0000000000..e0020606ee Binary files /dev/null and b/src/tests/data/test_messages/message.txt.signed-sm2 differ diff --git a/src/tests/data/test_stream_key_load/sm2-pub.asc b/src/tests/data/test_stream_key_load/sm2-pub.asc new file mode 100644 index 0000000000..2d98acba3b --- /dev/null +++ b/src/tests/data/test_stream_key_load/sm2-pub.asc @@ -0,0 +1,12 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xlIEZ31OEmMIKoEcz1UBgi0CAwSBHUuZLKowb96LTK99aItWk9VZvhE3kOnx9Cam1Q8cHtBoVAQV +2hss/jxyD94wAq4QwMjvhML0ofWl1o0ECEexzQdzbTIta2V5wokEE2NpADEWIQSR79KyZ+zBP3UO +vTg6FDwWla4UyQUCZ31OEgIbAwQLCQgHBRUICQoLBRYCAwEAAAoJEDoUPBaVrhTJ03IBALtmZmT4 +L0590L2+fa1XZ4QmJvpZk1T3X3l29VVb+2d+AP90hXbOc7l9LX42OCUElKx2xf94jg741abBZ3kU +Al40qs5SBGd9ThJjCCqBHM9VAYItAgME8XM9ti6P1ZI3SFL16hHQykgdNc/nKWCdJjywh7lVzJ43 +skIi2z5NAh6p1lvMDqHCCGGCl1F0G+5TTe6nCeRIncJ4BBhjaQAgFiEEke/SsmfswT91Dr04OhQ8 +FpWuFMkFAmd9ThICGwwACgkQOhQ8FpWuFMnr0QD/UQLvADle+5sHP5+6IU/pL8dyWeHQWpJYoF6N +qDD3Pt4BAMZoI9dhbF+M6bFmHKaMyXYyncp1uT66EU0rQmUXn2jp +=4c2b +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/tests/data/test_stream_key_load/sm2-sec.asc b/src/tests/data/test_stream_key_load/sm2-sec.asc new file mode 100644 index 0000000000..f9275d0971 --- /dev/null +++ b/src/tests/data/test_stream_key_load/sm2-sec.asc @@ -0,0 +1,15 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +xaUEZ31OEmMIKoEcz1UBgi0CAwSBHUuZLKowb96LTK99aItWk9VZvhE3kOnx9Cam1Q8cHtBoVAQV +2hss/jxyD94wAq4QwMjvhML0ofWl1o0ECEex/gkDCLgfGmDSPIXy7OwJGSArWpV4pIlv68iWm64b +csxuPEDIw2qwUoTeqofnrQzy86mAOkLQ6EzgL6Zw/0cftvUNNbKJq1wgNkyPYmAEQswk2rzNB3Nt +Mi1rZXnCiQQTY2kAMRYhBJHv0rJn7ME/dQ69ODoUPBaVrhTJBQJnfU4SAhsDBAsJCAcFFQgJCgsF +FgIDAQAACgkQOhQ8FpWuFMnTcgEAu2ZmZPgvTn3Qvb59rVdnhCYm+lmTVPdfeXb1VVv7Z34A/3SF +ds5zuX0tfjY4JQSUrHbF/3iODvjVpsFneRQCXjSqx6UEZ31OEmMIKoEcz1UBgi0CAwTxcz22Lo/V +kjdIUvXqEdDKSB01z+cpYJ0mPLCHuVXMnjeyQiLbPk0CHqnWW8wOocIIYYKXUXQb7lNN7qcJ5Eid +/gkDCEcwDBnhMzKl7GBwpbqSoYWaTjAFv9Za31q38brixtpWdIwLzioXTHU2JcFx3IUcjav03303 +TpW69pW8rhu/Q+0e4KASTXHTc+ABk8nSG1TCeAQYY2kAIBYhBJHv0rJn7ME/dQ69ODoUPBaVrhTJ +BQJnfU4SAhsMAAoJEDoUPBaVrhTJ69EA/1EC7wA5XvubBz+fuiFP6S/Hclnh0FqSWKBejagw9z7e +AQDGaCPXYWxfjOmxZhymjMl2Mp3Kdbk+uhFNK0JlF59o6Q== +=+0ss +-----END PGP PRIVATE KEY BLOCK-----