mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-30 16:17:02 +01:00
gpg: New option --include-key-block.
* common/openpgpdefs.h (SIGSUBPKT_KEY_BLOCK): New. * g10/gpg.c (oIncludeKeyBlock): New. (opts): New option --include-key-block. (main): Implement. * g10/options.h (opt): New flag include_key_block. * g10/parse-packet.c (dump_sig_subpkt): Support SIGSUBPKT_KEY_BLOCK. (parse_one_sig_subpkt): Ditto. (can_handle_critical): Ditto. * g10/sign.c (mk_sig_subpkt_key_block): New. (write_signature_packets): Call it for data signatures. -- This patch adds support for a to be proposed OpenPGP ferature: Introduce the Key Block subpacket to align OpenPGP with CMS. This new subpacket may be used similar to the CertificateSet of CMS (RFC-5652) and thus allows to start encrypted communication after having received a signed message. In practice a stripped down version of the key should be including having only the key material and the self-signatures which are really useful and shall be used by the recipient to reply encrypted. #### Key Block (1 octet with value 0, N octets of key data) This subpacket MAY be used to convey key data along with a signature of class 0x00, 0x01, or 0x02. It MUST contain the key used to create the signature; either as the primary key or as a subkey. The key SHOULD contain a primary or subkey capable of encryption and the entire key must be a valid OpenPGP key including at least one User ID packet and the corresponding self-signatures. Implementations MUST ignore this subpacket if the first octet does not have a value of zero or if the key data does not represent a valid transferable public key. GnuPG-bug-id: 4856 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
32493ce50a
commit
865d485180
@ -120,6 +120,7 @@ typedef enum
|
||||
SIGSUBPKT_PREF_AEAD = 34, /* Preferred AEAD algorithms. */
|
||||
|
||||
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
|
||||
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
|
||||
|
||||
SIGSUBPKT_FLAG_CRITICAL = 128
|
||||
}
|
||||
|
10
doc/gpg.texi
10
doc/gpg.texi
@ -2700,6 +2700,16 @@ As of now this is only done if the signing key has been specified with
|
||||
information can be helpful for verifier to locate the key; see option
|
||||
@option{--auto-key-retrieve}.
|
||||
|
||||
@item --include-key-block
|
||||
@opindex include-key-block
|
||||
This option is used to embed the actual signing key into a data
|
||||
signature. The embedded key is stripped down to a single user id and
|
||||
includes only the signing subkey used to create the signature as well
|
||||
as as valid encryption subkeys. All other info is removed from the
|
||||
key to keep it and thus the signature small. This option is the
|
||||
OpenPGP counterpart to the @command{gpgsm} option
|
||||
@option{--include-certs}.
|
||||
|
||||
@item --personal-cipher-preferences @var{string}
|
||||
@opindex personal-cipher-preferences
|
||||
Set the list of personal cipher preferences to @var{string}. Use
|
||||
|
@ -433,6 +433,7 @@ enum cmd_and_opt_values
|
||||
oNoSymkeyCache,
|
||||
oUseOnlyOpenPGPCard,
|
||||
oFullTimestrings,
|
||||
oIncludeKeyBlock,
|
||||
|
||||
oNoop
|
||||
};
|
||||
@ -748,7 +749,9 @@ static gpgrt_opt_t opts[] = {
|
||||
N_("|N|set compress level to N (0 disables)")),
|
||||
ARGPARSE_s_i (oCompressLevel, "compress-level", "@"),
|
||||
ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"),
|
||||
|
||||
ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
|
||||
ARGPARSE_s_n (oIncludeKeyBlock, "include-key-block",
|
||||
N_("include the public key in the signature")),
|
||||
|
||||
ARGPARSE_header ("ImportExport",
|
||||
N_("Options controlling key import and export")),
|
||||
@ -826,7 +829,6 @@ static gpgrt_opt_t opts[] = {
|
||||
ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
|
||||
ARGPARSE_s_s (oOverrideSessionKey, "override-session-key", "@"),
|
||||
ARGPARSE_s_i (oOverrideSessionKeyFD, "override-session-key-fd", "@"),
|
||||
ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
|
||||
|
||||
|
||||
ARGPARSE_header ("Security", N_("Options controlling the security")),
|
||||
@ -3032,6 +3034,7 @@ main (int argc, char **argv)
|
||||
case oForceAEAD: opt.force_aead = 1; break;
|
||||
|
||||
case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
|
||||
case oIncludeKeyBlock: opt.flags.include_key_block = 1; break;
|
||||
|
||||
case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break;
|
||||
case oS2KDigest: s2k_digest_string = xstrdup(pargs.r.ret_str); break;
|
||||
|
@ -241,6 +241,7 @@ struct
|
||||
unsigned int allow_weak_key_signatures:1;
|
||||
unsigned int large_rsa:1;
|
||||
unsigned int disable_signer_uid:1;
|
||||
unsigned int include_key_block:1;
|
||||
/* Flag to enable experimental features from RFC4880bis. */
|
||||
unsigned int rfc4880bis:1;
|
||||
/* Hack: --output is not given but OUTFILE was temporary set to "-". */
|
||||
|
@ -1615,6 +1615,23 @@ dump_sig_subpkt (int hashed, int type, int critical,
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGSUBPKT_KEY_BLOCK:
|
||||
es_fputs ("key-block: ", listfp);
|
||||
if (length && buffer[0])
|
||||
p = "[unknown reserved octet]";
|
||||
else if (length < 50) /* 50 is an arbitrary min. length. */
|
||||
p = "[invalid subpacket]";
|
||||
else
|
||||
{
|
||||
/* estream_t fp; */
|
||||
/* fp = es_fopen ("a.key-block", "wb"); */
|
||||
/* log_assert (fp); */
|
||||
/* es_fwrite ( buffer+1, length-1, 1, fp); */
|
||||
/* es_fclose (fp); */
|
||||
es_fprintf (listfp, "[%u octets]", (unsigned int)length-1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
if (type >= 100 && type <= 110)
|
||||
@ -1692,6 +1709,12 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
|
||||
if (n != 2)
|
||||
break;
|
||||
return 0;
|
||||
case SIGSUBPKT_KEY_BLOCK:
|
||||
if (n && buffer[0])
|
||||
return -1; /* Unknown version - ignore. */
|
||||
if (n < 50)
|
||||
break; /* Definitely too short to carry a key block. */
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -1760,6 +1783,12 @@ can_handle_critical (const byte * buffer, size_t n, int type)
|
||||
case SIGSUBPKT_REVOC_REASON: /* At least we know about it. */
|
||||
return 1;
|
||||
|
||||
case SIGSUBPKT_KEY_BLOCK:
|
||||
if (n && !buffer[0])
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
108
g10/sign.c
108
g10/sign.c
@ -202,6 +202,91 @@ mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Put the Key Block subpakcet into SIG for key PKSK. Returns an
|
||||
* error code on failure.
|
||||
*/
|
||||
static gpg_error_t
|
||||
mk_sig_subpkt_key_block (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pksk)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *mbox;
|
||||
char *filterexp = NULL;
|
||||
int save_opt_armor = opt.armor;
|
||||
int save_opt_verbose = opt.verbose;
|
||||
char hexfpr[2*MAX_FINGERPRINT_LEN + 1];
|
||||
void *data = NULL;
|
||||
size_t datalen;
|
||||
kbnode_t keyblock = NULL;
|
||||
|
||||
push_export_filters ();
|
||||
opt.armor = 0;
|
||||
|
||||
hexfingerprint (pksk, hexfpr, sizeof hexfpr);
|
||||
|
||||
/* Get the user id so that we know which one to insert into the
|
||||
* key. */
|
||||
if (pksk->user_id
|
||||
&& (mbox = mailbox_from_userid (pksk->user_id->name, 0)))
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("including key with UID '%s' (specified)\n", mbox);
|
||||
filterexp = xasprintf ("keep-uid= -- mbox = %s", mbox);
|
||||
xfree (mbox);
|
||||
}
|
||||
else if (opt.sender_list)
|
||||
{
|
||||
/* If --sender was given we use the first one from that list. */
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("including key with UID '%s' (--sender)\n",
|
||||
opt.sender_list->d);
|
||||
filterexp = xasprintf ("keep-uid= -- mbox = %s", opt.sender_list->d);
|
||||
}
|
||||
else /* Use the primary user id. */
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("including key with primary UID\n");
|
||||
filterexp = xstrdup ("keep-uid= primary -t");
|
||||
}
|
||||
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("export filter expression: %s\n", filterexp);
|
||||
err = parse_and_set_export_filter (filterexp);
|
||||
if (err)
|
||||
goto leave;
|
||||
xfree (filterexp);
|
||||
filterexp = xasprintf ("drop-subkey= fpr <> %s && usage !~ e", hexfpr);
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("export filter expression: %s\n", filterexp);
|
||||
err = parse_and_set_export_filter (filterexp);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
|
||||
opt.verbose = 0;
|
||||
err = export_pubkey_buffer (ctrl, hexfpr, EXPORT_MINIMAL|EXPORT_CLEAN,
|
||||
"", 1, /* Prefix with the reserved byte. */
|
||||
NULL, &keyblock, &data, &datalen);
|
||||
opt.verbose = save_opt_verbose;
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to get to be included key: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
build_sig_subpkt (sig, SIGSUBPKT_KEY_BLOCK, data, datalen);
|
||||
|
||||
leave:
|
||||
xfree (data);
|
||||
release_kbnode (keyblock);
|
||||
xfree (filterexp);
|
||||
opt.armor = save_opt_armor;
|
||||
pop_export_filters ();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper to hash a user ID packet.
|
||||
*/
|
||||
@ -835,7 +920,7 @@ write_signature_packets (ctrl_t ctrl,
|
||||
PKT_public_key *pk;
|
||||
PKT_signature *sig;
|
||||
gcry_md_hd_t md;
|
||||
int rc;
|
||||
gpg_error_t err;
|
||||
|
||||
pk = sk_rover->pk;
|
||||
|
||||
@ -865,12 +950,17 @@ write_signature_packets (ctrl_t ctrl,
|
||||
|
||||
build_sig_subpkt_from_sig (sig, pk);
|
||||
mk_notation_policy_etc (ctrl, sig, NULL, pk);
|
||||
if (opt.flags.include_key_block && IS_SIG (sig))
|
||||
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
|
||||
else
|
||||
err = 0;
|
||||
hash_sigversion_to_magic (md, sig, extrahash);
|
||||
gcry_md_final (md);
|
||||
|
||||
rc = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce, 0);
|
||||
if (!err)
|
||||
err = do_sign (ctrl, pk, sig, md, hash_for (pk), cache_nonce, 0);
|
||||
gcry_md_close (md);
|
||||
if (!rc)
|
||||
if (!err)
|
||||
{
|
||||
/* Write the packet. */
|
||||
PACKET pkt;
|
||||
@ -878,19 +968,19 @@ write_signature_packets (ctrl_t ctrl,
|
||||
init_packet (&pkt);
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
rc = build_packet (out, &pkt);
|
||||
if (!rc && is_status_enabled())
|
||||
err = build_packet (out, &pkt);
|
||||
if (!err && is_status_enabled())
|
||||
print_status_sig_created (pk, sig, status_letter);
|
||||
free_packet (&pkt, NULL);
|
||||
if (rc)
|
||||
if (err)
|
||||
log_error ("build signature packet failed: %s\n",
|
||||
gpg_strerror (rc));
|
||||
gpg_strerror (err));
|
||||
}
|
||||
else
|
||||
free_seckey_enc (sig);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user