From 432e4535a1725d25053b8197c1b441b672dc2b90 Mon Sep 17 00:00:00 2001 From: Johannes Roth Date: Thu, 16 Nov 2023 13:47:13 +0100 Subject: [PATCH] add mandatory direct-key signature for v6 certificates --- src/lib/generate-key.cpp | 6 +++++ src/lib/pgp-key.cpp | 29 +++++++++++++++++++++ src/lib/pgp-key.h | 17 +++++++++++++ src/lib/types.h | 2 ++ src/librepgp/stream-sig.cpp | 51 +++++++++++++++++++++++++++---------- 5 files changed, 91 insertions(+), 14 deletions(-) diff --git a/src/lib/generate-key.cpp b/src/lib/generate-key.cpp index c58629a6ee..88ff86197a 100644 --- a/src/lib/generate-key.cpp +++ b/src/lib/generate-key.cpp @@ -425,6 +425,12 @@ pgp_generate_primary_key(rnp_keygen_primary_desc_t &desc, pgp_key_t sec(secpkt); pgp_key_t pub(secpkt, true); +#if defined(ENABLE_CRYPTO_REFRESH) + // for v6 packets, a direct-key sig is mandatory. + if (sec.version() == PGP_V6) { + sec.add_direct_sig(desc.cert, desc.crypto.hash_alg, *desc.crypto.ctx, &pub); + } +#endif sec.add_uid_cert(desc.cert, desc.crypto.hash_alg, *desc.crypto.ctx, &pub); switch (secformat) { diff --git a/src/lib/pgp-key.cpp b/src/lib/pgp-key.cpp index 3cee5f3341..29212a7eff 100644 --- a/src/lib/pgp-key.cpp +++ b/src/lib/pgp-key.cpp @@ -2426,6 +2426,35 @@ pgp_key_t::sign_subkey_binding(pgp_key_t & sub, } } +#if defined(ENABLE_CRYPTO_REFRESH) +void +pgp_key_t::add_direct_sig(rnp_selfsig_cert_info_t &cert, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx, + pgp_key_t * pubkey) +{ + // We only support modifying v4 and newer keys + if (pkt().version < PGP_V4) { + RNP_LOG("adding a direct-key sig to V2/V3 key is not supported"); + throw rnp::rnp_exception(RNP_ERROR_BAD_STATE); + } + + pgp_signature_t sig; + sign_init(ctx.rng, sig, hash, ctx.time(), pkt().version); + sig.set_type(PGP_SIG_DIRECT); + cert.populate(sig); + sign_direct(pkt_, sig, ctx); + + add_sig(sig, PGP_UID_NONE); + refresh_data(ctx); + if (!pubkey) { + return; + } + pubkey->add_sig(sig, PGP_UID_NONE); + pubkey->refresh_data(ctx); +} +#endif + void pgp_key_t::add_uid_cert(rnp_selfsig_cert_info_t &cert, pgp_hash_alg_t hash, diff --git a/src/lib/pgp-key.h b/src/lib/pgp-key.h index c65d7b5d19..06eec2da5e 100644 --- a/src/lib/pgp-key.h +++ b/src/lib/pgp-key.h @@ -549,6 +549,23 @@ struct pgp_key_t { pgp_signature_t & sig, rnp::SecurityContext &ctx); +#if defined(ENABLE_CRYPTO_REFRESH) + /** + * @brief Add a direct-key self signature + * Note: secret key must be unlocked before calling this function. + * + * @param cert certification parameters. + * @param hash hash algorithm to use during signing. See sign_init() for more details. + * @param ctx security context. + * @param pubkey if non-NULL then the direct-key signature will be added to this key as + * well. + */ + void add_direct_sig(rnp_selfsig_cert_info_t &cert, + pgp_hash_alg_t hash, + rnp::SecurityContext & ctx, + pgp_key_t * pubkey = nullptr); +#endif + /** * @brief Add and certify userid. * Note: secret key must be unlocked before calling this function. diff --git a/src/lib/types.h b/src/lib/types.h index 850c4b0e91..f16c69aab1 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -502,6 +502,8 @@ typedef struct rnp_selfsig_cert_info_t { * At some point we should get rid of it. */ void populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig); + void populate(pgp_signature_t &sig); + void populate(pgp_userid_pkt_t &uid); } rnp_selfsig_cert_info_t; typedef struct rnp_selfsig_binding_info_t { diff --git a/src/librepgp/stream-sig.cpp b/src/librepgp/stream-sig.cpp index 0b15fdfc82..f32bbeca3c 100644 --- a/src/librepgp/stream-sig.cpp +++ b/src/librepgp/stream-sig.cpp @@ -1769,19 +1769,42 @@ pgp_signature_t::fill_hashed_data() } void -rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) +rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid) +{ + uid.tag = PGP_PKT_USER_ID; + uid.uid_len = userid.size(); + if (!(uid.uid = (uint8_t *) malloc(uid.uid_len))) { + RNP_LOG("alloc failed"); + throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); + } + memcpy(uid.uid, userid.data(), uid.uid_len); +} + +void +rnp_selfsig_cert_info_t::populate(pgp_signature_t &sig) { - /* populate signature */ - sig.set_type(PGP_CERT_POSITIVE); if (key_expiration) { sig.set_key_expiration(key_expiration); } - if (key_flags) { - sig.set_key_flags(key_flags); - } if (primary) { sig.set_primary_uid(true); } +#if defined(ENABLE_CRYPTO_REFRESH) + if ((sig.version == PGP_V6) && (sig.type() != PGP_SIG_DIRECT)) { + /* only set key expiraton and primary uid for v6 self-signatures + * since most information is stored in the direct-key signature of the primary key. + */ + + if (key_flags && (sig.type() == PGP_SIG_SUBKEY)) { + /* for v6 subkeys signatures we also add the key flags */ + sig.set_key_flags(key_flags); + } + return; + } +#endif + if (key_flags) { + sig.set_key_flags(key_flags); + } if (!prefs.symm_algs.empty()) { sig.set_preferred_symm_algs(prefs.symm_algs); } @@ -1797,12 +1820,12 @@ rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) if (!prefs.key_server.empty()) { sig.set_key_server(prefs.key_server); } - /* populate uid */ - uid.tag = PGP_PKT_USER_ID; - uid.uid_len = userid.size(); - if (!(uid.uid = (uint8_t *) malloc(uid.uid_len))) { - RNP_LOG("alloc failed"); - throw rnp::rnp_exception(RNP_ERROR_OUT_OF_MEMORY); - } - memcpy(uid.uid, userid.data(), uid.uid_len); +} + +void +rnp_selfsig_cert_info_t::populate(pgp_userid_pkt_t &uid, pgp_signature_t &sig) +{ + sig.set_type(PGP_CERT_POSITIVE); + populate(sig); + populate(uid); }