diff --git a/g10/Makefile.am b/g10/Makefile.am index e8e975342..eb23573b7 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -1,271 +1,256 @@ # Copyright (C) 1998, 1999, 2000, 2001, 2002, # 2003, 2006, 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 . ## Process this file with automake to produce Makefile.in EXTRA_DIST = distsigkey.gpg \ ChangeLog-2011 gpg-w32info.rc \ gpg.w32-manifest.in test.c t-keydb-keyring.kbx \ t-keydb-get-keyblock.gpg t-stutter-data.asc \ all-tests.scm AM_CPPFLAGS = include $(top_srcdir)/am/cmacros.am AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \ $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(GPG_ERROR_CFLAGS) needed_libs = ../kbx/libkeybox.a $(libcommonpth) ../regexp/libregexp.a # Because there are no program specific transform macros we need to # work around that to allow installing gpg as gpg2. gpg2_hack_list = gpg gpgv if USE_GPG2_HACK gpg2_hack_uninst = gpg2 gpgv2 use_gpg2_hack = yes else gpg2_hack_uninst = $(gpg2_hack_list) use_gpg2_hack = no endif # NB: We use noinst_ for gpg and gpgv so that we can install them with # the install-hook target under the name gpg2/gpgv2. noinst_PROGRAMS = gpg if !HAVE_W32CE_SYSTEM noinst_PROGRAMS += gpgv endif -#if MAINTAINER_MODE -#noinst_PROGRAMS += gpgcompose -#endif noinst_PROGRAMS += $(module_tests) if DISABLE_TESTS TESTS = else TESTS = $(module_tests) endif TESTS_ENVIRONMENT = \ abs_top_srcdir=$(abs_top_srcdir) if ENABLE_BZIP2_SUPPORT bzip2_source = compress-bz2.c else bzip2_source = endif if ENABLE_CARD_SUPPORT card_source = card-util.c else card_source = endif if NO_TRUST_MODELS trust_source = else trust_source = trustdb.c trustdb.h tdbdump.c tdbio.c tdbio.h endif if USE_TOFU tofu_source = tofu.h tofu.c gpgsql.c gpgsql.h else tofu_source = endif if HAVE_W32_SYSTEM resource_objs += gpg-w32info.o gpg-w32info.o : gpg.w32-manifest endif common_source = \ gpg.h \ dek.h \ build-packet.c \ compress.c \ $(bzip2_source) \ filter.h \ free-packet.c \ getkey.c \ expand-group.c \ keydb.h \ keydb-private.h \ call-keyboxd.c \ keydb.c \ keyring.c keyring.h \ seskey.c \ kbnode.c \ main.h \ mainproc.c \ armor.c \ mdfilter.c \ textfilter.c \ progress.c \ misc.c \ rmd160.c rmd160.h \ options.h \ openfile.c \ keyid.c \ packet.h \ parse-packet.c \ cpr.c \ plaintext.c \ sig-check.c \ keylist.c \ pkglue.c pkglue.h \ objcache.c objcache.h \ ecdh.c gpg_sources = server.c \ $(common_source) \ pkclist.c \ skclist.c \ pubkey-enc.c \ passphrase.c \ decrypt.c \ decrypt-data.c \ cipher-cfb.c \ cipher-aead.c \ encrypt.c \ sign.c \ verify.c \ revoke.c \ dearmor.c \ import.c \ export.c \ migrate.c \ delkey.c \ keygen.c \ helptext.c \ keyserver.c \ keyserver-internal.h \ call-dirmngr.c call-dirmngr.h \ photoid.c photoid.h \ call-agent.c call-agent.h \ trust.c $(trust_source) $(tofu_source) \ $(card_source) \ exec.c exec.h \ key-clean.c key-clean.h \ key-check.c key-check.h gpg_SOURCES = gpg.c \ keyedit.c keyedit.h \ $(gpg_sources) -#gpgcompose_SOURCES = gpgcompose.c $(gpg_sources) gpgv_SOURCES = gpgv.c \ $(common_source) \ verify.c -#gpgd_SOURCES = gpgd.c \ -# ks-proto.h \ -# ks-proto.c \ -# ks-db.c \ -# ks-db.h \ -# $(common_source) - LDADD = $(needed_libs) ../common/libgpgrl.a \ $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS) gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(resource_objs) $(extra_sys_libs) gpg_LDFLAGS = $(extra_bin_ldflags) gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(resource_objs) $(extra_sys_libs) gpgv_LDFLAGS = $(extra_bin_ldflags) -#gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \ -# $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \ -# $(LIBICONV) $(resource_objs) $(extra_sys_libs) -#gpgcompose_LDFLAGS = $(extra_bin_ldflags) t_common_ldadd = module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter t_rmd160_SOURCES = t-rmd160.c rmd160.c t_rmd160_LDADD = $(t_common_ldadd) t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source) t_keydb_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(t_common_ldadd) t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \ $(common_source) t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(t_common_ldadd) t_stutter_SOURCES = t-stutter.c test-stubs.c \ $(common_source) t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \ $(LIBASSUAN_LIBS) $(NPTH_LIBS) $(GPG_ERROR_LIBS) \ $(LIBICONV) $(t_common_ldadd) $(PROGRAMS): $(needed_libs) ../common/libgpgrl.a # NB: To install gpg and gpgv we use this -hook. This code has to # duplicate most of the automake generated install-binPROGRAMS target # so that directories are created and the transform feature works. install-exec-hook: @echo "running install-exec-hook"; \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)"; \ for p in $(gpg2_hack_list); do \ echo "$$p$(EXEEXT) $$p$(EXEEXT)"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ for f in $$files; do \ if test $(use_gpg2_hack) = yes ; \ then f2=`echo "$${f}" | sed 's/$(EXEEXT)$$//'`2$(EXEEXT); \ else f2="$${f}" ;\ fi ; \ echo "$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) \ $${f} '$(DESTDIR)$(bindir)/$${f2}'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) \ $${f} "$(DESTDIR)$(bindir)/$${f2}"; \ done; \ done install-data-local: $(mkinstalldirs) $(DESTDIR)$(pkgdatadir) $(INSTALL_DATA) $(srcdir)/distsigkey.gpg \ $(DESTDIR)$(pkgdatadir)/distsigkey.gpg # NB: For uninstalling gpg and gpgv we use -local because there is # no need for a specific order the targets need to be run. uninstall-local: -@rm $(DESTDIR)$(pkgdatadir)/distsigkey.gpg -@files=`for p in $(gpg2_hack_uninst); do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c deleted file mode 100644 index 0a2b21a4c..000000000 --- a/g10/gpgcompose.c +++ /dev/null @@ -1,3113 +0,0 @@ -/* gpgcompose.c - Maintainer tool to create OpenPGP messages by hand. - * Copyright (C) 2016 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 . - */ - -#include -#include - -#define INCLUDED_BY_MAIN_MODULE 1 -#include "gpg.h" -#include "packet.h" -#include "keydb.h" -#include "main.h" -#include "options.h" -#include "call-agent.h" - -static int do_debug; -#define debug(fmt, ...) \ - do { if (do_debug) log_debug (fmt, ##__VA_ARGS__); } while (0) - -/* --encryption, for instance, adds a filter in front of out. There - is an operator (--encryption-pop) to end this. We use the - following infrastructure to make it easy to pop the state. */ -struct filter -{ - void *func; - void *context; - int pkttype; - int partial_block_mode; - struct filter *next; -}; - - -/* Hack to ass CTRL to some functions. */ -static ctrl_t global_ctrl; - - -static struct filter *filters; - -static void -filter_push (iobuf_t out, void *func, void *context, - int type, int partial_block_mode) -{ - gpg_error_t err; - struct filter *f = xmalloc_clear (sizeof (*f)); - f->next = filters; - f->func = func; - f->context = context; - f->pkttype = type; - f->partial_block_mode = partial_block_mode; - - filters = f; - - err = iobuf_push_filter (out, func, context); - if (err) - log_fatal ("Adding filter: %s\n", gpg_strerror (err)); -} - -static void -filter_pop (iobuf_t out, int expected_type) -{ - gpg_error_t err; - struct filter *f = filters; - - log_assert (f); - - if (f->pkttype != expected_type) - log_fatal ("Attempted to pop a %s container, " - "but current container is a %s container.\n", - pkttype_str (f->pkttype), pkttype_str (expected_type)); - - if (f->pkttype == PKT_ENCRYPTED) - { - err = iobuf_pop_filter (out, f->func, f->context); - if (err) - log_fatal ("Popping encryption filter: %s\n", gpg_strerror (err)); - } - else - log_fatal ("FILTERS appears to be corrupted.\n"); - - if (f->partial_block_mode) - iobuf_set_partial_body_length_mode (out, 0); - - filters = f->next; - xfree (f); -} - -/* Return if CIPHER_ID is a valid cipher. */ -static int -valid_cipher (int cipher_id) -{ - return (cipher_id == CIPHER_ALGO_IDEA - || cipher_id == CIPHER_ALGO_3DES - || cipher_id == CIPHER_ALGO_CAST5 - || cipher_id == CIPHER_ALGO_BLOWFISH - || cipher_id == CIPHER_ALGO_AES - || cipher_id == CIPHER_ALGO_AES192 - || cipher_id == CIPHER_ALGO_AES256 - || cipher_id == CIPHER_ALGO_TWOFISH - || cipher_id == CIPHER_ALGO_CAMELLIA128 - || cipher_id == CIPHER_ALGO_CAMELLIA192 - || cipher_id == CIPHER_ALGO_CAMELLIA256); -} - -/* Parse a session key encoded as a string of the form x:HEXDIGITS - where x is the algorithm id. (This is the format emitted by gpg - --show-session-key.) */ -struct session_key -{ - int algo; - int keylen; - char *key; -}; - -static struct session_key -parse_session_key (const char *option, char *p, int require_algo) -{ - char *tail; - struct session_key sk; - - memset (&sk, 0, sizeof (sk)); - - /* Check for the optional "cipher-id:" at the start of the - string. */ - errno = 0; - sk.algo = strtol (p, &tail, 10); - if (! errno && tail && *tail == ':') - { - if (! valid_cipher (sk.algo)) - log_info ("%s: %d is not a known cipher (but using anyways)\n", - option, sk.algo); - p = tail + 1; - } - else if (require_algo) - log_fatal ("%s: Session key must have the form algo:HEXCHARACTERS.\n", - option); - else - sk.algo = 0; - - /* Ignore a leading 0x. */ - if (p[0] == '0' && p[1] == 'x') - p += 2; - - if (strlen (p) % 2 != 0) - log_fatal ("%s: session key must consist of an even number of hexadecimal characters.\n", - option); - - sk.keylen = strlen (p) / 2; - sk.key = xmalloc (sk.keylen); - - if (hex2bin (p, sk.key, sk.keylen) == -1) - log_fatal ("%s: Session key must only contain hexadecimal characters\n", - option); - - return sk; -} - -/* A callback. - - OPTION_STR is the option that was matched. ARGC is the number of - arguments following the option and ARGV are those arguments. - (Thus, argv[0] is the first string following the option and - argv[-1] is the option.) - - COOKIE is the opaque value passed to process_options. */ -typedef int (*option_prcessor_t) (const char *option_str, - int argc, char *argv[], - void *cookie); - -struct option -{ - /* The option that this matches. This must start with "--" or be - the empty string. The empty string matches bare arguments. */ - const char *option; - /* The function to call to process this option. */ - option_prcessor_t func; - /* Documentation. */ - const char *help; -}; - -/* Merge two lists of options. Note: this makes a shallow copy! The - caller must xfree() the result. */ -static struct option * -merge_options (struct option a[], struct option b[]) -{ - int i, j; - struct option *c; - - for (i = 0; a[i].option; i ++) - ; - for (j = 0; b[j].option; j ++) - ; - - c = xmalloc ((i + j + 1) * sizeof (struct option)); - memcpy (c, a, i * sizeof (struct option)); - memcpy (&c[i], b, j * sizeof (struct option)); - c[i + j].option = NULL; - - if (a[i].help && b[j].help) - c[i + j].help = xasprintf ("%s\n\n%s", a[i].help, b[j].help); - else if (a[i].help) - c[i + j].help = a[i].help; - else if (b[j].help) - c[i + j].help = b[j].help; - - return c; -} - -/* Returns whether ARG is an option. All options start with --. */ -static int -is_option (const char *arg) -{ - return arg[0] == '-' && arg[1] == '-'; -} - -/* OPTIONS is a NULL terminated array of struct option:s. Finds the - entry that is the same as ARG. Returns -1 if no entry is found. - The empty string option matches bare arguments. */ -static int -match_option (const struct option options[], const char *arg) -{ - int i; - int bare_arg = ! is_option (arg); - - for (i = 0; options[i].option; i ++) - if ((! bare_arg && strcmp (options[i].option, arg) == 0) - /* Non-options match the empty string. */ - || (bare_arg && options[i].option[0] == '\0')) - return i; - - return -1; -} - -static void -show_help (struct option options[]) -{ - int i; - int max_length = 0; - int space; - - for (i = 0; options[i].option; i ++) - { - const char *option = options[i].option[0] ? options[i].option : "ARG"; - int l = strlen (option); - if (l > max_length) - max_length = l; - } - - space = 72 - (max_length + 2); - if (space < 40) - space = 40; - - for (i = 0; ; i ++) - { - const char *option = options[i].option; - const char *help = options[i].help; - - int l; - int j; - char *tmp; - char *formatted; - char *p; - char *newline; - - if (! option && ! help) - break; - - if (option) - { - const char *o = option[0] ? option : "ARG"; - l = strlen (o); - fprintf (stdout, "%s", o); - } - - if (! help) - { - fputc ('\n', stdout); - continue; - } - - if (option) - for (j = l; j < max_length + 2; j ++) - fputc (' ', stdout); - -#define BOLD_START "\033[1m" -#define NORMAL_RESTORE "\033[0m" -#define BOLD(x) BOLD_START x NORMAL_RESTORE - - if (! option || options[i].func) - tmp = (char *) help; - else - tmp = xasprintf ("%s " BOLD("(Unimplemented.)"), help); - - if (! option) - space = 72; - formatted = format_text (tmp, space, space + 4); - if (!formatted) - abort (); - - if (tmp != help) - xfree (tmp); - - if (! option) - { - printf ("\n%s\n", formatted); - break; - } - - for (p = formatted; - p && *p; - p = (*newline == '\0') ? newline : newline + 1) - { - newline = strchr (p, '\n'); - if (! newline) - newline = &p[strlen (p)]; - - l = (size_t) newline - (size_t) p; - - if (p != formatted) - for (j = 0; j < max_length + 2; j ++) - fputc (' ', stdout); - - fwrite (p, l, 1, stdout); - fputc ('\n', stdout); - } - - xfree (formatted); - } -} - -/* Return value is number of consumed argv elements. */ -static int -process_options (const char *parent_option, - struct option break_options[], - struct option local_options[], void *lcookie, - struct option global_options[], void *gcookie, - int argc, char *argv[]) -{ - int i; - for (i = 0; i < argc; i ++) - { - int j; - struct option *option; - void *cookie; - int bare_arg; - option_prcessor_t func; - int consumed; - - if (break_options) - { - j = match_option (break_options, argv[i]); - if (j != -1) - /* Match. Break out. */ - return i; - } - - j = match_option (local_options, argv[i]); - if (j == -1) - { - if (global_options) - j = match_option (global_options, argv[i]); - if (j == -1) - { - if (strcmp (argv[i], "--help") == 0) - { - if (! global_options) - show_help (local_options); - else - { - struct option *combined - = merge_options (local_options, global_options); - show_help (combined); - xfree (combined); - } - g10_exit (0); - } - - if (parent_option) - log_fatal ("%s: Unknown option: %s\n", parent_option, argv[i]); - else - log_fatal ("Unknown option: %s\n", argv[i]); - } - - option = &global_options[j]; - cookie = gcookie; - } - else - { - option = &local_options[j]; - cookie = lcookie; - } - - bare_arg = strcmp (option->option, "") == 0; - - func = option->func; - if (! func) - { - if (bare_arg) - log_fatal ("Bare arguments unimplemented.\n"); - else - log_fatal ("Unimplemented option: %s\n", - option->option); - } - - consumed = func (bare_arg ? parent_option : argv[i], - argc - i - !bare_arg, &argv[i + !bare_arg], - cookie); - i += consumed; - if (bare_arg) - i --; - } - - return i; -} - -/* The keys, subkeys, user ids and user attributes in the order that - they were added. */ -PACKET components[20]; -/* The number of components. */ -int ncomponents; - -static int -add_component (int pkttype, void *component) -{ - int i = ncomponents ++; - - log_assert (i < sizeof (components) / sizeof (components[0])); - log_assert (pkttype == PKT_PUBLIC_KEY - || pkttype == PKT_PUBLIC_SUBKEY - || pkttype == PKT_SECRET_KEY - || pkttype == PKT_SECRET_SUBKEY - || pkttype == PKT_USER_ID - || pkttype == PKT_ATTRIBUTE); - - components[i].pkttype = pkttype; - components[i].pkt.generic = component; - - return i; -} - -static void -dump_component (PACKET *pkt) -{ - struct kbnode_struct kbnode; - - if (! do_debug) - return; - - memset (&kbnode, 0, sizeof (kbnode)); - kbnode.pkt = pkt; - dump_kbnode (&kbnode); -} - -/* Returns the first primary key in COMPONENTS or NULL if there is - none. */ -static PKT_public_key * -primary_key (void) -{ - int i; - for (i = 0; i < ncomponents; i ++) - if (components[i].pkttype == PKT_PUBLIC_KEY) - return components[i].pkt.public_key; - return NULL; -} - -/* The last session key (updated when adding a SK-ESK, PK-ESK or SED - packet. */ -static DEK session_key; - -static int user_id (const char *option, int argc, char *argv[], - void *cookie); -static int public_key (const char *option, int argc, char *argv[], - void *cookie); -static int sk_esk (const char *option, int argc, char *argv[], - void *cookie); -static int pk_esk (const char *option, int argc, char *argv[], - void *cookie); -static int encrypted (const char *option, int argc, char *argv[], - void *cookie); -static int encrypted_pop (const char *option, int argc, char *argv[], - void *cookie); -static int literal (const char *option, int argc, char *argv[], - void *cookie); -static int signature (const char *option, int argc, char *argv[], - void *cookie); -static int copy (const char *option, int argc, char *argv[], - void *cookie); - -static struct option major_options[] = { - { "--user-id", user_id, "Create a user id packet." }, - { "--public-key", public_key, "Create a public key packet." }, - { "--private-key", NULL, "Create a private key packet." }, - { "--public-subkey", public_key, "Create a subkey packet." }, - { "--private-subkey", NULL, "Create a private subkey packet." }, - { "--sk-esk", sk_esk, - "Create a symmetric-key encrypted session key packet." }, - { "--pk-esk", pk_esk, - "Create a public-key encrypted session key packet." }, - { "--encrypted", encrypted, "Create a symmetrically encrypted data packet." }, - { "--encrypted-mdc", encrypted, - "Create a symmetrically encrypted and integrity protected data packet." }, - { "--encrypted-pop", encrypted_pop, - "Pop the most recent encryption container started by either" - " --encrypted or --encrypted-mdc." }, - { "--compressed", NULL, "Create a compressed data packet." }, - { "--literal", literal, "Create a literal (plaintext) data packet." }, - { "--signature", signature, "Create a signature packet." }, - { "--onepass-sig", NULL, "Create a one-pass signature packet." }, - { "--copy", copy, "Copy the specified file." }, - { NULL, NULL, - "To get more information about a given command, use:\n\n" - " $ gpgcompose --command --help to list a command's options."}, -}; - -static struct option global_options[] = { - { NULL, NULL, NULL }, -}; - -/* Make our lives easier and use a static limit for the user name. - 10k is way more than enough anyways... */ -const int user_id_max_len = 10 * 1024; - -static int -user_id_name (const char *option, int argc, char *argv[], void *cookie) -{ - PKT_user_id *uid = cookie; - int l; - - if (argc == 0) - log_fatal ("Usage: %s USER_ID\n", option); - - if (uid->len) - log_fatal ("Attempt to set user id multiple times.\n"); - - l = strlen (argv[0]); - if (l > user_id_max_len) - log_fatal ("user id too long (max: %d)\n", user_id_max_len); - - memcpy (uid->name, argv[0], l); - uid->name[l] = 0; - uid->len = l; - - return 1; -} - -static struct option user_id_options[] = { - { "", user_id_name, - "Set the user id. This is usually in the format " - "\"Name (comment) \"" }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --user-id \"USERID\" | " GPG_NAME " --list-packets" } -}; - -static int -user_id (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - gpg_error_t err; - PKT_user_id *uid = xmalloc_clear (sizeof (*uid) + user_id_max_len); - int c = add_component (PKT_USER_ID, uid); - int processed; - - processed = process_options (option, - major_options, - user_id_options, uid, - global_options, NULL, - argc, argv); - - if (! uid->len) - log_fatal ("%s: user id not given", option); - - err = build_packet (out, &components[c]); - if (err) - log_fatal ("Serializing user id packet: %s\n", gpg_strerror (err)); - - debug ("Wrote user id packet:\n"); - dump_component (&components[c]); - - return processed; -} - -static int -pk_search_terms (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - KEYDB_HANDLE hd; - KEYDB_SEARCH_DESC desc; - kbnode_t kb; - PKT_public_key *pk = cookie; - PKT_public_key *pk_ref; - int i; - - if (argc == 0) - log_fatal ("Usage: %s KEYID\n", option); - - if (pk->pubkey_algo) - log_fatal ("%s: multiple keys provided\n", option); - - err = classify_user_id (argv[0], &desc, 0); - if (err) - log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); - - hd = keydb_new (ctrl); - - err = keydb_search (hd, &desc, 1, NULL); - if (err) - log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err)); - - err = keydb_get_keyblock (hd, &kb); - if (err) - log_fatal ("retrieving keyblock for '%s': %s\n", - argv[0], gpg_strerror (err)); - - keydb_release (hd); - - pk_ref = kb->pkt->pkt.public_key; - - /* Copy the timestamp (if not already set), algo and public key - parameters. */ - if (! pk->timestamp) - pk->timestamp = pk_ref->timestamp; - pk->pubkey_algo = pk_ref->pubkey_algo; - for (i = 0; i < pubkey_get_npkey (pk->pubkey_algo); i ++) - pk->pkey[i] = gcry_mpi_copy (pk_ref->pkey[i]); - - release_kbnode (kb); - - return 1; -} - -static int -pk_timestamp (const char *option, int argc, char *argv[], void *cookie) -{ - PKT_public_key *pk = cookie; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s TIMESTAMP\n", option); - - errno = 0; - pk->timestamp = parse_timestamp (argv[0], &tail); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - return 1; -} - -#define TIMESTAMP_HELP \ - "Either as seconds since the epoch or as an ISO 8601 formatted " \ - "string (yyyymmddThhmmss, where the T is a literal)." - -static struct option pk_options[] = { - { "--timestamp", pk_timestamp, - "The creation time. " TIMESTAMP_HELP }, - { "", pk_search_terms, - "The key to copy the creation time and public key parameters from." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --public-key $KEYID --user-id \"USERID\" \\\n" - " | " GPG_NAME " --list-packets" } -}; - -static int -public_key (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - iobuf_t out = cookie; - PKT_public_key *pk; - int c; - int processed; - int t = (strcmp (option, "--public-key") == 0 - ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY); - - (void) option; - - pk = xmalloc_clear (sizeof (*pk)); - pk->version = 4; - - c = add_component (t, pk); - - processed = process_options (option, - major_options, - pk_options, pk, - global_options, NULL, - argc, argv); - - if (! pk->pubkey_algo) - log_fatal ("%s: key to extract public key parameters from not given", - option); - - /* Clear the keyid in case we updated one of the relevant fields - after accessing it. */ - pk->keyid[0] = pk->keyid[1] = 0; - - err = build_packet (out, &components[c]); - if (err) - log_fatal ("serializing %s packet: %s\n", - t == PKT_PUBLIC_KEY ? "public key" : "subkey", - gpg_strerror (err)); - - debug ("Wrote %s packet:\n", - t == PKT_PUBLIC_KEY ? "public key" : "subkey"); - dump_component (&components[c]); - - return processed; -} - -struct signinfo -{ - /* Key with which to sign. */ - kbnode_t issuer_kb; - PKT_public_key *issuer_pk; - - /* Overrides the issuer's key id. */ - u32 issuer_keyid[2]; - /* Sets the issuer's keyid to the primary key's key id. */ - int issuer_keyid_self; - - /* Key to sign. */ - PKT_public_key *pk; - /* Subkey to sign. */ - PKT_public_key *sk; - /* User id to sign. */ - PKT_user_id *uid; - - int class; - int digest_algo; - u32 timestamp; - u32 key_expiration; - - byte *cipher_algorithms; - int cipher_algorithms_len; - byte *digest_algorithms; - int digest_algorithms_len; - byte *compress_algorithms; - int compress_algorithms_len; - - u32 expiration; - - int exportable_set; - int exportable; - - int revocable_set; - int revocable; - - int trust_level_set; - byte trust_args[2]; - - char *trust_scope; - - struct revocation_key *revocation_key; - int nrevocation_keys; - - struct notation *notations; - - byte *key_server_preferences; - int key_server_preferences_len; - - char *key_server; - - int primary_user_id_set; - int primary_user_id; - - char *policy_uri; - - byte *key_flags; - int key_flags_len; - - char *signers_user_id; - - byte reason_for_revocation_code; - char *reason_for_revocation; - - byte *features; - int features_len; - - /* Whether to corrupt the signature. */ - int corrupt; -}; - -static int -sig_issuer (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - KEYDB_HANDLE hd; - KEYDB_SEARCH_DESC desc; - struct signinfo *si = cookie; - - if (argc == 0) - log_fatal ("Usage: %s KEYID\n", option); - - if (si->issuer_pk) - log_fatal ("%s: multiple keys provided\n", option); - - err = classify_user_id (argv[0], &desc, 0); - if (err) - log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); - - hd = keydb_new (ctrl); - - err = keydb_search (hd, &desc, 1, NULL); - if (err) - log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err)); - - err = keydb_get_keyblock (hd, &si->issuer_kb); - if (err) - log_fatal ("retrieving keyblock for '%s': %s\n", - argv[0], gpg_strerror (err)); - - keydb_release (hd); - - si->issuer_pk = si->issuer_kb->pkt->pkt.public_key; - - return 1; -} - -static int -sig_issuer_keyid (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - KEYDB_SEARCH_DESC desc; - struct signinfo *si = cookie; - - if (argc == 0) - log_fatal ("Usage: %s KEYID|self\n", option); - - if (si->issuer_keyid[0] || si->issuer_keyid[1] || si->issuer_keyid_self) - log_fatal ("%s given multiple times.\n", option); - - if (strcasecmp (argv[0], "self") == 0) - { - si->issuer_keyid_self = 1; - return 1; - } - - err = classify_user_id (argv[0], &desc, 0); - if (err) - log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err)); - - if (desc.mode != KEYDB_SEARCH_MODE_LONG_KID) - log_fatal ("%s is not a valid long key id.\n", argv[0]); - - keyid_copy (si->issuer_keyid, desc.u.kid); - - return 1; -} - -static int -sig_pk (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int i; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s COMPONENT_INDEX\n", option); - - errno = 0; - i = strtoul (argv[0], &tail, 10); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - if (i >= ncomponents) - log_fatal ("%d: No such component (have %d components so far)\n", - i, ncomponents); - if (! (components[i].pkttype == PKT_PUBLIC_KEY - || components[i].pkttype == PKT_PUBLIC_SUBKEY)) - log_fatal ("Component %d is not a public key or a subkey.", i); - - if (strcmp (option, "--pk") == 0) - { - if (si->pk) - log_fatal ("%s already given.\n", option); - si->pk = components[i].pkt.public_key; - } - else if (strcmp (option, "--sk") == 0) - { - if (si->sk) - log_fatal ("%s already given.\n", option); - si->sk = components[i].pkt.public_key; - } - else - log_fatal ("Cannot handle %s\n", option); - - return 1; -} - -static int -sig_user_id (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int i; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s COMPONENT_INDEX\n", option); - if (si->uid) - log_fatal ("%s already given.\n", option); - - errno = 0; - i = strtoul (argv[0], &tail, 10); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - if (i >= ncomponents) - log_fatal ("%d: No such component (have %d components so far)\n", - i, ncomponents); - if (! (components[i].pkttype != PKT_USER_ID - || components[i].pkttype == PKT_ATTRIBUTE)) - log_fatal ("Component %d is not a public key or a subkey.", i); - - si->uid = components[i].pkt.user_id; - - return 1; -} - -static int -sig_class (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int i; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s CLASS\n", option); - - errno = 0; - i = strtoul (argv[0], &tail, 0); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - si->class = i; - - return 1; -} - -static int -sig_digest (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int i; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s DIGEST_ALGO\n", option); - - errno = 0; - i = strtoul (argv[0], &tail, 10); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - si->digest_algo = i; - - return 1; -} - -static int -sig_timestamp (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s TIMESTAMP\n", option); - - errno = 0; - si->timestamp = parse_timestamp (argv[0], &tail); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - return 1; -} - -static int -sig_expiration (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int is_expiration = strcmp (option, "--expiration") == 0; - u32 *i = is_expiration ? &si->expiration : &si->key_expiration; - - if (! is_expiration) - log_assert (strcmp (option, "--key-expiration") == 0); - - if (argc == 0) - log_fatal ("Usage: %s DURATION\n", option); - - *i = parse_expire_string (argv[0]); - if (*i == (u32)-1) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - - return 1; -} - -static int -sig_int_list (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int nvalues = 1; - char *values = xmalloc (nvalues * sizeof (values[0])); - char *tail = argv[0]; - int i; - byte **a; - int *n; - - if (argc == 0) - log_fatal ("Usage: %s VALUE[,VALUE...]\n", option); - - for (i = 0; tail && *tail; i ++) - { - int v; - char *old_tail = tail; - - errno = 0; - v = strtol (tail, &tail, 0); - if (errno || old_tail == tail || (tail && !(*tail == ',' || *tail == 0))) - log_fatal ("Invalid value passed to %s (%s). " - "Expected a list of comma separated numbers\n", - option, argv[0]); - - if (! (0 <= v && v <= 255)) - log_fatal ("%s: %d is out of range (Expected: 0-255)\n", option, v); - - if (i == nvalues) - { - nvalues *= 2; - values = xrealloc (values, nvalues * sizeof (values[0])); - } - - values[i] = v; - - if (*tail == ',') - tail ++; - else - log_assert (*tail == 0); - } - - if (strcmp ("--cipher-algos", option) == 0) - { - a = &si->cipher_algorithms; - n = &si->cipher_algorithms_len; - } - else if (strcmp ("--digest-algos", option) == 0) - { - a = &si->digest_algorithms; - n = &si->digest_algorithms_len; - } - else if (strcmp ("--compress-algos", option) == 0) - { - a = &si->compress_algorithms; - n = &si->compress_algorithms_len; - } - else - log_fatal ("Cannot handle %s\n", option); - - if (*a) - log_fatal ("Option %s given multiple times.\n", option); - - *a = values; - *n = i; - - return 1; -} - -static int -sig_flag (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int range[2] = {0, 255}; - char *tail; - int v; - - if (strcmp (option, "--primary-user-id") == 0) - range[1] = 1; - - if (argc <= 1) - { - if (range[0] == 0 && range[1] == 1) - log_fatal ("Usage: %s 0|1\n", option); - else - log_fatal ("Usage: %s %d-%d\n", option, range[0], range[1]); - } - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1])) - log_fatal ("Invalid value passed to %s (%s). Expected %d-%d\n", - option, argv[0], range[0], range[1]); - - if (strcmp (option, "--exportable") == 0) - { - si->exportable_set = 1; - si->exportable = v; - } - else if (strcmp (option, "--revocable") == 0) - { - si->revocable_set = 1; - si->revocable = v; - } - else if (strcmp (option, "--primary-user-id") == 0) - { - si->primary_user_id_set = 1; - si->primary_user_id = v; - } - else - log_fatal ("Cannot handle %s\n", option); - - return 1; -} - -static int -sig_trust_level (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int i; - char *tail; - - if (argc <= 1) - log_fatal ("Usage: %s DEPTH TRUST_AMOUNT\n", option); - - for (i = 0; i < sizeof (si->trust_args) / sizeof (si->trust_args[0]); i ++) - { - int v; - - errno = 0; - v = strtol (argv[i], &tail, 0); - if (errno || (tail && *tail) || !(0 <= v && v <= 255)) - log_fatal ("Invalid value passed to %s (%s). Expected 0-255\n", - option, argv[i]); - - si->trust_args[i] = v; - } - - si->trust_level_set = 1; - - return 2; -} - -static int -sig_string_arg (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - char *p = argv[0]; - char **s; - - if (argc == 0) - log_fatal ("Usage: %s STRING\n", option); - - if (strcmp (option, "--trust-scope") == 0) - s = &si->trust_scope; - else if (strcmp (option, "--key-server") == 0) - s = &si->key_server; - else if (strcmp (option, "--signers-user-id") == 0) - s = &si->signers_user_id; - else if (strcmp (option, "--policy-uri") == 0) - s = &si->policy_uri; - else - log_fatal ("Cannot handle %s\n", option); - - if (*s) - log_fatal ("%s already given.\n", option); - - *s = xstrdup (p); - - return 1; -} - -static int -sig_revocation_key (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - struct signinfo *si = cookie; - int v; - char *tail; - PKT_public_key pk; - struct revocation_key *revkey; - - if (argc < 2) - log_fatal ("Usage: %s CLASS KEYID\n", option); - - memset (&pk, 0, sizeof (pk)); - - errno = 0; - v = strtol (argv[0], &tail, 16); - if (errno || (tail && *tail) || !(0 <= v && v <= 255)) - log_fatal ("%s: Invalid class value (%s). Expected 0-255\n", - option, argv[0]); - - pk.req_usage = PUBKEY_USAGE_SIG; - err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL, - NULL, &pk, argv[1], NULL, NULL, 1); - if (err) - log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err)); - - si->nrevocation_keys ++; - si->revocation_key = xrealloc (si->revocation_key, - si->nrevocation_keys - * sizeof (*si->revocation_key)); - revkey = &si->revocation_key[si->nrevocation_keys - 1]; - - revkey->class = v; - revkey->algid = pk.pubkey_algo; - fingerprint_from_pk (&pk, revkey->fpr, NULL); - - release_public_key_parts (&pk); - - return 2; -} - -static int -sig_notation (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int is_blob = strcmp (option, "--notation") != 0; - struct notation *notation; - char *p = argv[0]; - int p_free = 0; - char *data; - int data_size; - int data_len; - - if (argc == 0) - log_fatal ("Usage: %s [!<]name=value\n", option); - - if ((p[0] == '!' && p[1] == '<') || p[0] == '<') - /* Read from a file. */ - { - char *filename = NULL; - iobuf_t in; - int prefix; - - if (p[0] == '<') - p ++; - else - { - /* Remove the '<', which string_to_notation does not - understand, and preserve the '!'. */ - p = xstrdup (&p[1]); - p_free = 1; - p[0] = '!'; - } - - filename = strchr (p, '='); - if (! filename) - log_fatal ("No value specified. Usage: %s [!<]name=value\n", - option); - filename ++; - - prefix = (size_t) filename - (size_t) p; - - errno = 0; - in = iobuf_open (filename); - if (! in) - log_fatal ("Opening '%s': %s\n", - filename, errno ? strerror (errno): "unknown error"); - - /* A notation can be at most about a few dozen bytes short of - 64k. Since this is relatively small, we just allocate that - much instead of trying to dynamically size a buffer. */ - data_size = 64 * 1024; - data = xmalloc (data_size); - log_assert (prefix <= data_size); - memcpy (data, p, prefix); - - data_len = iobuf_read (in, &data[prefix], data_size - prefix - 1); - if (data_len == -1) - /* EOF => 0 bytes read. */ - data_len = 0; - - if (data_len == data_size - prefix - 1) - /* Technically, we should do another read and check for EOF, - but what's one byte more or less? */ - log_fatal ("Notation data doesn't fit in the packet.\n"); - - iobuf_close (in); - - /* NUL terminate it. */ - data[prefix + data_len] = 0; - - if (p_free) - xfree (p); - p = data; - p_free = 1; - data = &p[prefix]; - - if (is_blob) - p[prefix - 1] = 0; - } - else if (is_blob) - { - data = strchr (p, '='); - if (! data) - { - data = p; - data_len = 0; - } - else - { - p = xstrdup (p); - p_free = 1; - - data = strchr (p, '='); - log_assert (data); - - /* NUL terminate the name. */ - *data = 0; - data ++; - data_len = strlen (data); - } - } - - if (is_blob) - notation = blob_to_notation (p, data, data_len); - else - notation = string_to_notation (p, 1); - if (! notation) - log_fatal ("creating notation: an unknown error occurred.\n"); - notation->next = si->notations; - si->notations = notation; - - if (p_free) - xfree (p); - - return 1; -} - -static int -sig_big_endian_arg (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - char *p = argv[0]; - int i; - int l; - char *bytes; - - if (argc == 0) - log_fatal ("Usage: %s HEXDIGITS\n", option); - - /* Skip a leading "0x". */ - if (p[0] == '0' && p[1] == 'x') - p += 2; - - for (i = 0; i < strlen (p); i ++) - if (!hexdigitp (&p[i])) - log_fatal ("%s: argument ('%s') must consist of hex digits.\n", - option, p); - if (strlen (p) % 2 != 0) - log_fatal ("%s: argument ('%s') must contain an even number of hex digits.\n", - option, p); - - l = strlen (p) / 2; - bytes = xmalloc (l); - hex2bin (p, bytes, l); - - if (strcmp (option, "--key-server-preferences") == 0) - { - if (si->key_server_preferences) - log_fatal ("%s given multiple times.\n", option); - si->key_server_preferences = bytes; - si->key_server_preferences_len = l; - } - else if (strcmp (option, "--key-flags") == 0) - { - if (si->key_flags) - log_fatal ("%s given multiple times.\n", option); - si->key_flags = bytes; - si->key_flags_len = l; - } - else if (strcmp (option, "--features") == 0) - { - if (si->features) - log_fatal ("%s given multiple times.\n", option); - si->features = bytes; - si->features_len = l; - } - else - log_fatal ("Cannot handle %s\n", option); - - return 1; -} - -static int -sig_reason_for_revocation (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - int v; - char *tail; - - if (argc < 2) - log_fatal ("Usage: %s REASON_CODE REASON_STRING\n", option); - - errno = 0; - v = strtol (argv[0], &tail, 16); - if (errno || (tail && *tail) || !(0 <= v && v <= 255)) - log_fatal ("%s: Invalid reason code (%s). Expected 0-255\n", - option, argv[0]); - - if (si->reason_for_revocation) - log_fatal ("%s given multiple times.\n", option); - - si->reason_for_revocation_code = v; - si->reason_for_revocation = xstrdup (argv[1]); - - return 2; -} - -static int -sig_corrupt (const char *option, int argc, char *argv[], void *cookie) -{ - struct signinfo *si = cookie; - - (void) option; - (void) argc; - (void) argv; - (void) cookie; - - si->corrupt = 1; - - return 0; -} - -static struct option sig_options[] = { - { "--issuer", sig_issuer, - "The key to use to generate the signature."}, - { "--issuer-keyid", sig_issuer_keyid, - "Set the issuer's key id. This is useful for creating a " - "self-signature. As a special case, the value \"self\" refers " - "to the primary key's key id. " - "(RFC 4880, Section 5.2.3.5)" }, - { "--pk", sig_pk, - "The primary keyas an index into the components (keys and uids) " - "created so far where the first component has the index 0." }, - { "--sk", sig_pk, - "The subkey as an index into the components (keys and uids) created " - "so far where the first component has the index 0. Only needed for " - "0x18, 0x19, and 0x28 signatures." }, - { "--user-id", sig_user_id, - "The user id as an index into the components (keys and uids) created " - "so far where the first component has the index 0. Only needed for " - "0x10-0x13 and 0x30 signatures." }, - { "--class", sig_class, - "The signature's class. Valid values are " - "0x10-0x13 (user id and primary-key certification), " - "0x18 (subkey binding), " - "0x19 (primary key binding), " - "0x1f (direct primary key signature), " - "0x20 (key revocation), " - "0x28 (subkey revocation), and " - "0x30 (certification revocation)." - }, - { "--digest", sig_digest, "The digest algorithm" }, - { "--timestamp", sig_timestamp, - "The signature's creation time. " TIMESTAMP_HELP " 0 means now. " - "(RFC 4880, Section 5.2.3.4)" }, - { "--key-expiration", sig_expiration, - "The number of days until the associated key expires. To specify " - "seconds, prefix the value with \"seconds=\". It is also possible " - "to use 'y', 'm' and 'w' as simple multipliers. For instance, 2y " - "means 2 years, etc. " - "(RFC 4880, Section 5.2.3.6)" }, - { "--cipher-algos", sig_int_list, - "A comma separated list of the preferred cipher algorithms (identified by " - "their number, see RFC 4880, Section 9). " - "(RFC 4880, Section 5.2.3.7)" }, - { "--digest-algos", sig_int_list, - "A comma separated list of the preferred algorithms (identified by " - "their number, see RFC 4880, Section 9). " - "(RFC 4880, Section 5.2.3.8)" }, - { "--compress-algos", sig_int_list, - "A comma separated list of the preferred algorithms (identified by " - "their number, see RFC 4880, Section 9)." - "(RFC 4880, Section 5.2.3.9)" }, - { "--expiration", sig_expiration, - "The number of days until the signature expires. To specify seconds, " - "prefix the value with \"seconds=\". It is also possible to use 'y', " - "'m' and 'w' as simple multipliers. For instance, 2y means 2 years, " - "etc. " - "(RFC 4880, Section 5.2.3.10)" }, - { "--exportable", sig_flag, - "Mark this signature as exportable (1) or local (0). " - "(RFC 4880, Section 5.2.3.11)" }, - { "--revocable", sig_flag, - "Mark this signature as revocable (1, revocations are ignored) " - "or non-revocable (0). " - "(RFC 4880, Section 5.2.3.12)" }, - { "--trust-level", sig_trust_level, - "Set the trust level. This takes two integer arguments (0-255): " - "the trusted-introducer level and the degree of trust. " - "(RFC 4880, Section 5.2.3.13.)" }, - { "--trust-scope", sig_string_arg, - "A regular expression that limits the scope of --trust-level. " - "(RFC 4880, Section 5.2.3.14.)" }, - { "--revocation-key", sig_revocation_key, - "Specify a designated revoker. Takes two arguments: the class " - "(normally 0x80 or 0xC0 (sensitive)) and the key id of the " - "designatured revoker. May be given multiple times. " - "(RFC 4880, Section 5.2.3.15)" }, - { "--notation", sig_notation, - "Add a human-readable notation of the form \"[!<]name=value\" where " - "\"!\" means that the critical flag should be set and \"<\" means " - "that VALUE is a file to read the data from. " - "(RFC 4880, Section 5.2.3.16)" }, - { "--notation-binary", sig_notation, - "Add a binary notation of the form \"[!<]name=value\" where " - "\"!\" means that the critical flag should be set and \"<\" means " - "that VALUE is a file to read the data from. " - "(RFC 4880, Section 5.2.3.16)" }, - { "--key-server-preferences", sig_big_endian_arg, - "Big-endian number encoding the keyserver preferences. " - "(RFC 4880, Section 5.2.3.17)" }, - { "--key-server", sig_string_arg, - "The preferred keyserver. (RFC 4880, Section 5.2.3.18)" }, - { "--primary-user-id", sig_flag, - "Sets the primary user id flag. (RFC 4880, Section 5.2.3.19)" }, - { "--policy-uri", sig_string_arg, - "URI of a document that describes the issuer's signing policy. " - "(RFC 4880, Section 5.2.3.20)" }, - { "--key-flags", sig_big_endian_arg, - "Big-endian number encoding the key flags. " - "(RFC 4880, Section 5.2.3.21)" }, - { "--signers-user-id", sig_string_arg, - "The user id (as a string) responsible for the signing. " - "(RFC 4880, Section 5.2.3.22)" }, - { "--reason-for-revocation", sig_reason_for_revocation, - "Takes two arguments: a reason for revocation code and a " - "user-provided string. " - "(RFC 4880, Section 5.2.3.23)" }, - { "--features", sig_big_endian_arg, - "Big-endian number encoding the feature flags. " - "(RFC 4880, Section 5.2.3.24)" }, - { "--signature-target", NULL, - "Takes three arguments: the target signature's public key algorithm " - " (as an integer), the hash algorithm (as an integer) and the hash " - " (as a hexadecimal string). " - "(RFC 4880, Section 5.2.3.25)" }, - { "--embedded-signature", NULL, - "An embedded signature. This must be immediately followed by a " - "signature packet (created using --signature ...) or a filename " - "containing the packet." - "(RFC 4880, Section 5.2.3.26)" }, - { "--hashed", NULL, - "The following attributes will be placed in the hashed area of " - "the signature. (This is the default and it reset at the end of" - "each signature.)" }, - { "--unhashed", NULL, - "The following attributes will be placed in the unhashed area of " - "the signature (and thus not integrity protected)." }, - { "--corrupt", sig_corrupt, - "Corrupt the signature." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --public-key $KEYID --user-id USERID \\\n" - " --signature --class 0x10 --issuer $KEYID --issuer-keyid self \\\n" - " | " GPG_NAME " --list-packets"} -}; - -static int -mksubpkt_callback (PKT_signature *sig, void *cookie) -{ - struct signinfo *si = cookie; - int i; - - if (si->key_expiration) - { - char buf[4]; - buf[0] = (si->key_expiration >> 24) & 0xff; - buf[1] = (si->key_expiration >> 16) & 0xff; - buf[2] = (si->key_expiration >> 8) & 0xff; - buf[3] = si->key_expiration & 0xff; - build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); - } - - if (si->cipher_algorithms) - build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, - si->cipher_algorithms, - si->cipher_algorithms_len); - - if (si->digest_algorithms) - build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, - si->digest_algorithms, - si->digest_algorithms_len); - - if (si->compress_algorithms) - build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, - si->compress_algorithms, - si->compress_algorithms_len); - - if (si->exportable_set) - { - char buf = si->exportable; - build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, &buf, 1); - } - - if (si->trust_level_set) - build_sig_subpkt (sig, SIGSUBPKT_TRUST, - si->trust_args, sizeof (si->trust_args)); - - if (si->trust_scope) - build_sig_subpkt (sig, SIGSUBPKT_REGEXP, - si->trust_scope, strlen (si->trust_scope)); - - for (i = 0; i < si->nrevocation_keys; i ++) - { - struct revocation_key *revkey = &si->revocation_key[i]; - gpg_error_t err = keygen_add_revkey (sig, revkey); - if (err) - { - u32 keyid[2]; - keyid_from_fingerprint (global_ctrl, revkey->fpr, 20, keyid); - log_fatal ("adding revocation key %s: %s\n", - keystr (keyid), gpg_strerror (err)); - } - } - - /* keygen_add_revkey sets revocable=0 so be sure to do this after - adding the rev keys. */ - if (si->revocable_set) - { - char buf = si->revocable; - build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, &buf, 1); - } - - keygen_add_notations (sig, si->notations); - - if (si->key_server_preferences) - build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, - si->key_server_preferences, - si->key_server_preferences_len); - - if (si->key_server) - build_sig_subpkt (sig, SIGSUBPKT_PREF_KS, - si->key_server, strlen (si->key_server)); - - if (si->primary_user_id_set) - { - char buf = si->primary_user_id; - build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, &buf, 1); - } - - if (si->policy_uri) - build_sig_subpkt (sig, SIGSUBPKT_POLICY, - si->policy_uri, strlen (si->policy_uri)); - - if (si->key_flags) - build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, - si->key_flags, si->key_flags_len); - - if (si->signers_user_id) - build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, - si->signers_user_id, strlen (si->signers_user_id)); - - if (si->reason_for_revocation) - { - int len = 1 + strlen (si->reason_for_revocation); - char *buf; - - buf = xmalloc (len); - - buf[0] = si->reason_for_revocation_code; - memcpy (&buf[1], si->reason_for_revocation, len - 1); - - build_sig_subpkt (sig, SIGSUBPKT_REVOC_REASON, buf, len); - - xfree (buf); - } - - if (si->features) - build_sig_subpkt (sig, SIGSUBPKT_FEATURES, - si->features, si->features_len); - - return 0; -} - -static int -signature (const char *option, int argc, char *argv[], void *cookie) -{ - gpg_error_t err; - iobuf_t out = cookie; - struct signinfo si; - int processed; - PKT_public_key *pk; - PKT_signature *sig; - PACKET pkt; - u32 keyid_orig[2], keyid[2]; - - (void) option; - - memset (&si, 0, sizeof (si)); - memset (&pkt, 0, sizeof (pkt)); - - processed = process_options (option, - major_options, - sig_options, &si, - global_options, NULL, - argc, argv); - - if (ncomponents) - { - int pkttype = components[ncomponents - 1].pkttype; - - if (pkttype == PKT_PUBLIC_KEY) - { - if (! si.class) - /* Direct key sig. */ - si.class = 0x1F; - } - else if (pkttype == PKT_PUBLIC_SUBKEY) - { - if (! si.sk) - si.sk = components[ncomponents - 1].pkt.public_key; - if (! si.class) - /* Subkey binding sig. */ - si.class = 0x18; - } - else if (pkttype == PKT_USER_ID) - { - if (! si.uid) - si.uid = components[ncomponents - 1].pkt.user_id; - if (! si.class) - /* Certification of a user id and public key packet. */ - si.class = 0x10; - } - } - - pk = NULL; - if (! si.pk || ! si.issuer_pk) - /* No primary key specified. Default to the first one that we - find. */ - { - int i; - for (i = 0; i < ncomponents; i ++) - if (components[i].pkttype == PKT_PUBLIC_KEY) - { - pk = components[i].pkt.public_key; - break; - } - } - - if (! si.pk) - { - if (! pk) - log_fatal ("%s: no primary key given and no primary key available", - "--pk"); - si.pk = pk; - } - if (! si.issuer_pk) - { - if (! pk) - log_fatal ("%s: no issuer key given and no primary key available", - "--issuer"); - si.issuer_pk = pk; - } - - if (si.class == 0x18 || si.class == 0x19 || si.class == 0x28) - /* Requires the primary key and a subkey. */ - { - if (! si.sk) - log_fatal ("sig class 0x%x requires a subkey (--sk)\n", si.class); - } - else if (si.class == 0x10 - || si.class == 0x11 - || si.class == 0x12 - || si.class == 0x13 - || si.class == 0x30) - /* Requires the primary key and a user id. */ - { - if (! si.uid) - log_fatal ("sig class 0x%x requires a uid (--uid)\n", si.class); - } - else if (si.class == 0x1F || si.class == 0x20) - /* Just requires the primary key. */ - ; - else - log_fatal ("Unsupported signature class: 0x%x\n", si.class); - - sig = xmalloc_clear (sizeof (*sig)); - - /* Save SI.ISSUER_PK->KEYID. */ - keyid_copy (keyid_orig, pk_keyid (si.issuer_pk)); - if (si.issuer_keyid[0] || si.issuer_keyid[1]) - keyid_copy (si.issuer_pk->keyid, si.issuer_keyid); - else if (si.issuer_keyid_self) - { - PKT_public_key *pripk = primary_key(); - if (! pripk) - log_fatal ("--issuer-keyid self given, but no primary key available.\n"); - keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk)); - } - - /* The reuse of core gpg stuff by this tool is questionable when it - * requires adding extra code to the actual gpg code. It does not - * make sense to pass an extra parameter and in particular not given - * that gpg already has opt.cert_digest_algo to override it. */ - if (si.digest_algo) - log_info ("note: digest algo can't be passed to make_keysig_packet\n"); - - /* Changing the issuer's key id is fragile. Check to make sure - make_keysig_packet didn't recompute the keyid. */ - keyid_copy (keyid, si.issuer_pk->keyid); - err = make_keysig_packet (global_ctrl, - &sig, si.pk, si.uid, si.sk, si.issuer_pk, - si.class, - si.timestamp, si.expiration, - mksubpkt_callback, &si, NULL); - log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0); - if (err) - log_fatal ("Generating signature: %s\n", gpg_strerror (err)); - - /* Restore SI.PK->KEYID. */ - keyid_copy (si.issuer_pk->keyid, keyid_orig); - - if (si.corrupt) - { - /* Set the top 32-bits to 0xBAD0DEAD. */ - int bits = gcry_mpi_get_nbits (sig->data[0]); - gcry_mpi_t x = gcry_mpi_new (0); - gcry_mpi_add_ui (x, x, 0xBAD0DEAD); - gcry_mpi_lshift (x, x, bits > 32 ? bits - 32 : bits); - gcry_mpi_clear_highbit (sig->data[0], bits > 32 ? bits - 32 : 0); - gcry_mpi_add (sig->data[0], sig->data[0], x); - gcry_mpi_release (x); - } - - pkt.pkttype = PKT_SIGNATURE; - pkt.pkt.signature = sig; - - err = build_packet (out, &pkt); - if (err) - log_fatal ("serializing public key packet: %s\n", gpg_strerror (err)); - - debug ("Wrote signature packet:\n"); - dump_component (&pkt); - - free_seckey_enc (sig); - release_kbnode (si.issuer_kb); - xfree (si.revocation_key); - - return processed; -} - -struct sk_esk_info -{ - /* The cipher used for encrypting the session key (when a session - key is used). */ - int cipher; - /* The cipher used for encryping the SED packet. */ - int sed_cipher; - - /* S2K related data. */ - int hash; - int mode; - int mode_set; - byte salt[8]; - int salt_set; - int iterations; - - /* If applying the S2K function to the passphrase is the session key - or if it is the decryption key for the session key. */ - int s2k_is_session_key; - /* Generate a new, random session key. */ - int new_session_key; - - /* The unencrypted session key. */ - int session_key_len; - char *session_key; - - char *password; -}; - -static int -sk_esk_cipher (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "integer|IDEA|3DES|CAST5|BLOWFISH|AES|AES192|AES256|CAMELLIA128|CAMELLIA192|CAMELLIA256"; - int cipher; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (strcasecmp (argv[0], "IDEA") == 0) - cipher = CIPHER_ALGO_IDEA; - else if (strcasecmp (argv[0], "3DES") == 0) - cipher = CIPHER_ALGO_3DES; - else if (strcasecmp (argv[0], "CAST5") == 0) - cipher = CIPHER_ALGO_CAST5; - else if (strcasecmp (argv[0], "BLOWFISH") == 0) - cipher = CIPHER_ALGO_BLOWFISH; - else if (strcasecmp (argv[0], "AES") == 0) - cipher = CIPHER_ALGO_AES; - else if (strcasecmp (argv[0], "AES192") == 0) - cipher = CIPHER_ALGO_AES192; - else if (strcasecmp (argv[0], "TWOFISH") == 0) - cipher = CIPHER_ALGO_TWOFISH; - else if (strcasecmp (argv[0], "CAMELLIA128") == 0) - cipher = CIPHER_ALGO_CAMELLIA128; - else if (strcasecmp (argv[0], "CAMELLIA192") == 0) - cipher = CIPHER_ALGO_CAMELLIA192; - else if (strcasecmp (argv[0], "CAMELLIA256") == 0) - cipher = CIPHER_ALGO_CAMELLIA256; - else - { - char *tail; - int v; - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) || ! valid_cipher (v)) - log_fatal ("Invalid or unsupported value. Usage: %s %s\n", - option, usage); - - cipher = v; - } - - if (strcmp (option, "--cipher") == 0) - { - if (si->cipher) - log_fatal ("%s given multiple times.", option); - si->cipher = cipher; - } - else if (strcmp (option, "--sed-cipher") == 0) - { - if (si->sed_cipher) - log_fatal ("%s given multiple times.", option); - si->sed_cipher = cipher; - } - - return 1; -} - -static int -sk_esk_mode (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "integer|simple|salted|iterated"; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (si->mode) - log_fatal ("%s given multiple times.", option); - - if (strcasecmp (argv[0], "simple") == 0) - si->mode = 0; - else if (strcasecmp (argv[0], "salted") == 0) - si->mode = 1; - else if (strcasecmp (argv[0], "iterated") == 0) - si->mode = 3; - else - { - char *tail; - int v; - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) || ! (v == 0 || v == 1 || v == 3)) - log_fatal ("Invalid or unsupported value. Usage: %s %s\n", - option, usage); - - si->mode = v; - } - - si->mode_set = 1; - - return 1; -} - -static int -sk_esk_hash_algorithm (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "integer|MD5|SHA1|RMD160|SHA256|SHA384|SHA512|SHA224"; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (si->hash) - log_fatal ("%s given multiple times.", option); - - if (strcasecmp (argv[0], "MD5") == 0) - si->hash = DIGEST_ALGO_MD5; - else if (strcasecmp (argv[0], "SHA1") == 0) - si->hash = DIGEST_ALGO_SHA1; - else if (strcasecmp (argv[0], "RMD160") == 0) - si->hash = DIGEST_ALGO_RMD160; - else if (strcasecmp (argv[0], "SHA256") == 0) - si->hash = DIGEST_ALGO_SHA256; - else if (strcasecmp (argv[0], "SHA384") == 0) - si->hash = DIGEST_ALGO_SHA384; - else if (strcasecmp (argv[0], "SHA512") == 0) - si->hash = DIGEST_ALGO_SHA512; - else if (strcasecmp (argv[0], "SHA224") == 0) - si->hash = DIGEST_ALGO_SHA224; - else - { - char *tail; - int v; - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) - || ! (v == DIGEST_ALGO_MD5 - || v == DIGEST_ALGO_SHA1 - || v == DIGEST_ALGO_RMD160 - || v == DIGEST_ALGO_SHA256 - || v == DIGEST_ALGO_SHA384 - || v == DIGEST_ALGO_SHA512 - || v == DIGEST_ALGO_SHA224)) - log_fatal ("Invalid or unsupported value. Usage: %s %s\n", - option, usage); - - si->hash = v; - } - - return 1; -} - -static int -sk_esk_salt (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "16-HEX-CHARACTERS"; - char *p = argv[0]; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (si->salt_set) - log_fatal ("%s given multiple times.", option); - - if (p[0] == '0' && p[1] == 'x') - p += 2; - - if (strlen (p) != 16) - log_fatal ("%s: Salt must be exactly 16 hexadecimal characters (have: %zd)\n", - option, strlen (p)); - - if (hex2bin (p, si->salt, sizeof (si->salt)) == -1) - log_fatal ("%s: Salt must only contain hexadecimal characters\n", - option); - - si->salt_set = 1; - - return 1; -} - -static int -sk_esk_iterations (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "ITERATION-COUNT"; - char *tail; - int v; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) || v < 0) - log_fatal ("%s: Non-negative integer expected.\n", option); - - si->iterations = v; - - return 1; -} - -static int -sk_esk_session_key (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "HEX-CHARACTERS|auto|none"; - char *p = argv[0]; - struct session_key sk; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (si->session_key || si->s2k_is_session_key - || si->new_session_key) - log_fatal ("%s given multiple times.", option); - - if (strcasecmp (p, "none") == 0) - { - si->s2k_is_session_key = 1; - return 1; - } - if (strcasecmp (p, "new") == 0) - { - si->new_session_key = 1; - return 1; - } - if (strcasecmp (p, "auto") == 0) - return 1; - - sk = parse_session_key (option, p, 0); - - if (si->session_key) - log_fatal ("%s given multiple times.", option); - - if (sk.algo) - si->sed_cipher = sk.algo; - - si->session_key_len = sk.keylen; - si->session_key = sk.key; - - return 1; -} - -static int -sk_esk_password (const char *option, int argc, char *argv[], void *cookie) -{ - struct sk_esk_info *si = cookie; - char *usage = "PASSWORD"; - - if (argc == 0) - log_fatal ("Usage: --sk-esk %s\n", usage); - - if (si->password) - log_fatal ("%s given multiple times.", option); - - si->password = xstrdup (argv[0]); - - return 1; -} - -static struct option sk_esk_options[] = { - { "--cipher", sk_esk_cipher, - "The encryption algorithm for encrypting the session key. " - "One of IDEA, 3DES, CAST5, BLOWFISH, AES (default), AES192, " - "AES256, TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." }, - { "--sed-cipher", sk_esk_cipher, - "The encryption algorithm for encrypting the SED packet. " - "One of IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, " - "AES256 (default), TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." }, - { "--mode", sk_esk_mode, - "The S2K mode. Either one of the strings \"simple\", \"salted\" " - "or \"iterated\" or an integer." }, - { "--hash", sk_esk_hash_algorithm, - "The hash algorithm to used to derive the key. One of " - "MD5, SHA1 (default), RMD160, SHA256, SHA384, SHA512, or SHA224." }, - { "--salt", sk_esk_salt, - "The S2K salt encoded as 16 hexadecimal characters. One needed " - "if the S2K function is in salted or iterated mode." }, - { "--iterations", sk_esk_iterations, - "The iteration count. If not provided, a reasonable value is chosen. " - "Note: due to the encoding scheme, not every value is valid. For " - "convenience, the provided value will be rounded appropriately. " - "Only needed if the S2K function is in iterated mode." }, - { "--session-key", sk_esk_session_key, - "The session key to be encrypted by the S2K function as a hexadecimal " - "string. If this is \"new\", then a new session key is generated." - "If this is \"auto\", then either the last session key is " - "used, if the was none, one is generated. If this is \"none\", then " - "the session key is the result of applying the S2K algorithms to the " - "password. The session key may be prefaced with an integer and a colon " - "to indicate the cipher to use for the SED packet (making --sed-cipher " - "unnecessary and allowing the direct use of the result of " - "\"" GPG_NAME " --show-session-key\")." }, - { "", sk_esk_password, "The password." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --sk-esk foobar --encrypted \\\n" - " --literal --value foo | " GPG_NAME " --list-packets" } -}; - -static int -sk_esk (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - gpg_error_t err; - int processed; - struct sk_esk_info si; - DEK sesdek; - DEK s2kdek; - PKT_symkey_enc *ske; - PACKET pkt; - - memset (&si, 0, sizeof (si)); - - processed = process_options (option, - major_options, - sk_esk_options, &si, - global_options, NULL, - argc, argv); - - if (! si.password) - log_fatal ("%s: missing password. Usage: %s PASSWORD", option, option); - - /* Fill in defaults, if appropriate. */ - if (! si.cipher) - si.cipher = CIPHER_ALGO_AES; - - if (! si.sed_cipher) - si.sed_cipher = CIPHER_ALGO_AES256; - - if (! si.hash) - si.hash = DIGEST_ALGO_SHA1; - - if (! si.mode_set) - /* Salted and iterated. */ - si.mode = 3; - - if (si.mode != 0 && ! si.salt_set) - /* Generate a salt. */ - gcry_randomize (si.salt, 8, GCRY_STRONG_RANDOM); - - if (si.mode == 0) - { - if (si.iterations) - log_info ("%s: --iterations provided, but not used for mode=0\n", - option); - si.iterations = 0; - } - else if (! si.iterations) - si.iterations = 10000; - - memset (&sesdek, 0, sizeof (sesdek)); - /* The session key is used to encrypt the SED packet. */ - sesdek.algo = si.sed_cipher; - if (si.session_key) - /* Copy the unencrypted session key into SESDEK. */ - { - sesdek.keylen = openpgp_cipher_get_algo_keylen (sesdek.algo); - if (sesdek.keylen != si.session_key_len) - log_fatal ("%s: Cipher algorithm requires a %d byte session key, but provided session key is %d bytes.", - option, sesdek.keylen, si.session_key_len); - - log_assert (sesdek.keylen <= sizeof (sesdek.key)); - memcpy (sesdek.key, si.session_key, sesdek.keylen); - } - else if (! si.s2k_is_session_key || si.new_session_key) - /* We need a session key, but one wasn't provided. Generate it. */ - make_session_key (&sesdek); - - /* The encrypted session key needs 1 + SESDEK.KEYLEN bytes of - space. */ - ske = xmalloc_clear (sizeof (*ske) + sesdek.keylen); - - ske->version = 4; - ske->cipher_algo = si.cipher; - - ske->s2k.mode = si.mode; - ske->s2k.hash_algo = si.hash; - log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt)); - memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt)); - if (! si.s2k_is_session_key) - { - if (!si.iterations) - ske->s2k.count = encode_s2k_iterations (agent_get_s2k_count ()); - else - ske->s2k.count = encode_s2k_iterations (si.iterations); - } - - /* Derive the symmetric key that is either the session key or the - key used to encrypt the session key. */ - memset (&s2kdek, 0, sizeof (s2kdek)); - - s2kdek.algo = si.cipher; - s2kdek.keylen = openpgp_cipher_get_algo_keylen (s2kdek.algo); - - err = gcry_kdf_derive (si.password, strlen (si.password), - ske->s2k.mode == 3 ? GCRY_KDF_ITERSALTED_S2K - : ske->s2k.mode == 1 ? GCRY_KDF_SALTED_S2K - : GCRY_KDF_SIMPLE_S2K, - ske->s2k.hash_algo, ske->s2k.salt, 8, - S2K_DECODE_COUNT (ske->s2k.count), - /* The size of the desired key and its - buffer. */ - s2kdek.keylen, s2kdek.key); - if (err) - log_fatal ("gcry_kdf_derive failed: %s", gpg_strerror (err)); - - - if (si.s2k_is_session_key) - { - ske->seskeylen = 0; - session_key = s2kdek; - } - else - /* Encrypt the session key using the s2k specifier. */ - { - DEK *sesdekp = &sesdek; - void *enckey; - size_t enckeylen; - - /* Now encrypt the session key (or rather, the algorithm used to - encrypt the SKESK plus the session key) using S2KDEK. */ - err = encrypt_seskey (&s2kdek, 0, &sesdekp, &enckey, &enckeylen); - - if (err) - log_fatal ("encrypt_seskey failed: %s\n", gpg_strerror (err)); - - if (enckeylen - 1 > sesdek.keylen) - log_fatal ("key size is too big: %zu\n", enckeylen); - else - { - ske->seskeylen = (byte)enckeylen; - memcpy (ske->seskey, enckey, enckeylen); - } - - /* Save the session key for later. */ - session_key = sesdek; - xfree (enckey); - } - - pkt.pkttype = PKT_SYMKEY_ENC; - pkt.pkt.symkey_enc = ske; - - err = build_packet (out, &pkt); - if (err) - log_fatal ("Serializing sym-key encrypted packet: %s\n", - gpg_strerror (err)); - - debug ("Wrote sym-key encrypted packet:\n"); - dump_component (&pkt); - - xfree (si.session_key); - xfree (si.password); - xfree (ske); - - return processed; -} - -struct pk_esk_info -{ - int session_key_set; - - int new_session_key; - - int sed_cipher; - int session_key_len; - char *session_key; - - int throw_keyid; - - char *keyid; -}; - -static int -pk_esk_session_key (const char *option, int argc, char *argv[], void *cookie) -{ - struct pk_esk_info *pi = cookie; - char *usage = "HEX-CHARACTERS|auto|none"; - char *p = argv[0]; - struct session_key sk; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (pi->session_key_set) - log_fatal ("%s given multiple times.", option); - pi->session_key_set = 1; - - if (strcasecmp (p, "new") == 0) - { - pi->new_session_key = 1; - return 1; - } - - if (strcasecmp (p, "auto") == 0) - return 1; - - sk = parse_session_key (option, p, 0); - - if (pi->session_key) - log_fatal ("%s given multiple times.", option); - - if (sk.algo) - pi->sed_cipher = sk.algo; - - pi->session_key_len = sk.keylen; - pi->session_key = sk.key; - - return 1; -} - -static int -pk_esk_throw_keyid (const char *option, int argc, char *argv[], void *cookie) -{ - struct pk_esk_info *pi = cookie; - - (void) option; - (void) argc; - (void) argv; - - pi->throw_keyid = 1; - - return 0; -} - -static int -pk_esk_keyid (const char *option, int argc, char *argv[], void *cookie) -{ - struct pk_esk_info *pi = cookie; - char *usage = "KEYID"; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (pi->keyid) - log_fatal ("Multiple key ids given, but only one is allowed."); - - pi->keyid = xstrdup (argv[0]); - - return 1; -} - -static struct option pk_esk_options[] = { - { "--session-key", pk_esk_session_key, - "The session key to be encrypted by the S2K function as a hexadecimal " - "string. If this is not given or is \"auto\", then the current " - "session key is used. If there is no session key or this is \"new\", " - "then a new session key is generated. The session key may be " - "prefaced with an integer and a colon to indicate the cipher to use " - "for the SED packet (making --sed-cipher unnecessary and allowing the " - "direct use of the result of \"" GPG_NAME " --show-session-key\")." }, - { "--throw-keyid", pk_esk_throw_keyid, - "Throw the keyid." }, - { "", pk_esk_keyid, "The key id." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --pk-esk $KEYID --encrypted --literal --value foo \\\n" - " | " GPG_NAME " --list-packets"} -}; - -static int -pk_esk (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - gpg_error_t err; - int processed; - struct pk_esk_info pi; - PKT_public_key pk; - - memset (&pi, 0, sizeof (pi)); - - processed = process_options (option, - major_options, - pk_esk_options, &pi, - global_options, NULL, - argc, argv); - - if (! pi.keyid) - log_fatal ("%s: missing keyid. Usage: %s KEYID", option, option); - - memset (&pk, 0, sizeof (pk)); - pk.req_usage = PUBKEY_USAGE_ENC; - err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL, - NULL, &pk, pi.keyid, NULL, NULL, 1); - if (err) - log_fatal ("%s: looking up key %s: %s\n", - option, pi.keyid, gpg_strerror (err)); - - if (pi.sed_cipher) - /* Have a session key. */ - { - session_key.algo = pi.sed_cipher; - session_key.keylen = pi.session_key_len; - log_assert (session_key.keylen <= sizeof (session_key.key)); - memcpy (session_key.key, pi.session_key, session_key.keylen); - } - - if (pi.new_session_key || ! session_key.algo) - { - if (! pi.new_session_key) - /* Default to AES256. */ - session_key.algo = CIPHER_ALGO_AES256; - make_session_key (&session_key); - } - - err = write_pubkey_enc (global_ctrl, &pk, pi.throw_keyid, &session_key, out); - if (err) - log_fatal ("%s: writing pk_esk packet for %s: %s\n", - option, pi.keyid, gpg_strerror (err)); - - debug ("Wrote pk_esk packet for %s\n", pi.keyid); - - xfree (pi.keyid); - xfree (pi.session_key); - - return processed; -} - -struct encinfo -{ - int saw_session_key; -}; - -static int -encrypted_session_key (const char *option, int argc, char *argv[], void *cookie) -{ - struct encinfo *ei = cookie; - char *usage = "HEX-CHARACTERS|auto"; - char *p = argv[0]; - struct session_key sk; - - if (argc == 0) - log_fatal ("Usage: %s %s\n", option, usage); - - if (ei->saw_session_key) - log_fatal ("%s given multiple times.", option); - ei->saw_session_key = 1; - - if (strcasecmp (p, "auto") == 0) - return 1; - - sk = parse_session_key (option, p, 1); - - session_key.algo = sk.algo; - log_assert (sk.keylen <= sizeof (session_key.key)); - memcpy (session_key.key, sk.key, sk.keylen); - xfree (sk.key); - - return 1; -} - -static struct option encrypted_options[] = { - { "--session-key", encrypted_session_key, - "The session key to be encrypted by the S2K function as a hexadecimal " - "string. If this is not given or is \"auto\", then the last session key " - "is used. If there was none, then an error is raised. The session key " - "must be prefaced with an integer and a colon to indicate the cipher " - "to use (this is format used by \"" GPG_NAME " --show-session-key\")." }, - { NULL, NULL, - "After creating the packet, this command clears the current " - "session key.\n\n" - "Example: nested encryption packets:\n\n" - " $ gpgcompose --sk-esk foo --encrypted-mdc \\\n" - " --sk-esk bar --encrypted-mdc \\\n" - " --literal --value 123 --encrypted-pop --encrypted-pop | " GPG_NAME" -d" } -}; - -static int -encrypted (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - int processed; - struct encinfo ei; - PKT_encrypted e; - cipher_filter_context_t *cfx; - - memset (&ei, 0, sizeof (ei)); - - processed = process_options (option, - major_options, - encrypted_options, &ei, - global_options, NULL, - argc, argv); - - if (! session_key.algo) - log_fatal ("%s: no session key configured\n" - " (use e.g. --sk-esk PASSWORD or --pk-esk KEYID).\n", - option); - - memset (&e, 0, sizeof (e)); - /* We only need to set E->LEN, E->EXTRALEN (if E->LEN is not - 0), and E->NEW_CTB. */ - e.len = 0; - e.new_ctb = 1; - - /* Register the cipher filter. */ - - cfx = xmalloc_clear (sizeof (*cfx)); - - /* Copy the session key. */ - cfx->dek = xmalloc (sizeof (*cfx->dek)); - *cfx->dek = session_key; - - if (do_debug) - { - char *buf; - - buf = xmalloc (2 * session_key.keylen + 1); - debug ("session key: algo: %d; keylen: %d; key: %s\n", - session_key.algo, session_key.keylen, - bin2hex (session_key.key, session_key.keylen, buf)); - xfree (buf); - } - - if (strcmp (option, "--encrypted-mdc") == 0) - cfx->dek->use_mdc = 1; - else if (strcmp (option, "--encrypted") == 0) - cfx->dek->use_mdc = 0; - else - log_fatal ("%s: option not handled by this function!\n", option); - - cfx->datalen = 0; - - filter_push (out, cipher_filter_cfb, cfx, PKT_ENCRYPTED, cfx->datalen == 0); - - debug ("Wrote encrypted packet:\n"); - - /* Clear the current session key. */ - memset (&session_key, 0, sizeof (session_key)); - - return processed; -} - -static struct option encrypted_pop_options[] = { - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --sk-esk PASSWORD \\\n" - " --encrypted-mdc \\\n" - " --literal --value foo \\\n" - " --encrypted-pop | " GPG_NAME " --list-packets" } -}; - -static int -encrypted_pop (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - int processed; - - processed = process_options (option, - major_options, - encrypted_pop_options, - NULL, - global_options, NULL, - argc, argv); - /* We only support a single option, --help, which causes the program - * to exit. */ - log_assert (processed == 0); - - filter_pop (out, PKT_ENCRYPTED); - - debug ("Popped encryption container.\n"); - - return processed; -} - -struct data -{ - int file; - union - { - char *data; - char *filename; - }; - struct data *next; -}; - -/* This must be the first member of the struct to be able to use - add_value! */ -struct datahead -{ - struct data *head; - struct data **last_next; -}; - -static int -add_value (const char *option, int argc, char *argv[], void *cookie) -{ - struct datahead *dh = cookie; - struct data *d = xmalloc_clear (sizeof (struct data)); - - d->file = strcmp ("--file", option) == 0; - if (! d->file) - log_assert (strcmp ("--value", option) == 0); - - if (argc == 0) - { - if (d->file) - log_fatal ("Usage: %s FILENAME\n", option); - else - log_fatal ("Usage: %s STRING\n", option); - } - - if (! dh->last_next) - /* First time through. Initialize DH->LAST_NEXT. */ - { - log_assert (! dh->head); - dh->last_next = &dh->head; - } - - if (d->file) - d->filename = argv[0]; - else - d->data = argv[0]; - - /* Append it. */ - *dh->last_next = d; - dh->last_next = &d->next; - - return 1; -} - -struct litinfo -{ - /* This must be the first element for add_value to work! */ - struct datahead data; - - int timestamp_set; - u32 timestamp; - char mode; - int partial_body_length_encoding; - char *name; -}; - -static int -literal_timestamp (const char *option, int argc, char *argv[], void *cookie) -{ - struct litinfo *li = cookie; - - char *tail = NULL; - - if (argc == 0) - log_fatal ("Usage: %s TIMESTAMP\n", option); - - errno = 0; - li->timestamp = parse_timestamp (argv[0], &tail); - if (errno || (tail && *tail)) - log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]); - li->timestamp_set = 1; - - return 1; -} - -static int -literal_mode (const char *option, int argc, char *argv[], void *cookie) -{ - struct litinfo *li = cookie; - - if (argc == 0 - || ! (strcmp (argv[0], "b") == 0 - || strcmp (argv[0], "t") == 0 - || strcmp (argv[0], "u") == 0)) - log_fatal ("Usage: %s [btu]\n", option); - - li->mode = argv[0][0]; - - return 1; -} - -static int -literal_partial_body_length (const char *option, int argc, char *argv[], - void *cookie) -{ - struct litinfo *li = cookie; - char *tail; - int v; - int range[2] = {0, 1}; - - if (argc <= 1) - log_fatal ("Usage: %s [0|1]\n", option); - - errno = 0; - v = strtol (argv[0], &tail, 0); - if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1])) - log_fatal ("Invalid value passed to %s (%s). Expected %d-%d\n", - option, argv[0], range[0], range[1]); - - li->partial_body_length_encoding = v; - - return 1; -} - -static int -literal_name (const char *option, int argc, char *argv[], void *cookie) -{ - struct litinfo *li = cookie; - - if (argc <= 0) - log_fatal ("Usage: %s NAME\n", option); - - if (strlen (argv[0]) > 255) - log_fatal ("%s: name is too long (%zd > 255 characters).\n", - option, strlen (argv[0])); - - li->name = argv[0]; - - return 1; -} - -static struct option literal_options[] = { - { "--value", add_value, - "A string to store in the literal packet." }, - { "--file", add_value, - "A file to copy into the literal packet." }, - { "--timestamp", literal_timestamp, - "The literal packet's time stamp. This defaults to the current time." }, - { "--mode", literal_mode, - "The content's mode (normally 'b' (default), 't' or 'u')." }, - { "--partial-body-length", literal_partial_body_length, - "Force partial body length encoding." }, - { "--name", literal_name, - "The literal's name." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --literal --value foobar | " GPG_NAME " -d"} -}; - -static int -literal (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - gpg_error_t err; - int processed; - struct litinfo li; - PKT_plaintext *pt; - PACKET pkt; - struct data *data; - - memset (&li, 0, sizeof (li)); - - processed = process_options (option, - major_options, - literal_options, &li, - global_options, NULL, - argc, argv); - - if (! li.data.head) - log_fatal ("%s: no data provided (use --value or --file)", option); - - pt = xmalloc_clear (sizeof (*pt) + (li.name ? strlen (li.name) : 0)); - pt->new_ctb = 1; - - if (li.timestamp_set) - pt->timestamp = li.timestamp; - else - /* Default to the current time. */ - pt->timestamp = make_timestamp (); - - pt->mode = li.mode; - if (! pt->mode) - /* Default to binary. */ - pt->mode = 'b'; - - if (li.name) - { - strcpy (pt->name, li.name); - pt->namelen = strlen (pt->name); - } - - pkt.pkttype = PKT_PLAINTEXT; - pkt.pkt.plaintext = pt; - - if (! li.partial_body_length_encoding) - /* Compute the amount of data. */ - { - pt->len = 0; - for (data = li.data.head; data; data = data->next) - { - if (data->file) - { - iobuf_t in; - int overflow; - off_t off; - - in = iobuf_open (data->filename); - if (! in) - /* An error opening the file. We do error handling - below so just break here. */ - { - pt->len = 0; - break; - } - - off = iobuf_get_filelength (in, &overflow); - iobuf_close (in); - - if (overflow || off == 0) - /* Length is unknown or there was an error - (unfortunately, iobuf_get_filelength doesn't - distinguish between 0 length files and an error!). - Fall back to partial body mode. */ - { - pt->len = 0; - break; - } - - pt->len += off; - } - else - pt->len += strlen (data->data); - } - } - - err = build_packet (out, &pkt); - if (err) - log_fatal ("Serializing literal packet: %s\n", gpg_strerror (err)); - - /* Write out the data. */ - for (data = li.data.head; data; data = data->next) - { - if (data->file) - { - iobuf_t in; - errno = 0; - in = iobuf_open (data->filename); - if (! in) - log_fatal ("Opening '%s': %s\n", - data->filename, - errno ? strerror (errno): "unknown error"); - - iobuf_copy (out, in); - if (iobuf_error (in)) - log_fatal ("Reading from %s: %s\n", - data->filename, - gpg_strerror (iobuf_error (in))); - if (iobuf_error (out)) - log_fatal ("Writing literal data from %s: %s\n", - data->filename, - gpg_strerror (iobuf_error (out))); - - iobuf_close (in); - } - else - { - err = iobuf_write (out, data->data, strlen (data->data)); - if (err) - log_fatal ("Writing literal data: %s\n", gpg_strerror (err)); - } - } - - if (! pt->len) - { - /* Disable partial body length mode. */ - log_assert (pt->new_ctb == 1); - iobuf_set_partial_body_length_mode (out, 0); - } - - debug ("Wrote literal packet:\n"); - dump_component (&pkt); - - while (li.data.head) - { - data = li.data.head->next; - xfree (li.data.head); - li.data.head = data; - } - xfree (pt); - - return processed; -} - -static int -copy_file (const char *option, int argc, char *argv[], void *cookie) -{ - char **filep = cookie; - - if (argc == 0) - log_fatal ("Usage: %s FILENAME\n", option); - - *filep = argv[0]; - - return 1; -} - -static struct option copy_options[] = { - { "", copy_file, "Copy the specified file to stdout." }, - { NULL, NULL, - "Example:\n\n" - " $ gpgcompose --copy /etc/hostname\n\n" - "This is particularly useful when combined with gpgsplit." } -}; - -static int -copy (const char *option, int argc, char *argv[], void *cookie) -{ - iobuf_t out = cookie; - char *file = NULL; - iobuf_t in; - - int processed; - - processed = process_options (option, - major_options, - copy_options, &file, - global_options, NULL, - argc, argv); - if (! file) - log_fatal ("Usage: %s FILE\n", option); - - errno = 0; - in = iobuf_open (file); - if (! in) - log_fatal ("Error opening %s: %s.\n", - file, errno ? strerror (errno): "unknown error"); - - iobuf_copy (out, in); - if (iobuf_error (out)) - log_fatal ("Copying data to destination: %s\n", - gpg_strerror (iobuf_error (out))); - if (iobuf_error (in)) - log_fatal ("Reading data from %s: %s\n", - argv[0], gpg_strerror (iobuf_error (in))); - - iobuf_close (in); - - return processed; -} - -int -main (int argc, char *argv[]) -{ - const char *filename = "-"; - iobuf_t out; - int preprocessed = 1; - int processed; - ctrl_t ctrl; - - opt.ignore_time_conflict = 1; - /* Allow notations in the IETF space, for instance. */ - opt.expert = 1; - - global_ctrl = ctrl = xcalloc (1, sizeof *ctrl); - - keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG, - KEYDB_RESOURCE_FLAG_DEFAULT); - - if (argc == 1) - /* Nothing to do. */ - return 0; - - if (strcmp (argv[1], "--output") == 0 - || strcmp (argv[1], "-o") == 0) - { - filename = argv[2]; - log_info ("Writing to %s\n", filename); - preprocessed += 2; - } - - out = iobuf_create (filename, 0); - if (! out) - log_fatal ("Failed to open stdout for writing\n"); - - processed = process_options (NULL, NULL, - major_options, out, - global_options, NULL, - argc - preprocessed, &argv[preprocessed]); - if (processed != argc - preprocessed) - log_fatal ("Didn't process %d options.\n", argc - preprocessed - processed); - - iobuf_close (out); - - return 0; -} - -/* Stubs duplicated from gpg.c. */ - -int g10_errors_seen = 0; - -/* Note: This function is used by signal handlers!. */ -static void -emergency_cleanup (void) -{ - gcry_control (GCRYCTL_TERM_SECMEM ); -} - -void -g10_exit( int rc ) -{ - gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); - - emergency_cleanup (); - - rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; - exit (rc); -} - -void -keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, - strlist_t commands, int quiet, int seckey_check) -{ - (void) ctrl; - (void) username; - (void) locusr; - (void) commands; - (void) quiet; - (void) seckey_check; -} - -void -show_basic_key_info (ctrl_t ctrl, KBNODE keyblock, int made_from_sec) -{ - (void)ctrl; - (void)keyblock; - (void)made_from_sec; -} - -int -keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, - int rc, kbnode_t keyblock, kbnode_t node, - int *inv_sigs, int *no_key, int *oth_err, - int is_selfsig, int print_without_key, int extended) -{ - (void) ctrl; - (void) fp; - (void) rc; - (void) keyblock; - (void) node; - (void) inv_sigs; - (void) no_key; - (void) oth_err; - (void) is_selfsig; - (void) print_without_key; - (void) extended; - return 0; -}