diff --git a/g10/gpgv.c b/g10/gpgv.c index c142cef86..b33590655 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -1,789 +1,789 @@ /* gpgv.c - The GnuPG signature verify utility * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006, * 2008, 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #ifdef HAVE_DOSISH_SYSTEM #include /* for setmode() */ #endif #ifdef HAVE_LIBREADLINE #define GNUPG_LIBREADLINE_H_INCLUDED #include #endif #define INCLUDED_BY_MAIN_MODULE 1 #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/iobuf.h" #include "main.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "filter.h" #include "../common/ttyio.h" #include "../common/i18n.h" #include "../common/sysutils.h" #include "../common/status.h" #include "call-agent.h" #include "../common/init.h" enum cmd_and_opt_values { aNull = 0, oQuiet = 'q', oVerbose = 'v', oOutput = 'o', oBatch = 500, oKeyring, oIgnoreTimeConflict, oStatusFD, oLoggerFD, oLoggerFile, oHomedir, oWeakDigest, oEnableSpecialFilenames, oDebug, aTest }; static ARGPARSE_OPTS opts[] = { ARGPARSE_group (300, N_("@\nOptions:\n ")), ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")), ARGPARSE_s_s (oKeyring, "keyring", N_("|FILE|take the keys from the keyring FILE")), ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")), ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", N_("make timestamp conflicts only a warning")), ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")), ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), ARGPARSE_s_s (oLoggerFile, "log-file", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_s (oWeakDigest, "weak-digest", N_("|ALGO|reject signatures made with ALGO")), ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"), ARGPARSE_s_s (oDebug, "debug", "@"), ARGPARSE_end () }; /* The list of supported debug flags. */ static struct debug_flags_s debug_flags [] = { { DBG_PACKET_VALUE , "packet" }, { DBG_MPI_VALUE , "mpi" }, { DBG_CRYPTO_VALUE , "crypto" }, { DBG_FILTER_VALUE , "filter" }, { DBG_IOBUF_VALUE , "iobuf" }, { DBG_MEMORY_VALUE , "memory" }, { DBG_CACHE_VALUE , "cache" }, { DBG_MEMSTAT_VALUE, "memstat" }, { DBG_TRUST_VALUE , "trust" }, { DBG_HASHING_VALUE, "hashing" }, { DBG_IPC_VALUE , "ipc" }, { DBG_CLOCK_VALUE , "clock" }, { DBG_LOOKUP_VALUE , "lookup" }, { DBG_EXTPROG_VALUE, "extprog" }, { 0, NULL } }; int g10_errors_seen = 0; static char * make_libversion (const char *libname, const char *(*getfnc)(const char*)) { const char *s; char *result; s = getfnc (NULL); result = xmalloc (strlen (libname) + 1 + strlen (s) + 1); strcpy (stpcpy (stpcpy (result, libname), " "), s); return result; } static const char * my_strusage( int level ) { static char *ver_gcry; const char *p; switch (level) { case 11: p = "@GPG@v (GnuPG)"; break; case 13: p = VERSION; break; case 17: p = PRINTABLE_OS_NAME; break; case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break; case 1: case 40: p = _("Usage: gpgv [options] [files] (-h for help)"); break; case 41: p = _("Syntax: gpgv [options] [files]\n" "Check signatures against known trusted keys\n"); break; case 20: if (!ver_gcry) ver_gcry = make_libversion ("libgcrypt", gcry_check_version); p = ver_gcry; break; default: p = NULL; } return p; } int main( int argc, char **argv ) { ARGPARSE_ARGS pargs; int rc=0; strlist_t sl; strlist_t nrings = NULL; unsigned configlineno; ctrl_t ctrl; early_system_init (); set_strusage (my_strusage); log_set_prefix ("gpgv", GPGRT_LOG_WITH_PREFIX); /* Make sure that our subsystems are ready. */ i18n_init(); init_common_subsystems (&argc, &argv); gcry_control (GCRYCTL_DISABLE_SECMEM, 0); gnupg_init_signals (0, NULL); opt.command_fd = -1; /* no command fd */ opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE; opt.trust_model = TM_ALWAYS; opt.no_sig_cache = 1; opt.flags.require_cross_cert = 1; opt.batch = 1; opt.answer_yes = 1; opt.weak_digests = NULL; tty_no_terminal(1); tty_batchmode(1); dotlock_disable (); gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); additional_weak_digest("MD5"); gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG); pargs.argc = &argc; pargs.argv = &argv; pargs.flags= 1; /* do not remove the args */ while (optfile_parse( NULL, NULL, &configlineno, &pargs, opts)) { switch (pargs.r_opt) { case oQuiet: opt.quiet = 1; break; case oVerbose: opt.verbose++; opt.list_sigs=1; gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); break; case oDebug: if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags)) { pargs.r_opt = ARGPARSE_INVALID_ARG; pargs.err = ARGPARSE_PRINT_ERROR; } break; case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break; case oOutput: opt.outfile = pargs.r.ret_str; break; case oStatusFD: set_status_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); break; case oLoggerFD: log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); break; case oLoggerFile: log_set_file (pargs.r.ret_str); log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID) ); break; case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break; case oWeakDigest: additional_weak_digest(pargs.r.ret_str); break; case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; case oEnableSpecialFilenames: enable_special_filenames (); break; default : pargs.err = ARGPARSE_PRINT_ERROR; break; } } if (log_get_errorcount (0)) g10_exit(2); if (opt.verbose > 1) set_packet_list_mode(1); /* Note: We open all keyrings in read-only mode. */ if (!nrings) /* No keyring given: use default one. */ keydb_add_resource ("trustedkeys" EXTSEP_S "kbx", (KEYDB_RESOURCE_FLAG_READONLY |KEYDB_RESOURCE_FLAG_GPGVDEF)); for (sl = nrings; sl; sl = sl->next) keydb_add_resource (sl->d, KEYDB_RESOURCE_FLAG_READONLY); FREE_STRLIST (nrings); ctrl = xcalloc (1, sizeof *ctrl); if ((rc = verify_signatures (ctrl, argc, argv))) log_error("verify signatures failed: %s\n", gpg_strerror (rc) ); keydb_release (ctrl->cached_getkey_kdb); xfree (ctrl); /* cleanup */ g10_exit (0); return 8; /*NOTREACHED*/ } void g10_exit( int rc ) { rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; exit(rc ); } /* Stub: * We have to override the trustcheck from pkclist.c because * this utility assumes that all keys in the keyring are trustworthy */ int check_signatures_trust (ctrl_t ctrl, PKT_signature *sig) { (void)ctrl; (void)sig; return 0; } void read_trust_options (ctrl_t ctrl, byte *trust_model, ulong *created, ulong *nextcheck, byte *marginals, byte *completes, byte *cert_depth, byte *min_cert_level) { (void)ctrl; (void)trust_model; (void)created; (void)nextcheck; (void)marginals; (void)completes; (void)cert_depth; (void)min_cert_level; } /* Stub: * We don't have the trustdb , so we have to provide some stub functions * instead */ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return 0; } void check_trustdb_stale (ctrl_t ctrl) { (void)ctrl; } int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid) { (void)ctrl; (void)kb; (void)pk; (void)uid; return '?'; } unsigned int get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig, int may_ask) { (void)ctrl; (void)kb; (void)pk; (void)uid; (void)sig; (void)may_ask; return 0; } const char * trust_value_to_string (unsigned int value) { (void)value; return "err"; } const char * uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid) { (void)ctrl; (void)key; (void)uid; return "err"; } int get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create) { (void)ctrl; (void)pk; (void)no_create; return '?'; } unsigned int get_ownertrust (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return TRUST_UNKNOWN; } /* Stubs: * Because we only work with trusted keys, it does not make sense to * get them from a keyserver */ struct keyserver_spec * keyserver_match (struct keyserver_spec *spec) { (void)spec; return NULL; } int keyserver_any_configured (ctrl_t ctrl) { (void)ctrl; return 0; } int keyserver_import_keyid (u32 *keyid, void *dummy, int quick) { (void)keyid; (void)dummy; (void)quick; return -1; } int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, struct keyserver_spec *keyserver, int quick) { (void)ctrl; (void)fprint; (void)fprint_len; (void)keyserver; (void)quick; return -1; } int keyserver_import_cert (const char *name) { (void)name; return -1; } int keyserver_import_pka (const char *name,unsigned char *fpr) { (void)name; (void)fpr; return -1; } gpg_error_t keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, unsigned char **fpr, size_t *fpr_len) { (void)ctrl; (void)name; (void)quick; (void)fpr; (void)fpr_len; return GPG_ERR_BUG; } int keyserver_import_name (const char *name,struct keyserver_spec *spec) { (void)name; (void)spec; return -1; } int keyserver_import_ldap (const char *name) { (void)name; return -1; } gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock) { (void)ctrl; (void)fname; (void)r_keyblock; return -1; } /* Stub: * No encryption here but mainproc links to these functions. */ gpg_error_t -get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek) { (void)ctrl; (void)k; (void)dek; return GPG_ERR_GENERAL; } /* Stub: */ gpg_error_t get_override_session_key (DEK *dek, const char *string) { (void)dek; (void)string; return GPG_ERR_GENERAL; } /* Stub: */ int decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { (void)ctrl; (void)procctx; (void)ed; (void)dek; return GPG_ERR_GENERAL; } /* Stub: * No interactive commands, so we don't need the helptexts */ void display_online_help (const char *keyword) { (void)keyword; } /* Stub: * We don't use secret keys, but getkey.c links to this */ int check_secret_key (PKT_public_key *pk, int n) { (void)pk; (void)n; return GPG_ERR_GENERAL; } /* Stub: * No secret key, so no passphrase needed */ DEK * passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, int create, int nocache, const char *tmp, int *canceled) { (void)cipher_algo; (void)s2k; (void)create; (void)nocache; (void)tmp; if (canceled) *canceled = 0; return NULL; } void passphrase_clear_cache (const char *cacheid) { (void)cacheid; } struct keyserver_spec * parse_preferred_keyserver(PKT_signature *sig) { (void)sig; return NULL; } struct keyserver_spec * parse_keyserver_uri (const char *uri, int require_scheme, const char *configname, unsigned int configlineno) { (void)uri; (void)require_scheme; (void)configname; (void)configlineno; return NULL; } void free_keyserver_spec (struct keyserver_spec *keyserver) { (void)keyserver; } /* Stubs to avoid linking to photoid.c */ void show_photos (const struct user_attribute *attrs, int count, PKT_public_key *pk) { (void)attrs; (void)count; (void)pk; } int parse_image_header (const struct user_attribute *attr, byte *type, u32 *len) { (void)attr; (void)type; (void)len; return 0; } char * image_type_to_string (byte type, int string) { (void)type; (void)string; return NULL; } #ifdef ENABLE_CARD_SUPPORT int agent_scd_getattr (const char *name, struct agent_card_info_s *info) { (void)name; (void)info; return 0; } #endif /* ENABLE_CARD_SUPPORT */ /* We do not do any locking, so use these stubs here */ void dotlock_disable (void) { } dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags) { (void)file_to_lock; (void)flags; return NULL; } void dotlock_destroy (dotlock_t h) { (void)h; } int dotlock_take (dotlock_t h, long timeout) { (void)h; (void)timeout; return 0; } int dotlock_release (dotlock_t h) { (void)h; return 0; } void dotlock_remove_lockfiles (void) { } gpg_error_t agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock) { (void)ctrl; (void)keyblock; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno, int *r_cleartext) { (void)ctrl; (void)hexkeygrip; (void)r_cleartext; *r_serialno = NULL; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, unsigned char **r_fpr, size_t *r_fprlen, char **r_url) { (void)ctrl; (void)userid; if (r_fpr) *r_fpr = NULL; if (r_fprlen) *r_fprlen = 0; if (r_url) *r_url = NULL; return gpg_error (GPG_ERR_NOT_FOUND); } gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen) { (void)ctrl; (void)keyspec; (void)options; (void)stats; *r_keyblock = NULL; *r_data = NULL; *r_datalen = 0; return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } gpg_error_t tofu_write_tfs_record (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, const char *user_id) { (void)ctrl; (void)fp; (void)pk; (void)user_id; return gpg_error (GPG_ERR_GENERAL); } gpg_error_t tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id, enum tofu_policy *policy) { (void)ctrl; (void)pk; (void)user_id; (void)policy; return gpg_error (GPG_ERR_GENERAL); } const char * tofu_policy_str (enum tofu_policy policy) { (void)policy; return "unknown"; } void tofu_begin_batch_update (ctrl_t ctrl) { (void)ctrl; } void tofu_end_batch_update (ctrl_t ctrl) { (void)ctrl; } gpg_error_t tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb) { (void) ctrl; (void) kb; return 0; } int get_revocation_reason (PKT_signature *sig, char **r_reason, char **r_comment, size_t *r_commentlen) { (void)sig; (void)r_commentlen; if (r_reason) *r_reason = NULL; if (r_comment) *r_comment = NULL; return 0; } diff --git a/g10/mainproc.c b/g10/mainproc.c index 1d56f1f30..6ec15894d 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,2705 +1,2671 @@ /* mainproc.c - handle packets * Copyright (C) 1998-2009 Free Software Foundation, Inc. * Copyright (C) 2013-2014 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/iobuf.h" #include "options.h" #include "keydb.h" #include "filter.h" #include "main.h" #include "../common/status.h" #include "../common/i18n.h" #include "trustdb.h" #include "keyserver-internal.h" #include "photoid.h" #include "../common/mbox-util.h" #include "call-dirmngr.h" #include "../common/compliance.h" /* Put an upper limit on nested packets. The 32 is an arbitrary value, a much lower should actually be sufficient. */ #define MAX_NESTING_DEPTH 32 -/* An object to build a list of keyid related info. */ -struct kidlist_item -{ - struct kidlist_item *next; - u32 kid[2]; - int pubkey_algo; - int reason; -}; - - /* * Object to hold the processing context. */ typedef struct mainproc_context *CTX; struct mainproc_context { ctrl_t ctrl; struct mainproc_context *anchor; /* May be useful in the future. */ PKT_public_key *last_pubkey; PKT_user_id *last_user_id; md_filter_context_t mfx; int sigs_only; /* Process only signatures and reject all other stuff. */ int encrypt_only; /* Process only encryption messages. */ /* Name of the file with the complete signature or the file with the detached signature. This is currently only used to deduce the file name of the data file if that has not been given. */ const char *sigfilename; /* A structure to describe the signed data in case of a detached signature. */ struct { /* A file descriptor of the signed data. Only used if not -1. */ int data_fd; /* A list of filenames with the data files or NULL. This is only used if DATA_FD is -1. */ strlist_t data_names; /* Flag to indicated that either one of the next previous fields is used. This is only needed for better readability. */ int used; } signed_data; DEK *dek; int last_was_session_key; kbnode_t list; /* The current list of packets. */ iobuf_t iobuf; /* Used to get the filename etc. */ int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ - struct kidlist_item *pkenc_list; /* List of encryption packets. */ + struct pubkey_enc_list *pkenc_list; /* List of encryption packets. */ struct { unsigned int sig_seen:1; /* Set to true if a signature packet has been seen. */ unsigned int data:1; /* Any data packet seen */ unsigned int uncompress_failed:1; } any; }; /* Counter with the number of literal data packets seen. Note that * this is also bumped at the end of an encryption. This counter is * used for a basic consistency check of a received PGP message. */ static int literals_seen; /*** Local prototypes. ***/ -static int do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a); +static int do_proc_packets (CTX c, iobuf_t a); static void list_node (CTX c, kbnode_t node); static void proc_tree (CTX c, kbnode_t node); /*** Functions. ***/ /* Reset the literal data counter. This is required to setup a new * decryption or verification context. */ void reset_literals_seen(void) { literals_seen = 0; } static void release_list( CTX c ) { proc_tree (c, c->list); release_kbnode (c->list); while (c->pkenc_list) { - struct kidlist_item *tmp = c->pkenc_list->next; + struct pubkey_enc_list *tmp = c->pkenc_list->next; + + mpi_release (c->pkenc_list->data[0]); + mpi_release (c->pkenc_list->data[1]); xfree (c->pkenc_list); c->pkenc_list = tmp; } c->pkenc_list = NULL; c->list = NULL; c->any.data = 0; c->any.uncompress_failed = 0; c->last_was_session_key = 0; xfree (c->dek); c->dek = NULL; } static int add_onepass_sig (CTX c, PACKET *pkt) { kbnode_t node; if (c->list) /* Add another packet. */ add_kbnode (c->list, new_kbnode (pkt)); else /* Insert the first one. */ c->list = node = new_kbnode (pkt); return 1; } static int add_gpg_control (CTX c, PACKET *pkt) { if ( pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* New clear text signature. * Process the last one and reset everything */ release_list(c); } if (c->list) /* Add another packet. */ add_kbnode (c->list, new_kbnode (pkt)); else /* Insert the first one. */ c->list = new_kbnode (pkt); return 1; } static int add_user_id (CTX c, PACKET *pkt) { if (!c->list) { log_error ("orphaned user ID\n"); return 0; } add_kbnode (c->list, new_kbnode (pkt)); return 1; } static int add_subkey (CTX c, PACKET *pkt) { if (!c->list) { log_error ("subkey w/o mainkey\n"); return 0; } add_kbnode (c->list, new_kbnode (pkt)); return 1; } static int add_ring_trust (CTX c, PACKET *pkt) { if (!c->list) { log_error ("ring trust w/o key\n"); return 0; } add_kbnode (c->list, new_kbnode (pkt)); return 1; } static int add_signature (CTX c, PACKET *pkt) { kbnode_t node; c->any.sig_seen = 1; if (pkt->pkttype == PKT_SIGNATURE && !c->list) { /* This is the first signature for the following datafile. * GPG does not write such packets; instead it always uses * onepass-sig packets. The drawback of PGP's method * of prepending the signature to the data is * that it is not possible to make a signature from data read * from stdin. (GPG is able to read PGP stuff anyway.) */ node = new_kbnode (pkt); c->list = node; return 1; } else if (!c->list) return 0; /* oops (invalid packet sequence)*/ else if (!c->list->pkt) BUG(); /* so nicht */ /* Add a new signature node item at the end. */ node = new_kbnode (pkt); add_kbnode (c->list, node); return 1; } static gpg_error_t symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen) { gpg_error_t err; gcry_cipher_hd_t hd; unsigned int noncelen, keylen; enum gcry_cipher_modes ciphermode; if (dek->use_aead) { err = openpgp_aead_algo_info (dek->use_aead, &ciphermode, &noncelen); if (err) return err; } else { ciphermode = GCRY_CIPHER_MODE_CFB; noncelen = 0; } /* Check that the session key has a size of 16 to 32 bytes. */ if ((dek->use_aead && (slen < (noncelen + 16 + 16) || slen > (noncelen + 32 + 16))) || (!dek->use_aead && (slen < 17 || slen > 33))) { log_error ( _("weird size for an encrypted session key (%d)\n"), (int)slen); return gpg_error (GPG_ERR_BAD_KEY); } err = openpgp_cipher_open (&hd, dek->algo, ciphermode, GCRY_CIPHER_SECURE); if (!err) err = gcry_cipher_setkey (hd, dek->key, dek->keylen); if (!err) err = gcry_cipher_setiv (hd, noncelen? seskey : NULL, noncelen); if (err) goto leave; if (dek->use_aead) { byte ad[4]; ad[0] = (0xc0 | PKT_SYMKEY_ENC); ad[1] = 5; ad[2] = dek->algo; ad[3] = dek->use_aead; err = gcry_cipher_authenticate (hd, ad, 4); if (err) goto leave; gcry_cipher_final (hd); keylen = slen - noncelen - 16; err = gcry_cipher_decrypt (hd, seskey+noncelen, keylen, NULL, 0); if (err) goto leave; err = gcry_cipher_checktag (hd, seskey+noncelen+keylen, 16); if (err) goto leave; /* Now we replace the dek components with the real session key to * decrypt the contents of the sequencing packet. */ if (keylen > DIM(dek->key)) { err = gpg_error (GPG_ERR_TOO_LARGE); goto leave; } dek->keylen = keylen; memcpy (dek->key, seskey + noncelen, dek->keylen); } else { gcry_cipher_decrypt (hd, seskey, slen, NULL, 0 ); /* Here we can only test whether the algo given in decrypted * session key is a valid OpenPGP algo. With 11 defined * symmetric algorithms we will miss 4.3% of wrong passphrases * here. The actual checking is done later during bulk * decryption; we can't bring this check forward easily. We * need to use the GPG_ERR_CHECKSUM so that we won't run into * the gnupg < 2.2 bug compatible case which would terminate the * process on GPG_ERR_CIPHER_ALGO. Note that with AEAD (above) * we will have a reliable test here. */ if (openpgp_cipher_test_algo (seskey[0])) { err = gpg_error (GPG_ERR_CHECKSUM); goto leave; } /* Now we replace the dek components with the real session key to * decrypt the contents of the sequencing packet. */ keylen = slen-1; if (keylen > DIM(dek->key)) { err = gpg_error (GPG_ERR_TOO_LARGE); goto leave; } dek->algo = seskey[0]; dek->keylen = keylen; memcpy (dek->key, seskey + 1, dek->keylen); } /*log_hexdump( "thekey", dek->key, dek->keylen );*/ leave: gcry_cipher_close (hd); return err; } static void proc_symkey_enc (CTX c, PACKET *pkt) { gpg_error_t err; PKT_symkey_enc *enc; enc = pkt->pkt.symkey_enc; if (!enc) log_error ("invalid symkey encrypted packet\n"); else if(!c->dek) { int algo = enc->cipher_algo; const char *s = openpgp_cipher_algo_name (algo); const char *a = (enc->aead_algo ? openpgp_aead_algo_name (enc->aead_algo) /**/ : "CFB"); if (!openpgp_cipher_test_algo (algo)) { if (!opt.quiet) { if (enc->seskeylen) log_info (_("%s.%s encrypted session key\n"), s, a ); else log_info (_("%s.%s encrypted data\n"), s, a ); } } else log_error (_("encrypted with unknown algorithm %d.%s\n"), algo, a); if (openpgp_md_test_algo (enc->s2k.hash_algo)) { log_error(_("passphrase generated with unknown digest" " algorithm %d\n"),enc->s2k.hash_algo); s = NULL; } c->last_was_session_key = 2; if (!s || opt.list_only) goto leave; if (opt.override_session_key) { c->dek = xmalloc_clear (sizeof *c->dek); if (get_override_session_key (c->dek, opt.override_session_key)) { xfree (c->dek); c->dek = NULL; } } else { c->dek = passphrase_to_dek (algo, &enc->s2k, 0, 0, NULL, NULL); if (c->dek) { c->dek->symmetric = 1; c->dek->use_aead = enc->aead_algo; /* FIXME: This doesn't work perfectly if a symmetric key comes before a public key in the message - if the user doesn't know the passphrase, then there is a chance that the "decrypted" algorithm will happen to be a valid one, which will make the returned dek appear valid, so we won't try any public keys that come later. */ if (enc->seskeylen) { err = symkey_decrypt_seskey (c->dek, enc->seskey, enc->seskeylen); if (err) { log_info ("decryption of the symmetrically encrypted" " session key failed: %s\n", gpg_strerror (err)); if (gpg_err_code (err) != GPG_ERR_BAD_KEY && gpg_err_code (err) != GPG_ERR_CHECKSUM) log_fatal ("process terminated to be bug compatible" " with GnuPG <= 2.2\n"); if (c->dek->s2k_cacheid[0]) { if (opt.debug) log_debug ("cleared passphrase cached with ID:" " %s\n", c->dek->s2k_cacheid); passphrase_clear_cache (c->dek->s2k_cacheid); } xfree (c->dek); c->dek = NULL; } } else c->dek->algo_info_printed = 1; } } } leave: c->symkeys++; free_packet (pkt, NULL); } static void -proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt) +proc_pubkey_enc (CTX c, PACKET *pkt) { PKT_pubkey_enc *enc; - int result = 0; /* Check whether the secret key is available and store in this case. */ c->last_was_session_key = 1; enc = pkt->pkt.pubkey_enc; /*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/ /* Hmmm: why do I have this algo check here - anyway there is * function to check it. */ if (opt.verbose) log_info (_("public key is %s\n"), keystr (enc->keyid)); - if (is_status_enabled()) + if (is_status_enabled ()) { char buf[50]; snprintf (buf, sizeof buf, "%08lX%08lX %d 0", - (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo); + (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo); write_status_text (STATUS_ENC_TO, buf); } - if (!opt.list_only && opt.override_session_key) + if (!opt.list_only && !opt.override_session_key) { - /* It does not make much sense to store the session key in - * secure memory because it has already been passed on the - * command line and the GCHQ knows about it. */ - c->dek = xmalloc_clear (sizeof *c->dek); - result = get_override_session_key (c->dek, opt.override_session_key); - if (result) - { - xfree (c->dek); - c->dek = NULL; - } - } - else if (enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E - || enc->pubkey_algo == PUBKEY_ALGO_ECDH - || enc->pubkey_algo == PUBKEY_ALGO_RSA - || enc->pubkey_algo == PUBKEY_ALGO_RSA_E - || enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) - { - /* Note that we also allow type 20 Elgamal keys for decryption. - There are still a couple of those keys in active use as a - subkey. */ - - /* FIXME: Store this all in a list and process it later so that - we can prioritize what key to use. This gives a better user - experience if wildcard keyids are used. */ - if (!c->dek && ((!enc->keyid[0] && !enc->keyid[1]) - || opt.try_all_secrets - || have_secret_key_with_kid (enc->keyid))) - { - if(opt.list_only) - result = GPG_ERR_MISSING_ACTION; /* fixme: Use better error code. */ - else - { - c->dek = xmalloc_secure_clear (sizeof *c->dek); - if ((result = get_session_key (ctrl, enc, c->dek))) - { - /* Error: Delete the DEK. */ - xfree (c->dek); - c->dek = NULL; - } - } - } - else - result = GPG_ERR_NO_SECKEY; - } - else - result = GPG_ERR_PUBKEY_ALGO; + struct pubkey_enc_list *x = xmalloc (sizeof *x); - if (1) - { - /* Store it for later display. */ - struct kidlist_item *x = xmalloc (sizeof *x); - x->kid[0] = enc->keyid[0]; - x->kid[1] = enc->keyid[1]; + x->keyid[0] = enc->keyid[0]; + x->keyid[1] = enc->keyid[1]; x->pubkey_algo = enc->pubkey_algo; - x->reason = result; + x->data[0] = x->data[1] = NULL; + if (enc->data[0]) + { + x->data[0] = mpi_copy (enc->data[0]); + x->data[1] = mpi_copy (enc->data[1]); + } x->next = c->pkenc_list; c->pkenc_list = x; - - if (!result && opt.verbose > 1) - log_info (_("public key encrypted data: good DEK\n")); } free_packet(pkt, NULL); } /* * Print the list of public key encrypted packets which we could * not decrypt. */ static void -print_pkenc_list (ctrl_t ctrl, struct kidlist_item *list, int failed) +print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list) { for (; list; list = list->next) { PKT_public_key *pk; const char *algstr; - if (failed && !list->reason) - continue; - if (!failed && list->reason) - continue; - algstr = openpgp_pk_algo_name (list->pubkey_algo); pk = xmalloc_clear (sizeof *pk); if (!algstr) algstr = "[?]"; pk->pubkey_algo = list->pubkey_algo; - if (!get_pubkey (ctrl, pk, list->kid)) + if (!get_pubkey (ctrl, pk, list->keyid)) { char *p; log_info (_("encrypted with %u-bit %s key, ID %s, created %s\n"), nbits_from_pk (pk), algstr, keystr_from_pk(pk), strtimestamp (pk->timestamp)); - p = get_user_id_native (ctrl, list->kid); + p = get_user_id_native (ctrl, list->keyid); log_printf (_(" \"%s\"\n"), p); xfree (p); } else log_info (_("encrypted with %s key, ID %s\n"), - algstr, keystr(list->kid)); + algstr, keystr(list->keyid)); free_public_key (pk); - - if (gpg_err_code (list->reason) == GPG_ERR_NO_SECKEY) - { - if (is_status_enabled()) - { - char buf[20]; - snprintf (buf, sizeof buf, "%08lX%08lX", - (ulong)list->kid[0], (ulong)list->kid[1]); - write_status_text (STATUS_NO_SECKEY, buf); - } - } - else if (gpg_err_code (list->reason) == GPG_ERR_MISSING_ACTION) - { - /* Not tested for secret key due to --list-only mode. */ - } - else if (list->reason) - { - log_info (_("public key decryption failed: %s\n"), - gpg_strerror (list->reason)); - write_status_error ("pkdecrypt_failed", list->reason); - } } } static void proc_encrypted (CTX c, PACKET *pkt) { int result = 0; int early_plaintext = literals_seen; if (early_plaintext) { log_info (_("WARNING: multiple plaintexts seen\n")); write_status_errcode ("decryption.early_plaintext", GPG_ERR_BAD_DATA); /* We fail only later so that we can print some more info first. */ } if (!opt.quiet) { if (c->symkeys>1) log_info (_("encrypted with %lu passphrases\n"), c->symkeys); else if (c->symkeys == 1) log_info (_("encrypted with 1 passphrase\n")); - print_pkenc_list (c->ctrl, c->pkenc_list, 1 ); - print_pkenc_list (c->ctrl, c->pkenc_list, 0 ); + print_pkenc_list (c->ctrl, c->pkenc_list); + } + + /* Figure out the session key by looking at all pkenc packets. */ + if (opt.list_only || c->dek) + ; + else if (opt.override_session_key) + { + c->dek = xmalloc_clear (sizeof *c->dek); + result = get_override_session_key (c->dek, opt.override_session_key); + if (result) + { + xfree (c->dek); + c->dek = NULL; + log_info (_("public key decryption failed: %s\n"), + gpg_strerror (result)); + write_status_error ("pkdecrypt_failed", result); + } + } + else + { + c->dek = xmalloc_secure_clear (sizeof *c->dek); + result = get_session_key (c->ctrl, c->pkenc_list, c->dek); + if (result == GPG_ERR_NO_SECKEY) + { + if (is_status_enabled ()) + { + struct pubkey_enc_list *list; + + for (list = c->pkenc_list; list; list = list->next) + { + char buf[20]; + snprintf (buf, sizeof buf, "%08lX%08lX", + (ulong)list->keyid[0], (ulong)list->keyid[1]); + write_status_text (STATUS_NO_SECKEY, buf); + } + } + } + else if (result) + { + log_info (_("public key decryption failed: %s\n"), + gpg_strerror (result)); + write_status_error ("pkdecrypt_failed", result); + + /* Error: Delete the DEK. */ + xfree (c->dek); + c->dek = NULL; + } } - /* FIXME: Figure out the session key by looking at all pkenc packets. */ + if (c->dek && opt.verbose > 1) + log_info (_("public key encrypted data: good DEK\n")); write_status (STATUS_BEGIN_DECRYPTION); /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/ if (opt.list_only) result = -1; else if (!c->dek && !c->last_was_session_key) { int algo; STRING2KEY s2kbuf; STRING2KEY *s2k = NULL; int canceled; if (opt.override_session_key) { c->dek = xmalloc_clear (sizeof *c->dek); result = get_override_session_key (c->dek, opt.override_session_key); if (result) { xfree (c->dek); c->dek = NULL; } } else { /* Assume this is old style conventional encrypted data. */ algo = opt.def_cipher_algo; if (algo) log_info (_("assuming %s encrypted data\n"), openpgp_cipher_algo_name (algo)); else if (openpgp_cipher_test_algo (CIPHER_ALGO_IDEA)) { algo = opt.def_cipher_algo; if (!algo) algo = opt.s2k_cipher_algo; log_info (_("IDEA cipher unavailable, " "optimistically attempting to use %s instead\n"), openpgp_cipher_algo_name (algo)); } else { algo = CIPHER_ALGO_IDEA; if (!opt.s2k_digest_algo) { /* If no digest is given we assume SHA-1. */ s2kbuf.mode = 0; s2kbuf.hash_algo = DIGEST_ALGO_SHA1; s2k = &s2kbuf; } log_info (_("assuming %s encrypted data\n"), "IDEA"); } c->dek = passphrase_to_dek (algo, s2k, 0, 0, NULL, &canceled); if (c->dek) c->dek->algo_info_printed = 1; else if (canceled) result = gpg_error (GPG_ERR_CANCELED); else result = gpg_error (GPG_ERR_INV_PASSPHRASE); } } else if (!c->dek) result = GPG_ERR_NO_SECKEY; /* Compute compliance with CO_DE_VS. */ if (!result && is_status_enabled () /* Symmetric encryption and asymmetric encryption voids compliance. */ && (c->symkeys != !!c->pkenc_list ) /* Overriding session key voids compliance. */ && !opt.override_session_key /* Check symmetric cipher. */ && gnupg_cipher_is_compliant (CO_DE_VS, c->dek->algo, GCRY_CIPHER_MODE_CFB)) { - struct kidlist_item *i; + struct pubkey_enc_list *i; int compliant = 1; PKT_public_key *pk = xmalloc (sizeof *pk); if ( !(c->pkenc_list || c->symkeys) ) log_debug ("%s: where else did the session key come from?\n", __func__); /* Now check that every key used to encrypt the session key is * compliant. */ for (i = c->pkenc_list; i && compliant; i = i->next) { memset (pk, 0, sizeof *pk); pk->pubkey_algo = i->pubkey_algo; - if (get_pubkey (c->ctrl, pk, i->kid) != 0 + if (get_pubkey (c->ctrl, pk, i->keyid) != 0 || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL)) compliant = 0; release_public_key_parts (pk); } xfree (pk); if (compliant) write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); } if (!result) result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); /* Trigger the deferred error. */ if (!result && early_plaintext) result = gpg_error (GPG_ERR_BAD_DATA); if (result == -1) ; else if (!result && !opt.ignore_mdc_error && !pkt->pkt.encrypted->mdc_method && !pkt->pkt.encrypted->aead_algo) { /* The message has been decrypted but does not carry an MDC or * uses AEAD encryption. --ignore-mdc-error has also not been * used. To avoid attacks changing an MDC message to a non-MDC * message, we fail here. */ log_error (_("WARNING: message was not integrity protected\n")); if (!pkt->pkt.encrypted->mdc_method && (openpgp_cipher_get_algo_blklen (c->dek->algo) == 8 || c->dek->algo == CIPHER_ALGO_TWOFISH)) { /* Before 2.2.8 we did not fail hard for a missing MDC if * one of the old ciphers where used. Although these cases * are rare in practice we print a hint on how to decrypt * such messages. */ log_string (GPGRT_LOGLVL_INFO, _("Hint: If this message was created before the year 2003 it is\n" "likely that this message is legitimate. This is because back\n" "then integrity protection was not widely used.\n")); log_info (_("Use the option '%s' to decrypt anyway.\n"), "--ignore-mdc-error"); write_status_errcode ("nomdc_with_legacy_cipher", GPG_ERR_DECRYPT_FAILED); } log_info (_("decryption forced to fail!\n")); write_status (STATUS_DECRYPTION_FAILED); } else if (!result || (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE && !pkt->pkt.encrypted->aead_algo && opt.ignore_mdc_error)) { /* All is fine or for an MDC message the MDC failed but the * --ignore-mdc-error option is active. For compatibility * reasons we issue GOODMDC also for AEAD messages. */ write_status (STATUS_DECRYPTION_OKAY); if (opt.verbose > 1) log_info(_("decryption okay\n")); if (pkt->pkt.encrypted->aead_algo) write_status (STATUS_GOODMDC); else if (pkt->pkt.encrypted->mdc_method && !result) write_status (STATUS_GOODMDC); else log_info (_("WARNING: message was not integrity protected\n")); } else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE || gpg_err_code (result) == GPG_ERR_TRUNCATED) { glo_ctrl.lasterr = result; log_error (_("WARNING: encrypted message has been manipulated!\n")); write_status (STATUS_BADMDC); write_status (STATUS_DECRYPTION_FAILED); } else { if ((gpg_err_code (result) == GPG_ERR_BAD_KEY || gpg_err_code (result) == GPG_ERR_CHECKSUM || gpg_err_code (result) == GPG_ERR_CIPHER_ALGO) && *c->dek->s2k_cacheid != '\0') { if (opt.debug) log_debug ("cleared passphrase cached with ID: %s\n", c->dek->s2k_cacheid); passphrase_clear_cache (c->dek->s2k_cacheid); } glo_ctrl.lasterr = result; write_status (STATUS_DECRYPTION_FAILED); log_error (_("decryption failed: %s\n"), gpg_strerror (result)); /* Hmmm: does this work when we have encrypted using multiple * ways to specify the session key (symmmetric and PK). */ } xfree (c->dek); c->dek = NULL; free_packet (pkt, NULL); c->last_was_session_key = 0; write_status (STATUS_END_DECRYPTION); /* Bump the counter even if we have not seen a literal data packet * inside an encryption container. This acts as a sentinel in case * a misplace extra literal data packets follows after this * encrypted packet. */ literals_seen++; } static void proc_plaintext( CTX c, PACKET *pkt ) { PKT_plaintext *pt = pkt->pkt.plaintext; int any, clearsig, rc; kbnode_t n; /* This is a literal data packet. Bumb a counter for later checks. */ literals_seen++; if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8)) log_info (_("Note: sender requested \"for-your-eyes-only\"\n")); else if (opt.verbose) { /* We don't use print_utf8_buffer because that would require a * string change which we don't want in 2.2. It is also not * clear whether the filename is always utf-8 encoded. */ char *tmp = make_printable_string (pt->name, pt->namelen, 0); log_info (_("original file name='%.*s'\n"), (int)strlen (tmp), tmp); xfree (tmp); } free_md_filter_context (&c->mfx); if (gcry_md_open (&c->mfx.md, 0, 0)) BUG (); /* fixme: we may need to push the textfilter if we have sigclass 1 * and no armoring - Not yet tested * Hmmm, why don't we need it at all if we have sigclass 1 * Should we assume that plaintext in mode 't' has always sigclass 1?? * See: Russ Allbery's mail 1999-02-09 */ any = clearsig = 0; for (n=c->list; n; n = n->next ) { if (n->pkt->pkttype == PKT_ONEPASS_SIG) { /* The onepass signature case. */ if (n->pkt->pkt.onepass_sig->digest_algo) { gcry_md_enable (c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo); any = 1; } } else if (n->pkt->pkttype == PKT_GPG_CONTROL && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START) { /* The clearsigned message case. */ size_t datalen = n->pkt->pkt.gpg_control->datalen; const byte *data = n->pkt->pkt.gpg_control->data; /* Check that we have at least the sigclass and one hash. */ if (datalen < 2) log_fatal ("invalid control packet CTRLPKT_CLEARSIGN_START\n"); /* Note that we don't set the clearsig flag for not-dash-escaped * documents. */ clearsig = (*data == 0x01); for (data++, datalen--; datalen; datalen--, data++) gcry_md_enable (c->mfx.md, *data); any = 1; break; /* Stop here as one-pass signature packets are not expected. */ } else if (n->pkt->pkttype == PKT_SIGNATURE) { /* The SIG+LITERAL case that PGP used to use. */ gcry_md_enable ( c->mfx.md, n->pkt->pkt.signature->digest_algo ); any = 1; } } if (!any && !opt.skip_verify) { /* This is for the old GPG LITERAL+SIG case. It's not legal according to 2440, so hopefully it won't come up that often. There is no good way to specify what algorithms to use in that case, so these there are the historical answer. */ gcry_md_enable (c->mfx.md, DIGEST_ALGO_RMD160); gcry_md_enable (c->mfx.md, DIGEST_ALGO_SHA1); } if (DBG_HASHING) { gcry_md_debug (c->mfx.md, "verify"); if (c->mfx.md2) gcry_md_debug (c->mfx.md2, "verify2"); } rc=0; if (literals_seen > 1) { log_info (_("WARNING: multiple plaintexts seen\n")); write_status_text (STATUS_ERROR, "proc_pkt.plaintext 89_BAD_DATA"); log_inc_errorcount (); rc = gpg_error (GPG_ERR_UNEXPECTED); } if (!rc) { /* It we are in --verify mode, we do not want to output the * signed text. However, if --output is also used we do what * has been requested and write out the signed data. */ rc = handle_plaintext (pt, &c->mfx, (opt.outfp || opt.outfile)? 0 : c->sigs_only, clearsig); if (gpg_err_code (rc) == GPG_ERR_EACCES && !c->sigs_only) { /* Can't write output but we hash it anyway to check the signature. */ rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); } } if (rc) log_error ("handle plaintext failed: %s\n", gpg_strerror (rc)); free_packet (pkt, NULL); c->last_was_session_key = 0; /* We add a marker control packet instead of the plaintext packet. * This is so that we can later detect invalid packet sequences. */ n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); if (c->list) add_kbnode (c->list, n); else c->list = n; } static int proc_compressed_cb (iobuf_t a, void *info) { if ( ((CTX)info)->signed_data.used && ((CTX)info)->signed_data.data_fd != -1) return proc_signature_packets_by_fd (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_fd); else return proc_signature_packets (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_names, ((CTX)info)->sigfilename ); } static int proc_encrypt_cb (iobuf_t a, void *info ) { CTX c = info; return proc_encryption_packets (c->ctrl, info, a ); } static int proc_compressed (CTX c, PACKET *pkt) { PKT_compressed *zd = pkt->pkt.compressed; int rc; /*printf("zip: compressed data packet\n");*/ if (c->sigs_only) rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c); else if( c->encrypt_only ) rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c); else rc = handle_compressed (c->ctrl, c, zd, NULL, NULL); if (gpg_err_code (rc) == GPG_ERR_BAD_DATA) { if (!c->any.uncompress_failed) { CTX cc; for (cc=c; cc; cc = cc->anchor) cc->any.uncompress_failed = 1; log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); } } else if (rc) log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); free_packet (pkt, NULL); c->last_was_session_key = 0; return rc; } /* * Check the signature. If R_PK is not NULL a copy of the public key * used to verify the signature will be stored there, or NULL if not * found. Returns: 0 = valid signature or an error code */ static int do_check_sig (CTX c, kbnode_t node, int *is_selfsig, int *is_expkey, int *is_revkey, PKT_public_key **r_pk) { PKT_signature *sig; gcry_md_hd_t md = NULL; gcry_md_hd_t md2 = NULL; gcry_md_hd_t md_good = NULL; int algo, rc; if (r_pk) *r_pk = NULL; log_assert (node->pkt->pkttype == PKT_SIGNATURE); if (is_selfsig) *is_selfsig = 0; sig = node->pkt->pkt.signature; algo = sig->digest_algo; rc = openpgp_md_test_algo (algo); if (rc) return rc; if (sig->sig_class == 0x00) { if (c->mfx.md) { if (gcry_md_copy (&md, c->mfx.md )) BUG (); } else /* detached signature */ { /* check_signature() will enable the md. */ if (gcry_md_open (&md, 0, 0 )) BUG (); } } else if (sig->sig_class == 0x01) { /* How do we know that we have to hash the (already hashed) text in canonical mode ??? (calculating both modes???) */ if (c->mfx.md) { if (gcry_md_copy (&md, c->mfx.md )) BUG (); if (c->mfx.md2 && gcry_md_copy (&md2, c->mfx.md2)) BUG (); } else /* detached signature */ { log_debug ("Do we really need this here?"); /* check_signature() will enable the md*/ if (gcry_md_open (&md, 0, 0 )) BUG (); if (gcry_md_open (&md2, 0, 0 )) BUG (); } } else if ((sig->sig_class&~3) == 0x10 || sig->sig_class == 0x18 || sig->sig_class == 0x1f || sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) { if (c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY) { return check_key_signature (c->ctrl, c->list, node, is_selfsig); } else if (sig->sig_class == 0x20) { log_error (_("standalone revocation - " "use \"gpg --import\" to apply\n")); return GPG_ERR_NOT_PROCESSED; } else { log_error ("invalid root packet for sigclass %02x\n", sig->sig_class); return GPG_ERR_SIG_CLASS; } } else return GPG_ERR_SIG_CLASS; /* We only get here if we are checking the signature of a binary (0x00) or text document (0x01). */ rc = check_signature2 (c->ctrl, sig, md, NULL, is_expkey, is_revkey, r_pk); if (! rc) md_good = md; else if (gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE && md2) { PKT_public_key *pk2; rc = check_signature2 (c->ctrl, sig, md2, NULL, is_expkey, is_revkey, r_pk? &pk2 : NULL); if (!rc) { md_good = md2; if (r_pk) { free_public_key (*r_pk); *r_pk = pk2; } } } if (md_good) { unsigned char *buffer = gcry_md_read (md_good, sig->digest_algo); sig->digest_len = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (algo)); memcpy (sig->digest, buffer, sig->digest_len); } gcry_md_close (md); gcry_md_close (md2); return rc; } static void print_userid (PACKET *pkt) { if (!pkt) BUG(); if (pkt->pkttype != PKT_USER_ID) { es_printf ("ERROR: unexpected packet type %d", pkt->pkttype ); return; } if (opt.with_colons) { if (pkt->pkt.user_id->attrib_data) es_printf("%u %lu", pkt->pkt.user_id->numattribs, pkt->pkt.user_id->attrib_len); else es_write_sanitized (es_stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len, ":", NULL); } else print_utf8_buffer (es_stdout, pkt->pkt.user_id->name, pkt->pkt.user_id->len ); } /* * List the keyblock in a user friendly way */ static void list_node (CTX c, kbnode_t node) { if (!node) ; else if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { PKT_public_key *pk = node->pkt->pkt.public_key; if (opt.with_colons) { u32 keyid[2]; keyid_from_pk( pk, keyid ); if (pk->flags.primary) c->trustletter = (opt.fast_list_mode ? 0 : get_validity_info (c->ctrl, node->pkt->pkttype == PKT_PUBLIC_KEY ? node : NULL, pk, NULL)); es_printf ("%s:", pk->flags.primary? "pub":"sub" ); if (c->trustletter) es_putc (c->trustletter, es_stdout); es_printf (":%u:%d:%08lX%08lX:%s:%s::", nbits_from_pk( pk ), pk->pubkey_algo, (ulong)keyid[0],(ulong)keyid[1], colon_datestr_from_pk( pk ), colon_strtime (pk->expiredate) ); if (pk->flags.primary && !opt.fast_list_mode) es_putc (get_ownertrust_info (c->ctrl, pk, 1), es_stdout); es_putc (':', es_stdout); es_putc ('\n', es_stdout); } else { print_key_line (c->ctrl, es_stdout, pk, 0); } if (opt.keyid_format == KF_NONE && !opt.with_colons) ; /* Already printed. */ else if ((pk->flags.primary && opt.fingerprint) || opt.fingerprint > 1) print_fingerprint (c->ctrl, NULL, pk, 0); if (pk->flags.primary) { int kl = opt.keyid_format == KF_NONE? 0 : keystrlen (); /* Now list all userids with their signatures. */ for (node = node->next; node; node = node->next) { if (node->pkt->pkttype == PKT_SIGNATURE) { list_node (c, node ); } else if (node->pkt->pkttype == PKT_USER_ID) { if (opt.with_colons) es_printf ("%s:::::::::", node->pkt->pkt.user_id->attrib_data?"uat":"uid"); else es_printf ("uid%*s", kl + (opt.legacy_list_mode? 9:11), "" ); print_userid (node->pkt); if (opt.with_colons) es_putc (':', es_stdout); es_putc ('\n', es_stdout); } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { list_node(c, node ); } } } } else if (node->pkt->pkttype == PKT_SECRET_KEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) { log_debug ("FIXME: No way to print secret key packets here\n"); /* fixme: We may use a function to turn a secret key packet into a public key one and use that here. */ } else if (node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; int is_selfsig = 0; int rc2 = 0; size_t n; char *p; int sigrc = ' '; if (!opt.verbose) return; if (sig->sig_class == 0x20 || sig->sig_class == 0x30) es_fputs ("rev", es_stdout); else es_fputs ("sig", es_stdout); if (opt.check_sigs) { fflush (stdout); rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL, NULL); switch (gpg_err_code (rc2)) { case 0: sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; default: sigrc = '%'; break; } } else /* Check whether this is a self signature. */ { u32 keyid[2]; if (c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_SECRET_KEY ) { keyid_from_pk (c->list->pkt->pkt.public_key, keyid); if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]) is_selfsig = 1; } } if (opt.with_colons) { es_putc (':', es_stdout); if (sigrc != ' ') es_putc (sigrc, es_stdout); es_printf ("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, (ulong)sig->keyid[0], (ulong)sig->keyid[1], colon_datestr_from_sig (sig), colon_expirestr_from_sig (sig)); if (sig->trust_depth || sig->trust_value) es_printf ("%d %d",sig->trust_depth,sig->trust_value); es_putc (':', es_stdout); if (sig->trust_regexp) es_write_sanitized (es_stdout, sig->trust_regexp, strlen (sig->trust_regexp), ":", NULL); es_putc (':', es_stdout); } else es_printf ("%c %s %s ", sigrc, keystr (sig->keyid), datestr_from_sig(sig)); if (sigrc == '%') es_printf ("[%s] ", gpg_strerror (rc2) ); else if (sigrc == '?') ; else if (is_selfsig) { if (opt.with_colons) es_putc (':', es_stdout); es_fputs (sig->sig_class == 0x18? "[keybind]":"[selfsig]", es_stdout); if (opt.with_colons) es_putc (':', es_stdout); } else if (!opt.fast_list_mode) { p = get_user_id (c->ctrl, sig->keyid, &n, NULL); es_write_sanitized (es_stdout, p, n, opt.with_colons?":":NULL, NULL ); xfree (p); } if (opt.with_colons) es_printf (":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); es_putc ('\n', es_stdout); } else log_error ("invalid node with packet of type %d\n", node->pkt->pkttype); } int proc_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) { int rc; CTX c = xmalloc_clear (sizeof *c); c->ctrl = ctrl; c->anchor = anchor; - rc = do_proc_packets (ctrl, c, a); + rc = do_proc_packets (c, a); xfree (c); return rc; } int proc_signature_packets (ctrl_t ctrl, void *anchor, iobuf_t a, strlist_t signedfiles, const char *sigfilename ) { CTX c = xmalloc_clear (sizeof *c); int rc; c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; c->signed_data.data_fd = -1; c->signed_data.data_names = signedfiles; c->signed_data.used = !!signedfiles; c->sigfilename = sigfilename; - rc = do_proc_packets (ctrl, c, a); + rc = do_proc_packets (c, a); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. Using log_error is required because verify_files does not check error codes for each file but we want to terminate the process with an error. */ if (!rc && !c->any.sig_seen) { write_status_text (STATUS_NODATA, "4"); log_error (_("no signature found\n")); rc = GPG_ERR_NO_DATA; } /* Propagate the signature seen flag upward. Do this only on success so that we won't issue the nodata status several times. */ if (!rc && c->anchor && c->any.sig_seen) c->anchor->any.sig_seen = 1; xfree (c); return rc; } int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, iobuf_t a, int signed_data_fd ) { int rc; CTX c; c = xtrycalloc (1, sizeof *c); if (!c) return gpg_error_from_syserror (); c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; c->signed_data.data_fd = signed_data_fd; c->signed_data.data_names = NULL; c->signed_data.used = (signed_data_fd != -1); - rc = do_proc_packets (ctrl, c, a); + rc = do_proc_packets (c, a); /* If we have not encountered any signature we print an error messages, send a NODATA status back and return an error code. Using log_error is required because verify_files does not check error codes for each file but we want to terminate the process with an error. */ if (!rc && !c->any.sig_seen) { write_status_text (STATUS_NODATA, "4"); log_error (_("no signature found\n")); rc = gpg_error (GPG_ERR_NO_DATA); } /* Propagate the signature seen flag upward. Do this only on success so that we won't issue the nodata status several times. */ if (!rc && c->anchor && c->any.sig_seen) c->anchor->any.sig_seen = 1; xfree ( c ); return rc; } int proc_encryption_packets (ctrl_t ctrl, void *anchor, iobuf_t a ) { CTX c = xmalloc_clear (sizeof *c); int rc; c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; - rc = do_proc_packets (ctrl, c, a); + rc = do_proc_packets (c, a); xfree (c); return rc; } static int check_nesting (CTX c) { int level; for (level=0; c; c = c->anchor) level++; if (level > MAX_NESTING_DEPTH) { log_error ("input data with too deeply nested packets\n"); write_status_text (STATUS_UNEXPECTED, "1"); return GPG_ERR_BAD_DATA; } return 0; } static int -do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a) +do_proc_packets (CTX c, iobuf_t a) { PACKET *pkt; struct parse_packet_ctx_s parsectx; int rc = 0; int any_data = 0; int newpkt; rc = check_nesting (c); if (rc) return rc; pkt = xmalloc( sizeof *pkt ); c->iobuf = a; init_packet(pkt); init_parse_packet (&parsectx, a); while ((rc=parse_packet (&parsectx, pkt)) != -1) { any_data = 1; if (rc) { free_packet (pkt, &parsectx); /* Stop processing when an invalid packet has been encountered * but don't do so when we are doing a --list-packets. */ if (gpg_err_code (rc) == GPG_ERR_INV_PACKET && opt.list_packets == 0) break; continue; } newpkt = -1; if (opt.list_packets) { switch (pkt->pkttype) { - case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; + case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD:proc_encrypted (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; default: newpkt = 0; break; } } else if (c->sigs_only) { switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: case PKT_SYMKEY_ENC: case PKT_PUBKEY_ENC: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: write_status_text( STATUS_UNEXPECTED, "0" ); rc = GPG_ERR_UNEXPECTED; goto leave; case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control (c, pkt); break; default: newpkt = 0; break; } } else if (c->encrypt_only) { switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: case PKT_USER_ID: write_status_text (STATUS_UNEXPECTED, "0"); rc = GPG_ERR_UNEXPECTED; goto leave; 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 (ctrl, c, pkt); break; + case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control (c, pkt); break; default: newpkt = 0; break; } } else { switch (pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_SECRET_KEY: release_list (c); c->list = new_kbnode (pkt); newpkt = 1; break; case PKT_PUBLIC_SUBKEY: case PKT_SECRET_SUBKEY: newpkt = add_subkey (c, pkt); break; case PKT_USER_ID: newpkt = add_user_id (c, pkt); break; case PKT_SIGNATURE: newpkt = add_signature (c, pkt); break; - case PKT_PUBKEY_ENC: proc_pubkey_enc (ctrl, c, pkt); break; + case PKT_PUBKEY_ENC: proc_pubkey_enc (c, pkt); break; case PKT_SYMKEY_ENC: proc_symkey_enc (c, pkt); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: case PKT_ENCRYPTED_AEAD: proc_encrypted (c, pkt); break; case PKT_PLAINTEXT: proc_plaintext (c, pkt); break; case PKT_COMPRESSED: rc = proc_compressed (c, pkt); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig (c, pkt); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; case PKT_RING_TRUST: newpkt = add_ring_trust (c, pkt); break; default: newpkt = 0; break; } } if (rc) goto leave; /* This is a very ugly construct and frankly, I don't remember why * I used it. Adding the MDC check here is a hack. * The right solution is to initiate another context for encrypted * packet and not to reuse the current one ... It works right * when there is a compression packet between which adds just * an extra layer. * Hmmm: Rewrite this whole module here?? */ if (pkt->pkttype != PKT_SIGNATURE && pkt->pkttype != PKT_MDC) c->any.data = (pkt->pkttype == PKT_PLAINTEXT); if (newpkt == -1) ; else if (newpkt) { pkt = xmalloc (sizeof *pkt); init_packet (pkt); } else free_packet (pkt, &parsectx); } if (rc == GPG_ERR_INV_PACKET) write_status_text (STATUS_NODATA, "3"); if (any_data) rc = 0; else if (rc == -1) write_status_text (STATUS_NODATA, "2"); leave: release_list (c); xfree(c->dek); free_packet (pkt, &parsectx); deinit_parse_packet (&parsectx); xfree (pkt); free_md_filter_context (&c->mfx); return rc; } /* Helper for pka_uri_from_sig to parse the to-be-verified address out of the notation data. */ static pka_info_t * get_pka_address (PKT_signature *sig) { pka_info_t *pka = NULL; struct notation *nd,*notation; notation=sig_to_notation(sig); for(nd=notation;nd;nd=nd->next) { if(strcmp(nd->name,"pka-address@gnupg.org")!=0) continue; /* Not the notation we want. */ /* For now we only use the first valid PKA notation. In future we might want to keep additional PKA notations in a linked list. */ if (is_valid_mailbox (nd->value)) { pka = xmalloc (sizeof *pka + strlen(nd->value)); pka->valid = 0; pka->checked = 0; pka->uri = NULL; strcpy (pka->email, nd->value); break; } } free_notation(notation); return pka; } /* Return the URI from a DNS PKA record. If this record has already be retrieved for the signature we merely return it; if not we go out and try to get that DNS record. */ static const char * pka_uri_from_sig (CTX c, PKT_signature *sig) { if (!sig->flags.pka_tried) { log_assert (!sig->pka_info); sig->flags.pka_tried = 1; sig->pka_info = get_pka_address (sig); if (sig->pka_info) { char *url; unsigned char *fpr; size_t fprlen; if (!gpg_dirmngr_get_pka (c->ctrl, sig->pka_info->email, &fpr, &fprlen, &url)) { if (fpr && fprlen == sizeof sig->pka_info->fpr) { memcpy (sig->pka_info->fpr, fpr, fprlen); if (url) { sig->pka_info->valid = 1; if (!*url) xfree (url); else sig->pka_info->uri = url; url = NULL; } } xfree (fpr); xfree (url); } } } return sig->pka_info? sig->pka_info->uri : NULL; } /* Return true if the AKL has the WKD method specified. */ static int akl_has_wkd_method (void) { struct akl *akl; for (akl = opt.auto_key_locate; akl; akl = akl->next) if (akl->type == AKL_WKD) return 1; return 0; } /* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. * Returns NULL if not available. The returned buffer is valid as * long as SIG is not modified. */ const byte * issuer_fpr_raw (PKT_signature *sig, size_t *r_len) { const byte *p; size_t n; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); if (p && n == 21 && p[0] == 4) { *r_len = n - 1; return p+1; } *r_len = 0; return NULL; } /* Return the ISSUER fingerprint string in human readable format if * available. Caller must release the string. */ /* FIXME: Move to another file. */ char * issuer_fpr_string (PKT_signature *sig) { const byte *p; size_t n; p = issuer_fpr_raw (sig, &n); return p? bin2hex (p, n, NULL) : NULL; } static void print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un, PKT_signature *sig, int rc) { char *p; write_status_text_and_buffer (statno, keyid_str, un? un->pkt->pkt.user_id->name:"[?]", un? un->pkt->pkt.user_id->len:3, -1); if (un) p = utf8_to_native (un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len, 0); else p = xstrdup ("[?]"); if (rc) log_info (_("BAD signature from \"%s\""), p); else if (sig->flags.expired) log_info (_("Expired signature from \"%s\""), p); else log_info (_("Good signature from \"%s\""), p); xfree (p); } static int check_sig_and_print (CTX c, kbnode_t node) { PKT_signature *sig = node->pkt->pkt.signature; const char *astr; int rc; int is_expkey = 0; int is_revkey = 0; char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ int tried_ks_by_fpr; if (opt.skip_verify) { log_info(_("signature verification suppressed\n")); return 0; } /* Check that the message composition is valid. * * Per RFC-2440bis (-15) allowed: * * S{1,n} -- detached signature. * S{1,n} P -- old style PGP2 signature * O{1,n} P S{1,n} -- standard OpenPGP signature. * C P S{1,n} -- cleartext signature. * * * O = One-Pass Signature packet. * S = Signature packet. * P = OpenPGP Message packet (Encrypted | Compressed | Literal) * (Note that the current rfc2440bis draft also allows * for a signed message but that does not work as it * introduces ambiguities.) * We keep track of these packages using the marker packet * CTRLPKT_PLAINTEXT_MARK. * C = Marker packet for cleartext signatures. * * We reject all other messages. * * Actually we are calling this too often, i.e. for verification of * each message but better have some duplicate work than to silently * introduce a bug here. */ { kbnode_t n; int n_onepass, n_sig; /* log_debug ("checking signature packet composition\n"); */ /* dump_kbnode (c->list); */ n = c->list; log_assert (n); if ( n->pkt->pkttype == PKT_SIGNATURE ) { /* This is either "S{1,n}" case (detached signature) or "S{1,n} P" (old style PGP2 signature). */ for (n = n->next; n; n = n->next) if (n->pkt->pkttype != PKT_SIGNATURE) break; if (!n) ; /* Okay, this is a detached signature. */ else if (n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK) ) { if (n->next) goto ambiguous; /* We only allow one P packet. */ } else goto ambiguous; } else if (n->pkt->pkttype == PKT_ONEPASS_SIG) { /* This is the "O{1,n} P S{1,n}" case (standard signature). */ for (n_onepass=1, n = n->next; n && n->pkt->pkttype == PKT_ONEPASS_SIG; n = n->next) n_onepass++; if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; if (!n_sig) goto ambiguous; /* If we wanted to disallow multiple sig verification, we'd do * something like this: * * if (n) * goto ambiguous; * * However, this can stay allowable as we can't get here. */ if (n_onepass != n_sig) { log_info ("number of one-pass packets does not match " "number of signature packets\n"); goto ambiguous; } } else if (n->pkt->pkttype == PKT_GPG_CONTROL && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* This is the "C P S{1,n}" case (clear text signature). */ n = n->next; if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL && (n->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK))) goto ambiguous; for (n_sig=0, n = n->next; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) n_sig++; if (n || !n_sig) goto ambiguous; } else { ambiguous: log_error(_("can't handle this ambiguous signature data\n")); return 0; } } if (sig->signers_uid) write_status_buffer (STATUS_NEWSIG, sig->signers_uid, strlen (sig->signers_uid), 0); else write_status_text (STATUS_NEWSIG, NULL); astr = openpgp_pk_algo_name ( sig->pubkey_algo ); issuer_fpr = issuer_fpr_string (sig); if (issuer_fpr) { log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); log_info (_(" using %s key %s\n"), astr? astr: "?", issuer_fpr); } else if (!keystrlen () || keystrlen () > 8) { log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); log_info (_(" using %s key %s\n"), astr? astr: "?", keystr(sig->keyid)); } else /* Legacy format. */ log_info (_("Signature made %s using %s key ID %s\n"), asctimestamp(sig->timestamp), astr? astr: "?", keystr(sig->keyid)); /* In verbose mode print the signers UID. */ if (sig->signers_uid) log_info (_(" issuer \"%s\"\n"), sig->signers_uid); rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); /* If the key isn't found, check for a preferred keyserver. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks) { const byte *p; int seq = 0; size_t n; while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) { /* According to my favorite copy editor, in English grammar, you say "at" if the key is located on a web page, but "from" if it is located on a keyserver. I'm not going to even try to make two strings here :) */ log_info(_("Key available at: ") ); print_utf8_buffer (log_get_stream(), p, n); log_printf ("\n"); if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) { struct keyserver_spec *spec; spec = parse_preferred_keyserver (sig); if (spec) { int res; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid,spec, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); free_keyserver_spec (spec); if (!rc) break; } } } } /* If the avove methods didn't work, our next try is to use the URI * from a DNS PKA record. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) { const char *uri = pka_uri_from_sig (c, sig); if (uri) { /* FIXME: We might want to locate the key using the fingerprint instead of the keyid. */ int res; struct keyserver_spec *spec; spec = parse_keyserver_uri (uri, 1); if (spec) { free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid, spec, 1); glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } } } /* If the above methods didn't work, our next try is to locate * the key via its fingerprint from a keyserver. This requires * that the signers fingerprint is encoded in the signature. We * favor this over the WKD method (to be tried next), because an * arbitrary keyserver is less subject to web bug like monitoring. */ tried_ks_by_fpr = 0; if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && keyserver_any_configured (c->ctrl)) { int res; const byte *p; size_t n; p = issuer_fpr_raw (sig, &n); if (p) { /* v4 packet with a SHA-1 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1); tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } } /* If the above methods didn't work, our next try is to retrieve the * key from the WKD. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) && !opt.flags.disable_signer_uid && akl_has_wkd_method () && sig->signers_uid) { int res; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL); glo_ctrl.in_auto_key_retrieve--; /* Fixme: If the fingerprint is embedded in the signature, * compare it to the fingerprint of the returned key. */ if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } /* If the above methods did't work, our next try is to use a * keyserver. */ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) && !tried_ks_by_fpr && keyserver_any_configured (c->ctrl)) { int res; free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1); glo_ctrl.in_auto_key_retrieve--; if (!res) rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey, &pk); } if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) { kbnode_t un, keyblock; int count = 0; int statno; char keyid_str[50]; PKT_public_key *mainpk = NULL; if (rc) statno = STATUS_BADSIG; else if (sig->flags.expired) statno = STATUS_EXPSIG; else if (is_expkey) statno = STATUS_EXPKEYSIG; else if(is_revkey) statno = STATUS_REVKEYSIG; else statno = STATUS_GOODSIG; /* FIXME: We should have the public key in PK and thus the * keyblock has already been fetched. Thus we could use the * fingerprint or PK itself to lookup the entire keyblock. That * would best be done with a cache. */ keyblock = get_pubkeyblock_for_sig (c->ctrl, sig); snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); /* Find and print the primary user ID along with the "Good|Expired|Bad signature" line. */ for (un=keyblock; un; un = un->next) { int valid; if (un->pkt->pkttype==PKT_PUBLIC_KEY) { mainpk = un->pkt->pkt.public_key; continue; } if (un->pkt->pkttype != PKT_USER_ID) continue; if (!un->pkt->pkt.user_id->created) continue; if (un->pkt->pkt.user_id->flags.revoked) continue; if (un->pkt->pkt.user_id->flags.expired) continue; if (!un->pkt->pkt.user_id->flags.primary) continue; /* We want the textual primary user ID here */ if (un->pkt->pkt.user_id->attrib_data) continue; log_assert (mainpk); /* Since this is just informational, don't actually ask the user to update any trust information. (Note: we register the signature later.) Because print_good_bad_signature does not print a LF we need to compute the validity before calling that function. */ if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) valid = get_validity (c->ctrl, keyblock, mainpk, un->pkt->pkt.user_id, NULL, 0); else valid = 0; /* Not used. */ keyid_str[17] = 0; /* cut off the "[uncertain]" part */ print_good_bad_signature (statno, keyid_str, un, sig, rc); if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) log_printf (" [%s]\n",trust_value_to_string(valid)); else log_printf ("\n"); count++; } log_assert (mainpk); /* In case we did not found a valid textual userid above we print the first user id packet or a "[?]" instead along with the "Good|Expired|Bad signature" line. */ if (!count) { /* Try for an invalid textual userid */ for (un=keyblock; un; un = un->next) { if (un->pkt->pkttype == PKT_USER_ID && !un->pkt->pkt.user_id->attrib_data) break; } /* Try for any userid at all */ if (!un) { for (un=keyblock; un; un = un->next) { if (un->pkt->pkttype == PKT_USER_ID) break; } } if (opt.trust_model==TM_ALWAYS || !un) keyid_str[17] = 0; /* cut off the "[uncertain]" part */ print_good_bad_signature (statno, keyid_str, un, sig, rc); if (opt.trust_model != TM_ALWAYS && un) log_printf (" %s",_("[uncertain]") ); log_printf ("\n"); } /* If we have a good signature and already printed * the primary user ID, print all the other user IDs */ if (count && !rc && !(opt.verify_options & VERIFY_SHOW_PRIMARY_UID_ONLY)) { char *p; for( un=keyblock; un; un = un->next) { if (un->pkt->pkttype != PKT_USER_ID) continue; if ((un->pkt->pkt.user_id->flags.revoked || un->pkt->pkt.user_id->flags.expired) && !(opt.verify_options & VERIFY_SHOW_UNUSABLE_UIDS)) continue; /* Skip textual primary user ids which we printed above. */ if (un->pkt->pkt.user_id->flags.primary && !un->pkt->pkt.user_id->attrib_data ) continue; /* If this user id has attribute data, print that. */ if (un->pkt->pkt.user_id->attrib_data) { dump_attribs (un->pkt->pkt.user_id, mainpk); if (opt.verify_options&VERIFY_SHOW_PHOTOS) show_photos (c->ctrl, un->pkt->pkt.user_id->attribs, un->pkt->pkt.user_id->numattribs, mainpk ,un->pkt->pkt.user_id); } p = utf8_to_native (un->pkt->pkt.user_id->name, un->pkt->pkt.user_id->len, 0); log_info (_(" aka \"%s\""), p); xfree (p); if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) { const char *valid; if (un->pkt->pkt.user_id->flags.revoked) valid = _("revoked"); else if (un->pkt->pkt.user_id->flags.expired) valid = _("expired"); else /* Since this is just informational, don't actually ask the user to update any trust information. */ valid = (trust_value_to_string (get_validity (c->ctrl, keyblock, mainpk, un->pkt->pkt.user_id, NULL, 0))); log_printf (" [%s]\n",valid); } else log_printf ("\n"); } } /* For good signatures print notation data. */ if (!rc) { if ((opt.verify_options & VERIFY_SHOW_POLICY_URLS)) show_policy_url (sig, 0, 1); else show_policy_url (sig, 0, 2); if ((opt.verify_options & VERIFY_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 0, 1); else show_keyserver_url (sig, 0, 2); if ((opt.verify_options & VERIFY_SHOW_NOTATIONS)) show_notation (sig, 0, 1, (((opt.verify_options&VERIFY_SHOW_STD_NOTATIONS)?1:0) + ((opt.verify_options&VERIFY_SHOW_USER_NOTATIONS)?2:0))); else show_notation (sig, 0, 2, 0); } /* For good signatures print the VALIDSIG status line. */ if (!rc && is_status_enabled () && pk) { char pkhex[MAX_FINGERPRINT_LEN*2+1]; char mainpkhex[MAX_FINGERPRINT_LEN*2+1]; hexfingerprint (pk, pkhex, sizeof pkhex); hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex); /* TODO: Replace the reserved '0' in the field below with bits for status flags (policy url, notation, etc.). */ write_status_printf (STATUS_VALIDSIG, "%s %s %lu %lu %d 0 %d %d %02X %s", pkhex, strtimestamp (sig->timestamp), (ulong)sig->timestamp, (ulong)sig->expiredate, sig->version, sig->pubkey_algo, sig->digest_algo, sig->sig_class, mainpkhex); } /* Print compliance warning for Good signatures. */ if (!rc && pk && !opt.quiet && !gnupg_pk_is_compliant (opt.compliance, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL)) { log_info (_("WARNING: This key is not suitable for signing" " in %s mode\n"), gnupg_compliance_option_string (opt.compliance)); } /* For good signatures compute and print the trust information. Note that in the Tofu trust model this may ask the user on how to resolve a conflict. */ if (!rc) { if ((opt.verify_options & VERIFY_PKA_LOOKUPS)) pka_uri_from_sig (c, sig); /* Make sure PKA info is available. */ rc = check_signatures_trust (c->ctrl, sig); } /* Print extra information about the signature. */ if (sig->flags.expired) { log_info (_("Signature expired %s\n"), asctimestamp(sig->expiredate)); rc = GPG_ERR_GENERAL; /* Need a better error here? */ } else if (sig->expiredate) log_info (_("Signature expires %s\n"), asctimestamp(sig->expiredate)); if (opt.verbose) { char pkstrbuf[PUBKEY_STRING_SIZE]; if (pk) pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); else *pkstrbuf = 0; log_info (_("%s signature, digest algorithm %s%s%s\n"), sig->sig_class==0x00?_("binary"): sig->sig_class==0x01?_("textmode"):_("unknown"), gcry_md_algo_name (sig->digest_algo), *pkstrbuf?_(", key algorithm "):"", pkstrbuf); } /* Print final warnings. */ if (!rc && !c->signed_data.used) { /* Signature is basically good but we test whether the deprecated command gpg --verify FILE.sig was used instead of gpg --verify FILE.sig FILE to verify a detached signature. If we figure out that a data file with a matching name exists, we print a warning. The problem is that the first form would also verify a standard signature. This behavior could be used to create a made up .sig file for a tarball by creating a standard signature from a valid detached signature packet (for example from a signed git tag). Then replace the sig file on the FTP server along with a changed tarball. Using the first form the verify command would correctly verify the signature but don't even consider the tarball. */ kbnode_t n; char *dfile; dfile = get_matching_datafile (c->sigfilename); if (dfile) { for (n = c->list; n; n = n->next) if (n->pkt->pkttype != PKT_SIGNATURE) break; if (n) { /* Not only signature packets in the tree thus this is not a detached signature. */ log_info (_("WARNING: not a detached signature; " "file '%s' was NOT verified!\n"), dfile); } xfree (dfile); } } /* Compute compliance with CO_DE_VS. */ if (pk && is_status_enabled () && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey, nbits_from_pk (pk), NULL) && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo)) write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS), NULL); free_public_key (pk); pk = NULL; release_kbnode( keyblock ); if (rc) g10_errors_seen = 1; if (opt.batch && rc) g10_exit (1); } else { write_status_printf (STATUS_ERRSIG, "%08lX%08lX %d %d %02x %lu %d %s", (ulong)sig->keyid[0], (ulong)sig->keyid[1], sig->pubkey_algo, sig->digest_algo, sig->sig_class, (ulong)sig->timestamp, gpg_err_code (rc), issuer_fpr? issuer_fpr:"-"); if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY) { write_status_printf (STATUS_NO_PUBKEY, "%08lX%08lX", (ulong)sig->keyid[0], (ulong)sig->keyid[1]); } if (gpg_err_code (rc) != GPG_ERR_NOT_PROCESSED) log_error (_("Can't check signature: %s\n"), gpg_strerror (rc)); } free_public_key (pk); xfree (issuer_fpr); return rc; } /* * Process the tree which starts at node */ static void proc_tree (CTX c, kbnode_t node) { kbnode_t n1; int rc; if (opt.list_packets || opt.list_only) return; /* We must skip our special plaintext marker packets here because they may be the root packet. These packets are only used in additional checks and skipping them here doesn't matter. */ while (node && node->pkt->pkttype == PKT_GPG_CONTROL && node->pkt->pkt.gpg_control->control == CTRLPKT_PLAINTEXT_MARK) { node = node->next; } if (!node) return; c->trustletter = ' '; if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { merge_keys_and_selfsig (c->ctrl, node); list_node (c, node); } else if (node->pkt->pkttype == PKT_SECRET_KEY) { merge_keys_and_selfsig (c->ctrl, node); list_node (c, node); } else if (node->pkt->pkttype == PKT_ONEPASS_SIG) { /* Check all signatures. */ if (!c->any.data) { int use_textmode = 0; free_md_filter_context (&c->mfx); /* Prepare to create all requested message digests. */ rc = gcry_md_open (&c->mfx.md, 0, 0); if (rc) goto hash_err; /* Fixme: why looking for the signature packet and not the one-pass packet? */ for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));) gcry_md_enable (c->mfx.md, n1->pkt->pkt.signature->digest_algo); if (n1 && n1->pkt->pkt.onepass_sig->sig_class == 0x01) use_textmode = 1; /* Ask for file and hash it. */ if (c->sigs_only) { if (c->signed_data.used && c->signed_data.data_fd != -1) rc = hash_datafile_by_fd (c->mfx.md, NULL, c->signed_data.data_fd, use_textmode); else rc = hash_datafiles (c->mfx.md, NULL, c->signed_data.data_names, c->sigfilename, use_textmode); } else { rc = ask_for_detached_datafile (c->mfx.md, c->mfx.md2, iobuf_get_real_fname (c->iobuf), use_textmode); } hash_err: if (rc) { log_error ("can't hash datafile: %s\n", gpg_strerror (rc)); return; } } else if (c->signed_data.used) { log_error (_("not a detached signature\n")); return; } for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));) check_sig_and_print (c, n1); } else if (node->pkt->pkttype == PKT_GPG_CONTROL && node->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START) { /* Clear text signed message. */ if (!c->any.data) { log_error ("cleartext signature without data\n"); return; } else if (c->signed_data.used) { log_error (_("not a detached signature\n")); return; } for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));) check_sig_and_print (c, n1); } else if (node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; int multiple_ok = 1; n1 = find_next_kbnode (node, PKT_SIGNATURE); if (n1) { byte class = sig->sig_class; byte hash = sig->digest_algo; for (; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE))) { /* We can't currently handle multiple signatures of * different classes (we'd pretty much have to run a * different hash context for each), but if they are all * the same and it is detached signature, we make an * exception. Note that the old code also disallowed * multiple signatures if the digest algorithms are * different. We softened this restriction only for * detached signatures, to be on the safe side. */ if (n1->pkt->pkt.signature->sig_class != class || (c->any.data && n1->pkt->pkt.signature->digest_algo != hash)) { multiple_ok = 0; log_info (_("WARNING: multiple signatures detected. " "Only the first will be checked.\n")); break; } } } if (sig->sig_class != 0x00 && sig->sig_class != 0x01) { log_info(_("standalone signature of class 0x%02x\n"), sig->sig_class); } else if (!c->any.data) { /* Detached signature */ free_md_filter_context (&c->mfx); rc = gcry_md_open (&c->mfx.md, sig->digest_algo, 0); if (rc) goto detached_hash_err; if (multiple_ok) { /* If we have and want to handle multiple signatures we * need to enable all hash algorithms for the context. */ for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE)); ) if (!openpgp_md_test_algo (n1->pkt->pkt.signature->digest_algo)) gcry_md_enable (c->mfx.md, map_md_openpgp_to_gcry (n1->pkt->pkt.signature->digest_algo)); } if (RFC2440 || RFC4880) ; /* Strict RFC mode. */ else if (sig->digest_algo == DIGEST_ALGO_SHA1 && sig->pubkey_algo == PUBKEY_ALGO_DSA && sig->sig_class == 0x01) { /* Enable a workaround for a pgp5 bug when the detached * signature has been created in textmode. Note that we * do not implement this for multiple signatures with * different hash algorithms. */ rc = gcry_md_open (&c->mfx.md2, sig->digest_algo, 0); if (rc) goto detached_hash_err; } /* Here we used to have another hack to work around a pgp * 2 bug: It worked by not using the textmode for detached * signatures; this would let the first signature check * (on md) fail but the second one (on md2), which adds an * extra CR would then have produced the "correct" hash. * This is very, very ugly hack but it may haved help in * some cases (and break others). * c->mfx.md2? 0 :(sig->sig_class == 0x01) */ if (DBG_HASHING) { gcry_md_debug (c->mfx.md, "verify"); if (c->mfx.md2) gcry_md_debug (c->mfx.md2, "verify2"); } if (c->sigs_only) { if (c->signed_data.used && c->signed_data.data_fd != -1) rc = hash_datafile_by_fd (c->mfx.md, c->mfx.md2, c->signed_data.data_fd, (sig->sig_class == 0x01)); else rc = hash_datafiles (c->mfx.md, c->mfx.md2, c->signed_data.data_names, c->sigfilename, (sig->sig_class == 0x01)); } else { rc = ask_for_detached_datafile (c->mfx.md, c->mfx.md2, iobuf_get_real_fname(c->iobuf), (sig->sig_class == 0x01)); } detached_hash_err: if (rc) { log_error ("can't hash datafile: %s\n", gpg_strerror (rc)); return; } } else if (c->signed_data.used) { log_error (_("not a detached signature\n")); return; } else if (!opt.quiet) log_info (_("old style (PGP 2.x) signature\n")); if (multiple_ok) { for (n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE))) check_sig_and_print (c, n1); } else check_sig_and_print (c, node); } else { dump_kbnode (c->list); log_error ("invalid root packet detected in proc_tree()\n"); dump_kbnode (node); } } diff --git a/g10/packet.h b/g10/packet.h index 695768695..3f872944b 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,932 +1,942 @@ /* packet.h - OpenPGP packet definitions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007 Free Software Foundation, Inc. * Copyright (C) 2015 g10 Code GmbH * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #ifndef G10_PACKET_H #define G10_PACKET_H #include "../common/types.h" #include "../common/iobuf.h" #include "../common/strlist.h" #include "dek.h" #include "filter.h" #include "../common/openpgpdefs.h" #include "../common/userids.h" #include "../common/util.h" #define DEBUG_PARSE_PACKET 1 /* Constants to allocate static MPI arrays. */ #define PUBKEY_MAX_NPKEY 5 #define PUBKEY_MAX_NSKEY 7 #define PUBKEY_MAX_NSIG 2 #define PUBKEY_MAX_NENC 2 /* Usage flags */ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ #define PUBKEY_USAGE_ENC GCRY_PK_USAGE_ENCR /* Good for encryption. */ #define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys.*/ #define PUBKEY_USAGE_AUTH GCRY_PK_USAGE_AUTH /* Good for authentication. */ #define PUBKEY_USAGE_UNKNOWN GCRY_PK_USAGE_UNKN /* Unknown usage flag. */ #define PUBKEY_USAGE_NONE 256 /* No usage given. */ #if (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR | GCRY_PK_USAGE_CERT \ | GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256 # error Please choose another value for PUBKEY_USAGE_NONE #endif /* Helper macros. */ #define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \ || (a)==PUBKEY_ALGO_RSA_S ) #define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL_E) #define is_DSA(a) ((a)==PUBKEY_ALGO_DSA) /* A pointer to the packet object. */ typedef struct packet_struct PACKET; /* PKT_GPG_CONTROL types */ typedef enum { CTRLPKT_CLEARSIGN_START = 1, CTRLPKT_PIPEMODE = 2, CTRLPKT_PLAINTEXT_MARK =3 } ctrlpkttype_t; typedef enum { PREFTYPE_NONE = 0, PREFTYPE_SYM = 1, PREFTYPE_HASH = 2, PREFTYPE_ZIP = 3, PREFTYPE_AEAD = 4 } preftype_t; typedef struct { byte type; byte value; } prefitem_t; /* A string-to-key specifier as defined in RFC 4880, Section 3.7. */ typedef struct { int mode; /* Must be an integer due to the GNU modes 1001 et al. */ byte hash_algo; byte salt[8]; /* The *coded* (i.e., the serialized version) iteration count. */ u32 count; } STRING2KEY; /* A symmetric-key encrypted session key packet as defined in RFC 4880, Section 5.3. All fields are serialized. */ typedef struct { /* We support version 4 (rfc4880) and 5 (rfc4880bis). */ byte version; /* The cipher algorithm used to encrypt the session key. Note that * this may be different from the algorithm that is used to encrypt * bulk data. */ byte cipher_algo; /* The AEAD algorithm or 0 for CFB encryption. */ byte aead_algo; /* The string-to-key specifier. */ STRING2KEY s2k; /* The length of SESKEY in bytes or 0 if this packet does not encrypt a session key. (In the latter case, the results of the S2K function on the password is the session key. See RFC 4880, Section 5.3.) */ byte seskeylen; /* The session key as encrypted by the S2K specifier. For AEAD this * includes the nonce and the authentication tag. */ byte seskey[1]; } PKT_symkey_enc; /* A public-key encrypted session key packet as defined in RFC 4880, Section 5.1. All fields are serialized. */ typedef struct { /* The 64-bit keyid. */ u32 keyid[2]; /* The packet's version. Currently, only version 3 is defined. */ byte version; /* The algorithm used for the public key encryption scheme. */ byte pubkey_algo; /* Whether to hide the key id. This value is not directly serialized. */ byte throw_keyid; /* The session key. */ gcry_mpi_t data[PUBKEY_MAX_NENC]; } PKT_pubkey_enc; +/* An object to build a list of public-key encrypted session key. */ +struct pubkey_enc_list +{ + struct pubkey_enc_list *next; + u32 keyid[2]; + int pubkey_algo; + gcry_mpi_t data[PUBKEY_MAX_NENC]; +}; + + /* A one-pass signature packet as defined in RFC 4880, Section 5.4. All fields are serialized. */ typedef struct { u32 keyid[2]; /* The 64-bit keyid */ /* The signature's classification (RFC 4880, Section 5.2.1). */ byte sig_class; byte digest_algo; /* algorithm used for digest */ byte pubkey_algo; /* algorithm used for public key scheme */ /* A message can be signed by multiple keys. In this case, there are n one-pass signature packets before the message to sign and n signatures packets after the message. It is conceivable that someone wants to not only sign the message, but all of the signatures. Now we need to distinguish between signing the message and signing the message plus the surrounding signatures. This is the point of this flag. If set, it means: I sign all of the data starting at the next packet. */ byte last; } PKT_onepass_sig; /* A v4 OpenPGP signature has a hashed and unhashed area containing co-called signature subpackets (RFC 4880, Section 5.2.3). These areas are described by this data structure. Use enum_sig_subpkt to parse this area. */ typedef struct { size_t size; /* allocated */ size_t len; /* used (serialized) */ byte data[1]; /* the serialized subpackes (serialized) */ } subpktarea_t; /* The in-memory representation of a designated revoker signature subpacket (RFC 4880, Section 5.2.3.15). */ struct revocation_key { /* A bit field. 0x80 must be set. 0x40 means this information is sensitive (and should not be uploaded to a keyserver by default). */ byte class; /* The public-key algorithm ID. */ byte algid; /* The fingerprint of the authorized key. */ byte fpr[MAX_FINGERPRINT_LEN]; }; /* Object to keep information about a PKA DNS record. */ typedef struct { int valid; /* An actual PKA record exists for EMAIL. */ int checked; /* Set to true if the FPR has been checked against the actual key. */ char *uri; /* Malloced string with the URI. NULL if the URI is not available.*/ unsigned char fpr[20]; /* The fingerprint as stored in the PKA RR. */ char email[1];/* The email address from the notation data. */ } pka_info_t; /* A signature packet (RFC 4880, Section 5.2). Only a subset of these fields are directly serialized (these are marked as such); the rest are read from the subpackets, which are not synthesized when serializing this data structure (i.e., when using build_packet()). Instead, the subpackets must be created by hand. */ typedef struct { struct { unsigned checked:1; /* Signature has been checked. */ unsigned valid:1; /* Signature is good (if checked is set). */ unsigned chosen_selfsig:1; /* A selfsig that is the chosen one. */ unsigned unknown_critical:1; unsigned exportable:1; unsigned revocable:1; unsigned policy_url:1; /* At least one policy URL is present */ unsigned notation:1; /* At least one notation is present */ unsigned pref_ks:1; /* At least one preferred keyserver is present */ unsigned expired:1; unsigned pka_tried:1; /* Set if we tried to retrieve the PKA record. */ } flags; /* The key that allegedly generated this signature. (Directly serialized in v3 sigs; for v4 sigs, this must be explicitly added as an issuer subpacket (5.2.3.5.) */ u32 keyid[2]; /* When the signature was made (seconds since the Epoch). (Directly serialized in v3 sigs; for v4 sigs, this must be explicitly added as a signature creation time subpacket (5.2.3.4).) */ u32 timestamp; u32 expiredate; /* Expires at this date or 0 if not at all. */ /* The serialization format used / to use. If 0, then defaults to version 3. (Serialized.) */ byte version; /* The signature type. (See RFC 4880, Section 5.2.1.) */ byte sig_class; /* Algorithm used for public key scheme (e.g., PUBKEY_ALGO_RSA). (Serialized.) */ byte pubkey_algo; /* Algorithm used for digest (e.g., DIGEST_ALGO_SHA1). (Serialized.) */ byte digest_algo; byte trust_depth; byte trust_value; const byte *trust_regexp; struct revocation_key *revkey; int numrevkeys; int help_counter; /* Used internally bu some fucntions. */ pka_info_t *pka_info; /* Malloced PKA data or NULL if not available. See also flags.pka_tried. */ char *signers_uid; /* Malloced value of the SIGNERS_UID * subpacket or NULL. This string has * already been sanitized. */ subpktarea_t *hashed; /* All subpackets with hashed data (v4 only). */ subpktarea_t *unhashed; /* Ditto for unhashed data. */ /* First 2 bytes of the digest. (Serialized. Note: this is not automatically filled in when serializing a signature!) */ byte digest_start[2]; /* The signature. (Serialized.) */ gcry_mpi_t data[PUBKEY_MAX_NSIG]; /* The message digest and its length (in bytes). Note the maximum digest length is 512 bits (64 bytes). If DIGEST_LEN is 0, then the digest's value has not been saved here. */ byte digest[512 / 8]; int digest_len; } PKT_signature; #define ATTRIB_IMAGE 1 /* This is the cooked form of attributes. */ struct user_attribute { byte type; const byte *data; u32 len; }; /* A user id (RFC 4880, Section 5.11) or a user attribute packet (RFC 4880, Section 5.12). Only a subset of these fields are directly serialized (these are marked as such); the rest are read from the self-signatures in merge_keys_and_selfsig()). */ typedef struct { int ref; /* reference counter */ /* The length of NAME. */ int len; struct user_attribute *attribs; int numattribs; /* If this is not NULL, the packet is a user attribute rather than a user id (See RFC 4880 5.12). (Serialized.) */ byte *attrib_data; /* The length of ATTRIB_DATA. */ unsigned long attrib_len; byte *namehash; int help_key_usage; u32 help_key_expire; int help_full_count; int help_marginal_count; u32 expiredate; /* expires at this date or 0 if not at all */ prefitem_t *prefs; /* list of preferences (may be NULL)*/ u32 created; /* according to the self-signature */ u32 keyupdate; /* From the ring trust packet. */ char *updateurl; /* NULL or the URL of the last update origin. */ byte keyorg; /* From the ring trust packet. */ byte selfsigversion; struct { unsigned int mdc:1; unsigned int aead:1; unsigned int ks_modify:1; unsigned int compacted:1; unsigned int primary:2; /* 2 if set via the primary flag, 1 if calculated */ unsigned int revoked:1; unsigned int expired:1; } flags; char *mbox; /* NULL or the result of mailbox_from_userid. */ /* The text contained in the user id packet, which is normally the * name and email address of the key holder (See RFC 4880 5.11). * (Serialized.). For convenience an extra Nul is always appended. */ char name[1]; } PKT_user_id; struct revoke_info { /* revoked at this date */ u32 date; /* the keyid of the revoking key (selfsig or designated revoker) */ u32 keyid[2]; /* the algo of the revoking key */ byte algo; }; /* Information pertaining to secret keys. */ struct seckey_info { int is_protected:1; /* The secret info is protected and must */ /* be decrypted before use, the protected */ /* MPIs are simply (void*) pointers to memory */ /* and should never be passed to a mpi_xxx() */ int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */ u16 csum; /* Checksum for old protection modes. */ byte algo; /* Cipher used to protect the secret information. */ STRING2KEY s2k; /* S2K parameter. */ byte ivlen; /* Used length of the IV. */ byte iv[16]; /* Initialization vector for CFB mode. */ }; /**************** * The in-memory representation of a public key (RFC 4880, Section * 5.5). Note: this structure contains significantly more information * than is contained in an OpenPGP public key packet. This * information is derived from the self-signed signatures (by * merge_keys_and_selfsig()) and is ignored when serializing the * packet. The fields that are actually written out when serializing * this packet are marked as accordingly. * * We assume that secret keys have the same number of parameters as * the public key and that the public parameters are the first items * in the PKEY array. Thus NPKEY is always less than NSKEY and it is * possible to compare the secret and public keys by comparing the * first NPKEY elements of the PKEY array. Note that since GnuPG 2.1 * we don't use secret keys anymore directly because they are managed * by gpg-agent. However for parsing OpenPGP key files we need a way * to temporary store those secret keys. We do this by putting them * into the public key structure and extending the PKEY field to NSKEY * elements; the extra secret key information are stored in the * SECKEY_INFO field. */ typedef struct { /* When the key was created. (Serialized.) */ u32 timestamp; u32 expiredate; /* expires at this date or 0 if not at all */ u32 max_expiredate; /* must not expire past this date */ struct revoke_info revoked; /* An OpenPGP packet consists of a header and a body. This is the size of the header. If this is 0, an appropriate size is automatically chosen based on the size of the body. (Serialized.) */ byte hdrbytes; /* The serialization format. If 0, the default version (4) is used when serializing. (Serialized.) */ byte version; byte selfsigversion; /* highest version of all of the self-sigs */ /* The public key algorithm. (Serialized.) */ byte pubkey_algo; byte pubkey_usage; /* for now only used to pass it to getkey() */ byte req_usage; /* hack to pass a request to getkey() */ u32 has_expired; /* set to the expiration date if expired */ /* keyid of the primary key. Never access this value directly. Instead, use pk_main_keyid(). */ u32 main_keyid[2]; /* keyid of this key. Never access this value directly! Instead, use pk_keyid(). */ u32 keyid[2]; prefitem_t *prefs; /* list of preferences (may be NULL) */ struct { unsigned int mdc:1; /* MDC feature set. */ unsigned int aead:1; /* AEAD feature set. */ unsigned int disabled_valid:1;/* The next flag is valid. */ unsigned int disabled:1; /* The key has been disabled. */ unsigned int primary:1; /* This is a primary key. */ unsigned int revoked:2; /* Key has been revoked. 1 = revoked by the owner 2 = revoked by designated revoker. */ unsigned int maybe_revoked:1; /* A designated revocation is present, but without the key to check it. */ unsigned int valid:1; /* Key (especially subkey) is valid. */ unsigned int dont_cache:1; /* Do not cache this key. */ unsigned int backsig:2; /* 0=none, 1=bad, 2=good. */ unsigned int serialno_valid:1;/* SERIALNO below is valid. */ unsigned int exact:1; /* Found via exact (!) search. */ } flags; PKT_user_id *user_id; /* If != NULL: found by that uid. */ struct revocation_key *revkey; int numrevkeys; u32 trust_timestamp; byte trust_depth; byte trust_value; byte keyorg; /* From the ring trust packet. */ u32 keyupdate; /* From the ring trust packet. */ char *updateurl; /* NULL or the URL of the last update origin. */ const byte *trust_regexp; char *serialno; /* Malloced hex string or NULL if it is likely not on a card. See also flags.serialno_valid. */ /* If not NULL this malloced structure describes a secret key. (Serialized.) */ struct seckey_info *seckey_info; /* The public key. Contains pubkey_get_npkey (pubkey_algo) + pubkey_get_nskey (pubkey_algo) MPIs. (If pubkey_get_npkey returns 0, then the algorithm is not understood and the PKEY contains a single opaque MPI.) (Serialized.) */ gcry_mpi_t pkey[PUBKEY_MAX_NSKEY]; /* Right, NSKEY elements. */ } PKT_public_key; /* Evaluates as true if the pk is disabled, and false if it isn't. If there is no disable value cached, fill one in. */ #define pk_is_disabled(a) \ (((a)->flags.disabled_valid)? \ ((a)->flags.disabled):(cache_disabled_value(ctrl,(a)))) typedef struct { int len; /* length of data */ char data[1]; } PKT_comment; /* A compression packet (RFC 4880, Section 5.6). */ typedef struct { /* Not used. */ u32 len; /* Whether the serialized version of the packet used / should use the new format. */ byte new_ctb; /* The compression algorithm. */ byte algorithm; /* An iobuf holding the data to be decompressed. (This is not used for compression!) */ iobuf_t buf; } PKT_compressed; /* A symmetrically encrypted data packet (RFC 4880, Section 5.7) or a symmetrically encrypted integrity protected data packet (Section 5.13) */ typedef struct { /* Remaining length of encrypted data. */ u32 len; /* When encrypting in CFB mode, the first block size bytes of data * are random data and the following 2 bytes are copies of the last * two bytes of the random data (RFC 4880, Section 5.7). This * provides a simple check that the key is correct. EXTRALEN is the * size of this extra data or, in AEAD mode, the length of the * headers and the tags. This is used by build_packet when writing * out the packet's header. */ int extralen; /* Whether the serialized version of the packet used / should use the new format. */ byte new_ctb; /* Whether the packet has an indeterminate length (old format) or was encoded using partial body length headers (new format). Note: this is ignored when encrypting. */ byte is_partial; /* If 0, MDC is disabled. Otherwise, the MDC method that was used (only DIGEST_ALGO_SHA1 has ever been defined). */ byte mdc_method; /* If 0, AEAD is not used. Otherwise, the used AEAD algorithm. * MDC_METHOD (above) shall be zero if AEAD is used. */ byte aead_algo; /* The cipher algo for/from the AEAD packet. 0 for other encryption * packets. */ byte cipher_algo; /* The chunk byte from the AEAD packet. */ byte chunkbyte; /* An iobuf holding the data to be decrypted. (This is not used for encryption!) */ iobuf_t buf; } PKT_encrypted; typedef struct { byte hash[20]; } PKT_mdc; /* Subtypes for the ring trust packet. */ #define RING_TRUST_SIG 0 /* The classical signature cache. */ #define RING_TRUST_KEY 1 /* A KEYORG on a primary key. */ #define RING_TRUST_UID 2 /* A KEYORG on a user id. */ /* The local only ring trust packet which OpenPGP declares as * implementation defined. GnuPG uses this to cache signature * verification status and since 2.1.18 also to convey information * about the origin of a key. Note that this packet is not part * struct packet_struct because we use it only local in the packet * parser and builder. */ typedef struct { unsigned int trustval; unsigned int sigcache; unsigned char subtype; /* The subtype of this ring trust packet. */ unsigned char keyorg; /* The origin of the key (KEYORG_*). */ u32 keyupdate; /* The wall time the key was last updated. */ char *url; /* NULL or the URL of the source. */ } PKT_ring_trust; /* A plaintext packet (see RFC 4880, 5.9). */ typedef struct { /* The length of data in BUF or 0 if unknown. */ u32 len; /* A buffer containing the data stored in the packet's body. */ iobuf_t buf; byte new_ctb; byte is_partial; /* partial length encoded */ /* The data's formatting. This is either 'b', 't', 'u', 'l' or '1' (however, the last two are deprecated). */ int mode; u32 timestamp; /* The name of the file. This can be at most 255 characters long, since namelen is just a byte in the serialized format. */ int namelen; char name[1]; } PKT_plaintext; typedef struct { int control; size_t datalen; char data[1]; } PKT_gpg_control; /* combine all packets into a union */ struct packet_struct { pkttype_t pkttype; union { void *generic; PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */ PKT_signature *signature; /* PKT_SIGNATURE */ PKT_public_key *public_key; /* PKT_PUBLIC_[SUB]KEY */ PKT_public_key *secret_key; /* PKT_SECRET_[SUB]KEY */ PKT_comment *comment; /* PKT_COMMENT */ PKT_user_id *user_id; /* PKT_USER_ID */ PKT_compressed *compressed; /* PKT_COMPRESSED */ PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */ PKT_mdc *mdc; /* PKT_MDC */ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */ PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */ } pkt; }; #define init_packet(a) do { (a)->pkttype = 0; \ (a)->pkt.generic = NULL; \ } while(0) /* A notation. See RFC 4880, Section 5.2.3.16. */ struct notation { /* The notation's name. */ char *name; /* If the notation is human readable, then the value is stored here as a NUL-terminated string. If it is not human readable a human readable approximation of the binary value _may_ be stored here. */ char *value; /* Sometimes we want to %-expand the value. In these cases, we save that transformed value here. */ char *altvalue; /* If the notation is not human readable, then the value is stored here. */ unsigned char *bdat; /* The amount of data stored in BDAT. Note: if this is 0 and BDAT is NULL, this does not necessarily mean that the value is human readable. It could be that we have a 0-length value. To determine whether the notation is human readable, always check if VALUE is not NULL. This works, because if a human-readable value has a length of 0, we will still allocate space for the NUL byte. */ size_t blen; struct { /* The notation is critical. */ unsigned int critical:1; /* The notation is human readable. */ unsigned int human:1; /* The notation should be deleted. */ unsigned int ignore:1; } flags; /* A field to facilitate creating a list of notations. */ struct notation *next; }; typedef struct notation *notation_t; /*-- mainproc.c --*/ void reset_literals_seen(void); int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a ); int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a, strlist_t signedfiles, const char *sigfile ); int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a, int signed_data_fd ); int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len); char *issuer_fpr_string (PKT_signature *sig); /*-- parse-packet.c --*/ /* Sets the packet list mode to MODE (i.e., whether we are dumping a packet or not). Returns the current mode. This allows for temporarily suspending dumping by doing the following: int saved_mode = set_packet_list_mode (0); ... set_packet_list_mode (saved_mode); */ int set_packet_list_mode( int mode ); /* A context used with parse_packet. */ struct parse_packet_ctx_s { iobuf_t inp; /* The input stream with the packets. */ struct packet_struct last_pkt; /* The last parsed packet. */ int free_last_pkt; /* Indicates that LAST_PKT must be freed. */ int skip_meta; /* Skip ring trust packets. */ unsigned int n_parsed_packets; /* Number of parsed packets. */ }; typedef struct parse_packet_ctx_s *parse_packet_ctx_t; #define init_parse_packet(a,i) do { \ (a)->inp = (i); \ (a)->last_pkt.pkttype = 0; \ (a)->last_pkt.pkt.generic= NULL;\ (a)->free_last_pkt = 0; \ (a)->skip_meta = 0; \ (a)->n_parsed_packets = 0; \ } while (0) #define deinit_parse_packet(a) do { \ if ((a)->free_last_pkt) \ free_packet (NULL, (a)); \ } while (0) #if DEBUG_PARSE_PACKET /* There are debug functions and should not be used directly. */ int dbg_search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t *retpos, int with_uid, const char* file, int lineno ); int dbg_parse_packet (parse_packet_ctx_t ctx, PACKET *ret_pkt, const char *file, int lineno); int dbg_copy_all_packets( iobuf_t inp, iobuf_t out, const char* file, int lineno ); int dbg_copy_some_packets( iobuf_t inp, iobuf_t out, off_t stopoff, const char* file, int lineno ); int dbg_skip_some_packets( iobuf_t inp, unsigned n, const char* file, int lineno ); #define search_packet( a,b,c,d ) \ dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ ) #define parse_packet( a, b ) \ dbg_parse_packet( (a), (b), __FILE__, __LINE__ ) #define copy_all_packets( a,b ) \ dbg_copy_all_packets((a),(b), __FILE__, __LINE__ ) #define copy_some_packets( a,b,c ) \ dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ ) #define skip_some_packets( a,b ) \ dbg_skip_some_packets((a),(b), __FILE__, __LINE__ ) #else /* Return the next valid OpenPGP packet in *PKT. (This function will * skip any packets whose type is 0.) CTX must have been setup prior to * calling this function. * * Returns 0 on success, -1 if EOF is reached, and an error code * otherwise. In the case of an error, the packet in *PKT may be * partially constructed. As such, even if there is an error, it is * necessary to free *PKT to avoid a resource leak. To detect what * has been allocated, clear *PKT before calling this function. */ int parse_packet (parse_packet_ctx_t ctx, PACKET *pkt); /* Return the first OpenPGP packet in *PKT that contains a key (either * a public subkey, a public key, a secret subkey or a secret key) or, * if WITH_UID is set, a user id. * * Saves the position in the pipeline of the start of the returned * packet (according to iobuf_tell) in RETPOS, if it is not NULL. * * The return semantics are the same as parse_packet. */ int search_packet (parse_packet_ctx_t ctx, PACKET *pkt, off_t *retpos, int with_uid); /* Copy all packets (except invalid packets, i.e., those with a type * of 0) from INP to OUT until either an error occurs or EOF is * reached. * * Returns -1 when end of file is reached or an error code, if an * error occurred. (Note: this function never returns 0, because it * effectively keeps going until it gets an EOF.) */ int copy_all_packets (iobuf_t inp, iobuf_t out ); /* Like copy_all_packets, but stops at the first packet that starts at * or after STOPOFF (as indicated by iobuf_tell). * * Example: if STOPOFF is 100, the first packet in INP goes from * 0 to 110 and the next packet starts at offset 111, then the packet * starting at offset 0 will be completely processed (even though it * extends beyond STOPOFF) and the packet starting at offset 111 will * not be processed at all. */ int copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff); /* Skips the next N packets from INP. * * If parsing a packet returns an error code, then the function stops * immediately and returns the error code. Note: in the case of an * error, this function does not indicate how many packets were * successfully processed. */ int skip_some_packets (iobuf_t inp, unsigned int n); #endif /* Parse a signature packet and store it in *SIG. The signature packet is read from INP. The OpenPGP header (the tag and the packet's length) have already been read; the next byte read from INP should be the first byte of the packet's contents. The packet's type (as extract from the tag) must be passed as PKTTYPE and the packet's length must be passed as PKTLEN. This is used as the upper bound on the amount of data read from INP. If the packet is shorter than PKTLEN, the data at the end will be silently skipped. If an error occurs, an error code will be returned. -1 means the EOF was encountered. 0 means parsing was successful. */ int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen, PKT_signature *sig ); /* Given a subpacket area (typically either PKT_signature.hashed or PKT_signature.unhashed), either: - test whether there are any subpackets with the critical bit set that we don't understand, - list the subpackets, or, - find a subpacket with a specific type. REQTYPE indicates the type of operation. If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks whether there are any subpackets that have the critical bit and which GnuPG cannot handle. If GnuPG understands all subpackets whose critical bit is set, then this function returns simply returns SUBPKTS. If there is a subpacket whose critical bit is set and which GnuPG does not understand, then this function returns NULL and, if START is not NULL, sets *START to the 1-based index of the subpacket that violates the constraint. If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED, this function does not check whether the hash is correct; this is merely an indication of the section that the subpackets came from. If REQTYPE is anything else, then this function interprets the values as a subpacket type and looks for the first subpacket with that type. If such a packet is found, *CRITICAL (if not NULL) is set if the critical bit was set, *RET_N is set to the offset of the subpacket's content within the SUBPKTS buffer, *START is set to the 1-based index of the subpacket within the buffer, and returns &SUBPKTS[*RET_N]. *START is the number of initial subpackets to not consider. Thus, if *START is 2, then the first 2 subpackets are ignored. */ const byte *enum_sig_subpkt ( const subpktarea_t *subpkts, sigsubpkttype_t reqtype, size_t *ret_n, int *start, int *critical ); /* Shorthand for: enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); */ const byte *parse_sig_subpkt ( const subpktarea_t *buffer, sigsubpkttype_t reqtype, size_t *ret_n ); /* This calls parse_sig_subpkt first on the hashed signature area in SIG and then, if that returns NULL, calls parse_sig_subpkt on the unhashed subpacket area in SIG. */ const byte *parse_sig_subpkt2 ( PKT_signature *sig, sigsubpkttype_t reqtype); /* Returns whether the N byte large buffer BUFFER is sufficient to hold a subpacket of type TYPE. Note: the buffer refers to the contents of the subpacket (not the header) and it must already be initialized: for some subpackets, it checks some internal constraints. Returns 0 if the size is acceptable. Returns -2 if the buffer is definitely too short. To check for an error, check whether the return value is less than 0. */ int parse_one_sig_subpkt( const byte *buffer, size_t n, int type ); /* Looks for revocation key subpackets (see RFC 4880 5.2.3.15) in the hashed area of the signature packet. Any that are found are added to SIG->REVKEY and SIG->NUMREVKEYS is updated appropriately. */ void parse_revkeys(PKT_signature *sig); /* Extract the attributes from the buffer at UID->ATTRIB_DATA and update UID->ATTRIBS and UID->NUMATTRIBS accordingly. */ int parse_attribute_subpkts(PKT_user_id *uid); /* Set the UID->NAME field according to the attributes. MAX_NAMELEN must be at least 71. */ void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen); /* Allocate and initialize a new GPG control packet. DATA is the data to save in the packet. */ PACKET *create_gpg_control ( ctrlpkttype_t type, const byte *data, size_t datalen ); /*-- build-packet.c --*/ int build_packet (iobuf_t out, PACKET *pkt); gpg_error_t build_packet_and_meta (iobuf_t out, PACKET *pkt); gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a); gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a); u32 calc_packet_length( PACKET *pkt ); void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ); void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk); int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type ); void build_attribute_subpkt(PKT_user_id *uid,byte type, const void *buf,u32 buflen, const void *header,u32 headerlen); struct notation *string_to_notation(const char *string,int is_utf8); struct notation *blob_to_notation(const char *name, const char *data, size_t len); struct notation *sig_to_notation(PKT_signature *sig); void free_notation(struct notation *notation); /*-- free-packet.c --*/ void free_symkey_enc( PKT_symkey_enc *enc ); void free_pubkey_enc( PKT_pubkey_enc *enc ); void free_seckey_enc( PKT_signature *enc ); void release_public_key_parts( PKT_public_key *pk ); void free_public_key( PKT_public_key *key ); void free_attributes(PKT_user_id *uid); void free_user_id( PKT_user_id *uid ); void free_comment( PKT_comment *rem ); void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx); prefitem_t *copy_prefs (const prefitem_t *prefs); PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s ); PKT_user_id *scopy_user_id (PKT_user_id *sd ); int cmp_public_keys( PKT_public_key *a, PKT_public_key *b ); int cmp_signatures( PKT_signature *a, PKT_signature *b ); int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); /*-- sig-check.c --*/ /* Check a signature. This is shorthand for check_signature2 with the unnamed arguments passed as NULL. */ int check_signature (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest); /* Check a signature. Looks up the public key from the key db. (If * R_PK is not NULL, it is stored at RET_PK.) DIGEST contains a * valid hash context that already includes the signed data. This * function adds the relevant meta-data to the hash before finalizing * it and verifying the signature. */ gpg_error_t check_signature2 (ctrl_t ctrl, PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key **r_pk); /*-- pubkey-enc.c --*/ -gpg_error_t get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek); +gpg_error_t get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek); gpg_error_t get_override_session_key (DEK *dek, const char *string); /*-- compress.c --*/ int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru ); /*-- encr-data.c --*/ int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ gpg_error_t get_output_file (const byte *embedded_name, int embedded_namelen, iobuf_t data, char **fnamep, estream_t *fpp); int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ); int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2, const char *inname, int textmode ); /*-- sign.c --*/ int make_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, int digest_algo, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce); gpg_error_t update_keysig_packet (ctrl_t ctrl, PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque ); /*-- keygen.c --*/ PKT_user_id *generate_user_id (kbnode_t keyblock, const char *uidstr); #endif /*G10_PACKET_H*/ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 0185097a4..8540e03c9 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -1,486 +1,486 @@ /* pubkey-enc.c - Process a public key encoded packet. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009, * 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "keydb.h" #include "trustdb.h" #include "../common/status.h" #include "options.h" #include "main.h" #include "../common/i18n.h" #include "pkglue.h" #include "call-agent.h" #include "../common/host2net.h" #include "../common/compliance.h" -static gpg_error_t get_it (ctrl_t ctrl, PKT_pubkey_enc *k, +static gpg_error_t get_it (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek, PKT_public_key *sk, u32 *keyid); /* Check that the given algo is mentioned in one of the valid user-ids. */ static int is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo) { kbnode_t k; for (k = keyblock; k; k = k->next) { if (k->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = k->pkt->pkt.user_id; prefitem_t *prefs = uid->prefs; if (uid->created && prefs && !uid->flags.revoked && !uid->flags.expired) { for (; prefs->type; prefs++) if (prefs->type == type && prefs->value == algo) return 1; } } } return 0; } /* * Get the session key from a pubkey enc packet and return it in DEK, * which should have been allocated in secure memory by the caller. */ gpg_error_t -get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek) { PKT_public_key *sk = NULL; int rc; + void *enum_context = NULL; + u32 keyid[2]; + int search_for_secret_keys = 1; if (DBG_CLOCK) log_clock ("get_session_key enter"); - rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC); - if (rc) - goto leave; - - if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets) + while (search_for_secret_keys) { + struct pubkey_enc_list *k; + + free_public_key (sk); sk = xmalloc_clear (sizeof *sk); - sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */ - if (!(rc = get_seckey (ctrl, sk, k->keyid))) + rc = enum_secret_keys (ctrl, &enum_context, sk); + if (rc) { - /* Check compliance. */ - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, - sk->pkey, nbits_from_pk (sk), NULL)) - { - log_info (_("key %s is not suitable for decryption" - " in %s mode\n"), - keystr_from_pk (sk), - gnupg_compliance_option_string (opt.compliance)); - rc = gpg_error (GPG_ERR_PUBKEY_ALGO); - } - else - rc = get_it (ctrl, k, dek, sk, k->keyid); + rc = GPG_ERR_NO_SECKEY; + break; } - } - else if (opt.skip_hidden_recipients) - rc = gpg_error (GPG_ERR_NO_SECKEY); - else /* Anonymous receiver: Try all available secret keys. */ - { - void *enum_context = NULL; - u32 keyid[2]; - for (;;) + if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + continue; + + /* Check compliance. */ + if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, + sk->pubkey_algo, + sk->pkey, nbits_from_pk (sk), NULL)) { - free_public_key (sk); - sk = xmalloc_clear (sizeof *sk); - rc = enum_secret_keys (ctrl, &enum_context, sk); - if (rc) - { - rc = GPG_ERR_NO_SECKEY; - break; - } - if (sk->pubkey_algo != k->pubkey_algo) + log_info (_("key %s is not suitable for decryption" + " in %s mode\n"), + keystr_from_pk (sk), + gnupg_compliance_option_string (opt.compliance)); + continue; + } + + for (k = list; k; k = k->next) + { + if (!(k->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E + || k->pubkey_algo == PUBKEY_ALGO_ECDH + || k->pubkey_algo == PUBKEY_ALGO_RSA + || k->pubkey_algo == PUBKEY_ALGO_RSA_E + || k->pubkey_algo == PUBKEY_ALGO_ELGAMAL)) continue; - if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC)) + + if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC)) + continue; + + if (sk->pubkey_algo != k->pubkey_algo) continue; + keyid_from_pk (sk, keyid); - if (!opt.quiet) - log_info (_("anonymous recipient; trying secret key %s ...\n"), - keystr (keyid)); - - /* Check compliance. */ - if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION, - sk->pubkey_algo, - sk->pkey, nbits_from_pk (sk), NULL)) + + if (!k->keyid[0] && !k->keyid[1]) { - log_info (_("key %s is not suitable for decryption" - " in %s mode\n"), - keystr_from_pk (sk), - gnupg_compliance_option_string (opt.compliance)); - continue; + if (!opt.quiet) + log_info (_("anonymous recipient; trying secret key %s ...\n"), + keystr (keyid)); } + else if (opt.try_all_secrets + || (k->keyid[0] == keyid[0] && k->keyid[1] == keyid[1])) + ; + else + continue; rc = get_it (ctrl, k, dek, sk, keyid); if (!rc) { - if (!opt.quiet) + if (!opt.quiet && !k->keyid[0] && !k->keyid[1]) log_info (_("okay, we are the anonymous recipient.\n")); + search_for_secret_keys = 0; break; } else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) - break; /* Don't try any more secret keys. */ + { + search_for_secret_keys = 0; + break; /* Don't try any more secret keys. */ + } } - enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ } - - leave: + enum_secret_keys (ctrl, &enum_context, NULL); /* free context */ free_public_key (sk); + if (DBG_CLOCK) log_clock ("get_session_key leave"); return rc; } static gpg_error_t get_it (ctrl_t ctrl, - PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) + struct pubkey_enc_list *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) { gpg_error_t err; byte *frame = NULL; unsigned int n; size_t nframe; u16 csum, csum2; int padding; gcry_sexp_t s_data; char *desc; char *keygrip; byte fp[MAX_FINGERPRINT_LEN]; size_t fpn; if (DBG_CLOCK) log_clock ("decryption start"); /* Get the keygrip. */ err = hexkeygrip_from_pk (sk, &keygrip); if (err) goto leave; /* Convert the data to an S-expression. */ if (sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL || sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E) { if (!enc->data[0] || !enc->data[1]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))", enc->data[0], enc->data[1]); } else if (sk->pubkey_algo == PUBKEY_ALGO_RSA || sk->pubkey_algo == PUBKEY_ALGO_RSA_E) { if (!enc->data[0]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", enc->data[0]); } else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { if (!enc->data[0] || !enc->data[1]) err = gpg_error (GPG_ERR_BAD_MPI); else err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))", enc->data[1], enc->data[0]); } else err = gpg_error (GPG_ERR_BUG); if (err) goto leave; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { fingerprint_from_pk (sk, fp, &fpn); log_assert (fpn == 20); } /* Decrypt. */ desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1); err = agent_pkdecrypt (NULL, keygrip, desc, sk->keyid, sk->main_keyid, sk->pubkey_algo, s_data, &frame, &nframe, &padding); xfree (desc); gcry_sexp_release (s_data); if (err) goto leave; /* Now get the DEK (data encryption key) from the frame * * Old versions encode the DEK in this format (msb is left): * * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 * * Later versions encode the DEK like this: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (mpi_get_buffer already removed the leading zero). * * RND are non-zero randow bytes. * A is the cipher algorithm * DEK is the encryption key (session key) with length k * CSUM */ if (DBG_CRYPTO) log_printhex (frame, nframe, "DEK frame:"); n = 0; if (sk->pubkey_algo == PUBKEY_ALGO_ECDH) { gcry_mpi_t shared_mpi; gcry_mpi_t decoded; /* At the beginning the frame are the bytes of shared point MPI. */ err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL); if (err) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/, shared_mpi, sk->pkey); mpi_release (shared_mpi); if(err) goto leave; xfree (frame); err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded); mpi_release (decoded); if (err) goto leave; /* Now the frame are the bytes decrypted but padded session key. */ /* Allow double padding for the benefit of DEK size concealment. Higher than this is wasteful. */ if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8 || frame[nframe-1] > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } nframe -= frame[nframe-1]; /* Remove padding. */ log_assert (!n); /* (used just below) */ } else { if (padding) { if (n + 7 > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } if (frame[n] == 1 && frame[nframe - 1] == 2) { log_info (_("old encoding of the DEK is not supported\n")); err = gpg_error (GPG_ERR_CIPHER_ALGO); goto leave; } if (frame[n] != 2) /* Something went wrong. */ { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */ ; n++; /* Skip the zero byte. */ } } if (n + 4 > nframe) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } dek->keylen = nframe - (n + 1) - 2; dek->algo = frame[n++]; err = openpgp_cipher_test_algo (dek->algo); if (err) { if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO) { log_info (_("cipher algorithm %d%s is unknown or disabled\n"), dek->algo, dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : ""); } dek->algo = 0; goto leave; } if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo)) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } /* Copy the key to DEK and compare the checksum. */ csum = buf16_to_u16 (frame+nframe-2); memcpy (dek->key, frame + n, dek->keylen); for (csum2 = 0, n = 0; n < dek->keylen; n++) csum2 += dek->key[n]; if (csum != csum2) { err = gpg_error (GPG_ERR_WRONG_SECKEY); goto leave; } if (DBG_CLOCK) log_clock ("decryption ready"); if (DBG_CRYPTO) log_printhex (dek->key, dek->keylen, "DEK is:"); /* Check that the algo is in the preferences and whether it has * expired. Also print a status line with the key's fingerprint. */ { PKT_public_key *pk = NULL; PKT_public_key *mainpk = NULL; KBNODE pkb = get_pubkeyblock (ctrl, keyid); if (!pkb) { err = -1; log_error ("oops: public key not found for preference check\n"); } else if (pkb->pkt->pkt.public_key->selfsigversion > 3 && dek->algo != CIPHER_ALGO_3DES && !opt.quiet && !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo)) log_info (_("WARNING: cipher algorithm %s not found in recipient" " preferences\n"), openpgp_cipher_algo_name (dek->algo)); if (!err) { kbnode_t k; int first = 1; for (k = pkb; k; k = k->next) { if (k->pkt->pkttype == PKT_PUBLIC_KEY || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) { u32 aki[2]; if (first) { first = 0; mainpk = k->pkt->pkt.public_key; } keyid_from_pk (k->pkt->pkt.public_key, aki); if (aki[0] == keyid[0] && aki[1] == keyid[1]) { pk = k->pkt->pkt.public_key; break; } } } if (!pk) BUG (); if (pk->expiredate && pk->expiredate <= make_timestamp ()) { log_info (_("Note: secret key %s expired at %s\n"), keystr (keyid), asctimestamp (pk->expiredate)); } } if (pk && pk->flags.revoked) { log_info (_("Note: key has been revoked")); log_printf ("\n"); show_revocation_reason (ctrl, pk, 1); } if (is_status_enabled () && pk && mainpk) { char pkhex[MAX_FINGERPRINT_LEN*2+1]; char mainpkhex[MAX_FINGERPRINT_LEN*2+1]; hexfingerprint (pk, pkhex, sizeof pkhex); hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex); /* Note that we do not want to create a trustdb just for * getting the ownertrust: If there is no trustdb there can't * be ulitmately trusted key anyway and thus the ownertrust * value is irrelevant. */ write_status_printf (STATUS_DECRYPTION_KEY, "%s %s %c", pkhex, mainpkhex, get_ownertrust_info (ctrl, mainpk, 1)); } release_kbnode (pkb); err = 0; } leave: xfree (frame); xfree (keygrip); return err; } /* * Get the session key from the given string. * String is supposed to be formatted as this: * : */ gpg_error_t get_override_session_key (DEK *dek, const char *string) { const char *s; int i; if (!string) return GPG_ERR_BAD_KEY; dek->algo = atoi (string); if (dek->algo < 1) return GPG_ERR_BAD_KEY; if (!(s = strchr (string, ':'))) return GPG_ERR_BAD_KEY; s++; for (i = 0; i < DIM (dek->key) && *s; i++, s += 2) { int c = hextobyte (s); if (c == -1) return GPG_ERR_BAD_KEY; dek->key[i] = c; } if (*s) return GPG_ERR_BAD_KEY; dek->keylen = i; return 0; } diff --git a/g10/test-stubs.c b/g10/test-stubs.c index 1e1363266..a2b0d2906 100644 --- a/g10/test-stubs.c +++ b/g10/test-stubs.c @@ -1,551 +1,551 @@ /* test-stubs.c - The GnuPG signature verify utility * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006, * 2008, 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include #include #include #include #include #include #include #define INCLUDED_BY_MAIN_MODULE 1 #include "gpg.h" #include "../common/util.h" #include "packet.h" #include "../common/iobuf.h" #include "main.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "filter.h" #include "../common/ttyio.h" #include "../common/i18n.h" #include "../common/sysutils.h" #include "../common/status.h" #include "call-agent.h" int g10_errors_seen; void g10_exit( int rc ) { rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; exit(rc ); } /* Stub: * We have to override the trustcheck from pkclist.c because * this utility assumes that all keys in the keyring are trustworthy */ int check_signatures_trust (ctrl_t ctrl, PKT_signature *sig) { (void)ctrl; (void)sig; return 0; } void read_trust_options (ctrl_t ctrl, byte *trust_model, ulong *created, ulong *nextcheck, byte *marginals, byte *completes, byte *cert_depth, byte *min_cert_level) { (void)ctrl; (void)trust_model; (void)created; (void)nextcheck; (void)marginals; (void)completes; (void)cert_depth; (void)min_cert_level; } /* Stub: * We don't have the trustdb , so we have to provide some stub functions * instead */ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return 0; } void check_trustdb_stale (ctrl_t ctrl) { (void)ctrl; } int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid) { (void)ctrl; (void)kb; (void)pk; (void)uid; return '?'; } unsigned int get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig, int may_ask) { (void)ctrl; (void)kb; (void)pk; (void)uid; (void)sig; (void)may_ask; return 0; } const char * trust_value_to_string (unsigned int value) { (void)value; return "err"; } const char * uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid) { (void)ctrl; (void)key; (void)uid; return "err"; } int get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create) { (void)ctrl; (void)pk; (void)no_create; return '?'; } unsigned int get_ownertrust (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return TRUST_UNKNOWN; } /* Stubs: * Because we only work with trusted keys, it does not make sense to * get them from a keyserver */ struct keyserver_spec * keyserver_match (struct keyserver_spec *spec) { (void)spec; return NULL; } int keyserver_any_configured (ctrl_t ctrl) { (void)ctrl; return 0; } int keyserver_import_keyid (u32 *keyid, void *dummy, int quick) { (void)keyid; (void)dummy; (void)quick; return -1; } int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, struct keyserver_spec *keyserver, int quick) { (void)ctrl; (void)fprint; (void)fprint_len; (void)keyserver; (void)quick; return -1; } int keyserver_import_cert (const char *name) { (void)name; return -1; } int keyserver_import_pka (const char *name,unsigned char *fpr) { (void)name; (void)fpr; return -1; } gpg_error_t keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick, unsigned char **fpr, size_t *fpr_len) { (void)ctrl; (void)name; (void)quick; (void)fpr; (void)fpr_len; return GPG_ERR_BUG; } int keyserver_import_name (const char *name,struct keyserver_spec *spec) { (void)name; (void)spec; return -1; } int keyserver_import_ldap (const char *name) { (void)name; return -1; } gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock) { (void)ctrl; (void)fname; (void)r_keyblock; return -1; } /* Stub: * No encryption here but mainproc links to these functions. */ gpg_error_t -get_session_key (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek) +get_session_key (ctrl_t ctrl, struct pubkey_enc_list *k, DEK *dek) { (void)ctrl; (void)k; (void)dek; return GPG_ERR_GENERAL; } /* Stub: */ gpg_error_t get_override_session_key (DEK *dek, const char *string) { (void)dek; (void)string; return GPG_ERR_GENERAL; } /* Stub: */ int decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { (void)ctrl; (void)procctx; (void)ed; (void)dek; return GPG_ERR_GENERAL; } /* Stub: * No interactive commands, so we don't need the helptexts */ void display_online_help (const char *keyword) { (void)keyword; } /* Stub: * We don't use secret keys, but getkey.c links to this */ int check_secret_key (PKT_public_key *pk, int n) { (void)pk; (void)n; return GPG_ERR_GENERAL; } /* Stub: * No secret key, so no passphrase needed */ DEK * passphrase_to_dek (int cipher_algo, STRING2KEY *s2k, int create, int nocache, const char *tmp, int *canceled) { (void)cipher_algo; (void)s2k; (void)create; (void)nocache; (void)tmp; if (canceled) *canceled = 0; return NULL; } void passphrase_clear_cache (const char *cacheid) { (void)cacheid; } struct keyserver_spec * parse_preferred_keyserver(PKT_signature *sig) { (void)sig; return NULL; } struct keyserver_spec * parse_keyserver_uri (const char *uri, int require_scheme, const char *configname, unsigned int configlineno) { (void)uri; (void)require_scheme; (void)configname; (void)configlineno; return NULL; } void free_keyserver_spec (struct keyserver_spec *keyserver) { (void)keyserver; } /* Stubs to avoid linking to photoid.c */ void show_photos (const struct user_attribute *attrs, int count, PKT_public_key *pk) { (void)attrs; (void)count; (void)pk; } int parse_image_header (const struct user_attribute *attr, byte *type, u32 *len) { (void)attr; (void)type; (void)len; return 0; } char * image_type_to_string (byte type, int string) { (void)type; (void)string; return NULL; } #ifdef ENABLE_CARD_SUPPORT int agent_scd_getattr (const char *name, struct agent_card_info_s *info) { (void)name; (void)info; return 0; } #endif /* ENABLE_CARD_SUPPORT */ /* We do not do any locking, so use these stubs here */ void dotlock_disable (void) { } dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags) { (void)file_to_lock; (void)flags; return NULL; } void dotlock_destroy (dotlock_t h) { (void)h; } int dotlock_take (dotlock_t h, long timeout) { (void)h; (void)timeout; return 0; } int dotlock_release (dotlock_t h) { (void)h; return 0; } void dotlock_remove_lockfiles (void) { } gpg_error_t agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk) { (void)ctrl; (void)pk; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock) { (void)ctrl; (void)keyblock; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno, int *r_cleartext) { (void)ctrl; (void)hexkeygrip; (void)r_cleartext; *r_serialno = NULL; return gpg_error (GPG_ERR_NO_SECKEY); } gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, unsigned char **r_fpr, size_t *r_fprlen, char **r_url) { (void)ctrl; (void)userid; if (r_fpr) *r_fpr = NULL; if (r_fprlen) *r_fprlen = 0; if (r_url) *r_url = NULL; return gpg_error (GPG_ERR_NOT_FOUND); } gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, export_stats_t stats, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen) { (void)ctrl; (void)keyspec; (void)options; (void)stats; *r_keyblock = NULL; *r_data = NULL; *r_datalen = 0; return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } gpg_error_t tofu_write_tfs_record (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, const char *user_id) { (void)ctrl; (void)fp; (void)pk; (void)user_id; return gpg_error (GPG_ERR_GENERAL); } gpg_error_t tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id, enum tofu_policy *policy) { (void)ctrl; (void)pk; (void)user_id; (void)policy; return gpg_error (GPG_ERR_GENERAL); } const char * tofu_policy_str (enum tofu_policy policy) { (void)policy; return "unknown"; } void tofu_begin_batch_update (ctrl_t ctrl) { (void)ctrl; } void tofu_end_batch_update (ctrl_t ctrl) { (void)ctrl; } gpg_error_t tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb) { (void) ctrl; (void) kb; return 0; } int get_revocation_reason (PKT_signature *sig, char **r_reason, char **r_comment, size_t *r_commentlen) { (void)sig; (void)r_commentlen; if (r_reason) *r_reason = NULL; if (r_comment) *r_comment = NULL; return 0; }