mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
gpg: New commands --add-recipients and --change-recipients.
* g10/gpg.c (aAddRecipients, aChangeRecipients): New consts. (opts): Add --add-recipients and --change-recipients. (main): Handle them. * g10/gpg.h (struct server_control_s): Add fields modify_recipients, clear_recipients, and last_read_ctb. * g10/armor.c (was_armored): New. * g10/decrypt.c (decrypt_message): Add optional arg 'remusr'. Handle re-encryption if desired. * g10/encrypt.c (write_pubkey_enc): Factor info printing out to ... (show_encrypted_for_user_info): new. (reencrypt_to_new_recipients): New. * g10/packet.h (struct parse_packet_ctx_s): Add fields only_fookey_enc and last_ctb. (init_parse_packet): Clear them. * g10/parse-packet.c (parse): Store CTB in the context. Early return on pubkey_enc and symkey_enc packets if requested. * g10/mainproc.c (proc_encrypted): Allow for PKT being NULL. Return early in modify-recipients mode. (proc_encryption_packets): Add two optional args 'r_dek' and 'r_list'. Adjust callers. Call do_proc_packets in modify-recipients mode depending on the optional args. (do_proc_packets): Add arg 'keep_dek_and_list'. Adjust callers. Save the last read CTB in CTRL and return after the last fooenc_enc packets. -- This basically works but does not yet handle symmetric encrypted packets (symkey_enc). GnuPG-bug-id: 1825 (Yes, this is an at least 9 year old feature request)
This commit is contained in:
parent
2cc340eca0
commit
d528d0b065
@ -162,6 +162,14 @@ push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function returns true if the armor filter detected that the
|
||||||
|
* input was indeed armored. Gives a valid result only after the
|
||||||
|
* first PGP packet has been read. */
|
||||||
|
int
|
||||||
|
was_armored (armor_filter_context_t *afx)
|
||||||
|
{
|
||||||
|
return (afx && !afx->inp_bypass);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* decrypt.c - decrypt and verify data
|
/* decrypt.c - decrypt and verify data
|
||||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
|
||||||
* 2007, 2009 Free Software Foundation, Inc.
|
* 2007, 2009 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2024 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -16,6 +17,7 @@
|
|||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -35,19 +37,26 @@
|
|||||||
#include "../common/status.h"
|
#include "../common/status.h"
|
||||||
#include "../common/i18n.h"
|
#include "../common/i18n.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Assume that the input is an encrypted message and decrypt
|
/* Assume that the input is an encrypted message and decrypt
|
||||||
* (and if signed, verify the signature on) it.
|
* (and if signed, verify the signature on) it.
|
||||||
* This command differs from the default operation, as it never
|
* This command differs from the default operation, as it never
|
||||||
* writes to the filename which is included in the file and it
|
* writes to the filename which is included in the file and it
|
||||||
* rejects files which don't begin with an encrypted message.
|
* rejects files which don't begin with an encrypted message.
|
||||||
|
*
|
||||||
|
* REMUSR is only used in the modify_recipients mode and speicifies
|
||||||
|
* the additional or new recipients to use.
|
||||||
*/
|
*/
|
||||||
int
|
gpg_error_t
|
||||||
decrypt_message (ctrl_t ctrl, const char *filename)
|
decrypt_message (ctrl_t ctrl, const char *filename, strlist_t remusr)
|
||||||
{
|
{
|
||||||
IOBUF fp;
|
gpg_error_t err;
|
||||||
|
iobuf_t fp;
|
||||||
armor_filter_context_t *afx = NULL;
|
armor_filter_context_t *afx = NULL;
|
||||||
progress_filter_context_t *pfx;
|
progress_filter_context_t *pfx;
|
||||||
int rc;
|
DEK *dek = NULL;
|
||||||
|
struct pubkey_enc_list *pkenc_list = NULL;
|
||||||
|
|
||||||
pfx = new_progress_context ();
|
pfx = new_progress_context ();
|
||||||
|
|
||||||
@ -61,14 +70,18 @@ decrypt_message (ctrl_t ctrl, const char *filename)
|
|||||||
}
|
}
|
||||||
if ( !fp )
|
if ( !fp )
|
||||||
{
|
{
|
||||||
rc = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error (_("can't open '%s': %s\n"), print_fname_stdin(filename),
|
log_error (_("can't open '%s': %s\n"), print_fname_stdin(filename),
|
||||||
gpg_strerror (rc));
|
gpg_strerror (err));
|
||||||
release_progress_context (pfx);
|
release_progress_context (pfx);
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_progress (pfx, fp, filename);
|
/* Push the progress filter unless we are in add recipient mode.
|
||||||
|
* The latter may also work but for now we better avoid any possible
|
||||||
|
* complications. */
|
||||||
|
if (!ctrl->modify_recipients)
|
||||||
|
handle_progress (pfx, fp, filename);
|
||||||
|
|
||||||
if ( !opt.no_armor )
|
if ( !opt.no_armor )
|
||||||
{
|
{
|
||||||
@ -86,19 +99,44 @@ decrypt_message (ctrl_t ctrl, const char *filename)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
opt.flags.dummy_outfile = 0;
|
opt.flags.dummy_outfile = 0;
|
||||||
rc = proc_encryption_packets (ctrl, NULL, fp );
|
if (!ctrl->modify_recipients)
|
||||||
|
err = proc_encryption_packets (ctrl, NULL, fp, NULL, NULL);
|
||||||
|
else
|
||||||
|
err = proc_encryption_packets (ctrl, NULL, fp, &dek, &pkenc_list);
|
||||||
if (opt.flags.dummy_outfile)
|
if (opt.flags.dummy_outfile)
|
||||||
opt.outfile = NULL;
|
opt.outfile = NULL;
|
||||||
|
|
||||||
|
if (ctrl->modify_recipients && (err || !dek) )
|
||||||
|
log_error (_("modifiying the recipients is not possible: %s\n"),
|
||||||
|
err? gpg_strerror (err) : _("decryption failed"));
|
||||||
|
else if (ctrl->modify_recipients)
|
||||||
|
{
|
||||||
|
/* We apply an armor to the output if --armor was used or if the
|
||||||
|
* input was already armored and --no-armor was not given. */
|
||||||
|
int armor = opt.armor || (was_armored (afx) && !opt.no_armor);
|
||||||
|
|
||||||
|
err = reencrypt_to_new_recipients (ctrl, armor, filename, fp,
|
||||||
|
remusr, dek, pkenc_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (dek);
|
||||||
|
while (pkenc_list)
|
||||||
|
{
|
||||||
|
struct pubkey_enc_list *tmp = pkenc_list->next;
|
||||||
|
|
||||||
|
release_pubkey_enc_parts (&pkenc_list->d);
|
||||||
|
xfree (pkenc_list);
|
||||||
|
pkenc_list = tmp;
|
||||||
|
}
|
||||||
iobuf_close (fp);
|
iobuf_close (fp);
|
||||||
release_armor_context (afx);
|
release_armor_context (afx);
|
||||||
release_progress_context (pfx);
|
release_progress_context (pfx);
|
||||||
return rc;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Same as decrypt_message but takes a file descriptor for input and
|
/* Same as decrypt_message but takes a file descriptor for input and
|
||||||
output. */
|
output. Only used by the unfinished server mode. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
||||||
gnupg_fd_t output_fd)
|
gnupg_fd_t output_fd)
|
||||||
@ -173,7 +211,7 @@ decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = proc_encryption_packets (ctrl, NULL, fp );
|
err = proc_encryption_packets (ctrl, NULL, fp, NULL, NULL);
|
||||||
|
|
||||||
iobuf_close (fp);
|
iobuf_close (fp);
|
||||||
es_fclose (opt.outfp);
|
es_fclose (opt.outfp);
|
||||||
|
134
g10/encrypt.c
134
g10/encrypt.c
@ -46,6 +46,30 @@ static int encrypt_simple( const char *filename, int mode, int use_seskey );
|
|||||||
static int write_pubkey_enc_from_list (ctrl_t ctrl,
|
static int write_pubkey_enc_from_list (ctrl_t ctrl,
|
||||||
PK_LIST pk_list, DEK *dek, iobuf_t out);
|
PK_LIST pk_list, DEK *dek, iobuf_t out);
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for show the "encrypted for USER" during encryption.
|
||||||
|
* PUBKEY_USAGE is used to figure out whether this is an ADSK key. */
|
||||||
|
static void
|
||||||
|
show_encrypted_for_user_info (ctrl_t ctrl, unsigned int pubkey_usage,
|
||||||
|
PKT_pubkey_enc *enc, DEK *dek)
|
||||||
|
{
|
||||||
|
char *ustr = get_user_id_string_native (ctrl, enc->keyid);
|
||||||
|
if ((pubkey_usage & PUBKEY_USAGE_RENC))
|
||||||
|
{
|
||||||
|
char *tmpustr = xstrconcat (ustr, " [ADSK]", NULL);
|
||||||
|
xfree (ustr);
|
||||||
|
ustr = tmpustr;
|
||||||
|
}
|
||||||
|
log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
|
||||||
|
openpgp_pk_algo_name (enc->pubkey_algo),
|
||||||
|
openpgp_cipher_algo_name (dek->algo),
|
||||||
|
dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
|
||||||
|
/**/ : "CFB",
|
||||||
|
ustr );
|
||||||
|
xfree (ustr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Encrypt FILENAME with only the symmetric cipher. Take input from
|
* Encrypt FILENAME with only the symmetric cipher. Take input from
|
||||||
* stdin if FILENAME is NULL. If --force-aead is used we use an SKESK.
|
* stdin if FILENAME is NULL. If --force-aead is used we use an SKESK.
|
||||||
@ -389,10 +413,11 @@ use_mdc (pk_list_t pk_list,int algo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* We don't want to use use_seskey yet because older gnupg versions
|
/* This function handles the --symmetric only (MODE true) and --store
|
||||||
can't handle it, and there isn't really any point unless we're
|
* (MODE false) cases. We don't want to use USE_SESKEY by default
|
||||||
making a message that can be decrypted by a public key or
|
* very old gnupg versions can't handle it, and there isn't really any
|
||||||
passphrase. */
|
* point unless we're making a message that can be decrypted by a
|
||||||
|
* public key or passphrase. */
|
||||||
static int
|
static int
|
||||||
encrypt_simple (const char *filename, int mode, int use_seskey)
|
encrypt_simple (const char *filename, int mode, int use_seskey)
|
||||||
{
|
{
|
||||||
@ -1034,6 +1059,90 @@ encrypt_crypt (ctrl_t ctrl, gnupg_fd_t filefd, const char *filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Re-encrypt files with a set of new recipients. Note that this
|
||||||
|
* function is called by decrypt_message. INFP is the iobuf from the
|
||||||
|
* input file which is positioned right after the pubkey_enc and
|
||||||
|
* symkey_enc packets. */
|
||||||
|
gpg_error_t
|
||||||
|
reencrypt_to_new_recipients (ctrl_t ctrl, int armor, const char *filename,
|
||||||
|
iobuf_t infp, strlist_t recipients,
|
||||||
|
DEK *dek, struct pubkey_enc_list *pkenc_list)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int save_no_encrypt_to;
|
||||||
|
pk_list_t newpk_list = NULL;
|
||||||
|
iobuf_t outfp = NULL;
|
||||||
|
armor_filter_context_t *outafx = NULL;
|
||||||
|
PACKET pkt;
|
||||||
|
struct pubkey_enc_list *el;
|
||||||
|
unsigned int count;
|
||||||
|
|
||||||
|
/* Get the keys for all additional recipients but do not encrypt to
|
||||||
|
* the encrypt-to keys. */
|
||||||
|
save_no_encrypt_to = opt.no_encrypt_to;
|
||||||
|
opt.no_encrypt_to = 1;
|
||||||
|
err = build_pk_list (ctrl, recipients, &newpk_list);
|
||||||
|
opt.no_encrypt_to = save_no_encrypt_to;
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Note that we use by default the suffixes .gpg or .asc */
|
||||||
|
err = open_outfile (GNUPG_INVALID_FD, filename, armor? 1:0, 0, &outfp);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (armor)
|
||||||
|
{
|
||||||
|
outafx = new_armor_context ();
|
||||||
|
push_armor_filter (outafx, outfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the new recipients first. */
|
||||||
|
err = write_pubkey_enc_from_list (ctrl, newpk_list, dek, outfp);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* The write the old recipients in --add-recipients mode. */
|
||||||
|
for (count=0, el = pkenc_list; el; el = el->next, count++)
|
||||||
|
if (!ctrl->clear_recipients)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
show_encrypted_for_user_info (ctrl, 0, &el->d, dek);
|
||||||
|
init_packet (&pkt);
|
||||||
|
pkt.pkttype = PKT_PUBKEY_ENC;
|
||||||
|
pkt.pkt.pubkey_enc = &el->d;
|
||||||
|
err = build_packet (outfp, &pkt);
|
||||||
|
if (err)
|
||||||
|
log_error ("build_packet(pubkey_enc) failed: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
}
|
||||||
|
if (ctrl->clear_recipients && opt.verbose)
|
||||||
|
log_info (_("number of removed recipients: %u\n"), count);
|
||||||
|
|
||||||
|
iobuf_put (outfp, ctrl->last_read_ctb);
|
||||||
|
|
||||||
|
/* Finally copy the bulk of the message. */
|
||||||
|
iobuf_copy (outfp, infp);
|
||||||
|
if ((err = iobuf_error (infp)))
|
||||||
|
log_error (_("error reading '%s': %s\n"),
|
||||||
|
iobuf_get_fname_nonnull (infp), gpg_strerror (err));
|
||||||
|
else if ((err = iobuf_error (outfp)))
|
||||||
|
log_error (_("error writing '%s': %s\n"),
|
||||||
|
iobuf_get_fname_nonnull (outfp), gpg_strerror (err));
|
||||||
|
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (err)
|
||||||
|
iobuf_cancel (outfp);
|
||||||
|
else
|
||||||
|
iobuf_close (outfp);
|
||||||
|
release_armor_context (outafx);
|
||||||
|
release_pk_list (newpk_list);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filter to do a complete public key encryption.
|
* Filter to do a complete public key encryption.
|
||||||
*/
|
*/
|
||||||
@ -1144,22 +1253,7 @@ write_pubkey_enc (ctrl_t ctrl,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( opt.verbose )
|
if ( opt.verbose )
|
||||||
{
|
show_encrypted_for_user_info (ctrl, pk->pubkey_usage, enc, dek);
|
||||||
char *ustr = get_user_id_string_native (ctrl, enc->keyid);
|
|
||||||
if ((pk->pubkey_usage & PUBKEY_USAGE_RENC))
|
|
||||||
{
|
|
||||||
char *tmpustr = xstrconcat (ustr, " [ADSK]", NULL);
|
|
||||||
xfree (ustr);
|
|
||||||
ustr = tmpustr;
|
|
||||||
}
|
|
||||||
log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
|
|
||||||
openpgp_pk_algo_name (enc->pubkey_algo),
|
|
||||||
openpgp_cipher_algo_name (dek->algo),
|
|
||||||
dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
|
|
||||||
/**/ : "CFB",
|
|
||||||
ustr );
|
|
||||||
xfree (ustr);
|
|
||||||
}
|
|
||||||
/* And write it. */
|
/* And write it. */
|
||||||
init_packet (&pkt);
|
init_packet (&pkt);
|
||||||
pkt.pkttype = PKT_PUBKEY_ENC;
|
pkt.pkttype = PKT_PUBKEY_ENC;
|
||||||
|
@ -175,6 +175,7 @@ void free_md_filter_context( md_filter_context_t *mfx );
|
|||||||
armor_filter_context_t *new_armor_context (void);
|
armor_filter_context_t *new_armor_context (void);
|
||||||
void release_armor_context (armor_filter_context_t *afx);
|
void release_armor_context (armor_filter_context_t *afx);
|
||||||
int push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf);
|
int push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf);
|
||||||
|
int was_armored (armor_filter_context_t *afx);
|
||||||
int use_armor_filter( iobuf_t a );
|
int use_armor_filter( iobuf_t a );
|
||||||
|
|
||||||
/*-- compress.c --*/
|
/*-- compress.c --*/
|
||||||
|
38
g10/gpg.c
38
g10/gpg.c
@ -115,6 +115,8 @@ enum cmd_and_opt_values
|
|||||||
oKnownNotation,
|
oKnownNotation,
|
||||||
aEncrFiles,
|
aEncrFiles,
|
||||||
aEncrSym,
|
aEncrSym,
|
||||||
|
aAddRecipients,
|
||||||
|
aChangeRecipients,
|
||||||
aDecryptFiles,
|
aDecryptFiles,
|
||||||
aClearsign,
|
aClearsign,
|
||||||
aStore,
|
aStore,
|
||||||
@ -481,6 +483,8 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_c (aDecryptFiles, "decrypt-files", "@"),
|
ARGPARSE_c (aDecryptFiles, "decrypt-files", "@"),
|
||||||
ARGPARSE_c (aVerify, "verify" , N_("verify a signature")),
|
ARGPARSE_c (aVerify, "verify" , N_("verify a signature")),
|
||||||
ARGPARSE_c (aVerifyFiles, "verify-files" , "@" ),
|
ARGPARSE_c (aVerifyFiles, "verify-files" , "@" ),
|
||||||
|
ARGPARSE_c (aAddRecipients, "add-recipients", "@" ),
|
||||||
|
ARGPARSE_c (aChangeRecipients, "change-recipients", "@" ),
|
||||||
ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
|
ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
|
||||||
ARGPARSE_c (aListKeys, "list-public-keys", "@" ),
|
ARGPARSE_c (aListKeys, "list-public-keys", "@" ),
|
||||||
ARGPARSE_c (aListSigs, "list-signatures", N_("list keys and signatures")),
|
ARGPARSE_c (aListSigs, "list-signatures", N_("list keys and signatures")),
|
||||||
@ -2739,6 +2743,8 @@ main (int argc, char **argv)
|
|||||||
case aExportOwnerTrust:
|
case aExportOwnerTrust:
|
||||||
case aImportOwnerTrust:
|
case aImportOwnerTrust:
|
||||||
case aRebuildKeydbCaches:
|
case aRebuildKeydbCaches:
|
||||||
|
case aAddRecipients:
|
||||||
|
case aChangeRecipients:
|
||||||
set_cmd (&cmd, pargs.r_opt);
|
set_cmd (&cmd, pargs.r_opt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4168,6 +4174,12 @@ main (int argc, char **argv)
|
|||||||
case aStore:
|
case aStore:
|
||||||
cmdname="--store";
|
cmdname="--store";
|
||||||
break;
|
break;
|
||||||
|
case aAddRecipients:
|
||||||
|
cmdname="--add-recipients";
|
||||||
|
break;
|
||||||
|
case aChangeRecipients:
|
||||||
|
cmdname="--change-recipients";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cmdname=NULL;
|
cmdname=NULL;
|
||||||
break;
|
break;
|
||||||
@ -4262,7 +4274,9 @@ main (int argc, char **argv)
|
|||||||
|| cmd == aEncrSym
|
|| cmd == aEncrSym
|
||||||
|| cmd == aSym
|
|| cmd == aSym
|
||||||
|| cmd == aSignSym
|
|| cmd == aSignSym
|
||||||
|| cmd == aSignEncrSym,
|
|| cmd == aSignEncrSym
|
||||||
|
|| cmd == aAddRecipients
|
||||||
|
|| cmd == aChangeRecipients,
|
||||||
opt.def_cipher_algo,
|
opt.def_cipher_algo,
|
||||||
GCRY_CIPHER_MODE_NONE))
|
GCRY_CIPHER_MODE_NONE))
|
||||||
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
|
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
|
||||||
@ -4509,6 +4523,26 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case aChangeRecipients: /* Change recipients of the encrypted file. */
|
||||||
|
ctrl->clear_recipients = 1;
|
||||||
|
/* fallthru */
|
||||||
|
case aAddRecipients: /* Add recipients to the encrypted file. */
|
||||||
|
ctrl->modify_recipients = 1;
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
if (cmd == aAddRecipients)
|
||||||
|
wrong_args("--add-recipients [filename]");
|
||||||
|
else
|
||||||
|
wrong_args("--change-recipients [filename]");
|
||||||
|
}
|
||||||
|
if ((rc = decrypt_message (ctrl, fname, remusr)))
|
||||||
|
{
|
||||||
|
write_status_failure ("modify-recipients", rc);
|
||||||
|
log_error ("%s: modify recipients failed: %s\n",
|
||||||
|
print_fname_stdin (fname), gpg_strerror (rc));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case aEncrSym:
|
case aEncrSym:
|
||||||
/* This works with PGP 8 in the sense that it acts just like a
|
/* This works with PGP 8 in the sense that it acts just like a
|
||||||
symmetric message. It doesn't work at all with 2 or 6. It
|
symmetric message. It doesn't work at all with 2 or 6. It
|
||||||
@ -4650,7 +4684,7 @@ main (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if( argc > 1 )
|
if( argc > 1 )
|
||||||
wrong_args("--decrypt [filename]");
|
wrong_args("--decrypt [filename]");
|
||||||
if( (rc = decrypt_message (ctrl, fname) ))
|
if( (rc = decrypt_message (ctrl, fname, NULL) ))
|
||||||
{
|
{
|
||||||
write_status_failure ("decrypt", rc);
|
write_status_failure ("decrypt", rc);
|
||||||
log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
|
log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
|
||||||
|
@ -122,6 +122,15 @@ struct server_control_s
|
|||||||
unsigned char *secret_keygrips;
|
unsigned char *secret_keygrips;
|
||||||
size_t secret_keygrips_len;
|
size_t secret_keygrips_len;
|
||||||
int no_more_secret_keygrips;
|
int no_more_secret_keygrips;
|
||||||
|
|
||||||
|
/* This first flag is set to true if we are running a
|
||||||
|
* --add-recipients or --change-recipients command. The second if
|
||||||
|
* it is --change-recipients. */
|
||||||
|
unsigned int modify_recipients:1;
|
||||||
|
unsigned int clear_recipients:1;
|
||||||
|
|
||||||
|
/* Temporary used to pass the last read byte up the call chain. */
|
||||||
|
int last_read_ctb;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,6 +248,11 @@ int encrypt_crypt (ctrl_t ctrl, gnupg_fd_t filefd, const char *filename,
|
|||||||
gnupg_fd_t outputfd);
|
gnupg_fd_t outputfd);
|
||||||
void encrypt_crypt_files (ctrl_t ctrl,
|
void encrypt_crypt_files (ctrl_t ctrl,
|
||||||
int nfiles, char **files, strlist_t remusr);
|
int nfiles, char **files, strlist_t remusr);
|
||||||
|
gpg_error_t reencrypt_to_new_recipients (ctrl_t ctrl, int armor,
|
||||||
|
const char *filename, iobuf_t infp,
|
||||||
|
strlist_t recipients,
|
||||||
|
DEK *dek,
|
||||||
|
struct pubkey_enc_list *pkenc_list);
|
||||||
int encrypt_filter (void *opaque, int control,
|
int encrypt_filter (void *opaque, int control,
|
||||||
iobuf_t a, byte *buf, size_t *ret_len);
|
iobuf_t a, byte *buf, size_t *ret_len);
|
||||||
|
|
||||||
@ -501,7 +506,8 @@ void check_assert_signer_list (const char *mainpkhex, const char *pkhex);
|
|||||||
void check_assert_pubkey_algo (const char *algostr, const char *pkhex);
|
void check_assert_pubkey_algo (const char *algostr, const char *pkhex);
|
||||||
|
|
||||||
/*-- decrypt.c --*/
|
/*-- decrypt.c --*/
|
||||||
int decrypt_message (ctrl_t ctrl, const char *filename );
|
gpg_error_t decrypt_message (ctrl_t ctrl, const char *filename,
|
||||||
|
strlist_t remusr);
|
||||||
gpg_error_t decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
gpg_error_t decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
||||||
gnupg_fd_t output_fd);
|
gnupg_fd_t output_fd);
|
||||||
void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]);
|
void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]);
|
||||||
|
@ -116,7 +116,7 @@ static int literals_seen;
|
|||||||
|
|
||||||
|
|
||||||
/*** Local prototypes. ***/
|
/*** Local prototypes. ***/
|
||||||
static int do_proc_packets (CTX c, iobuf_t a);
|
static int do_proc_packets (CTX c, iobuf_t a, int keep_dek_and_list);
|
||||||
static void list_node (CTX c, kbnode_t node);
|
static void list_node (CTX c, kbnode_t node);
|
||||||
static void proc_tree (CTX c, kbnode_t node);
|
static void proc_tree (CTX c, kbnode_t node);
|
||||||
|
|
||||||
@ -580,10 +580,15 @@ proc_encrypted (CTX c, PACKET *pkt)
|
|||||||
int early_plaintext = literals_seen;
|
int early_plaintext = literals_seen;
|
||||||
unsigned int compliance_de_vs = 0;
|
unsigned int compliance_de_vs = 0;
|
||||||
|
|
||||||
if (pkt->pkttype == PKT_ENCRYPTED_AEAD)
|
if (pkt)
|
||||||
c->seen_pkt_encrypted_aead = 1;
|
{
|
||||||
if (pkt->pkttype == PKT_ENCRYPTED_MDC)
|
if (pkt->pkttype == PKT_ENCRYPTED_AEAD)
|
||||||
c->seen_pkt_encrypted_mdc = 1;
|
c->seen_pkt_encrypted_aead = 1;
|
||||||
|
if (pkt->pkttype == PKT_ENCRYPTED_MDC)
|
||||||
|
c->seen_pkt_encrypted_mdc = 1;
|
||||||
|
}
|
||||||
|
else /* No PKT indicates the the add-recipients mode. */
|
||||||
|
log_assert (c->ctrl->modify_recipients);
|
||||||
|
|
||||||
if (early_plaintext)
|
if (early_plaintext)
|
||||||
{
|
{
|
||||||
@ -650,6 +655,22 @@ proc_encrypted (CTX c, PACKET *pkt)
|
|||||||
if (c->dek && opt.verbose > 1)
|
if (c->dek && opt.verbose > 1)
|
||||||
log_info (_("public key encrypted data: good DEK\n"));
|
log_info (_("public key encrypted data: good DEK\n"));
|
||||||
|
|
||||||
|
if (c->ctrl->modify_recipients)
|
||||||
|
{
|
||||||
|
if (c->anchor)
|
||||||
|
{
|
||||||
|
log_error ("command not possible with nested data\n");
|
||||||
|
write_status_errcode ("decryption.mod_recp", GPG_ERR_BAD_DATA);
|
||||||
|
xfree (c->dek);
|
||||||
|
c->dek = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
literals_seen++;
|
||||||
|
/* Simply return here. Our caller will then test for DEK and
|
||||||
|
* the PK_list to decide whether decryption worked. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!opt.show_only_session_key)
|
if (!opt.show_only_session_key)
|
||||||
write_status (STATUS_BEGIN_DECRYPTION);
|
write_status (STATUS_BEGIN_DECRYPTION);
|
||||||
|
|
||||||
@ -1112,7 +1133,7 @@ static int
|
|||||||
proc_encrypt_cb (iobuf_t a, void *info )
|
proc_encrypt_cb (iobuf_t a, void *info )
|
||||||
{
|
{
|
||||||
CTX c = info;
|
CTX c = info;
|
||||||
return proc_encryption_packets (c->ctrl, info, a );
|
return proc_encryption_packets (c->ctrl, info, a, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1502,7 +1523,7 @@ proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
|
|||||||
|
|
||||||
c->ctrl = ctrl;
|
c->ctrl = ctrl;
|
||||||
c->anchor = anchor;
|
c->anchor = anchor;
|
||||||
rc = do_proc_packets (c, a);
|
rc = do_proc_packets (c, a, 0);
|
||||||
xfree (c);
|
xfree (c);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -1525,7 +1546,7 @@ proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
|
|||||||
c->signed_data.used = !!signedfiles;
|
c->signed_data.used = !!signedfiles;
|
||||||
|
|
||||||
c->sigfilename = sigfilename;
|
c->sigfilename = sigfilename;
|
||||||
rc = do_proc_packets (c, a);
|
rc = do_proc_packets (c, a, 0);
|
||||||
|
|
||||||
/* If we have not encountered any signature we print an error
|
/* If we have not encountered any signature we print an error
|
||||||
messages, send a NODATA status back and return an error code.
|
messages, send a NODATA status back and return an error code.
|
||||||
@ -1568,7 +1589,7 @@ proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a,
|
|||||||
c->signed_data.data_names = NULL;
|
c->signed_data.data_names = NULL;
|
||||||
c->signed_data.used = (signed_data_fd != GNUPG_INVALID_FD);
|
c->signed_data.used = (signed_data_fd != GNUPG_INVALID_FD);
|
||||||
|
|
||||||
rc = do_proc_packets (c, a);
|
rc = do_proc_packets (c, a, 0);
|
||||||
|
|
||||||
/* If we have not encountered any signature we print an error
|
/* If we have not encountered any signature we print an error
|
||||||
messages, send a NODATA status back and return an error code.
|
messages, send a NODATA status back and return an error code.
|
||||||
@ -1592,8 +1613,13 @@ proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
/* Handle encryption packets. If called recursively the caller's CTX
|
||||||
proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
|
* should be given for ANCHOR. If R_DEK and R_LIST are not NULL the
|
||||||
|
* DEK (or NULL) is returned there and the list at R_LIST; the caller
|
||||||
|
* needs to release them; even if the function returns an error. */
|
||||||
|
gpg_error_t
|
||||||
|
proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a,
|
||||||
|
DEK **r_dek, struct pubkey_enc_list **r_list)
|
||||||
{
|
{
|
||||||
CTX c = xmalloc_clear (sizeof *c);
|
CTX c = xmalloc_clear (sizeof *c);
|
||||||
int rc;
|
int rc;
|
||||||
@ -1601,7 +1627,16 @@ proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a )
|
|||||||
c->ctrl = ctrl;
|
c->ctrl = ctrl;
|
||||||
c->anchor = anchor;
|
c->anchor = anchor;
|
||||||
c->encrypt_only = 1;
|
c->encrypt_only = 1;
|
||||||
rc = do_proc_packets (c, a);
|
if (r_dek && r_list)
|
||||||
|
{
|
||||||
|
rc = do_proc_packets (c, a, 1);
|
||||||
|
*r_dek = c->dek;
|
||||||
|
c->dek = NULL;
|
||||||
|
*r_list = c->pkenc_list;
|
||||||
|
c->pkenc_list = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rc = do_proc_packets (c, a, 0);
|
||||||
xfree (c);
|
xfree (c);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1626,8 +1661,11 @@ check_nesting (CTX c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Main processing loop. If KEEP_DEK_AND_LIST is set the DEK and
|
||||||
|
* PKENC_LIST of the context C are not released at the end of the
|
||||||
|
* function. The caller is then required to do this. */
|
||||||
static int
|
static int
|
||||||
do_proc_packets (CTX c, iobuf_t a)
|
do_proc_packets (CTX c, iobuf_t a, int keep_dek_and_list)
|
||||||
{
|
{
|
||||||
PACKET *pkt;
|
PACKET *pkt;
|
||||||
struct parse_packet_ctx_s parsectx;
|
struct parse_packet_ctx_s parsectx;
|
||||||
@ -1648,6 +1686,18 @@ do_proc_packets (CTX c, iobuf_t a)
|
|||||||
any_data = 1;
|
any_data = 1;
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
if (c->ctrl->modify_recipients && gpg_err_code (rc) == GPG_ERR_TRUE)
|
||||||
|
{
|
||||||
|
/* Save the last read CTB (which was the last byte
|
||||||
|
* actually read from the input) and get out of the
|
||||||
|
* loop. */
|
||||||
|
c->ctrl->last_read_ctb = parsectx.last_ctb;
|
||||||
|
/* We need to call the first part of the encrypted data
|
||||||
|
* handler to get the DEK. */
|
||||||
|
proc_encrypted (c, NULL);
|
||||||
|
rc = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
free_packet (pkt, &parsectx);
|
free_packet (pkt, &parsectx);
|
||||||
/* Stop processing when an invalid packet has been encountered
|
/* Stop processing when an invalid packet has been encountered
|
||||||
* but don't do so when we are doing a --list-packets. */
|
* but don't do so when we are doing a --list-packets. */
|
||||||
@ -1706,8 +1756,19 @@ do_proc_packets (CTX c, iobuf_t a)
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break;
|
case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break;
|
||||||
case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break;
|
|
||||||
case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break;
|
case PKT_SYMKEY_ENC:
|
||||||
|
case PKT_PUBKEY_ENC:
|
||||||
|
/* In --add-recipients mode set the stop flag as soon as
|
||||||
|
* we see the first of these packets. */
|
||||||
|
if (c->ctrl->modify_recipients)
|
||||||
|
parsectx.only_fookey_enc = 1;
|
||||||
|
if (pkt->pkttype == PKT_SYMKEY_ENC)
|
||||||
|
proc_symkey_enc (c, pkt);
|
||||||
|
else
|
||||||
|
proc_pubkey_enc (c, pkt);
|
||||||
|
break;
|
||||||
|
|
||||||
case PKT_ENCRYPTED:
|
case PKT_ENCRYPTED:
|
||||||
case PKT_ENCRYPTED_MDC:
|
case PKT_ENCRYPTED_MDC:
|
||||||
case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
|
case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break;
|
||||||
@ -1783,8 +1844,8 @@ do_proc_packets (CTX c, iobuf_t a)
|
|||||||
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
release_list (c);
|
if (!keep_dek_and_list)
|
||||||
xfree(c->dek);
|
release_list (c);
|
||||||
free_packet (pkt, &parsectx);
|
free_packet (pkt, &parsectx);
|
||||||
deinit_parse_packet (&parsectx);
|
deinit_parse_packet (&parsectx);
|
||||||
xfree (pkt);
|
xfree (pkt);
|
||||||
|
@ -165,7 +165,7 @@ ask_outfile_name( const char *name, size_t namelen )
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Make an output filename for the inputfile INAME.
|
* Make an output filename for the inputfile INAME.
|
||||||
* Returns an IOBUF and an errorcode
|
* Returns an IOBUF at A and an errorcode
|
||||||
* Mode 0 = use ".gpg"
|
* Mode 0 = use ".gpg"
|
||||||
* 1 = use ".asc"
|
* 1 = use ".asc"
|
||||||
* 2 = use ".sig"
|
* 2 = use ".sig"
|
||||||
|
@ -644,7 +644,10 @@ int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a,
|
|||||||
strlist_t signedfiles, const char *sigfile );
|
strlist_t signedfiles, const char *sigfile );
|
||||||
int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a,
|
int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a,
|
||||||
gnupg_fd_t signed_data_fd);
|
gnupg_fd_t signed_data_fd);
|
||||||
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
|
gpg_error_t proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a,
|
||||||
|
DEK **r_dek,
|
||||||
|
struct pubkey_enc_list **r_list);
|
||||||
|
|
||||||
int list_packets( iobuf_t a );
|
int list_packets( iobuf_t a );
|
||||||
|
|
||||||
const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len);
|
const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len);
|
||||||
@ -673,7 +676,9 @@ struct parse_packet_ctx_s
|
|||||||
struct packet_struct last_pkt; /* The last parsed packet. */
|
struct packet_struct last_pkt; /* The last parsed packet. */
|
||||||
int free_last_pkt; /* Indicates that LAST_PKT must be freed. */
|
int free_last_pkt; /* Indicates that LAST_PKT must be freed. */
|
||||||
int skip_meta; /* Skip ring trust packets. */
|
int skip_meta; /* Skip ring trust packets. */
|
||||||
|
int only_fookey_enc; /* Stop if the packet is not {sym,pub}key_enc. */
|
||||||
unsigned int n_parsed_packets; /* Number of parsed packets. */
|
unsigned int n_parsed_packets; /* Number of parsed packets. */
|
||||||
|
int last_ctb; /* The last CTB read. */
|
||||||
};
|
};
|
||||||
typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
|
typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
|
||||||
|
|
||||||
@ -683,7 +688,9 @@ typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
|
|||||||
(a)->last_pkt.pkt.generic= NULL;\
|
(a)->last_pkt.pkt.generic= NULL;\
|
||||||
(a)->free_last_pkt = 0; \
|
(a)->free_last_pkt = 0; \
|
||||||
(a)->skip_meta = 0; \
|
(a)->skip_meta = 0; \
|
||||||
|
(a)->only_fookey_enc = 0; \
|
||||||
(a)->n_parsed_packets = 0; \
|
(a)->n_parsed_packets = 0; \
|
||||||
|
(a)->last_ctb = 1; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define deinit_parse_packet(a) do { \
|
#define deinit_parse_packet(a) do { \
|
||||||
|
@ -763,6 +763,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
ctx->last_ctb = ctb;
|
||||||
hdrlen = 0;
|
hdrlen = 0;
|
||||||
hdr[hdrlen++] = ctb;
|
hdr[hdrlen++] = ctb;
|
||||||
|
|
||||||
@ -774,18 +775,28 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Immediately following the header is the length. There are two
|
/* Immediately following the header is the length. There are two
|
||||||
formats: the old format and the new format. If bit 6 (where the
|
* formats: the old format and the new format. If bit 6 (where the
|
||||||
least significant bit is bit 0) is set in the tag, then we are
|
* least significant bit is bit 0) is set in the tag, then we are
|
||||||
dealing with a new format packet. Otherwise, it is an old format
|
* dealing with a new format packet. Otherwise, it is an old format
|
||||||
packet. */
|
* packet. In the new format the packet's type is encoded in the 6
|
||||||
|
* least significant bits of the tag; in the old format it is
|
||||||
|
* encoded in bits 2-5. */
|
||||||
pktlen = 0;
|
pktlen = 0;
|
||||||
new_ctb = !!(ctb & 0x40);
|
new_ctb = !!(ctb & 0x40);
|
||||||
if (new_ctb)
|
if (new_ctb)
|
||||||
{
|
pkttype = ctb & 0x3f;
|
||||||
/* Get the packet's type. This is encoded in the 6 least
|
else
|
||||||
significant bits of the tag. */
|
pkttype = (ctb >> 2) & 0xf;
|
||||||
pkttype = ctb & 0x3f;
|
|
||||||
|
|
||||||
|
if (ctx->only_fookey_enc
|
||||||
|
&& !(pkttype == PKT_SYMKEY_ENC || pkttype == PKT_PUBKEY_ENC))
|
||||||
|
{
|
||||||
|
rc = gpg_error (GPG_ERR_TRUE);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_ctb)
|
||||||
|
{
|
||||||
/* Extract the packet's length. New format packets have 4 ways
|
/* Extract the packet's length. New format packets have 4 ways
|
||||||
to encode the packet length. The value of the first byte
|
to encode the packet length. The value of the first byte
|
||||||
determines the encoding and partially determines the length.
|
determines the encoding and partially determines the length.
|
||||||
@ -855,12 +866,8 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else /* This is an old format packet. */
|
||||||
/* This is an old format packet. */
|
|
||||||
{
|
{
|
||||||
/* Extract the packet's type. This is encoded in bits 2-5. */
|
|
||||||
pkttype = (ctb >> 2) & 0xf;
|
|
||||||
|
|
||||||
/* The type of length encoding is encoded in bits 0-1 of the
|
/* The type of length encoding is encoded in bits 0-1 of the
|
||||||
tag. */
|
tag. */
|
||||||
lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3));
|
lenbytes = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3));
|
||||||
|
Loading…
Reference in New Issue
Block a user