diff --git a/common/compliance.c b/common/compliance.c
index 49aada144..b7d4d4970 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -1,590 +1,588 @@
/* compliance.c - Functions for compliance modi
* Copyright (C) 2017 g10 Code GmbH
* Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file 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 "openpgpdefs.h"
#include "logging.h"
#include "util.h"
#include "i18n.h"
#include "compliance.h"
static int initialized;
static int module;
/* Initializes the module. Must be called with the current
* GNUPG_MODULE_NAME. Checks a few invariants, and tunes the policies
* for the given module. */
void
gnupg_initialize_compliance (int gnupg_module_name)
{
log_assert (! initialized);
/* We accept both OpenPGP-style and gcrypt-style algorithm ids.
* Assert that they are compatible. */
log_assert ((int) GCRY_PK_RSA == (int) PUBKEY_ALGO_RSA);
log_assert ((int) GCRY_PK_RSA_E == (int) PUBKEY_ALGO_RSA_E);
log_assert ((int) GCRY_PK_RSA_S == (int) PUBKEY_ALGO_RSA_S);
log_assert ((int) GCRY_PK_ELG_E == (int) PUBKEY_ALGO_ELGAMAL_E);
log_assert ((int) GCRY_PK_DSA == (int) PUBKEY_ALGO_DSA);
log_assert ((int) GCRY_PK_ECC == (int) PUBKEY_ALGO_ECDH);
log_assert ((int) GCRY_PK_ELG == (int) PUBKEY_ALGO_ELGAMAL);
log_assert ((int) GCRY_CIPHER_NONE == (int) CIPHER_ALGO_NONE);
log_assert ((int) GCRY_CIPHER_IDEA == (int) CIPHER_ALGO_IDEA);
log_assert ((int) GCRY_CIPHER_3DES == (int) CIPHER_ALGO_3DES);
log_assert ((int) GCRY_CIPHER_CAST5 == (int) CIPHER_ALGO_CAST5);
log_assert ((int) GCRY_CIPHER_BLOWFISH == (int) CIPHER_ALGO_BLOWFISH);
log_assert ((int) GCRY_CIPHER_AES == (int) CIPHER_ALGO_AES);
log_assert ((int) GCRY_CIPHER_AES192 == (int) CIPHER_ALGO_AES192);
log_assert ((int) GCRY_CIPHER_AES256 == (int) CIPHER_ALGO_AES256);
log_assert ((int) GCRY_CIPHER_TWOFISH == (int) CIPHER_ALGO_TWOFISH);
log_assert ((int) GCRY_MD_MD5 == (int) DIGEST_ALGO_MD5);
log_assert ((int) GCRY_MD_SHA1 == (int) DIGEST_ALGO_SHA1);
log_assert ((int) GCRY_MD_RMD160 == (int) DIGEST_ALGO_RMD160);
log_assert ((int) GCRY_MD_SHA256 == (int) DIGEST_ALGO_SHA256);
log_assert ((int) GCRY_MD_SHA384 == (int) DIGEST_ALGO_SHA384);
log_assert ((int) GCRY_MD_SHA512 == (int) DIGEST_ALGO_SHA512);
log_assert ((int) GCRY_MD_SHA224 == (int) DIGEST_ALGO_SHA224);
switch (gnupg_module_name)
{
case GNUPG_MODULE_NAME_GPGSM:
case GNUPG_MODULE_NAME_GPG:
break;
default:
log_assert (!"no policies for this module");
}
module = gnupg_module_name;
initialized = 1;
}
/* Return true if ALGO with a key of KEYLENGTH is compliant to the
* given COMPLIANCE mode. If KEY is not NULL, various bits of
* information will be extracted from it. If CURVENAME is not NULL, it
* is assumed to be the already computed. ALGO may be either an
* OpenPGP-style pubkey_algo_t, or a gcrypt-style enum gcry_pk_algos,
* both are compatible from the point of view of this function. */
int
gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename)
{
enum { is_rsa, is_dsa, is_elg, is_ecc } algotype;
int result = 0;
if (! initialized)
return 0;
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S:
algotype = is_rsa;
break;
case PUBKEY_ALGO_DSA:
algotype = is_dsa;
break;
case PUBKEY_ALGO_ELGAMAL_E:
algotype = is_elg;
break;
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_EDDSA:
algotype = is_ecc;
break;
case PUBKEY_ALGO_ELGAMAL:
return 0; /* Signing with Elgamal is not at all supported. */
default: /* Unknown. */
return 0;
}
if (compliance == CO_DE_VS)
{
char *curve = NULL;
switch (algotype)
{
case is_elg:
result = 0;
break;
case is_rsa:
result = (keylength == 2048
|| keylength == 3072
|| keylength == 4096);
break;
case is_dsa:
if (key)
{
size_t P = gcry_mpi_get_nbits (key[0]);
size_t Q = gcry_mpi_get_nbits (key[1]);
result = (Q == 256
&& (P == 2048 || P == 3072));
}
break;
case is_ecc:
if (!curvename && key)
{
curve = openpgp_oid_to_str (key[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
}
result = (curvename
&& (algo == PUBKEY_ALGO_ECDH
|| algo == PUBKEY_ALGO_ECDSA)
&& (!strcmp (curvename, "brainpoolP256r1")
|| !strcmp (curvename, "brainpoolP384r1")
|| !strcmp (curvename, "brainpoolP512r1")));
break;
default:
result = 0;
}
xfree (curve);
}
else
{
result = 1; /* Assume compliance. */
}
return result;
}
/* Return true if ALGO with the given KEYLENGTH is allowed in the
* given COMPLIANCE mode. USE specifies for which use case the
* predicate is evaluated. This way policies can be strict in what
* they produce, and liberal in what they accept. */
int
gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
enum pk_use_case use, int algo, gcry_mpi_t key[],
unsigned int keylength, const char *curvename)
{
int result = 0;
if (! initialized)
return 1;
switch (compliance)
{
case CO_DE_VS:
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S:
switch (use)
{
case PK_USE_DECRYPTION:
case PK_USE_VERIFICATION:
result = 1;
break;
case PK_USE_ENCRYPTION:
case PK_USE_SIGNING:
result = (keylength == 2048
|| keylength == 3072
|| keylength == 4096);
break;
default:
log_assert (!"reached");
}
break;
case PUBKEY_ALGO_DSA:
if (use == PK_USE_VERIFICATION)
result = 1;
else if (use == PK_USE_SIGNING && key)
{
size_t P = gcry_mpi_get_nbits (key[0]);
size_t Q = gcry_mpi_get_nbits (key[1]);
result = (Q == 256 && (P == 2048 || P == 3072));
}
break;
case PUBKEY_ALGO_ELGAMAL:
case PUBKEY_ALGO_ELGAMAL_E:
result = (use == PK_USE_DECRYPTION);
break;
case PUBKEY_ALGO_ECDH:
if (use == PK_USE_DECRYPTION)
result = 1;
else if (use == PK_USE_ENCRYPTION)
{
char *curve = NULL;
if (!curvename && key)
{
curve = openpgp_oid_to_str (key[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
}
result = (curvename
&& (!strcmp (curvename, "brainpoolP256r1")
|| !strcmp (curvename, "brainpoolP384r1")
|| !strcmp (curvename, "brainpoolP512r1")));
xfree (curve);
}
break;
case PUBKEY_ALGO_ECDSA:
if (use == PK_USE_VERIFICATION)
result = 1;
else
{
char *curve = NULL;
if (! curvename && key)
{
curve = openpgp_oid_to_str (key[0]);
curvename = openpgp_oid_to_curve (curve, 0);
if (!curvename)
curvename = curve;
}
result = (use == PK_USE_SIGNING
&& curvename
&& (!strcmp (curvename, "brainpoolP256r1")
|| !strcmp (curvename, "brainpoolP384r1")
|| !strcmp (curvename, "brainpoolP512r1")));
xfree (curve);
}
break;
case PUBKEY_ALGO_EDDSA:
break;
default:
break;
}
break;
default:
/* The default policy is to allow all algorithms. */
result = 1;
}
return result;
}
/* Return true if (CIPHER, MODE) is compliant to the given COMPLIANCE mode. */
int
gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
cipher_algo_t cipher,
enum gcry_cipher_modes mode)
{
if (! initialized)
return 0;
switch (compliance)
{
case CO_DE_VS:
switch (cipher)
{
case CIPHER_ALGO_AES:
case CIPHER_ALGO_AES192:
case CIPHER_ALGO_AES256:
case CIPHER_ALGO_3DES:
switch (module)
{
case GNUPG_MODULE_NAME_GPG:
return mode == GCRY_CIPHER_MODE_CFB;
case GNUPG_MODULE_NAME_GPGSM:
return mode == GCRY_CIPHER_MODE_CBC;
}
log_assert (!"reached");
default:
return 0;
}
log_assert (!"reached");
default:
return 0;
}
log_assert (!"reached");
}
/* Return true if CIPHER is allowed in the given COMPLIANCE mode. If
* PRODUCER is true, the predicate is evaluated for the producer, if
* false for the consumer. This way policies can be strict in what
* they produce, and liberal in what they accept. */
int
gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance, int producer,
cipher_algo_t cipher,
enum gcry_cipher_modes mode)
{
if (! initialized)
return 1;
switch (compliance)
{
case CO_DE_VS:
switch (cipher)
{
case CIPHER_ALGO_AES:
case CIPHER_ALGO_AES192:
case CIPHER_ALGO_AES256:
case CIPHER_ALGO_3DES:
switch (module)
{
case GNUPG_MODULE_NAME_GPG:
return (mode == GCRY_CIPHER_MODE_NONE
|| mode == GCRY_CIPHER_MODE_CFB);
case GNUPG_MODULE_NAME_GPGSM:
return (mode == GCRY_CIPHER_MODE_NONE
|| mode == GCRY_CIPHER_MODE_CBC);
}
log_assert (!"reached");
case CIPHER_ALGO_BLOWFISH:
case CIPHER_ALGO_CAMELLIA128:
case CIPHER_ALGO_CAMELLIA192:
case CIPHER_ALGO_CAMELLIA256:
case CIPHER_ALGO_CAST5:
case CIPHER_ALGO_IDEA:
case CIPHER_ALGO_TWOFISH:
return (module == GNUPG_MODULE_NAME_GPG
&& (mode == GCRY_CIPHER_MODE_NONE
|| mode == GCRY_CIPHER_MODE_CFB)
&& ! producer);
default:
return 0;
}
log_assert (!"reached");
default:
/* The default policy is to allow all algorithms. */
return 1;
}
log_assert (!"reached");
}
/* Return true if DIGEST is compliant to the given COMPLIANCE mode. */
int
gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
digest_algo_t digest)
{
if (! initialized)
return 0;
switch (compliance)
{
case CO_DE_VS:
switch (digest)
{
case DIGEST_ALGO_SHA256:
case DIGEST_ALGO_SHA384:
case DIGEST_ALGO_SHA512:
return 1;
default:
return 0;
}
log_assert (!"reached");
default:
return 0;
}
log_assert (!"reached");
}
/* Return true if DIGEST is allowed in the given COMPLIANCE mode. If
* PRODUCER is true, the predicate is evaluated for the producer, if
* false for the consumer. This way policies can be strict in what
* they produce, and liberal in what they accept. */
int
gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
digest_algo_t digest)
{
if (! initialized)
return 1;
switch (compliance)
{
case CO_DE_VS:
switch (digest)
{
case DIGEST_ALGO_SHA256:
case DIGEST_ALGO_SHA384:
case DIGEST_ALGO_SHA512:
return 1;
case DIGEST_ALGO_SHA1:
case DIGEST_ALGO_SHA224:
case DIGEST_ALGO_RMD160:
return ! producer;
case DIGEST_ALGO_MD5:
return ! producer && module == GNUPG_MODULE_NAME_GPGSM;
default:
return 0;
}
log_assert (!"reached");
default:
/* The default policy is to allow all algorithms. */
return 1;
}
log_assert (!"reached");
}
/* Return True if the random number generator is compliant in
* COMPLIANCE mode. */
int
gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
{
static int result = -1;
if (result != -1)
; /* Use cached result. */
else if (compliance == CO_DE_VS)
{
/* In DE_VS mode under Windows we require that the JENT RNG
* is active. */
#ifdef HAVE_W32_SYSTEM
# if GCRYPT_VERSION_NUMBER >= 0x010800
char *buf;
char *fields[5];
buf = gcry_get_config (0, "rng-type");
if (buf
&& split_fields_colon (buf, fields, DIM (fields)) >= 5
&& atoi (fields[4]) > 0)
result = 1;
else
result = 0;
gcry_free (buf);
# else
result = 0; /* No JENT - can't be compliant. */
# endif
#else /*!HAVE_W32_SYSTEM*/
result = 1; /* Not Windows - RNG is good. */
#endif /*!HAVE_W32_SYSTEM*/
}
else
result = 1;
return result;
}
const char *
gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
{
switch (compliance)
{
case CO_GNUPG:
return "8";
case CO_RFC4880:
case CO_RFC2440:
- case CO_PGP6:
case CO_PGP7:
case CO_PGP8:
log_assert (!"no status code assigned for this compliance mode");
case CO_DE_VS:
return "23";
}
log_assert (!"invalid compliance mode");
}
/* Parse the value of --compliance. Returns the value corresponding
* to the given STRING according to OPTIONS of size LENGTH, or -1
* indicating that the lookup was unsuccessful, or the list of options
* was printed. If quiet is false, an additional hint to use 'help'
* is printed on unsuccessful lookups. */
int
gnupg_parse_compliance_option (const char *string,
struct gnupg_compliance_option options[],
size_t length,
int quiet)
{
size_t i;
if (! ascii_strcasecmp (string, "help"))
{
log_info (_("valid values for option '%s':\n"), "--compliance");
for (i = 0; i < length; i++)
log_info (" %s\n", options[i].keyword);
return -1;
}
for (i = 0; i < length; i++)
if (! ascii_strcasecmp (string, options[i].keyword))
return options[i].value;
log_error (_("invalid value for option '%s'\n"), "--compliance");
if (! quiet)
log_info (_("(use \"help\" to list choices)\n"));
return -1;
}
/* Return the command line option for the given COMPLIANCE mode. */
const char *
gnupg_compliance_option_string (enum gnupg_compliance_mode compliance)
{
switch (compliance)
{
case CO_GNUPG: return "--compliance=gnupg";
case CO_RFC4880: return "--compliance=openpgp";
case CO_RFC2440: return "--compliance=rfc2440";
- case CO_PGP6: return "--compliance=pgp6";
case CO_PGP7: return "--compliance=pgp7";
case CO_PGP8: return "--compliance=pgp8";
case CO_DE_VS: return "--compliance=de-vs";
}
log_assert (!"invalid compliance mode");
}
diff --git a/common/compliance.h b/common/compliance.h
index 2076e79cb..d36c7c131 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -1,88 +1,88 @@
/* compliance.h - Definitions for compliance modi
* Copyright (C) 2017 g10 Code GmbH
* Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file 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 GNUPG_COMMON_COMPLIANCE_H
#define GNUPG_COMMON_COMPLIANCE_H
#include
#include "openpgpdefs.h"
void gnupg_initialize_compliance (int gnupg_module_name);
enum gnupg_compliance_mode
{
CO_GNUPG, CO_RFC4880, CO_RFC2440,
- CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS
+ CO_PGP7, CO_PGP8, CO_DE_VS
};
enum pk_use_case
{
PK_USE_ENCRYPTION, PK_USE_DECRYPTION,
PK_USE_SIGNING, PK_USE_VERIFICATION,
};
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename);
int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
enum pk_use_case use, int algo, gcry_mpi_t key[],
unsigned int keylength, const char *curvename);
int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
cipher_algo_t cipher,
enum gcry_cipher_modes mode);
int gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance,
int producer,
cipher_algo_t cipher,
enum gcry_cipher_modes mode);
int gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
digest_algo_t digest);
int gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance,
int producer,
digest_algo_t digest);
int gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance);
const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode
compliance);
struct gnupg_compliance_option
{
const char *keyword;
int value;
};
int gnupg_parse_compliance_option (const char *string,
struct gnupg_compliance_option options[],
size_t length,
int quiet);
const char *gnupg_compliance_option_string (enum gnupg_compliance_mode
compliance);
#endif /*GNUPG_COMMON_COMPLIANCE_H*/
diff --git a/doc/gpg.texi b/doc/gpg.texi
index baad58657..9754c1703 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -1,4221 +1,4214 @@
@c Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
@c 2008, 2009, 2010 Free Software Foundation, Inc.
@c This is part of the GnuPG manual.
@c For copying conditions, see the file gnupg.texi.
@include defs.inc
@node Invoking GPG
@chapter Invoking GPG
@cindex GPG command options
@cindex command options
@cindex options, GPG command
@c Begin standard stuff
@ifclear gpgtwohack
@manpage gpg.1
@ifset manverb
.B gpg
\- OpenPGP encryption and signing tool
@end ifset
@mansect synopsis
@ifset manverb
.B gpg
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.I command
.RI [ args ]
@end ifset
@end ifclear
@c End standard stuff
@c Begin gpg2 hack stuff
@ifset gpgtwohack
@manpage gpg2.1
@ifset manverb
.B gpg2
\- OpenPGP encryption and signing tool
@end ifset
@mansect synopsis
@ifset manverb
.B gpg2
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.I command
.RI [ args ]
@end ifset
@end ifset
@c End gpg2 hack stuff
@mansect description
@command{@gpgname} is the OpenPGP part of the GNU Privacy Guard (GnuPG). It
is a tool to provide digital encryption and signing services using the
OpenPGP standard. @command{@gpgname} features complete key management and
all the bells and whistles you would expect from a full OpenPGP
implementation.
There are two main versions of GnuPG: GnuPG 1.x and GnuPG 2.x. GnuPG
2.x supports modern encryption algorithms and thus should be preferred
over GnuPG 1.x. You only need to use GnuPG 1.x if your platform
doesn't support GnuPG 2.x, or you need support for some features that
GnuPG 2.x has deprecated, e.g., decrypting data created with PGP-2
keys.
@ifclear gpgtwohack
If you are looking for version 1 of GnuPG, you may find that version
installed under the name @command{gpg1}.
@end ifclear
@ifset gpgtwohack
In contrast to the standalone command @command{gpg} from GnuPG 1.x,
the 2.x version is commonly installed under the name
@command{@gpgname}.
@end ifset
@manpause
@xref{Option Index}, for an index to @command{@gpgname}'s commands and options.
@mancont
@menu
* GPG Commands:: List of all commands.
* GPG Options:: List of all options.
* GPG Configuration:: Configuration files.
* GPG Examples:: Some usage examples.
Developer information:
* Unattended Usage of GPG:: Using @command{gpg} from other programs.
@end menu
@c * GPG Protocol:: The protocol the server mode uses.
@c *******************************************
@c *************** ****************
@c *************** COMMANDS ****************
@c *************** ****************
@c *******************************************
@mansect commands
@node GPG Commands
@section Commands
Commands are not distinguished from options except for the fact that
only one command is allowed. Generally speaking, irrelevant options
are silently ignored, and may not be checked for correctness.
@command{@gpgname} may be run with no commands. In this case it will
perform a reasonable action depending on the type of file it is given
as input (an encrypted message is decrypted, a signature is verified,
a file containing keys is listed, etc.).
@menu
* General GPG Commands:: Commands not specific to the functionality.
* Operational GPG Commands:: Commands to select the type of operation.
* OpenPGP Key Management:: How to manage your keys.
@end menu
@c *******************************************
@c ********** GENERAL COMMANDS *************
@c *******************************************
@node General GPG Commands
@subsection Commands not specific to the function
@table @gnupgtabopt
@item --version
@opindex version
Print the program version and licensing information. Note that you
cannot abbreviate this command.
@item --help
@itemx -h
@opindex help
Print a usage message summarizing the most useful command-line options.
Note that you cannot arbitrarily abbreviate this command
(though you can use its short form @option{-h}).
@item --warranty
@opindex warranty
Print warranty information.
@item --dump-options
@opindex dump-options
Print a list of all available options and commands. Note that you cannot
abbreviate this command.
@end table
@c *******************************************
@c ******** OPERATIONAL COMMANDS ***********
@c *******************************************
@node Operational GPG Commands
@subsection Commands to select the type of operation
@table @gnupgtabopt
@item --sign
@itemx -s
@opindex sign
Sign a message. This command may be combined with @option{--encrypt}
(to sign and encrypt a message), @option{--symmetric} (to sign and
symmetrically encrypt a message), or both @option{--encrypt} and
@option{--symmetric} (to sign and encrypt a message that can be
decrypted using a secret key or a passphrase). The signing key is
chosen by default or can be set explicitly using the
@option{--local-user} and @option{--default-key} options.
@item --clear-sign
@opindex clear-sign
@itemx --clearsign
@opindex clearsign
Make a cleartext signature. The content in a cleartext signature is
readable without any special software. OpenPGP software is only needed
to verify the signature. cleartext signatures may modify end-of-line
whitespace for platform independence and are not intended to be
reversible. The signing key is chosen by default or can be set
explicitly using the @option{--local-user} and @option{--default-key}
options.
@item --detach-sign
@itemx -b
@opindex detach-sign
Make a detached signature.
@item --encrypt
@itemx -e
@opindex encrypt
Encrypt data to one or more public keys. This command may be combined
with @option{--sign} (to sign and encrypt a message),
@option{--symmetric} (to encrypt a message that can decrypted using a
secret key or a passphrase), or @option{--sign} and
@option{--symmetric} together (for a signed message that can be
decrypted using a secret key or a passphrase). @option{--recipient}
and related options specify which public keys to use for encryption.
@item --symmetric
@itemx -c
@opindex symmetric
Encrypt with a symmetric cipher using a passphrase. The default
symmetric cipher used is @value{GPGSYMENCALGO}, but may be chosen with the
@option{--cipher-algo} option. This command may be combined with
@option{--sign} (for a signed and symmetrically encrypted message),
@option{--encrypt} (for a message that may be decrypted via a secret key
or a passphrase), or @option{--sign} and @option{--encrypt} together
(for a signed message that may be decrypted via a secret key or a
passphrase). @command{@gpgname} caches the passphrase used for
symmetric encryption so that a decrypt operation may not require that
the user needs to enter the passphrase. The option
@option{--no-symkey-cache} can be used to disable this feature.
@item --store
@opindex store
Store only (make a simple literal data packet).
@item --decrypt
@itemx -d
@opindex decrypt
Decrypt the file given on the command line (or STDIN if no file
is specified) and write it to STDOUT (or the file specified with
@option{--output}). If the decrypted file is signed, the signature is also
verified. This command differs from the default operation, as it never
writes to the filename which is included in the file and it rejects
files that don't begin with an encrypted message.
@item --verify
@opindex verify
Assume that the first argument is a signed file and verify it without
generating any output. With no arguments, the signature packet is
read from STDIN. If only one argument is given, the specified file is
expected to include a complete signature.
With more than one argument, the first argument should specify a file
with a detached signature and the remaining files should contain the
signed data. To read the signed data from STDIN, use @samp{-} as the
second filename. For security reasons, a detached signature will not
read the signed material from STDIN if not explicitly specified.
Note: If the option @option{--batch} is not used, @command{@gpgname}
may assume that a single argument is a file with a detached signature,
and it will try to find a matching data file by stripping certain
suffixes. Using this historical feature to verify a detached
signature is strongly discouraged; you should always specify the data file
explicitly.
Note: When verifying a cleartext signature, @command{@gpgname} verifies
only what makes up the cleartext signed data and not any extra data
outside of the cleartext signature or the header lines directly following
the dash marker line. The option @code{--output} may be used to write
out the actual signed data, but there are other pitfalls with this
format as well. It is suggested to avoid cleartext signatures in
favor of detached signatures.
Note: Sometimes the use of the @command{gpgv} tool is easier than
using the full-fledged @command{gpg} with this option. @command{gpgv}
is designed to compare signed data against a list of trusted keys and
returns with success only for a good signature. It has its own manual
page.
@item --multifile
@opindex multifile
This modifies certain other commands to accept multiple files for
processing on the command line or read from STDIN with each filename on
a separate line. This allows for many files to be processed at
once. @option{--multifile} may currently be used along with
@option{--verify}, @option{--encrypt}, and @option{--decrypt}. Note that
@option{--multifile --verify} may not be used with detached signatures.
@item --verify-files
@opindex verify-files
Identical to @option{--multifile --verify}.
@item --encrypt-files
@opindex encrypt-files
Identical to @option{--multifile --encrypt}.
@item --decrypt-files
@opindex decrypt-files
Identical to @option{--multifile --decrypt}.
@item --list-keys
@itemx -k
@itemx --list-public-keys
@opindex list-keys
List the specified keys. If no keys are specified, then all keys from
the configured public keyrings are listed.
Never use the output of this command in scripts or other programs.
The output is intended only for humans and its format is likely to
change. The @option{--with-colons} option emits the output in a
stable, machine-parseable format, which is intended for use by scripts
and other programs.
@item --list-secret-keys
@itemx -K
@opindex list-secret-keys
List the specified secret keys. If no keys are specified, then all
known secret keys are listed. A @code{#} after the initial tags
@code{sec} or @code{ssb} means that the secret key or subkey is
currently not usable. We also say that this key has been taken
offline (for example, a primary key can be taken offline by exporting
the key using the command @option{--export-secret-subkeys}). A
@code{>} after these tags indicate that the key is stored on a
smartcard. See also @option{--list-keys}.
@item --check-signatures
@opindex check-signatures
@itemx --check-sigs
@opindex check-sigs
Same as @option{--list-keys}, but the key signatures are verified and
listed too. Note that for performance reasons the revocation status
of a signing key is not shown. This command has the same effect as
using @option{--list-keys} with @option{--with-sig-check}.
The status of the verification is indicated by a flag directly
following the "sig" tag (and thus before the flags described below. A
"!" indicates that the signature has been successfully verified, a "-"
denotes a bad signature and a "%" is used if an error occurred while
checking the signature (e.g. a non supported algorithm). Signatures
where the public key is not availabale are not listed; to see their
keyids the command @option{--list-sigs} can be used.
For each signature listed, there are several flags in between the
signature status flag and keyid. These flags give additional
information about each key signature. From left to right, they are
the numbers 1-3 for certificate check level (see
@option{--ask-cert-level}), "L" for a local or non-exportable
signature (see @option{--lsign-key}), "R" for a nonRevocable signature
(see the @option{--edit-key} command "nrsign"), "P" for a signature
that contains a policy URL (see @option{--cert-policy-url}), "N" for a
signature that contains a notation (see @option{--cert-notation}), "X"
for an eXpired signature (see @option{--ask-cert-expire}), and the
numbers 1-9 or "T" for 10 and above to indicate trust signature levels
(see the @option{--edit-key} command "tsign").
@item --locate-keys
@opindex locate-keys
Locate the keys given as arguments. This command basically uses the
same algorithm as used when locating keys for encryption or signing and
may thus be used to see what keys @command{@gpgname} might use. In
particular external methods as defined by @option{--auto-key-locate} may
be used to locate a key. Only public keys are listed.
@item --fingerprint
@opindex fingerprint
List all keys (or the specified ones) along with their
fingerprints. This is the same output as @option{--list-keys} but with
the additional output of a line with the fingerprint. May also be
combined with @option{--check-signatures}. If this
command is given twice, the fingerprints of all secondary keys are
listed too. This command also forces pretty printing of fingerprints
if the keyid format has been set to "none".
@item --list-packets
@opindex list-packets
List only the sequence of packets. This command is only useful for
debugging. When used with option @option{--verbose} the actual MPI
values are dumped and not only their lengths. Note that the output of
this command may change with new releases.
@item --edit-card
@opindex edit-card
@itemx --card-edit
@opindex card-edit
Present a menu to work with a smartcard. The subcommand "help" provides
an overview on available commands. For a detailed description, please
see the Card HOWTO at
https://gnupg.org/documentation/howtos.html#GnuPG-cardHOWTO .
@item --card-status
@opindex card-status
Show the content of the smart card.
@item --change-pin
@opindex change-pin
Present a menu to allow changing the PIN of a smartcard. This
functionality is also available as the subcommand "passwd" with the
@option{--edit-card} command.
@item --delete-keys @var{name}
@opindex delete-keys
Remove key from the public keyring. In batch mode either @option{--yes} is
required or the key must be specified by fingerprint. This is a
safeguard against accidental deletion of multiple keys.
@item --delete-secret-keys @var{name}
@opindex delete-secret-keys
Remove key from the secret keyring. In batch mode the key must be
specified by fingerprint. The option @option{--yes} can be used to
advice gpg-agent not to request a confirmation. This extra
pre-caution is done because @command{@gpgname} can't be sure that the
secret key (as controlled by gpg-agent) is only used for the given
OpenPGP public key.
@item --delete-secret-and-public-key @var{name}
@opindex delete-secret-and-public-key
Same as @option{--delete-key}, but if a secret key exists, it will be
removed first. In batch mode the key must be specified by fingerprint.
The option @option{--yes} can be used to advice gpg-agent not to
request a confirmation.
@item --export
@opindex export
Either export all keys from all keyrings (default keyrings and those
registered via option @option{--keyring}), or if at least one name is given,
those of the given name. The exported keys are written to STDOUT or to the
file given with option @option{--output}. Use together with
@option{--armor} to mail those keys.
@item --send-keys @var{keyIDs}
@opindex send-keys
Similar to @option{--export} but sends the keys to a keyserver.
Fingerprints may be used instead of key IDs. Option
@option{--keyserver} must be used to give the name of this
keyserver. Don't send your complete keyring to a keyserver --- select
only those keys which are new or changed by you. If no @var{keyIDs}
are given, @command{@gpgname} does nothing.
@item --export-secret-keys
@itemx --export-secret-subkeys
@opindex export-secret-keys
@opindex export-secret-subkeys
Same as @option{--export}, but exports the secret keys instead. The
exported keys are written to STDOUT or to the file given with option
@option{--output}. This command is often used along with the option
@option{--armor} to allow for easy printing of the key for paper backup;
however the external tool @command{paperkey} does a better job of
creating backups on paper. Note that exporting a secret key can be a
security risk if the exported keys are sent over an insecure channel.
The second form of the command has the special property to render the
secret part of the primary key useless; this is a GNU extension to
OpenPGP and other implementations can not be expected to successfully
import such a key. Its intended use is in generating a full key with
an additional signing subkey on a dedicated machine. This command
then exports the key without the primary key to the main machine.
GnuPG may ask you to enter the passphrase for the key. This is
required, because the internal protection method of the secret key is
different from the one specified by the OpenPGP protocol.
@item --export-ssh-key
@opindex export-ssh-key
This command is used to export a key in the OpenSSH public key format.
It requires the specification of one key by the usual means and
exports the latest valid subkey which has an authentication capability
to STDOUT or to the file given with option @option{--output}. That
output can directly be added to ssh's @file{authorized_key} file.
By specifying the key to export using a key ID or a fingerprint
suffixed with an exclamation mark (!), a specific subkey or the
primary key can be exported. This does not even require that the key
has the authentication capability flag set.
@item --import
@itemx --fast-import
@opindex import
Import/merge keys. This adds the given keys to the
keyring. The fast version is currently just a synonym.
There are a few other options which control how this command works.
Most notable here is the @option{--import-options merge-only} option
which does not insert new keys but does only the merging of new
signatures, user-IDs and subkeys.
@item --receive-keys @var{keyIDs}
@opindex receive-keys
@itemx --recv-keys @var{keyIDs}
@opindex recv-keys
Import the keys with the given @var{keyIDs} from a keyserver. Option
@option{--keyserver} must be used to give the name of this keyserver.
@item --refresh-keys
@opindex refresh-keys
Request updates from a keyserver for keys that already exist on the
local keyring. This is useful for updating a key with the latest
signatures, user IDs, etc. Calling this with no arguments will refresh
the entire keyring. Option @option{--keyserver} must be used to give the
name of the keyserver for all keys that do not have preferred keyservers
set (see @option{--keyserver-options honor-keyserver-url}).
@item --search-keys @var{names}
@opindex search-keys
Search the keyserver for the given @var{names}. Multiple names given here will
be joined together to create the search string for the keyserver.
Option @option{--keyserver} must be used to give the name of this
keyserver. Keyservers that support different search methods allow using
the syntax specified in "How to specify a user ID" below. Note that
different keyserver types support different search methods. Currently
only LDAP supports them all.
@item --fetch-keys @var{URIs}
@opindex fetch-keys
Retrieve keys located at the specified @var{URIs}. Note that different
installations of GnuPG may support different protocols (HTTP, FTP,
LDAP, etc.). When using HTTPS the system provided root certificates
are used by this command.
@item --update-trustdb
@opindex update-trustdb
Do trust database maintenance. This command iterates over all keys and
builds the Web of Trust. This is an interactive command because it may
have to ask for the "ownertrust" values for keys. The user has to give
an estimation of how far she trusts the owner of the displayed key to
correctly certify (sign) other keys. GnuPG only asks for the ownertrust
value if it has not yet been assigned to a key. Using the
@option{--edit-key} menu, the assigned value can be changed at any time.
@item --check-trustdb
@opindex check-trustdb
Do trust database maintenance without user interaction. From time to
time the trust database must be updated so that expired keys or
signatures and the resulting changes in the Web of Trust can be
tracked. Normally, GnuPG will calculate when this is required and do it
automatically unless @option{--no-auto-check-trustdb} is set. This
command can be used to force a trust database check at any time. The
processing is identical to that of @option{--update-trustdb} but it
skips keys with a not yet defined "ownertrust".
For use with cron jobs, this command can be used together with
@option{--batch} in which case the trust database check is done only if
a check is needed. To force a run even in batch mode add the option
@option{--yes}.
@anchor{option --export-ownertrust}
@item --export-ownertrust
@opindex export-ownertrust
Send the ownertrust values to STDOUT. This is useful for backup purposes
as these values are the only ones which can't be re-created from a
corrupted trustdb. Example:
@c man:.RS
@example
@gpgname{} --export-ownertrust > otrust.txt
@end example
@c man:.RE
@item --import-ownertrust
@opindex import-ownertrust
Update the trustdb with the ownertrust values stored in @code{files} (or
STDIN if not given); existing values will be overwritten. In case of a
severely damaged trustdb and if you have a recent backup of the
ownertrust values (e.g. in the file @file{otrust.txt}), you may re-create
the trustdb using these commands:
@c man:.RS
@example
cd ~/.gnupg
rm trustdb.gpg
@gpgname{} --import-ownertrust < otrust.txt
@end example
@c man:.RE
@item --rebuild-keydb-caches
@opindex rebuild-keydb-caches
When updating from version 1.0.6 to 1.0.7 this command should be used
to create signature caches in the keyring. It might be handy in other
situations too.
@item --print-md @var{algo}
@itemx --print-mds
@opindex print-md
Print message digest of algorithm @var{algo} for all given files or STDIN.
With the second form (or a deprecated "*" for @var{algo}) digests for all
available algorithms are printed.
@item --gen-random @var{0|1|2} @var{count}
@opindex gen-random
Emit @var{count} random bytes of the given quality level 0, 1 or 2. If
@var{count} is not given or zero, an endless sequence of random bytes
will be emitted. If used with @option{--armor} the output will be
base64 encoded. PLEASE, don't use this command unless you know what
you are doing; it may remove precious entropy from the system!
@item --gen-prime @var{mode} @var{bits}
@opindex gen-prime
Use the source, Luke :-). The output format is subject to change
with ant release.
@item --enarmor
@itemx --dearmor
@opindex enarmor
@opindex dearmor
Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor.
This is a GnuPG extension to OpenPGP and in general not very useful.
@item --tofu-policy @{auto|good|unknown|bad|ask@} @var{keys}
@opindex tofu-policy
Set the TOFU policy for all the bindings associated with the specified
@var{keys}. For more information about the meaning of the policies,
@pxref{trust-model-tofu}. The @var{keys} may be specified either by their
fingerprint (preferred) or their keyid.
@c @item --server
@c @opindex server
@c Run gpg in server mode. This feature is not yet ready for use and
@c thus not documented.
@end table
@c *******************************************
@c ******* KEY MANGEMENT COMMANDS **********
@c *******************************************
@node OpenPGP Key Management
@subsection How to manage your keys
This section explains the main commands for key management.
@table @gnupgtabopt
@item --quick-generate-key @var{user-id} [@var{algo} [@var{usage} [@var{expire}]]]
@itemx --quick-gen-key
@opindex quick-generate-key
@opindex quick-gen-key
This is a simple command to generate a standard key with one user id.
In contrast to @option{--generate-key} the key is generated directly
without the need to answer a bunch of prompts. Unless the option
@option{--yes} is given, the key creation will be canceled if the
given user id already exists in the keyring.
If invoked directly on the console without any special options an
answer to a ``Continue?'' style confirmation prompt is required. In
case the user id already exists in the keyring a second prompt to
force the creation of the key will show up.
If @var{algo} or @var{usage} are given, only the primary key is
created and no prompts are shown. To specify an expiration date but
still create a primary and subkey use ``default'' or
``future-default'' for @var{algo} and ``default'' for @var{usage}.
For a description of these optional arguments see the command
@code{--quick-add-key}. The @var{usage} accepts also the value
``cert'' which can be used to create a certification only primary key;
the default is to a create certification and signing key.
The @var{expire} argument can be used to specify an expiration date
for the key. Several formats are supported; commonly the ISO formats
``YYYY-MM-DD'' or ``YYYYMMDDThhmmss'' are used. To make the key
expire in N seconds, N days, N weeks, N months, or N years use
``seconds=N'', ``Nd'', ``Nw'', ``Nm'', or ``Ny'' respectively. Not
specifying a value, or using ``-'' results in a key expiring in a
reasonable default interval. The values ``never'', ``none'' can be
used for no expiration date.
If this command is used with @option{--batch},
@option{--pinentry-mode} has been set to @code{loopback}, and one of
the passphrase options (@option{--passphrase},
@option{--passphrase-fd}, or @option{passphrase-file}) is used, the
supplied passphrase is used for the new key and the agent does not ask
for it. To create a key without any protection @code{--passphrase ''}
may be used.
@item --quick-set-expire @var{fpr} @var{expire} [*|@var{subfprs}]
@opindex quick-set-expire
With two arguments given, directly set the expiration time of the
primary key identified by @var{fpr} to @var{expire}. To remove the
expiration time @code{0} can be used. With three arguments and the
third given as an asterisk, the expiration time of all non-revoked and
not yet expired subkeys are set to @var{expire}. With more than two
arguments and a list of fingerprints given for @var{subfprs}, all
non-revoked subkeys matching these fingerprints are set to
@var{expire}.
@item --quick-add-key @var{fpr} [@var{algo} [@var{usage} [@var{expire}]]]
@opindex quick-add-key
Directly add a subkey to the key identified by the fingerprint
@var{fpr}. Without the optional arguments an encryption subkey is
added. If any of the arguments are given a more specific subkey is
added.
@var{algo} may be any of the supported algorithms or curve names
given in the format as used by key listings. To use the default
algorithm the string ``default'' or ``-'' can be used. Supported
algorithms are ``rsa'', ``dsa'', ``elg'', ``ed25519'', ``cv25519'',
and other ECC curves. For example the string ``rsa'' adds an RSA key
with the default key length; a string ``rsa4096'' requests that the
key length is 4096 bits. The string ``future-default'' is an alias
for the algorithm which will likely be used as default algorithm in
future versions of gpg.
Depending on the given @var{algo} the subkey may either be an
encryption subkey or a signing subkey. If an algorithm is capable of
signing and encryption and such a subkey is desired, a @var{usage}
string must be given. This string is either ``default'' or ``-'' to
keep the default or a comma delimited list (or space delimited list)
of keywords: ``sign'' for a signing subkey, ``auth'' for an
authentication subkey, and ``encr'' for an encryption subkey
(``encrypt'' can be used as alias for ``encr''). The valid
combinations depend on the algorithm.
The @var{expire} argument can be used to specify an expiration date
for the key. Several formats are supported; commonly the ISO formats
``YYYY-MM-DD'' or ``YYYYMMDDThhmmss'' are used. To make the key
expire in N seconds, N days, N weeks, N months, or N years use
``seconds=N'', ``Nd'', ``Nw'', ``Nm'', or ``Ny'' respectively. Not
specifying a value, or using ``-'' results in a key expiring in a
reasonable default interval. The values ``never'', ``none'' can be
used for no expiration date.
@item --generate-key
@opindex generate-key
@itemx --gen-key
@opindex gen-key
Generate a new key pair using the current default parameters. This is
the standard command to create a new key. In addition to the key a
revocation certificate is created and stored in the
@file{openpgp-revocs.d} directory below the GnuPG home directory.
@item --full-generate-key
@opindex full-generate-key
@itemx --full-gen-key
@opindex full-gen-key
Generate a new key pair with dialogs for all options. This is an
extended version of @option{--generate-key}.
There is also a feature which allows you to create keys in batch
mode. See the manual section ``Unattended key generation'' on how
to use this.
@item --generate-revocation @var{name}
@opindex generate-revocation
@itemx --gen-revoke @var{name}
@opindex gen-revoke
Generate a revocation certificate for the complete key. To only revoke
a subkey or a key signature, use the @option{--edit} command.
This command merely creates the revocation certificate so that it can
be used to revoke the key if that is ever needed. To actually revoke
a key the created revocation certificate needs to be merged with the
key to revoke. This is done by importing the revocation certificate
using the @option{--import} command. Then the revoked key needs to be
published, which is best done by sending the key to a keyserver
(command @option{--send-key}) and by exporting (@option{--export}) it
to a file which is then send to frequent communication partners.
@item --generate-designated-revocation @var{name}
@opindex generate-designated-revocation
@itemx --desig-revoke @var{name}
@opindex desig-revoke
Generate a designated revocation certificate for a key. This allows a
user (with the permission of the keyholder) to revoke someone else's
key.
@item --edit-key
@opindex edit-key
Present a menu which enables you to do most of the key management
related tasks. It expects the specification of a key on the command
line.
@c ******** Begin Edit-key Options **********
@table @asis
@item uid @var{n}
@opindex keyedit:uid
Toggle selection of user ID or photographic user ID with index @var{n}.
Use @code{*} to select all and @code{0} to deselect all.
@item key @var{n}
@opindex keyedit:key
Toggle selection of subkey with index @var{n} or key ID @var{n}.
Use @code{*} to select all and @code{0} to deselect all.
@item sign
@opindex keyedit:sign
Make a signature on key of user @code{name}. If the key is not yet
signed by the default user (or the users given with @option{-u}), the program
displays the information of the key again, together with its
fingerprint and asks whether it should be signed. This question is
repeated for all users specified with
@option{-u}.
@item lsign
@opindex keyedit:lsign
Same as "sign" but the signature is marked as non-exportable and will
therefore never be used by others. This may be used to make keys
valid only in the local environment.
@item nrsign
@opindex keyedit:nrsign
Same as "sign" but the signature is marked as non-revocable and can
therefore never be revoked.
@item tsign
@opindex keyedit:tsign
Make a trust signature. This is a signature that combines the notions
of certification (like a regular signature), and trust (like the
"trust" command). It is generally only useful in distinct communities
or groups. For more information please read the sections
``Trust Signature'' and ``Regular Expression'' in RFC-4880.
@end table
@c man:.RS
Note that "l" (for local / non-exportable), "nr" (for non-revocable,
and "t" (for trust) may be freely mixed and prefixed to "sign" to
create a signature of any type desired.
@c man:.RE
If the option @option{--only-sign-text-ids} is specified, then any
non-text based user ids (e.g., photo IDs) will not be selected for
signing.
@table @asis
@item delsig
@opindex keyedit:delsig
Delete a signature. Note that it is not possible to retract a signature,
once it has been send to the public (i.e. to a keyserver). In that case
you better use @code{revsig}.
@item revsig
@opindex keyedit:revsig
Revoke a signature. For every signature which has been generated by
one of the secret keys, GnuPG asks whether a revocation certificate
should be generated.
@item check
@opindex keyedit:check
Check the signatures on all selected user IDs. With the extra
option @code{selfsig} only self-signatures are shown.
@item adduid
@opindex keyedit:adduid
Create an additional user ID.
@item addphoto
@opindex keyedit:addphoto
Create a photographic user ID. This will prompt for a JPEG file that
will be embedded into the user ID. Note that a very large JPEG will make
for a very large key. Also note that some programs will display your
JPEG unchanged (GnuPG), and some programs will scale it to fit in a
dialog box (PGP).
@item showphoto
@opindex keyedit:showphoto
Display the selected photographic user ID.
@item deluid
@opindex keyedit:deluid
Delete a user ID or photographic user ID. Note that it is not
possible to retract a user id, once it has been send to the public
(i.e. to a keyserver). In that case you better use @code{revuid}.
@item revuid
@opindex keyedit:revuid
Revoke a user ID or photographic user ID.
@item primary
@opindex keyedit:primary
Flag the current user id as the primary one, removes the primary user
id flag from all other user ids and sets the timestamp of all affected
self-signatures one second ahead. Note that setting a photo user ID
as primary makes it primary over other photo user IDs, and setting a
regular user ID as primary makes it primary over other regular user
IDs.
@item keyserver
@opindex keyedit:keyserver
Set a preferred keyserver for the specified user ID(s). This allows
other users to know where you prefer they get your key from. See
@option{--keyserver-options honor-keyserver-url} for more on how this
works. Setting a value of "none" removes an existing preferred
keyserver.
@item notation
@opindex keyedit:notation
Set a name=value notation for the specified user ID(s). See
@option{--cert-notation} for more on how this works. Setting a value of
"none" removes all notations, setting a notation prefixed with a minus
sign (-) removes that notation, and setting a notation name (without the
=value) prefixed with a minus sign removes all notations with that name.
@item pref
@opindex keyedit:pref
List preferences from the selected user ID. This shows the actual
preferences, without including any implied preferences.
@item showpref
@opindex keyedit:showpref
More verbose preferences listing for the selected user ID. This shows
the preferences in effect by including the implied preferences of 3DES
(cipher), SHA-1 (digest), and Uncompressed (compression) if they are
not already included in the preference list. In addition, the
preferred keyserver and signature notations (if any) are shown.
@item setpref @var{string}
@opindex keyedit:setpref
Set the list of user ID preferences to @var{string} for all (or just
the selected) user IDs. Calling setpref with no arguments sets the
preference list to the default (either built-in or set via
@option{--default-preference-list}), and calling setpref with "none"
as the argument sets an empty preference list. Use @command{@gpgname
--version} to get a list of available algorithms. Note that while you
can change the preferences on an attribute user ID (aka "photo ID"),
GnuPG does not select keys via attribute user IDs so these preferences
will not be used by GnuPG.
When setting preferences, you should list the algorithms in the order
which you'd like to see them used by someone else when encrypting a
message to your key. If you don't include 3DES, it will be
automatically added at the end. Note that there are many factors that
go into choosing an algorithm (for example, your key may not be the
only recipient), and so the remote OpenPGP application being used to
send to you may or may not follow your exact chosen order for a given
message. It will, however, only choose an algorithm that is present
on the preference list of every recipient key. See also the
INTEROPERABILITY WITH OTHER OPENPGP PROGRAMS section below.
@item addkey
@opindex keyedit:addkey
Add a subkey to this key.
@item addcardkey
@opindex keyedit:addcardkey
Generate a subkey on a card and add it to this key.
@item keytocard
@opindex keyedit:keytocard
Transfer the selected secret subkey (or the primary key if no subkey
has been selected) to a smartcard. The secret key in the keyring will
be replaced by a stub if the key could be stored successfully on the
card and you use the save command later. Only certain key types may be
transferred to the card. A sub menu allows you to select on what card
to store the key. Note that it is not possible to get that key back
from the card - if the card gets broken your secret key will be lost
unless you have a backup somewhere.
@item bkuptocard @var{file}
@opindex keyedit:bkuptocard
Restore the given @var{file} to a card. This command may be used to restore a
backup key (as generated during card initialization) to a new card. In
almost all cases this will be the encryption key. You should use this
command only with the corresponding public key and make sure that the
file given as argument is indeed the backup to restore. You should then
select 2 to restore as encryption key. You will first be asked to enter
the passphrase of the backup key and then for the Admin PIN of the card.
@item delkey
@opindex keyedit:delkey
Remove a subkey (secondary key). Note that it is not possible to retract
a subkey, once it has been send to the public (i.e. to a keyserver). In
that case you better use @code{revkey}. Also note that this only
deletes the public part of a key.
@item revkey
@opindex keyedit:revkey
Revoke a subkey.
@item expire
@opindex keyedit:expire
Change the key or subkey expiration time. If a subkey is selected, the
expiration time of this subkey will be changed. With no selection, the
key expiration of the primary key is changed.
@item trust
@opindex keyedit:trust
Change the owner trust value for the key. This updates the trust-db
immediately and no save is required.
@item disable
@itemx enable
@opindex keyedit:disable
@opindex keyedit:enable
Disable or enable an entire key. A disabled key can not normally be
used for encryption.
@item addrevoker
@opindex keyedit:addrevoker
Add a designated revoker to the key. This takes one optional argument:
"sensitive". If a designated revoker is marked as sensitive, it will
not be exported by default (see export-options).
@item passwd
@opindex keyedit:passwd
Change the passphrase of the secret key.
@item toggle
@opindex keyedit:toggle
This is dummy command which exists only for backward compatibility.
@item clean
@opindex keyedit:clean
Compact (by removing all signatures except the selfsig) any user ID
that is no longer usable (e.g. revoked, or expired). Then, remove any
signatures that are not usable by the trust calculations.
Specifically, this removes any signature that does not validate, any
signature that is superseded by a later signature, revoked signatures,
and signatures issued by keys that are not present on the keyring.
@item minimize
@opindex keyedit:minimize
Make the key as small as possible. This removes all signatures from
each user ID except for the most recent self-signature.
@item change-usage
@opindex keyedit:change-usage
Change the usage flags (capabilities) of the primary key or of
subkeys. These usage flags (e.g. Certify, Sign, Authenticate,
Encrypt) are set during key creation. Sometimes it is useful to
have the opportunity to change them (for example to add
Authenticate) after they have been created. Please take care when
doing this; the allowed usage flags depend on the key algorithm.
@item cross-certify
@opindex keyedit:cross-certify
Add cross-certification signatures to signing subkeys that may not
currently have them. Cross-certification signatures protect against a
subtle attack against signing subkeys. See
@option{--require-cross-certification}. All new keys generated have
this signature by default, so this command is only useful to bring
older keys up to date.
@item save
@opindex keyedit:save
Save all changes to the keyrings and quit.
@item quit
@opindex keyedit:quit
Quit the program without updating the
keyrings.
@end table
@c man:.RS
The listing shows you the key with its secondary keys and all user
IDs. The primary user ID is indicated by a dot, and selected keys or
user IDs are indicated by an asterisk. The trust
value is displayed with the primary key: "trust" is the assigned owner
trust and "validity" is the calculated validity of the key. Validity
values are also displayed for all user IDs.
For possible values of trust, @pxref{trust-values}.
@c man:.RE
@c ******** End Edit-key Options **********
@item --sign-key @var{name}
@opindex sign-key
Signs a public key with your secret key. This is a shortcut version of
the subcommand "sign" from @option{--edit}.
@item --lsign-key @var{name}
@opindex lsign-key
Signs a public key with your secret key but marks it as
non-exportable. This is a shortcut version of the subcommand "lsign"
from @option{--edit-key}.
@item --quick-sign-key @var{fpr} [@var{names}]
@itemx --quick-lsign-key @var{fpr} [@var{names}]
@opindex quick-sign-key
@opindex quick-lsign-key
Directly sign a key from the passphrase without any further user
interaction. The @var{fpr} must be the verified primary fingerprint
of a key in the local keyring. If no @var{names} are given, all
useful user ids are signed; with given [@var{names}] only useful user
ids matching one of theses names are signed. By default, or if a name
is prefixed with a '*', a case insensitive substring match is used.
If a name is prefixed with a '=' a case sensitive exact match is done.
The command @option{--quick-lsign-key} marks the signatures as
non-exportable. If such a non-exportable signature already exists the
@option{--quick-sign-key} turns it into a exportable signature.
This command uses reasonable defaults and thus does not provide the
full flexibility of the "sign" subcommand from @option{--edit-key}.
Its intended use is to help unattended key signing by utilizing a list
of verified fingerprints.
@item --quick-add-uid @var{user-id} @var{new-user-id}
@opindex quick-add-uid
This command adds a new user id to an existing key. In contrast to
the interactive sub-command @code{adduid} of @option{--edit-key} the
@var{new-user-id} is added verbatim with only leading and trailing
white space removed, it is expected to be UTF-8 encoded, and no checks
on its form are applied.
@item --quick-revoke-uid @var{user-id} @var{user-id-to-revoke}
@opindex quick-revoke-uid
This command revokes a user ID on an existing key. It cannot be used
to revoke the last user ID on key (some non-revoked user ID must
remain), with revocation reason ``User ID is no longer valid''. If
you want to specify a different revocation reason, or to supply
supplementary revocation text, you should use the interactive
sub-command @code{revuid} of @option{--edit-key}.
@item --quick-set-primary-uid @var{user-id} @var{primary-user-id}
@opindex quick-set-primary-uid
This command sets or updates the primary user ID flag on an existing
key. @var{user-id} specifies the key and @var{primary-user-id} the
user ID which shall be flagged as the primary user ID. The primary
user ID flag is removed from all other user ids and the timestamp of
all affected self-signatures is set one second ahead.
@item --change-passphrase @var{user-id}
@opindex change-passphrase
@itemx --passwd @var{user-id}
@opindex passwd
Change the passphrase of the secret key belonging to the certificate
specified as @var{user-id}. This is a shortcut for the sub-command
@code{passwd} of the edit key menu. When using together with the
option @option{--dry-run} this will not actually change the passphrase
but check that the current passphrase is correct.
@end table
@c *******************************************
@c *************** ****************
@c *************** OPTIONS ****************
@c *************** ****************
@c *******************************************
@mansect options
@node GPG Options
@section Option Summary
@command{@gpgname} features a bunch of options to control the exact
behaviour and to change the default configuration.
@menu
* GPG Configuration Options:: How to change the configuration.
* GPG Key related Options:: Key related options.
* GPG Input and Output:: Input and Output.
* OpenPGP Options:: OpenPGP protocol specific options.
* Compliance Options:: Compliance options.
* GPG Esoteric Options:: Doing things one usually doesn't want to do.
* Deprecated Options:: Deprecated options.
@end menu
Long options can be put in an options file (default
"~/.gnupg/gpg.conf"). Short option names will not work - for example,
"armor" is a valid option for the options file, while "a" is not. Do not
write the 2 dashes, but simply the name of the option and any required
arguments. Lines with a hash ('#') as the first non-white-space
character are ignored. Commands may be put in this file too, but that is
not generally useful as the command will execute automatically with
every execution of gpg.
Please remember that option parsing stops as soon as a non-option is
encountered, you can explicitly stop parsing by using the special option
@option{--}.
@c *******************************************
@c ******** CONFIGURATION OPTIONS **********
@c *******************************************
@node GPG Configuration Options
@subsection How to change the configuration
These options are used to change the configuration and are usually found
in the option file.
@table @gnupgtabopt
@item --default-key @var{name}
@opindex default-key
Use @var{name} as the default key to sign with. If this option is not
used, the default key is the first key found in the secret keyring.
Note that @option{-u} or @option{--local-user} overrides this option.
This option may be given multiple times. In this case, the last key
for which a secret key is available is used. If there is no secret
key available for any of the specified values, GnuPG will not emit an
error message but continue as if this option wasn't given.
@item --default-recipient @var{name}
@opindex default-recipient
Use @var{name} as default recipient if option @option{--recipient} is
not used and don't ask if this is a valid one. @var{name} must be
non-empty.
@item --default-recipient-self
@opindex default-recipient-self
Use the default key as default recipient if option @option{--recipient} is not
used and don't ask if this is a valid one. The default key is the first
one from the secret keyring or the one set with @option{--default-key}.
@item --no-default-recipient
@opindex no-default-recipient
Reset @option{--default-recipient} and @option{--default-recipient-self}.
@item -v, --verbose
@opindex verbose
Give more information during processing. If used
twice, the input data is listed in detail.
@item --no-verbose
@opindex no-verbose
Reset verbose level to 0.
@item -q, --quiet
@opindex quiet
Try to be as quiet as possible.
@item --batch
@itemx --no-batch
@opindex batch
@opindex no-batch
Use batch mode. Never ask, do not allow interactive commands.
@option{--no-batch} disables this option. Note that even with a
filename given on the command line, gpg might still need to read from
STDIN (in particular if gpg figures that the input is a
detached signature and no data file has been specified). Thus if you
do not want to feed data via STDIN, you should connect STDIN to
g@file{/dev/null}.
It is highly recommended to use this option along with the options
@option{--status-fd} and @option{--with-colons} for any unattended use of
@command{gpg}.
@item --no-tty
@opindex no-tty
Make sure that the TTY (terminal) is never used for any output.
This option is needed in some cases because GnuPG sometimes prints
warnings to the TTY even if @option{--batch} is used.
@item --yes
@opindex yes
Assume "yes" on most questions.
@item --no
@opindex no
Assume "no" on most questions.
@item --list-options @var{parameters}
@opindex list-options
This is a space or comma delimited string that gives options used when
listing keys and signatures (that is, @option{--list-keys},
@option{--check-signatures}, @option{--list-public-keys},
@option{--list-secret-keys}, and the @option{--edit-key} functions).
Options can be prepended with a @option{no-} (after the two dashes) to
give the opposite meaning. The options are:
@table @asis
@item show-photos
@opindex list-options:show-photos
Causes @option{--list-keys}, @option{--check-signatures},
@option{--list-public-keys}, and @option{--list-secret-keys} to
display any photo IDs attached to the key. Defaults to no. See also
@option{--photo-viewer}. Does not work with @option{--with-colons}:
see @option{--attribute-fd} for the appropriate way to get photo data
for scripts and other frontends.
@item show-usage
@opindex list-options:show-usage
Show usage information for keys and subkeys in the standard key
listing. This is a list of letters indicating the allowed usage for a
key (@code{E}=encryption, @code{S}=signing, @code{C}=certification,
@code{A}=authentication). Defaults to yes.
@item show-policy-urls
@opindex list-options:show-policy-urls
Show policy URLs in the @option{--check-signatures}
listings. Defaults to no.
@item show-notations
@itemx show-std-notations
@itemx show-user-notations
@opindex list-options:show-notations
@opindex list-options:show-std-notations
@opindex list-options:show-user-notations
Show all, IETF standard, or user-defined signature notations in the
@option{--check-signatures} listings. Defaults to no.
@item show-keyserver-urls
@opindex list-options:show-keyserver-urls
Show any preferred keyserver URL in the
@option{--check-signatures} listings. Defaults to no.
@item show-uid-validity
@opindex list-options:show-uid-validity
Display the calculated validity of user IDs during key listings.
Defaults to yes.
@item show-unusable-uids
@opindex list-options:show-unusable-uids
Show revoked and expired user IDs in key listings. Defaults to no.
@item show-unusable-subkeys
@opindex list-options:show-unusable-subkeys
Show revoked and expired subkeys in key listings. Defaults to no.
@item show-keyring
@opindex list-options:show-keyring
Display the keyring name at the head of key listings to show which
keyring a given key resides on. Defaults to no.
@item show-sig-expire
@opindex list-options:show-sig-expire
Show signature expiration dates (if any) during
@option{--check-signatures} listings. Defaults to no.
@item show-sig-subpackets
@opindex list-options:show-sig-subpackets
Include signature subpackets in the key listing. This option can take an
optional argument list of the subpackets to list. If no argument is
passed, list all subpackets. Defaults to no. This option is only
meaningful when using @option{--with-colons} along with
@option{--check-signatures}.
@end table
@item --verify-options @var{parameters}
@opindex verify-options
This is a space or comma delimited string that gives options used when
verifying signatures. Options can be prepended with a `no-' to give
the opposite meaning. The options are:
@table @asis
@item show-photos
@opindex verify-options:show-photos
Display any photo IDs present on the key that issued the signature.
Defaults to no. See also @option{--photo-viewer}.
@item show-policy-urls
@opindex verify-options:show-policy-urls
Show policy URLs in the signature being verified. Defaults to yes.
@item show-notations
@itemx show-std-notations
@itemx show-user-notations
@opindex verify-options:show-notations
@opindex verify-options:show-std-notations
@opindex verify-options:show-user-notations
Show all, IETF standard, or user-defined signature notations in the
signature being verified. Defaults to IETF standard.
@item show-keyserver-urls
@opindex verify-options:show-keyserver-urls
Show any preferred keyserver URL in the signature being verified.
Defaults to yes.
@item show-uid-validity
@opindex verify-options:show-uid-validity
Display the calculated validity of the user IDs on the key that issued
the signature. Defaults to yes.
@item show-unusable-uids
@opindex verify-options:show-unusable-uids
Show revoked and expired user IDs during signature verification.
Defaults to no.
@item show-primary-uid-only
@opindex verify-options:show-primary-uid-only
Show only the primary user ID during signature verification. That is
all the AKA lines as well as photo Ids are not shown with the signature
verification status.
@item pka-lookups
@opindex verify-options:pka-lookups
Enable PKA lookups to verify sender addresses. Note that PKA is based
on DNS, and so enabling this option may disclose information on when
and what signatures are verified or to whom data is encrypted. This
is similar to the "web bug" described for the @option{--auto-key-retrieve}
option.
@item pka-trust-increase
@opindex verify-options:pka-trust-increase
Raise the trust in a signature to full if the signature passes PKA
validation. This option is only meaningful if pka-lookups is set.
@end table
@item --enable-large-rsa
@itemx --disable-large-rsa
@opindex enable-large-rsa
@opindex disable-large-rsa
With --generate-key and --batch, enable the creation of RSA secret keys as
large as 8192 bit. Note: 8192 bit is more than is generally
recommended. These large keys don't significantly improve security,
but they are more expensive to use, and their signatures and
certifications are larger. This option is only available if the
binary was build with large-secmem support.
@item --enable-dsa2
@itemx --disable-dsa2
@opindex enable-dsa2
@opindex disable-dsa2
Enable hash truncation for all DSA keys even for old DSA Keys up to
1024 bit. This is also the default with @option{--openpgp}. Note
that older versions of GnuPG also required this flag to allow the
generation of DSA larger than 1024 bit.
@item --photo-viewer @var{string}
@opindex photo-viewer
This is the command line that should be run to view a photo ID. "%i"
will be expanded to a filename containing the photo. "%I" does the
same, except the file will not be deleted once the viewer exits.
Other flags are "%k" for the key ID, "%K" for the long key ID, "%f"
for the key fingerprint, "%t" for the extension of the image type
(e.g. "jpg"), "%T" for the MIME type of the image (e.g. "image/jpeg"),
"%v" for the single-character calculated validity of the image being
viewed (e.g. "f"), "%V" for the calculated validity as a string (e.g.
"full"), "%U" for a base32 encoded hash of the user ID,
and "%%" for an actual percent sign. If neither %i or %I are present,
then the photo will be supplied to the viewer on standard input.
The default viewer is "xloadimage -fork -quiet -title 'KeyID 0x%k'
STDIN". Note that if your image viewer program is not secure, then
executing it from GnuPG does not make it secure.
@item --exec-path @var{string}
@opindex exec-path
@efindex PATH
Sets a list of directories to search for photo viewers and keyserver
helpers. If not provided, keyserver helpers use the compiled-in
default directory, and photo viewers use the @code{PATH} environment
variable.
Note, that on W32 system this value is ignored when searching for
keyserver helpers.
@item --keyring @var{file}
@opindex keyring
Add @var{file} to the current list of keyrings. If @var{file} begins
with a tilde and a slash, these are replaced by the $HOME directory. If
the filename does not contain a slash, it is assumed to be in the GnuPG
home directory ("~/.gnupg" if @option{--homedir} or $GNUPGHOME is not
used).
Note that this adds a keyring to the current list. If the intent is to
use the specified keyring alone, use @option{--keyring} along with
@option{--no-default-keyring}.
If the option @option{--no-keyring} has been used no keyrings will
be used at all.
@item --secret-keyring @var{file}
@opindex secret-keyring
This is an obsolete option and ignored. All secret keys are stored in
the @file{private-keys-v1.d} directory below the GnuPG home directory.
@item --primary-keyring @var{file}
@opindex primary-keyring
Designate @var{file} as the primary public keyring. This means that
newly imported keys (via @option{--import} or keyserver
@option{--recv-from}) will go to this keyring.
@item --trustdb-name @var{file}
@opindex trustdb-name
Use @var{file} instead of the default trustdb. If @var{file} begins
with a tilde and a slash, these are replaced by the $HOME directory. If
the filename does not contain a slash, it is assumed to be in the GnuPG
home directory (@file{~/.gnupg} if @option{--homedir} or $GNUPGHOME is
not used).
@include opt-homedir.texi
@item --display-charset @var{name}
@opindex display-charset
Set the name of the native character set. This is used to convert
some informational strings like user IDs to the proper UTF-8 encoding.
Note that this has nothing to do with the character set of data to be
encrypted or signed; GnuPG does not recode user-supplied data. If
this option is not used, the default character set is determined from
the current locale. A verbosity level of 3 shows the chosen set.
Valid values for @var{name} are:
@table @asis
@item iso-8859-1
@opindex display-charset:iso-8859-1
This is the Latin 1 set.
@item iso-8859-2
@opindex display-charset:iso-8859-2
The Latin 2 set.
@item iso-8859-15
@opindex display-charset:iso-8859-15
This is currently an alias for
the Latin 1 set.
@item koi8-r
@opindex display-charset:koi8-r
The usual Russian set (RFC-1489).
@item utf-8
@opindex display-charset:utf-8
Bypass all translations and assume
that the OS uses native UTF-8 encoding.
@end table
@item --utf8-strings
@itemx --no-utf8-strings
@opindex utf8-strings
Assume that command line arguments are given as UTF-8 strings. The
default (@option{--no-utf8-strings}) is to assume that arguments are
encoded in the character set as specified by
@option{--display-charset}. These options affect all following
arguments. Both options may be used multiple times.
@anchor{gpg-option --options}
@item --options @var{file}
@opindex options
Read options from @var{file} and do not try to read them from the
default options file in the homedir (see @option{--homedir}). This
option is ignored if used in an options file.
@item --no-options
@opindex no-options
Shortcut for @option{--options /dev/null}. This option is detected
before an attempt to open an option file. Using this option will also
prevent the creation of a @file{~/.gnupg} homedir.
@item -z @var{n}
@itemx --compress-level @var{n}
@itemx --bzip2-compress-level @var{n}
@opindex compress-level
@opindex bzip2-compress-level
Set compression level to @var{n} for the ZIP and ZLIB compression
algorithms. The default is to use the default compression level of zlib
(normally 6). @option{--bzip2-compress-level} sets the compression level
for the BZIP2 compression algorithm (defaulting to 6 as well). This is a
different option from @option{--compress-level} since BZIP2 uses a
significant amount of memory for each additional compression level.
@option{-z} sets both. A value of 0 for @var{n} disables compression.
@item --bzip2-decompress-lowmem
@opindex bzip2-decompress-lowmem
Use a different decompression method for BZIP2 compressed files. This
alternate method uses a bit more than half the memory, but also runs
at half the speed. This is useful under extreme low memory
circumstances when the file was originally compressed at a high
@option{--bzip2-compress-level}.
@item --mangle-dos-filenames
@itemx --no-mangle-dos-filenames
@opindex mangle-dos-filenames
@opindex no-mangle-dos-filenames
Older version of Windows cannot handle filenames with more than one
dot. @option{--mangle-dos-filenames} causes GnuPG to replace (rather
than add to) the extension of an output filename to avoid this
problem. This option is off by default and has no effect on non-Windows
platforms.
@item --ask-cert-level
@itemx --no-ask-cert-level
@opindex ask-cert-level
When making a key signature, prompt for a certification level. If this
option is not specified, the certification level used is set via
@option{--default-cert-level}. See @option{--default-cert-level} for
information on the specific levels and how they are
used. @option{--no-ask-cert-level} disables this option. This option
defaults to no.
@item --default-cert-level @var{n}
@opindex default-cert-level
The default to use for the check level when signing a key.
0 means you make no particular claim as to how carefully you verified
the key.
1 means you believe the key is owned by the person who claims to own
it but you could not, or did not verify the key at all. This is
useful for a "persona" verification, where you sign the key of a
pseudonymous user.
2 means you did casual verification of the key. For example, this
could mean that you verified the key fingerprint and checked the
user ID on the key against a photo ID.
3 means you did extensive verification of the key. For example, this
could mean that you verified the key fingerprint with the owner of the
key in person, and that you checked, by means of a hard to forge
document with a photo ID (such as a passport) that the name of the key
owner matches the name in the user ID on the key, and finally that you
verified (by exchange of email) that the email address on the key
belongs to the key owner.
Note that the examples given above for levels 2 and 3 are just that:
examples. In the end, it is up to you to decide just what "casual"
and "extensive" mean to you.
This option defaults to 0 (no particular claim).
@item --min-cert-level
@opindex min-cert-level
When building the trust database, treat any signatures with a
certification level below this as invalid. Defaults to 2, which
disregards level 1 signatures. Note that level 0 "no particular
claim" signatures are always accepted.
@item --trusted-key @var{long key ID}
@opindex trusted-key
Assume that the specified key (which must be given
as a full 8 byte key ID) is as trustworthy as one of
your own secret keys. This option is useful if you
don't want to keep your secret keys (or one of them)
online but still want to be able to check the validity of a given
recipient's or signator's key.
@item --trust-model @{pgp|classic|tofu|tofu+pgp|direct|always|auto@}
@opindex trust-model
Set what trust model GnuPG should follow. The models are:
@table @asis
@item pgp
@opindex trust-model:pgp
This is the Web of Trust combined with trust signatures as used in PGP
5.x and later. This is the default trust model when creating a new
trust database.
@item classic
@opindex trust-model:classic
This is the standard Web of Trust as introduced by PGP 2.
@item tofu
@opindex trust-model:tofu
@anchor{trust-model-tofu}
TOFU stands for Trust On First Use. In this trust model, the first
time a key is seen, it is memorized. If later another key with a
user id with the same email address is seen, both keys are marked as
suspect. In that case, the next time either is used, a warning is
displayed describing the conflict, why it might have occurred
(either the user generated a new key and failed to cross sign the
old and new keys, the key is forgery, or a man-in-the-middle attack
is being attempted), and the user is prompted to manually confirm
the validity of the key in question.
Because a potential attacker is able to control the email address
and thereby circumvent the conflict detection algorithm by using an
email address that is similar in appearance to a trusted email
address, whenever a message is verified, statistics about the number
of messages signed with the key are shown. In this way, a user can
easily identify attacks using fake keys for regular correspondents.
When compared with the Web of Trust, TOFU offers significantly
weaker security guarantees. In particular, TOFU only helps ensure
consistency (that is, that the binding between a key and email
address doesn't change). A major advantage of TOFU is that it
requires little maintenance to use correctly. To use the web of
trust properly, you need to actively sign keys and mark users as
trusted introducers. This is a time-consuming process and anecdotal
evidence suggests that even security-conscious users rarely take the
time to do this thoroughly and instead rely on an ad-hoc TOFU
process.
In the TOFU model, policies are associated with bindings between
keys and email addresses (which are extracted from user ids and
normalized). There are five policies, which can be set manually
using the @option{--tofu-policy} option. The default policy can be
set using the @option{--tofu-default-policy} option.
The TOFU policies are: @code{auto}, @code{good}, @code{unknown},
@code{bad} and @code{ask}. The @code{auto} policy is used by
default (unless overridden by @option{--tofu-default-policy}) and
marks a binding as marginally trusted. The @code{good},
@code{unknown} and @code{bad} policies mark a binding as fully
trusted, as having unknown trust or as having trust never,
respectively. The @code{unknown} policy is useful for just using
TOFU to detect conflicts, but to never assign positive trust to a
binding. The final policy, @code{ask} prompts the user to indicate
the binding's trust. If batch mode is enabled (or input is
inappropriate in the context), then the user is not prompted and the
@code{undefined} trust level is returned.
@item tofu+pgp
@opindex trust-model:tofu+pgp
This trust model combines TOFU with the Web of Trust. This is done
by computing the trust level for each model and then taking the
maximum trust level where the trust levels are ordered as follows:
@code{unknown < undefined < marginal < fully < ultimate < expired <
never}.
By setting @option{--tofu-default-policy=unknown}, this model can be
used to implement the web of trust with TOFU's conflict detection
algorithm, but without its assignment of positive trust values,
which some security-conscious users don't like.
@item direct
@opindex trust-model:direct
Key validity is set directly by the user and not calculated via the
Web of Trust. This model is solely based on the key and does
not distinguish user IDs. Note that when changing to another trust
model the trust values assigned to a key are transformed into
ownertrust values, which also indicate how you trust the owner of
the key to sign other keys.
@item always
@opindex trust-model:always
Skip key validation and assume that used keys are always fully
valid. You generally won't use this unless you are using some
external validation scheme. This option also suppresses the
"[uncertain]" tag printed with signature checks when there is no
evidence that the user ID is bound to the key. Note that this
trust model still does not allow the use of expired, revoked, or
disabled keys.
@item auto
@opindex trust-model:auto
Select the trust model depending on whatever the internal trust
database says. This is the default model if such a database already
exists.
@end table
@item --auto-key-locate @var{mechanisms}
@itemx --no-auto-key-locate
@opindex auto-key-locate
GnuPG can automatically locate and retrieve keys as needed using this
option. This happens when encrypting to an email address (in the
"user@@example.com" form), and there are no "user@@example.com" keys
on the local keyring. This option takes any number of the mechanisms
listed below, in the order they are to be tried. Instead of listing
the mechanisms as comma delimited arguments, the option may also be
given several times to add more mechanism. The option
@option{--no-auto-key-locate} or the mechanism "clear" resets the
list. The default is "local,wkd".
@table @asis
@item cert
Locate a key using DNS CERT, as specified in RFC-4398.
@item pka
Locate a key using DNS PKA.
@item dane
Locate a key using DANE, as specified
in draft-ietf-dane-openpgpkey-05.txt.
@item wkd
Locate a key using the Web Key Directory protocol.
@item ldap
Using DNS Service Discovery, check the domain in question for any LDAP
keyservers to use. If this fails, attempt to locate the key using the
PGP Universal method of checking @samp{ldap://keys.(thedomain)}.
@item keyserver
Locate a key using whatever keyserver is defined using the
@option{--keyserver} option.
@item keyserver-URL
In addition, a keyserver URL as used in the @option{--keyserver} option
may be used here to query that particular keyserver.
@item local
Locate the key using the local keyrings. This mechanism allows the user to
select the order a local key lookup is done. Thus using
@samp{--auto-key-locate local} is identical to
@option{--no-auto-key-locate}.
@item nodefault
This flag disables the standard local key lookup, done before any of the
mechanisms defined by the @option{--auto-key-locate} are tried. The
position of this mechanism in the list does not matter. It is not
required if @code{local} is also used.
@item clear
Clear all defined mechanisms. This is useful to override
mechanisms given in a config file.
@end table
@item --auto-key-retrieve
@itemx --no-auto-key-retrieve
@opindex auto-key-retrieve
@opindex no-auto-key-retrieve
These options enable or disable the automatic retrieving of keys from
a keyserver when verifying signatures made by keys that are not on the
local keyring. The default is @option{--no-auto-key-retrieve}.
If the method "wkd" is included in the list of methods given to
@option{auto-key-locate}, the signer's user ID is part of the
signature, and the option @option{--disable-signer-uid} is not used,
the "wkd" method may also be used to retrieve a key.
Note that this option makes a "web bug" like behavior possible.
Keyserver or Web Key Directory operators can see which keys you
request, so by sending you a message signed by a brand new key (which
you naturally will not have on your local keyring), the operator can
tell both your IP address and the time when you verified the
signature.
@item --keyid-format @{none|short|0xshort|long|0xlong@}
@opindex keyid-format
Select how to display key IDs. "none" does not show the key ID at all
but shows the fingerprint in a separate line. "short" is the
traditional 8-character key ID. "long" is the more accurate (but less
convenient) 16-character key ID. Add an "0x" to either to include an
"0x" at the beginning of the key ID, as in 0x99242560. Note that this
option is ignored if the option @option{--with-colons} is used.
@item --keyserver @var{name}
@opindex keyserver
This option is deprecated - please use the @option{--keyserver} in
@file{dirmngr.conf} instead.
Use @var{name} as your keyserver. This is the server that
@option{--receive-keys}, @option{--send-keys}, and @option{--search-keys}
will communicate with to receive keys from, send keys to, and search for
keys on. The format of the @var{name} is a URI:
`scheme:[//]keyservername[:port]' The scheme is the type of keyserver:
"hkp" for the HTTP (or compatible) keyservers, "ldap" for the LDAP
keyservers, or "mailto" for the Graff email keyserver. Note that your
particular installation of GnuPG may have other keyserver types
available as well. Keyserver schemes are case-insensitive. After the
keyserver name, optional keyserver configuration options may be
provided. These are the same as the global @option{--keyserver-options}
from below, but apply only to this particular keyserver.
Most keyservers synchronize with each other, so there is generally no
need to send keys to more than one server. The keyserver
@code{hkp://keys.gnupg.net} uses round robin DNS to give a different
keyserver each time you use it.
@item --keyserver-options @{@var{name}=@var{value}@}
@opindex keyserver-options
This is a space or comma delimited string that gives options for the
keyserver. Options can be prefixed with a `no-' to give the opposite
meaning. Valid import-options or export-options may be used here as
well to apply to importing (@option{--recv-key}) or exporting
(@option{--send-key}) a key from a keyserver. While not all options
are available for all keyserver types, some common options are:
@table @asis
@item include-revoked
When searching for a key with @option{--search-keys}, include keys that
are marked on the keyserver as revoked. Note that not all keyservers
differentiate between revoked and unrevoked keys, and for such
keyservers this option is meaningless. Note also that most keyservers do
not have cryptographic verification of key revocations, and so turning
this option off may result in skipping keys that are incorrectly marked
as revoked.
@item include-disabled
When searching for a key with @option{--search-keys}, include keys that
are marked on the keyserver as disabled. Note that this option is not
used with HKP keyservers.
@item auto-key-retrieve
This is an obsolete alias for the option @option{auto-key-retrieve}.
Please do not use it; it will be removed in future versions..
@item honor-keyserver-url
When using @option{--refresh-keys}, if the key in question has a preferred
keyserver URL, then use that preferred keyserver to refresh the key
from. In addition, if auto-key-retrieve is set, and the signature
being verified has a preferred keyserver URL, then use that preferred
keyserver to fetch the key from. Note that this option introduces a
"web bug": The creator of the key can see when the keys is
refreshed. Thus this option is not enabled by default.
@item honor-pka-record
If @option{--auto-key-retrieve} is used, and the signature being
verified has a PKA record, then use the PKA information to fetch
the key. Defaults to "yes".
@item include-subkeys
When receiving a key, include subkeys as potential targets. Note that
this option is not used with HKP keyservers, as they do not support
retrieving keys by subkey id.
@item timeout
Tell the keyserver helper program how long (in seconds) to try and
perform a keyserver action before giving up. Note that performing
multiple actions at the same time uses this timeout value per action.
For example, when retrieving multiple keys via @option{--receive-keys}, the
timeout applies separately to each key retrieval, and not to the
@option{--receive-keys} command as a whole. Defaults to 30 seconds.
@item http-proxy=@var{value}
This option is deprecated.
Set the proxy to use for HTTP and HKP keyservers.
This overrides any proxy defined in @file{dirmngr.conf}.
@item verbose
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@item debug
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@item check-cert
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@item ca-cert-file
This option has no more function since GnuPG 2.1. Use the
@code{dirmngr} configuration options instead.
@end table
@item --completes-needed @var{n}
@opindex compliant-needed
Number of completely trusted users to introduce a new
key signer (defaults to 1).
@item --marginals-needed @var{n}
@opindex marginals-needed
Number of marginally trusted users to introduce a new
key signer (defaults to 3)
@item --tofu-default-policy @{auto|good|unknown|bad|ask@}
@opindex tofu-default-policy
The default TOFU policy (defaults to @code{auto}). For more
information about the meaning of this option, @pxref{trust-model-tofu}.
@item --max-cert-depth @var{n}
@opindex max-cert-depth
Maximum depth of a certification chain (default is 5).
@item --no-sig-cache
@opindex no-sig-cache
Do not cache the verification status of key signatures.
Caching gives a much better performance in key listings. However, if
you suspect that your public keyring is not safe against write
modifications, you can use this option to disable the caching. It
probably does not make sense to disable it because all kind of damage
can be done if someone else has write access to your public keyring.
@item --auto-check-trustdb
@itemx --no-auto-check-trustdb
@opindex auto-check-trustdb
If GnuPG feels that its information about the Web of Trust has to be
updated, it automatically runs the @option{--check-trustdb} command
internally. This may be a time consuming
process. @option{--no-auto-check-trustdb} disables this option.
@item --use-agent
@itemx --no-use-agent
@opindex use-agent
This is dummy option. @command{@gpgname} always requires the agent.
@item --gpg-agent-info
@opindex gpg-agent-info
This is dummy option. It has no effect when used with @command{@gpgname}.
@item --agent-program @var{file}
@opindex agent-program
Specify an agent program to be used for secret key operations. The
default value is determined by running @command{gpgconf} with the
option @option{--list-dirs}. Note that the pipe symbol (@code{|}) is
used for a regression test suite hack and may thus not be used in the
file name.
@item --dirmngr-program @var{file}
@opindex dirmngr-program
Specify a dirmngr program to be used for keyserver access. The
default value is @file{@value{BINDIR}/dirmngr}.
@item --disable-dirmngr
Entirely disable the use of the Dirmngr.
@item --no-autostart
@opindex no-autostart
Do not start the gpg-agent or the dirmngr if it has not yet been
started and its service is required. This option is mostly useful on
machines where the connection to gpg-agent has been redirected to
another machines. If dirmngr is required on the remote machine, it
may be started manually using @command{gpgconf --launch dirmngr}.
@item --lock-once
@opindex lock-once
Lock the databases the first time a lock is requested
and do not release the lock until the process
terminates.
@item --lock-multiple
@opindex lock-multiple
Release the locks every time a lock is no longer
needed. Use this to override a previous @option{--lock-once}
from a config file.
@item --lock-never
@opindex lock-never
Disable locking entirely. This option should be used only in very
special environments, where it can be assured that only one process
is accessing those files. A bootable floppy with a stand-alone
encryption system will probably use this. Improper usage of this
option may lead to data and key corruption.
@item --exit-on-status-write-error
@opindex exit-on-status-write-error
This option will cause write errors on the status FD to immediately
terminate the process. That should in fact be the default but it never
worked this way and thus we need an option to enable this, so that the
change won't break applications which close their end of a status fd
connected pipe too early. Using this option along with
@option{--enable-progress-filter} may be used to cleanly cancel long
running gpg operations.
@item --limit-card-insert-tries @var{n}
@opindex limit-card-insert-tries
With @var{n} greater than 0 the number of prompts asking to insert a
smartcard gets limited to N-1. Thus with a value of 1 gpg won't at
all ask to insert a card if none has been inserted at startup. This
option is useful in the configuration file in case an application does
not know about the smartcard support and waits ad infinitum for an
inserted card.
@item --no-random-seed-file
@opindex no-random-seed-file
GnuPG uses a file to store its internal random pool over invocations.
This makes random generation faster; however sometimes write operations
are not desired. This option can be used to achieve that with the cost of
slower random generation.
@item --no-greeting
@opindex no-greeting
Suppress the initial copyright message.
@item --no-secmem-warning
@opindex no-secmem-warning
Suppress the warning about "using insecure memory".
@item --no-permission-warning
@opindex permission-warning
Suppress the warning about unsafe file and home directory (@option{--homedir})
permissions. Note that the permission checks that GnuPG performs are
not intended to be authoritative, but rather they simply warn about
certain common permission problems. Do not assume that the lack of a
warning means that your system is secure.
Note that the warning for unsafe @option{--homedir} permissions cannot be
suppressed in the gpg.conf file, as this would allow an attacker to
place an unsafe gpg.conf file in place, and use this file to suppress
warnings about itself. The @option{--homedir} permissions warning may only be
suppressed on the command line.
@item --require-secmem
@itemx --no-require-secmem
@opindex require-secmem
Refuse to run if GnuPG cannot get secure memory. Defaults to no
(i.e. run, but give a warning).
@item --require-cross-certification
@itemx --no-require-cross-certification
@opindex require-cross-certification
When verifying a signature made from a subkey, ensure that the cross
certification "back signature" on the subkey is present and valid. This
protects against a subtle attack against subkeys that can sign.
Defaults to @option{--require-cross-certification} for
@command{@gpgname}.
@item --expert
@itemx --no-expert
@opindex expert
Allow the user to do certain nonsensical or "silly" things like
signing an expired or revoked key, or certain potentially incompatible
things like generating unusual key types. This also disables certain
warning messages about potentially incompatible actions. As the name
implies, this option is for experts only. If you don't fully
understand the implications of what it allows you to do, leave this
off. @option{--no-expert} disables this option.
@end table
@c *******************************************
@c ******** KEY RELATED OPTIONS ************
@c *******************************************
@node GPG Key related Options
@subsection Key related options
@table @gnupgtabopt
@item --recipient @var{name}
@itemx -r
@opindex recipient
Encrypt for user id @var{name}. If this option or
@option{--hidden-recipient} is not specified, GnuPG asks for the user-id
unless @option{--default-recipient} is given.
@item --hidden-recipient @var{name}
@itemx -R
@opindex hidden-recipient
Encrypt for user ID @var{name}, but hide the key ID of this user's
key. This option helps to hide the receiver of the message and is a
limited countermeasure against traffic analysis. If this option or
@option{--recipient} is not specified, GnuPG asks for the user ID unless
@option{--default-recipient} is given.
@item --recipient-file @var{file}
@itemx -f
@opindex recipient-file
This option is similar to @option{--recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{@gpgname} assumes that
the key in this file is fully valid.
@item --hidden-recipient-file @var{file}
@itemx -F
@opindex hidden-recipient-file
This option is similar to @option{--hidden-recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{@gpgname} assumes that
the key in this file is fully valid.
@item --encrypt-to @var{name}
@opindex encrypt-to
Same as @option{--recipient} but this one is intended for use in the
options file and may be used with your own user-id as an
"encrypt-to-self". These keys are only used when there are other
recipients given either by use of @option{--recipient} or by the asked
user id. No trust checking is performed for these user ids and even
disabled keys can be used.
@item --hidden-encrypt-to @var{name}
@opindex hidden-encrypt-to
Same as @option{--hidden-recipient} but this one is intended for use in the
options file and may be used with your own user-id as a hidden
"encrypt-to-self". These keys are only used when there are other
recipients given either by use of @option{--recipient} or by the asked user id.
No trust checking is performed for these user ids and even disabled
keys can be used.
@item --no-encrypt-to
@opindex no-encrypt-to
Disable the use of all @option{--encrypt-to} and
@option{--hidden-encrypt-to} keys.
@item --group @{@var{name}=@var{value}@}
@opindex group
Sets up a named group, which is similar to aliases in email programs.
Any time the group name is a recipient (@option{-r} or
@option{--recipient}), it will be expanded to the values
specified. Multiple groups with the same name are automatically merged
into a single group.
The values are @code{key IDs} or fingerprints, but any key description
is accepted. Note that a value with spaces in it will be treated as
two different values. Note also there is only one level of expansion
--- you cannot make an group that points to another group. When used
from the command line, it may be necessary to quote the argument to
this option to prevent the shell from treating it as multiple
arguments.
@item --ungroup @var{name}
@opindex ungroup
Remove a given entry from the @option{--group} list.
@item --no-groups
@opindex no-groups
Remove all entries from the @option{--group} list.
@item --local-user @var{name}
@itemx -u
@opindex local-user
Use @var{name} as the key to sign with. Note that this option overrides
@option{--default-key}.
@item --sender @var{mbox}
@opindex sender
This option has two purposes. @var{mbox} must either be a complete
user id with a proper mail address or just a mail address. When
creating a signature this option tells gpg the user id of a key used
to make a signature if the key was not directly specified by a user
id. When verifying a signature the @var{mbox} is used to restrict the
information printed by the TOFU code to matching user ids.
@item --try-secret-key @var{name}
@opindex try-secret-key
For hidden recipients GPG needs to know the keys to use for trial
decryption. The key set with @option{--default-key} is always tried
first, but this is often not sufficient. This option allows setting more
keys to be used for trial decryption. Although any valid user-id
specification may be used for @var{name} it makes sense to use at least
the long keyid to avoid ambiguities. Note that gpg-agent might pop up a
pinentry for a lot keys to do the trial decryption. If you want to stop
all further trial decryption you may use close-window button instead of
the cancel button.
@item --try-all-secrets
@opindex try-all-secrets
Don't look at the key ID as stored in the message but try all secret
keys in turn to find the right decryption key. This option forces the
behaviour as used by anonymous recipients (created by using
@option{--throw-keyids} or @option{--hidden-recipient}) and might come
handy in case where an encrypted message contains a bogus key ID.
@item --skip-hidden-recipients
@itemx --no-skip-hidden-recipients
@opindex skip-hidden-recipients
@opindex no-skip-hidden-recipients
During decryption skip all anonymous recipients. This option helps in
the case that people use the hidden recipients feature to hide their
own encrypt-to key from others. If one has many secret keys this
may lead to a major annoyance because all keys are tried in turn to
decrypt something which was not really intended for it. The drawback
of this option is that it is currently not possible to decrypt a
message which includes real anonymous recipients.
@end table
@c *******************************************
@c ******** INPUT AND OUTPUT ***************
@c *******************************************
@node GPG Input and Output
@subsection Input and Output
@table @gnupgtabopt
@item --armor
@itemx -a
@opindex armor
Create ASCII armored output. The default is to create the binary
OpenPGP format.
@item --no-armor
@opindex no-armor
Assume the input data is not in ASCII armored format.
@item --output @var{file}
@itemx -o @var{file}
@opindex output
Write output to @var{file}. To write to stdout use @code{-} as the
filename.
@item --max-output @var{n}
@opindex max-output
This option sets a limit on the number of bytes that will be generated
when processing a file. Since OpenPGP supports various levels of
compression, it is possible that the plaintext of a given message may be
significantly larger than the original OpenPGP message. While GnuPG
works properly with such messages, there is often a desire to set a
maximum file size that will be generated before processing is forced to
stop by the OS limits. Defaults to 0, which means "no limit".
@item --chunk-size @var{n}
@opindex chunk-size
The AEAD encryption mode encrypts the data in chunks so that a
receiving side can check for transmission errors or tampering at the
end of each chunk and does not need to delay this until all data has
been received. The used chunk size is 2^@var{n} byte. The lowest
allowed value for @var{n} is 6 (64 byte) and the largest is 62 (4
EiB). The default value for @var{n} is 30 which creates chunks not
larger than 1 GiB.
@item --input-size-hint @var{n}
@opindex input-size-hint
This option can be used to tell GPG the size of the input data in
bytes. @var{n} must be a positive base-10 number. This option is
only useful if the input is not taken from a file. GPG may use this
hint to optimize its buffer allocation strategy. It is also used by
the @option{--status-fd} line ``PROGRESS'' to provide a value for
``total'' if that is not available by other means.
@item --key-origin @var{string}[,@var{url}]
@opindex key-origin
gpg can track the origin of a key. Certain origins are implicitly
known (e.g. keyserver, web key directory) and set. For a standard
import the origin of the keys imported can be set with this option.
To list the possible values use "help" for @var{string}. Some origins
can store an optional @var{url} argument. That URL can appended to
@var{string} after a comma.
@item --import-options @var{parameters}
@opindex import-options
This is a space or comma delimited string that gives options for
importing keys. Options can be prepended with a `no-' to give the
opposite meaning. The options are:
@table @asis
@item import-local-sigs
Allow importing key signatures marked as "local". This is not
generally useful unless a shared keyring scheme is being used.
Defaults to no.
@item keep-ownertrust
Normally possible still existing ownertrust values of a key are
cleared if a key is imported. This is in general desirable so that
a formerly deleted key does not automatically gain an ownertrust
values merely due to import. On the other hand it is sometimes
necessary to re-import a trusted set of keys again but keeping
already assigned ownertrust values. This can be achieved by using
this option.
@item repair-pks-subkey-bug
During import, attempt to repair the damage caused by the PKS keyserver
bug (pre version 0.9.6) that mangles keys with multiple subkeys. Note
that this cannot completely repair the damaged key as some crucial data
is removed by the keyserver, but it does at least give you back one
subkey. Defaults to no for regular @option{--import} and to yes for
keyserver @option{--receive-keys}.
@item import-show
@itemx show-only
Show a listing of the key as imported right before it is stored.
This can be combined with the option @option{--dry-run} to only look
at keys; the option @option{show-only} is a shortcut for this
combination. Note that suffixes like '#' for "sec" and "sbb" lines
may or may not be printed.
@item import-export
Run the entire import code but instead of storing the key to the
local keyring write it to the output. The export options
@option{export-pka} and @option{export-dane} affect the output. This
option can be used to remove all invalid parts from a key without the
need to store it.
@item merge-only
During import, allow key updates to existing keys, but do not allow
any new keys to be imported. Defaults to no.
@item import-clean
After import, compact (remove all signatures except the
self-signature) any user IDs from the new key that are not usable.
Then, remove any signatures from the new key that are not usable.
This includes signatures that were issued by keys that are not present
on the keyring. This option is the same as running the @option{--edit-key}
command "clean" after import. Defaults to no.
@item repair-keys. After import, fix various problems with the
keys. For example, this reorders signatures, and strips duplicate
signatures. Defaults to yes.
@item import-minimal
Import the smallest key possible. This removes all signatures except
the most recent self-signature on each user ID. This option is the
same as running the @option{--edit-key} command "minimize" after import.
Defaults to no.
@item restore
@itemx import-restore
Import in key restore mode. This imports all data which is usually
skipped during import; including all GnuPG specific data. All other
contradicting options are overridden.
@end table
@item --import-filter @{@var{name}=@var{expr}@}
@itemx --export-filter @{@var{name}=@var{expr}@}
@opindex import-filter
@opindex export-filter
These options define an import/export filter which are applied to the
imported/exported keyblock right before it will be stored/written.
@var{name} defines the type of filter to use, @var{expr} the
expression to evaluate. The option can be used several times which
then appends more expression to the same @var{name}.
@noindent
The available filter types are:
@table @asis
@item keep-uid
This filter will keep a user id packet and its dependent packets in
the keyblock if the expression evaluates to true.
@item drop-subkey
This filter drops the selected subkeys.
Currently only implemented for --export-filter.
@item drop-sig
This filter drops the selected key signatures on user ids.
Self-signatures are not considered.
Currently only implemented for --import-filter.
@end table
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
The property names for the expressions depend on the actual filter
type and are indicated in the following table.
The available properties are:
@table @asis
@item uid
A string with the user id. (keep-uid)
@item mbox
The addr-spec part of a user id with mailbox or the empty string.
(keep-uid)
@item key_algo
A number with the public key algorithm of a key or subkey packet.
(drop-subkey)
@item key_created
@itemx key_created_d
The first is the timestamp a public key or subkey packet was
created. The second is the same but given as an ISO string,
e.g. "2016-08-17". (drop-subkey)
@item primary
Boolean indicating whether the user id is the primary one. (keep-uid)
@item expired
Boolean indicating whether a user id (keep-uid), a key (drop-subkey), or a
signature (drop-sig) expired.
@item revoked
Boolean indicating whether a user id (keep-uid) or a key (drop-subkey) has
been revoked.
@item disabled
Boolean indicating whether a primary key is disabled. (not used)
@item secret
Boolean indicating whether a key or subkey is a secret one.
(drop-subkey)
@item sig_created
@itemx sig_created_d
The first is the timestamp a signature packet was created. The
second is the same but given as an ISO date string,
e.g. "2016-08-17". (drop-sig)
@item sig_algo
A number with the public key algorithm of a signature packet. (drop-sig)
@item sig_digest_algo
A number with the digest algorithm of a signature packet. (drop-sig)
@end table
@item --export-options @var{parameters}
@opindex export-options
This is a space or comma delimited string that gives options for
exporting keys. Options can be prepended with a `no-' to give the
opposite meaning. The options are:
@table @asis
@item export-local-sigs
Allow exporting key signatures marked as "local". This is not
generally useful unless a shared keyring scheme is being used.
Defaults to no.
@item export-attributes
Include attribute user IDs (photo IDs) while exporting. Not
including attribute user IDs is useful to export keys that are going
to be used by an OpenPGP program that does not accept attribute user
IDs. Defaults to yes.
@item export-sensitive-revkeys
Include designated revoker information that was marked as
"sensitive". Defaults to no.
@c Since GnuPG 2.1 gpg-agent manages the secret key and thus the
@c export-reset-subkey-passwd hack is not anymore justified. Such use
@c cases may be implemented using a specialized secret key export
@c tool.
@c @item export-reset-subkey-passwd
@c When using the @option{--export-secret-subkeys} command, this option resets
@c the passphrases for all exported subkeys to empty. This is useful
@c when the exported subkey is to be used on an unattended machine where
@c a passphrase doesn't necessarily make sense. Defaults to no.
@item backup
@itemx export-backup
Export for use as a backup. The exported data includes all data
which is needed to restore the key or keys later with GnuPG. The
format is basically the OpenPGP format but enhanced with GnuPG
specific data. All other contradicting options are overridden.
@item export-clean
Compact (remove all signatures from) user IDs on the key being
exported if the user IDs are not usable. Also, do not export any
signatures that are not usable. This includes signatures that were
issued by keys that are not present on the keyring. This option is
the same as running the @option{--edit-key} command "clean" before export
except that the local copy of the key is not modified. Defaults to
no.
@item export-minimal
Export the smallest key possible. This removes all signatures except the
most recent self-signature on each user ID. This option is the same as
running the @option{--edit-key} command "minimize" before export except
that the local copy of the key is not modified. Defaults to no.
@item export-pka
Instead of outputting the key material output PKA records suitable
to put into DNS zone files. An ORIGIN line is printed before each
record to allow diverting the records to the corresponding zone file.
@item export-dane
Instead of outputting the key material output OpenPGP DANE records
suitable to put into DNS zone files. An ORIGIN line is printed before
each record to allow diverting the records to the corresponding zone
file.
@end table
@item --with-colons
@opindex with-colons
Print key listings delimited by colons. Note that the output will be
encoded in UTF-8 regardless of any @option{--display-charset} setting. This
format is useful when GnuPG is called from scripts and other programs
as it is easily machine parsed. The details of this format are
documented in the file @file{doc/DETAILS}, which is included in the GnuPG
source distribution.
@item --fixed-list-mode
@opindex fixed-list-mode
Do not merge primary user ID and primary key in @option{--with-colon}
listing mode and print all timestamps as seconds since 1970-01-01.
Since GnuPG 2.0.10, this mode is always used and thus this option is
obsolete; it does not harm to use it though.
@item --legacy-list-mode
@opindex legacy-list-mode
Revert to the pre-2.1 public key list mode. This only affects the
human readable output and not the machine interface
(i.e. @code{--with-colons}). Note that the legacy format does not
convey suitable information for elliptic curves.
@item --with-fingerprint
@opindex with-fingerprint
Same as the command @option{--fingerprint} but changes only the format
of the output and may be used together with another command.
@item --with-subkey-fingerprint
@opindex with-subkey-fingerprint
If a fingerprint is printed for the primary key, this option forces
printing of the fingerprint for all subkeys. This could also be
achieved by using the @option{--with-fingerprint} twice but by using
this option along with keyid-format "none" a compact fingerprint is
printed.
@item --with-icao-spelling
@opindex with-icao-spelling
Print the ICAO spelling of the fingerprint in addition to the hex digits.
@item --with-keygrip
@opindex with-keygrip
Include the keygrip in the key listings. In @code{--with-colons} mode
this is implicitly enable for secret keys.
@item --with-key-origin
@opindex with-key-origin
Include the locally held information on the origin and last update of
a key in a key listing. In @code{--with-colons} mode this is always
printed. This data is currently experimental and shall not be
considered part of the stable API.
@item --with-wkd-hash
@opindex with-wkd-hash
Print a Web Key Directory identifier along with each user ID in key
listings. This is an experimental feature and semantics may change.
@item --with-secret
@opindex with-secret
Include info about the presence of a secret key in public key listings
done with @code{--with-colons}.
@end table
@c *******************************************
@c ******** OPENPGP OPTIONS ****************
@c *******************************************
@node OpenPGP Options
@subsection OpenPGP protocol specific options
@table @gnupgtabopt
@item -t, --textmode
@itemx --no-textmode
@opindex textmode
Treat input files as text and store them in the OpenPGP canonical text
form with standard "CRLF" line endings. This also sets the necessary
flags to inform the recipient that the encrypted or signed data is text
and may need its line endings converted back to whatever the local
system uses. This option is useful when communicating between two
platforms that have different line ending conventions (UNIX-like to Mac,
Mac to Windows, etc). @option{--no-textmode} disables this option, and
is the default.
@item --force-v3-sigs
@itemx --no-force-v3-sigs
@item --force-v4-certs
@itemx --no-force-v4-certs
These options are obsolete and have no effect since GnuPG 2.1.
@item --force-aead
@opindex force-aead
Force the use of AEAD encryption over MDC encryption. AEAD is a
modern and faster way to do authenticated encrytion than the old MDC
method. See also options @option{--aead-algo} and
@option{--chunk-size}.
As of now this option requires the use of option @option{--rfc4880bis}
to declare that a not yet standardized feature is used.
@item --force-mdc
@itemx --disable-mdc
@opindex force-mdc
@opindex disable-mdc
These options are obsolete and have no effect since GnuPG 2.2.8. The
MDC is always used unless the keys indicate that an AEAD algorithm can
be used in which case AEAD is used. But note: If the creation or of a
legacy non-MDC message is exceptionally required, the option
@option{--rfc2440} allows for this.
@item --disable-signer-uid
@opindex disable-signer-uid
By default the user ID of the signing key is embedded in the data
signature. As of now this is only done if the signing key has been
specified with @option{local-user} using a mail address. This
information can be helpful for verifier to locate the key; see
option @option{--auto-key-retrieve}.
@item --personal-cipher-preferences @var{string}
@opindex personal-cipher-preferences
Set the list of personal cipher preferences to @var{string}. Use
@command{@gpgname --version} to get a list of available algorithms,
and use @code{none} to set no preference at all. This allows the user
to safely override the algorithm chosen by the recipient key
preferences, as GPG will only select an algorithm that is usable by
all recipients. The most highly ranked cipher in this list is also
used for the @option{--symmetric} encryption command.
@item --personal-aead-preferences @var{string}
@opindex personal-aead-preferences
Set the list of personal AEAD preferences to @var{string}. Use
@command{@gpgname --version} to get a list of available algorithms,
and use @code{none} to set no preference at all. This allows the user
to safely override the algorithm chosen by the recipient key
preferences, as GPG will only select an algorithm that is usable by
all recipients. The most highly ranked cipher in this list is also
used for the @option{--symmetric} encryption command.
@item --personal-digest-preferences @var{string}
@opindex personal-digest-preferences
Set the list of personal digest preferences to @var{string}. Use
@command{@gpgname --version} to get a list of available algorithms,
and use @code{none} to set no preference at all. This allows the user
to safely override the algorithm chosen by the recipient key
preferences, as GPG will only select an algorithm that is usable by
all recipients. The most highly ranked digest algorithm in this list
is also used when signing without encryption
(e.g. @option{--clear-sign} or @option{--sign}).
@item --personal-compress-preferences @var{string}
@opindex personal-compress-preferences
Set the list of personal compression preferences to @var{string}.
Use @command{@gpgname --version} to get a list of available
algorithms, and use @code{none} to set no preference at all. This
allows the user to safely override the algorithm chosen by the
recipient key preferences, as GPG will only select an algorithm that
is usable by all recipients. The most highly ranked compression
algorithm in this list is also used when there are no recipient keys
to consider (e.g. @option{--symmetric}).
@item --s2k-cipher-algo @var{name}
@opindex s2k-cipher-algo
Use @var{name} as the cipher algorithm for symmetric encryption with
a passphrase if @option{--personal-cipher-preferences} and
@option{--cipher-algo} are not given. The default is @value{GPGSYMENCALGO}.
@item --s2k-digest-algo @var{name}
@opindex s2k-digest-algo
Use @var{name} as the digest algorithm used to mangle the passphrases
for symmetric encryption. The default is SHA-1.
@item --s2k-mode @var{n}
@opindex s2k-mode
Selects how passphrases for symmetric encryption are mangled. If
@var{n} is 0 a plain passphrase (which is in general not recommended)
will be used, a 1 adds a salt (which should not be used) to the
passphrase and a 3 (the default) iterates the whole process a number
of times (see @option{--s2k-count}).
@item --s2k-count @var{n}
@opindex s2k-count
Specify how many times the passphrases mangling for symmetric
encryption is repeated. This value may range between 1024 and
65011712 inclusive. The default is inquired from gpg-agent. Note
that not all values in the 1024-65011712 range are legal and if an
illegal value is selected, GnuPG will round up to the nearest legal
value. This option is only meaningful if @option{--s2k-mode} is set
to the default of 3.
@end table
@c ***************************
@c ******* Compliance ********
@c ***************************
@node Compliance Options
@subsection Compliance options
These options control what GnuPG is compliant to. Only one of these
options may be active at a time. Note that the default setting of
this is nearly always the correct one. See the INTEROPERABILITY WITH
OTHER OPENPGP PROGRAMS section below before using one of these
options.
@table @gnupgtabopt
@item --gnupg
@opindex gnupg
Use standard GnuPG behavior. This is essentially OpenPGP behavior
(see @option{--openpgp}), but with some additional workarounds for common
compatibility problems in different versions of PGP. This is the
default option, so it is not generally needed, but it may be useful to
override a different compliance option in the gpg.conf file.
@item --openpgp
@opindex openpgp
Reset all packet, cipher and digest options to strict OpenPGP
behavior. Use this option to reset all previous options like
@option{--s2k-*}, @option{--cipher-algo}, @option{--digest-algo} and
@option{--compress-algo} to OpenPGP compliant values. All PGP
workarounds are disabled.
@item --rfc4880
@opindex rfc4880
Reset all packet, cipher and digest options to strict RFC-4880
behavior. Note that this is currently the same thing as
@option{--openpgp}.
@item --rfc4880bis
@opindex rfc4880bis
Enable experimental features from proposed updates to RFC-4880. This
option can be used in addition to the other compliance options.
Warning: The behavior may change with any GnuPG release and created
keys or data may not be usable with future GnuPG versions.
@item --rfc2440
@opindex rfc2440
Reset all packet, cipher and digest options to strict RFC-2440
behavior. Note that by using this option encryption packets are
created in a legacy mode without MDC protection. This is dangerous
and should thus only be used for experiments. See also option
@option{--ignore-mdc-error}.
@item --pgp6
@opindex pgp6
-Set up all options to be as PGP 6 compliant as possible. This
-restricts you to the ciphers IDEA (if the IDEA plugin is installed),
-3DES, and CAST5, the hashes MD5, SHA1 and RIPEMD160, and the
-compression algorithms none and ZIP. This also disables
-@option{--throw-keyids}, and making signatures with signing subkeys as PGP 6
-does not understand signatures made by signing subkeys.
-FIXME: remove this options.
-
-This option implies @option{--escape-from-lines}.
+This option is obsolete; it is handled as an alias for @option{--pgp7}
@item --pgp7
@opindex pgp7
-Set up all options to be as PGP 7 compliant as possible. This is
-identical to @option{--pgp6} except that MDCs are not disabled, and the
-list of allowable ciphers is expanded to add AES128, AES192, AES256, and
-TWOFISH.
+Set up all options to be as PGP 7 compliant as possible. This allowd
+the ciphers IDEA, 3DES, CAST5,AES128, AES192, AES256, and TWOFISH.,
+the hashes MD5, SHA1 and RIPEMD160, and the compression algorithms
+none and ZIP. This option implies @option{--escape-from-lines} and
+disables @option{--throw-keyids},
@item --pgp8
@opindex pgp8
Set up all options to be as PGP 8 compliant as possible. PGP 8 is a lot
closer to the OpenPGP standard than previous versions of PGP, so all
this does is disable @option{--throw-keyids} and set
@option{--escape-from-lines}. All algorithms are allowed except for the
SHA224, SHA384, and SHA512 digests.
@item --compliance @var{string}
@opindex compliance
This option can be used instead of one of the options above. Valid
values for @var{string} are the above option names (without the double
dash) and possibly others as shown when using "help" for @var{value}.
@end table
@c *******************************************
@c ******** ESOTERIC OPTIONS ***************
@c *******************************************
@node GPG Esoteric Options
@subsection Doing things one usually doesn't want to do
@table @gnupgtabopt
@item -n
@itemx --dry-run
@opindex dry-run
Don't make any changes (this is not completely implemented).
@item --list-only
@opindex list-only
Changes the behaviour of some commands. This is like @option{--dry-run} but
different in some cases. The semantic of this option may be extended in
the future. Currently it only skips the actual decryption pass and
therefore enables a fast listing of the encryption keys.
@item -i
@itemx --interactive
@opindex interactive
Prompt before overwriting any files.
@item --debug-level @var{level}
@opindex debug-level
Select the debug level for investigating problems. @var{level} may be
a numeric value or by a keyword:
@table @code
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
More verbose debug messages. A value between 3 and 5 may be used
instead of the keyword.
@item expert
Even more detailed messages. A value between 6 and 8 may be used
instead of the keyword.
@item guru
All of the debug messages you can get. A value greater than 8 may be
used instead of the keyword. The creation of hash tracing files is
only enabled if the keyword is used.
@end table
How these messages are mapped to the actual debugging flags is not
specified and may change with newer releases of this program. They are
however carefully selected to best aid in debugging.
@item --debug @var{flags}
@opindex debug
Set debugging flags. All flags are or-ed and @var{flags} may be given
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
To get a list of all supported flags the single word "help" can be
used.
@item --debug-all
@opindex debug-all
Set all useful debugging flags.
@item --debug-iolbf
@opindex debug-iolbf
Set stdout into line buffered mode. This option is only honored when
given on the command line.
@item --debug-set-iobuf-size @var{n}
@opindex debug-iolbf
Change the buffer size of the IOBUFs to @var{n} kilobyte. Using 0
prints the current size. Note well: This is a maintainer only option
and may thus be changed or removed at any time without notice.
@item --faked-system-time @var{epoch}
@opindex faked-system-time
This option is only useful for testing; it sets the system time back or
forth to @var{epoch} which is the number of seconds elapsed since the year
1970. Alternatively @var{epoch} may be given as a full ISO time string
(e.g. "20070924T154812").
If you suffix @var{epoch} with an exclamation mark (!), the system time
will appear to be frozen at the specified time.
@item --enable-progress-filter
@opindex enable-progress-filter
Enable certain PROGRESS status outputs. This option allows frontends
to display a progress indicator while gpg is processing larger files.
There is a slight performance overhead using it.
@item --status-fd @var{n}
@opindex status-fd
Write special status strings to the file descriptor @var{n}.
See the file DETAILS in the documentation for a listing of them.
@item --status-file @var{file}
@opindex status-file
Same as @option{--status-fd}, except the status data is written to file
@var{file}.
@item --logger-fd @var{n}
@opindex logger-fd
Write log output to file descriptor @var{n} and not to STDERR.
@item --log-file @var{file}
@itemx --logger-file @var{file}
@opindex log-file
Same as @option{--logger-fd}, except the logger data is written to
file @var{file}. Use @file{socket://} to log to s socket.
@item --attribute-fd @var{n}
@opindex attribute-fd
Write attribute subpackets to the file descriptor @var{n}. This is most
useful for use with @option{--status-fd}, since the status messages are
needed to separate out the various subpackets from the stream delivered
to the file descriptor.
@item --attribute-file @var{file}
@opindex attribute-file
Same as @option{--attribute-fd}, except the attribute data is written to
file @var{file}.
@item --comment @var{string}
@itemx --no-comments
@opindex comment
Use @var{string} as a comment string in cleartext signatures and ASCII
armored messages or keys (see @option{--armor}). The default behavior is
not to use a comment string. @option{--comment} may be repeated multiple
times to get multiple comment strings. @option{--no-comments} removes
all comments. It is a good idea to keep the length of a single comment
below 60 characters to avoid problems with mail programs wrapping such
lines. Note that comment lines, like all other header lines, are not
protected by the signature.
@item --emit-version
@itemx --no-emit-version
@opindex emit-version
Force inclusion of the version string in ASCII armored output. If
given once only the name of the program and the major number is
emitted, given twice the minor is also emitted, given thrice
the micro is added, and given four times an operating system identification
is also emitted. @option{--no-emit-version} (default) disables the version
line.
@item --sig-notation @{@var{name}=@var{value}@}
@itemx --cert-notation @{@var{name}=@var{value}@}
@itemx -N, --set-notation @{@var{name}=@var{value}@}
@opindex sig-notation
@opindex cert-notation
@opindex set-notation
Put the name value pair into the signature as notation data.
@var{name} must consist only of printable characters or spaces, and
must contain a '@@' character in the form keyname@@domain.example.com
(substituting the appropriate keyname and domain name, of course). This
is to help prevent pollution of the IETF reserved notation
namespace. The @option{--expert} flag overrides the '@@'
check. @var{value} may be any printable string; it will be encoded in
UTF-8, so you should check that your @option{--display-charset} is set
correctly. If you prefix @var{name} with an exclamation mark (!), the
notation data will be flagged as critical
(rfc4880:5.2.3.16). @option{--sig-notation} sets a notation for data
signatures. @option{--cert-notation} sets a notation for key signatures
(certifications). @option{--set-notation} sets both.
There are special codes that may be used in notation names. "%k" will
be expanded into the key ID of the key being signed, "%K" into the
long key ID of the key being signed, "%f" into the fingerprint of the
key being signed, "%s" into the key ID of the key making the
signature, "%S" into the long key ID of the key making the signature,
"%g" into the fingerprint of the key making the signature (which might
be a subkey), "%p" into the fingerprint of the primary key of the key
making the signature, "%c" into the signature count from the OpenPGP
smartcard, and "%%" results in a single "%". %k, %K, and %f are only
meaningful when making a key signature (certification), and %c is only
meaningful when using the OpenPGP smartcard.
@item --sig-policy-url @var{string}
@itemx --cert-policy-url @var{string}
@itemx --set-policy-url @var{string}
@opindex sig-policy-url
@opindex cert-policy-url
@opindex set-policy-url
Use @var{string} as a Policy URL for signatures (rfc4880:5.2.3.20). If
you prefix it with an exclamation mark (!), the policy URL packet will
be flagged as critical. @option{--sig-policy-url} sets a policy url for
data signatures. @option{--cert-policy-url} sets a policy url for key
signatures (certifications). @option{--set-policy-url} sets both.
The same %-expandos used for notation data are available here as well.
@item --sig-keyserver-url @var{string}
@opindex sig-keyserver-url
Use @var{string} as a preferred keyserver URL for data signatures. If
you prefix it with an exclamation mark (!), the keyserver URL packet
will be flagged as critical.
The same %-expandos used for notation data are available here as well.
@item --set-filename @var{string}
@opindex set-filename
Use @var{string} as the filename which is stored inside messages.
This overrides the default, which is to use the actual filename of the
file being encrypted. Using the empty string for @var{string}
effectively removes the filename from the output.
@item --for-your-eyes-only
@itemx --no-for-your-eyes-only
@opindex for-your-eyes-only
Set the `for your eyes only' flag in the message. This causes GnuPG to
refuse to save the file unless the @option{--output} option is given,
and PGP to use a "secure viewer" with a claimed Tempest-resistant font
to display the message. This option overrides @option{--set-filename}.
@option{--no-for-your-eyes-only} disables this option.
@item --use-embedded-filename
@itemx --no-use-embedded-filename
@opindex use-embedded-filename
Try to create a file with a name as embedded in the data. This can be
a dangerous option as it enables overwriting files. Defaults to no.
@item --cipher-algo @var{name}
@opindex cipher-algo
Use @var{name} as cipher algorithm. Running the program with the
command @option{--version} yields a list of supported algorithms. If
this is not used the cipher algorithm is selected from the preferences
stored with the key. In general, you do not want to use this option as
it allows you to violate the OpenPGP standard. The option
@option{--personal-cipher-preferences} is the safe way to accomplish the
same thing.
@item --aead-algo @var{name}
@opindex aead-algo
Specify that the AEAD algorithm @var{name} is to be used. This is
useful for symmetric encryption where no key preference are available
to select the AEAD algorithm. Runing @command{@gpgname} with option
@option{--version} shows the available AEAD algorithms. In general,
you do not want to use this option as it allows you to violate the
OpenPGP standard. The option @option{--personal-aead-preferences} is
the safe way to accomplish the same thing.
@item --digest-algo @var{name}
@opindex digest-algo
Use @var{name} as the message digest algorithm. Running the program
with the command @option{--version} yields a list of supported
algorithms. In general, you do not want to use this option as it
allows you to violate the OpenPGP standard. The option
@option{--personal-digest-preferences} is the safe way to accomplish
the same thing.
@item --compress-algo @var{name}
@opindex compress-algo
Use compression algorithm @var{name}. "zlib" is RFC-1950 ZLIB
compression. "zip" is RFC-1951 ZIP compression which is used by PGP.
"bzip2" is a more modern compression scheme that can compress some
things better than zip or zlib, but at the cost of more memory used
during compression and decompression. "uncompressed" or "none"
disables compression. If this option is not used, the default
behavior is to examine the recipient key preferences to see which
algorithms the recipient supports. If all else fails, ZIP is used for
maximum compatibility.
ZLIB may give better compression results than ZIP, as the compression
window size is not limited to 8k. BZIP2 may give even better
compression results than that, but will use a significantly larger
amount of memory while compressing and decompressing. This may be
significant in low memory situations. Note, however, that PGP (all
versions) only supports ZIP compression. Using any algorithm other
than ZIP or "none" will make the message unreadable with PGP. In
general, you do not want to use this option as it allows you to
violate the OpenPGP standard. The option
@option{--personal-compress-preferences} is the safe way to accomplish
the same thing.
@item --cert-digest-algo @var{name}
@opindex cert-digest-algo
Use @var{name} as the message digest algorithm used when signing a
key. Running the program with the command @option{--version} yields a
list of supported algorithms. Be aware that if you choose an algorithm
that GnuPG supports but other OpenPGP implementations do not, then some
users will not be able to use the key signatures you make, or quite
possibly your entire key.
@item --disable-cipher-algo @var{name}
@opindex disable-cipher-algo
Never allow the use of @var{name} as cipher algorithm.
The given name will not be checked so that a later loaded algorithm
will still get disabled.
@item --disable-pubkey-algo @var{name}
@opindex disable-pubkey-algo
Never allow the use of @var{name} as public key algorithm.
The given name will not be checked so that a later loaded algorithm
will still get disabled.
@item --throw-keyids
@itemx --no-throw-keyids
@opindex throw-keyids
Do not put the recipient key IDs into encrypted messages. This helps to
hide the receivers of the message and is a limited countermeasure
against traffic analysis.@footnote{Using a little social engineering
anyone who is able to decrypt the message can check whether one of the
other recipients is the one he suspects.} On the receiving side, it may
slow down the decryption process because all available secret keys must
be tried. @option{--no-throw-keyids} disables this option. This option
is essentially the same as using @option{--hidden-recipient} for all
recipients.
@item --not-dash-escaped
@opindex not-dash-escaped
This option changes the behavior of cleartext signatures
so that they can be used for patch files. You should not
send such an armored file via email because all spaces
and line endings are hashed too. You can not use this
option for data which has 5 dashes at the beginning of a
line, patch files don't have this. A special armor header
line tells GnuPG about this cleartext signature option.
@item --escape-from-lines
@itemx --no-escape-from-lines
@opindex escape-from-lines
Because some mailers change lines starting with "From " to ">From " it
is good to handle such lines in a special way when creating cleartext
signatures to prevent the mail system from breaking the signature. Note
that all other PGP versions do it this way too. Enabled by
default. @option{--no-escape-from-lines} disables this option.
@item --passphrase-repeat @var{n}
@opindex passphrase-repeat
Specify how many times @command{@gpgname} will request a new
passphrase be repeated. This is useful for helping memorize a
passphrase. Defaults to 1 repetition.
@item --passphrase-fd @var{n}
@opindex passphrase-fd
Read the passphrase from file descriptor @var{n}. Only the first line
will be read from file descriptor @var{n}. If you use 0 for @var{n},
the passphrase will be read from STDIN. This can only be used if only
one passphrase is supplied.
Note that since Version 2.0 this passphrase is only used if the
option @option{--batch} has also been given. Since Version 2.1
the @option{--pinentry-mode} also needs to be set to @code{loopback}.
@item --passphrase-file @var{file}
@opindex passphrase-file
Read the passphrase from file @var{file}. Only the first line will
be read from file @var{file}. This can only be used if only one
passphrase is supplied. Obviously, a passphrase stored in a file is
of questionable security if other users can read this file. Don't use
this option if you can avoid it.
Note that since Version 2.0 this passphrase is only used if the
option @option{--batch} has also been given. Since Version 2.1
the @option{--pinentry-mode} also needs to be set to @code{loopback}.
@item --passphrase @var{string}
@opindex passphrase
Use @var{string} as the passphrase. This can only be used if only one
passphrase is supplied. Obviously, this is of very questionable
security on a multi-user system. Don't use this option if you can
avoid it.
Note that since Version 2.0 this passphrase is only used if the
option @option{--batch} has also been given. Since Version 2.1
the @option{--pinentry-mode} also needs to be set to @code{loopback}.
@item --pinentry-mode @var{mode}
@opindex pinentry-mode
Set the pinentry mode to @var{mode}. Allowed values for @var{mode}
are:
@table @asis
@item default
Use the default of the agent, which is @code{ask}.
@item ask
Force the use of the Pinentry.
@item cancel
Emulate use of Pinentry's cancel button.
@item error
Return a Pinentry error (``No Pinentry'').
@item loopback
Redirect Pinentry queries to the caller. Note that in contrast to
Pinentry the user is not prompted again if he enters a bad password.
@end table
@item --no-symkey-cache
@opindex no-symkey-cache
Disable the passphrase cache used for symmetrical en- and decryption.
This cache is based on the message specific salt value
(cf. @option{--s2k-mode}).
@item --request-origin @var{origin}
@opindex request-origin
Tell gpg to assume that the operation ultimately originated at
@var{origin}. Depending on the origin certain restrictions are applied
and the Pinentry may include an extra note on the origin. Supported
values for @var{origin} are: @code{local} which is the default,
@code{remote} to indicate a remote origin or @code{browser} for an
operation requested by a web browser.
@item --command-fd @var{n}
@opindex command-fd
This is a replacement for the deprecated shared-memory IPC mode.
If this option is enabled, user input on questions is not expected
from the TTY but from the given file descriptor. It should be used
together with @option{--status-fd}. See the file doc/DETAILS in the source
distribution for details on how to use it.
@item --command-file @var{file}
@opindex command-file
Same as @option{--command-fd}, except the commands are read out of file
@var{file}
@item --allow-non-selfsigned-uid
@itemx --no-allow-non-selfsigned-uid
@opindex allow-non-selfsigned-uid
Allow the import and use of keys with user IDs which are not
self-signed. This is not recommended, as a non self-signed user ID is
trivial to forge. @option{--no-allow-non-selfsigned-uid} disables.
@item --allow-freeform-uid
@opindex allow-freeform-uid
Disable all checks on the form of the user ID while generating a new
one. This option should only be used in very special environments as
it does not ensure the de-facto standard format of user IDs.
@item --ignore-time-conflict
@opindex ignore-time-conflict
GnuPG normally checks that the timestamps associated with keys and
signatures have plausible values. However, sometimes a signature
seems to be older than the key due to clock problems. This option
makes these checks just a warning. See also @option{--ignore-valid-from} for
timestamp issues on subkeys.
@item --ignore-valid-from
@opindex ignore-valid-from
GnuPG normally does not select and use subkeys created in the future.
This option allows the use of such keys and thus exhibits the
pre-1.0.7 behaviour. You should not use this option unless there
is some clock problem. See also @option{--ignore-time-conflict} for timestamp
issues with signatures.
@item --ignore-crc-error
@opindex ignore-crc-error
The ASCII armor used by OpenPGP is protected by a CRC checksum against
transmission errors. Occasionally the CRC gets mangled somewhere on
the transmission channel but the actual content (which is protected by
the OpenPGP protocol anyway) is still okay. This option allows GnuPG
to ignore CRC errors.
@item --ignore-mdc-error
@opindex ignore-mdc-error
This option changes a MDC integrity protection failure into a warning.
It is required to decrypt old messages which did not use an MDC. It
may also be useful if a message is partially garbled, but it is
necessary to get as much data as possible out of that garbled message.
Be aware that a missing or failed MDC can be an indication of an
attack. Use with great caution; see also option @option{--rfc2440}.
@item --allow-weak-digest-algos
@opindex allow-weak-digest-algos
Signatures made with known-weak digest algorithms are normally
rejected with an ``invalid digest algorithm'' message. This option
allows the verification of signatures made with such weak algorithms.
MD5 is the only digest algorithm considered weak by default. See also
@option{--weak-digest} to reject other digest algorithms.
@item --weak-digest @var{name}
@opindex weak-digest
Treat the specified digest algorithm as weak. Signatures made over
weak digests algorithms are normally rejected. This option can be
supplied multiple times if multiple algorithms should be considered
weak. See also @option{--allow-weak-digest-algos} to disable
rejection of weak digests. MD5 is always considered weak, and does
not need to be listed explicitly.
@item --no-default-keyring
@opindex no-default-keyring
Do not add the default keyrings to the list of keyrings. Note that
GnuPG will not operate without any keyrings, so if you use this option
and do not provide alternate keyrings via @option{--keyring} or
@option{--secret-keyring}, then GnuPG will still use the default public or
secret keyrings.
@item --no-keyring
@opindex no-keyring
Do not add use any keyrings even if specified as options.
@item --skip-verify
@opindex skip-verify
Skip the signature verification step. This may be
used to make the decryption faster if the signature
verification is not needed.
@item --with-key-data
@opindex with-key-data
Print key listings delimited by colons (like @option{--with-colons}) and
print the public key data.
@item --list-signatures
@opindex list-signatures
@itemx --list-sigs
@opindex list-sigs
Same as @option{--list-keys}, but the signatures are listed too. This
command has the same effect as using @option{--list-keys} with
@option{--with-sig-list}. Note that in contrast to
@option{--check-signatures} the key signatures are not verified. This
command can be used to create a list of signing keys missing in the
lcoal keyring; for example:
@example
gpg --list-sigs --with-colons USERID | \
awk -F: '$1=="sig" && $2=="?" @{if($13)@{print $13@}else@{print $5@}@}'
@end example
@item --fast-list-mode
@opindex fast-list-mode
Changes the output of the list commands to work faster; this is achieved
by leaving some parts empty. Some applications don't need the user ID
and the trust information given in the listings. By using this options
they can get a faster listing. The exact behaviour of this option may
change in future versions. If you are missing some information, don't
use this option.
@item --no-literal
@opindex no-literal
This is not for normal use. Use the source to see for what it might be useful.
@item --set-filesize
@opindex set-filesize
This is not for normal use. Use the source to see for what it might be useful.
@item --show-session-key
@opindex show-session-key
Display the session key used for one message. See
@option{--override-session-key} for the counterpart of this option.
We think that Key Escrow is a Bad Thing; however the user should have
the freedom to decide whether to go to prison or to reveal the content
of one specific message without compromising all messages ever
encrypted for one secret key.
You can also use this option if you receive an encrypted message which
is abusive or offensive, to prove to the administrators of the
messaging system that the ciphertext transmitted corresponds to an
inappropriate plaintext so they can take action against the offending
user.
@item --override-session-key @var{string}
@itemx --override-session-key-fd @var{fd}
@opindex override-session-key
Don't use the public key but the session key @var{string} respective
the session key taken from the first line read from file descriptor
@var{fd}. The format of this string is the same as the one printed
by @option{--show-session-key}. This option is normally not used but
comes handy in case someone forces you to reveal the content of an
encrypted message; using this option you can do this without handing
out the secret key. Note that using @option{--override-session-key}
may reveal the session key to all local users via the global process
table.
@item --ask-sig-expire
@itemx --no-ask-sig-expire
@opindex ask-sig-expire
When making a data signature, prompt for an expiration time. If this
option is not specified, the expiration time set via
@option{--default-sig-expire} is used. @option{--no-ask-sig-expire}
disables this option.
@item --default-sig-expire
@opindex default-sig-expire
The default expiration time to use for signature expiration. Valid
values are "0" for no expiration, a number followed by the letter d
(for days), w (for weeks), m (for months), or y (for years) (for
example "2m" for two months, or "5y" for five years), or an absolute
date in the form YYYY-MM-DD. Defaults to "0".
@item --ask-cert-expire
@itemx --no-ask-cert-expire
@opindex ask-cert-expire
When making a key signature, prompt for an expiration time. If this
option is not specified, the expiration time set via
@option{--default-cert-expire} is used. @option{--no-ask-cert-expire}
disables this option.
@item --default-cert-expire
@opindex default-cert-expire
The default expiration time to use for key signature expiration.
Valid values are "0" for no expiration, a number followed by the
letter d (for days), w (for weeks), m (for months), or y (for years)
(for example "2m" for two months, or "5y" for five years), or an
absolute date in the form YYYY-MM-DD. Defaults to "0".
@item --default-new-key-algo @var{string}
@opindex default-new-key-algo @var{string}
This option can be used to change the default algorithms for key
generation. The @var{string} is similar to the arguments required for
the command @option{--quick-add-key} but slighly different. For
example the current default of @code{"rsa2048/cert,sign+rsa2048/encr"}
(or @code{"rsa3072"}) can be changed to the value of what we currently
call future default, which is @code{"ed25519/cert,sign+cv25519/encr"}.
You need to consult the source code to learn the details. Note that
the advanced key generation commands can always be used to specify a
key algorithm directly.
@item --allow-secret-key-import
@opindex allow-secret-key-import
This is an obsolete option and is not used anywhere.
@item --allow-multiple-messages
@item --no-allow-multiple-messages
@opindex allow-multiple-messages
Allow processing of multiple OpenPGP messages contained in a single file
or stream. Some programs that call GPG are not prepared to deal with
multiple messages being processed together, so this option defaults to
no. Note that versions of GPG prior to 1.4.7 always allowed multiple
messages.
Warning: Do not use this option unless you need it as a temporary
workaround!
@item --enable-special-filenames
@opindex enable-special-filenames
This option enables a mode in which filenames of the form
@file{-&n}, where n is a non-negative decimal number,
refer to the file descriptor n and not to a file with that name.
@item --no-expensive-trust-checks
@opindex no-expensive-trust-checks
Experimental use only.
@item --preserve-permissions
@opindex preserve-permissions
Don't change the permissions of a secret keyring back to user
read/write only. Use this option only if you really know what you are doing.
@item --default-preference-list @var{string}
@opindex default-preference-list
Set the list of default preferences to @var{string}. This preference
list is used for new keys and becomes the default for "setpref" in the
edit menu.
@item --default-keyserver-url @var{name}
@opindex default-keyserver-url
Set the default keyserver URL to @var{name}. This keyserver will be
used as the keyserver URL when writing a new self-signature on a key,
which includes key generation and changing preferences.
@item --list-config
@opindex list-config
Display various internal configuration parameters of GnuPG. This option
is intended for external programs that call GnuPG to perform tasks, and
is thus not generally useful. See the file @file{doc/DETAILS} in the
source distribution for the details of which configuration items may be
listed. @option{--list-config} is only usable with
@option{--with-colons} set.
@item --list-gcrypt-config
@opindex list-gcrypt-config
Display various internal configuration parameters of Libgcrypt.
@item --gpgconf-list
@opindex gpgconf-list
This command is similar to @option{--list-config} but in general only
internally used by the @command{gpgconf} tool.
@item --gpgconf-test
@opindex gpgconf-test
This is more or less dummy action. However it parses the configuration
file and returns with failure if the configuration file would prevent
@command{@gpgname} from startup. Thus it may be used to run a syntax check
on the configuration file.
@end table
@c *******************************
@c ******* Deprecated ************
@c *******************************
@node Deprecated Options
@subsection Deprecated options
@table @gnupgtabopt
@item --show-photos
@itemx --no-show-photos
@opindex show-photos
Causes @option{--list-keys}, @option{--list-signatures},
@option{--list-public-keys}, @option{--list-secret-keys}, and verifying
a signature to also display the photo ID attached to the key, if
any. See also @option{--photo-viewer}. These options are deprecated. Use
@option{--list-options [no-]show-photos} and/or @option{--verify-options
[no-]show-photos} instead.
@item --show-keyring
@opindex show-keyring
Display the keyring name at the head of key listings to show which
keyring a given key resides on. This option is deprecated: use
@option{--list-options [no-]show-keyring} instead.
@item --always-trust
@opindex always-trust
Identical to @option{--trust-model always}. This option is deprecated.
@item --show-notation
@itemx --no-show-notation
@opindex show-notation
Show signature notations in the @option{--list-signatures} or @option{--check-signatures} listings
as well as when verifying a signature with a notation in it. These
options are deprecated. Use @option{--list-options [no-]show-notation}
and/or @option{--verify-options [no-]show-notation} instead.
@item --show-policy-url
@itemx --no-show-policy-url
@opindex show-policy-url
Show policy URLs in the @option{--list-signatures} or @option{--check-signatures}
listings as well as when verifying a signature with a policy URL in
it. These options are deprecated. Use @option{--list-options
[no-]show-policy-url} and/or @option{--verify-options
[no-]show-policy-url} instead.
@end table
@c *******************************************
@c *************** ****************
@c *************** FILES ****************
@c *************** ****************
@c *******************************************
@mansect files
@node GPG Configuration
@section Configuration files
There are a few configuration files to control certain aspects of
@command{@gpgname}'s operation. Unless noted, they are expected in the
current home directory (@pxref{option --homedir}).
@table @file
@item gpg.conf
@efindex gpg.conf
This is the standard configuration file read by @command{@gpgname} on
startup. It may contain any valid long option; the leading two dashes
may not be entered and the option may not be abbreviated. This default
name may be changed on the command line (@pxref{gpg-option --options}).
You should backup this file.
@end table
Note that on larger installations, it is useful to put predefined files
into the directory @file{@value{SYSCONFSKELDIR}} so that
newly created users start up with a working configuration.
For existing users a small
helper script is provided to create these files (@pxref{addgnupghome}).
For internal purposes @command{@gpgname} creates and maintains a few other
files; They all live in the current home directory (@pxref{option
--homedir}). Only the @command{@gpgname} program may modify these files.
@table @file
@item ~/.gnupg
@efindex ~/.gnupg
This is the default home directory which is used if neither the
environment variable @code{GNUPGHOME} nor the option
@option{--homedir} is given.
@item ~/.gnupg/pubring.gpg
@efindex pubring.gpg
The public keyring. You should backup this file.
@item ~/.gnupg/pubring.gpg.lock
The lock file for the public keyring.
@item ~/.gnupg/pubring.kbx
@efindex pubring.kbx
The public keyring using a different format. This file is shared
with @command{gpgsm}. You should backup this file.
@item ~/.gnupg/pubring.kbx.lock
The lock file for @file{pubring.kbx}.
@item ~/.gnupg/secring.gpg
@efindex secring.gpg
A secret keyring as used by GnuPG versions before 2.1. It is not
used by GnuPG 2.1 and later.
@item ~/.gnupg/secring.gpg.lock
The lock file for the secret keyring.
@item ~/.gnupg/.gpg-v21-migrated
@efindex .gpg-v21-migrated
File indicating that a migration to GnuPG 2.1 has been done.
@item ~/.gnupg/trustdb.gpg
@efindex trustdb.gpg
The trust database. There is no need to backup this file; it is better
to backup the ownertrust values (@pxref{option --export-ownertrust}).
@item ~/.gnupg/trustdb.gpg.lock
The lock file for the trust database.
@item ~/.gnupg/random_seed
@efindex random_seed
A file used to preserve the state of the internal random pool.
@item ~/.gnupg/openpgp-revocs.d/
@efindex openpgp-revocs.d
This is the directory where gpg stores pre-generated revocation
certificates. The file name corresponds to the OpenPGP fingerprint of
the respective key. It is suggested to backup those certificates and
if the primary private key is not stored on the disk to move them to
an external storage device. Anyone who can access theses files is
able to revoke the corresponding key. You may want to print them out.
You should backup all files in this directory and take care to keep
this backup closed away.
@end table
Operation is further controlled by a few environment variables:
@table @asis
@item HOME
@efindex HOME
Used to locate the default home directory.
@item GNUPGHOME
@efindex GNUPGHOME
If set directory used instead of "~/.gnupg".
@item GPG_AGENT_INFO
This variable is obsolete; it was used by GnuPG versions before 2.1.
@item PINENTRY_USER_DATA
@efindex PINENTRY_USER_DATA
This value is passed via gpg-agent to pinentry. It is useful to convey
extra information to a custom pinentry.
@item COLUMNS
@itemx LINES
@efindex COLUMNS
@efindex LINES
Used to size some displays to the full size of the screen.
@item LANGUAGE
@efindex LANGUAGE
Apart from its use by GNU, it is used in the W32 version to override the
language selection done through the Registry. If used and set to a
valid and available language name (@var{langid}), the file with the
translation is loaded from
@code{@var{gpgdir}/gnupg.nls/@var{langid}.mo}. Here @var{gpgdir} is the
directory out of which the gpg binary has been loaded. If it can't be
loaded the Registry is tried and as last resort the native Windows
locale system is used.
@end table
@c *******************************************
@c *************** ****************
@c *************** EXAMPLES ****************
@c *************** ****************
@c *******************************************
@mansect examples
@node GPG Examples
@section Examples
@table @asis
@item gpg -se -r @code{Bob} @code{file}
sign and encrypt for user Bob
@item gpg --clear-sign @code{file}
make a cleartext signature
@item gpg -sb @code{file}
make a detached signature
@item gpg -u 0x12345678 -sb @code{file}
make a detached signature with the key 0x12345678
@item gpg --list-keys @code{user_ID}
show keys
@item gpg --fingerprint @code{user_ID}
show fingerprint
@item gpg --verify @code{pgpfile}
@itemx gpg --verify @code{sigfile} [@code{datafile}]
Verify the signature of the file but do not output the data unless
requested. The second form is used for detached signatures, where
@code{sigfile} is the detached signature (either ASCII armored or
binary) and @code{datafile} are the signed data; if this is not given, the name of the
file holding the signed data is constructed by cutting off the
extension (".asc" or ".sig") of @code{sigfile} or by asking the user
for the filename. If the option @option{--output} is also used the
signed data is written to the file specified by that option; use
@code{-} to write the signed data to stdout.
@end table
@c *******************************************
@c *************** ****************
@c *************** USER ID ****************
@c *************** ****************
@c *******************************************
@mansect how to specify a user id
@ifset isman
@include specify-user-id.texi
@end ifset
@mansect filter expressions
@chapheading FILTER EXPRESSIONS
The options @option{--import-filter} and @option{--export-filter} use
expressions with this syntax (square brackets indicate an optional
part and curly braces a repetition, white space between the elements
are allowed):
@c man:.RS
@example
[lc] @{[@{flag@}] PROPNAME op VALUE [lc]@}
@end example
@c man:.RE
The name of a property (@var{PROPNAME}) may only consist of letters,
digits and underscores. The description for the filter type
describes which properties are defined. If an undefined property is
used it evaluates to the empty string. Unless otherwise noted, the
@var{VALUE} must always be given and may not be the empty string. No
quoting is defined for the value, thus the value may not contain the
strings @code{&&} or @code{||}, which are used as logical connection
operators. The flag @code{--} can be used to remove this restriction.
Numerical values are computed as long int; standard C notation
applies. @var{lc} is the logical connection operator; either
@code{&&} for a conjunction or @code{||} for a disjunction. A
conjunction is assumed at the begin of an expression. Conjunctions
have higher precedence than disjunctions. If @var{VALUE} starts with
one of the characters used in any @var{op} a space after the
@var{op} is required.
@noindent
The supported operators (@var{op}) are:
@table @asis
@item =~
Substring must match.
@item !~
Substring must not match.
@item =
The full string must match.
@item <>
The full string must not match.
@item ==
The numerical value must match.
@item !=
The numerical value must not match.
@item <=
The numerical value of the field must be LE than the value.
@item <
The numerical value of the field must be LT than the value.
@item >
The numerical value of the field must be GT than the value.
@item >=
The numerical value of the field must be GE than the value.
@item -le
The string value of the field must be less or equal than the value.
@item -lt
The string value of the field must be less than the value.
@item -gt
The string value of the field must be greater than the value.
@item -ge
The string value of the field must be greater or equal than the value.
@item -n
True if value is not empty (no value allowed).
@item -z
True if value is empty (no value allowed).
@item -t
Alias for "PROPNAME != 0" (no value allowed).
@item -f
Alias for "PROPNAME == 0" (no value allowed).
@end table
@noindent
Values for @var{flag} must be space separated. The supported flags
are:
@table @asis
@item --
@var{VALUE} spans to the end of the expression.
@item -c
The string match in this part is done case-sensitive.
@end table
The filter options concatenate several specifications for a filter of
the same type. For example the four options in this example:
@c man:.RS
@example
--import-option keep-uid="uid =~ Alfa"
--import-option keep-uid="&& uid !~ Test"
--import-option keep-uid="|| uid =~ Alpha"
--import-option keep-uid="uid !~ Test"
@end example
@c man:.RE
@noindent
which is equivalent to
@c man:.RS
@example
--import-option \
keep-uid="uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test"
@end example
@c man:.RE
imports only the user ids of a key containing the strings "Alfa"
or "Alpha" but not the string "test".
@mansect trust values
@ifset isman
@include trust-values.texi
@end ifset
@mansect return value
@chapheading RETURN VALUE
The program returns 0 if everything was fine, 1 if at least
a signature was bad, and other error codes for fatal errors.
@mansect warnings
@chapheading WARNINGS
Use a *good* password for your user account and a *good* passphrase
to protect your secret key. This passphrase is the weakest part of the
whole system. Programs to do dictionary attacks on your secret keyring
are very easy to write and so you should protect your "~/.gnupg/"
directory very well.
Keep in mind that, if this program is used over a network (telnet), it
is *very* easy to spy out your passphrase!
If you are going to verify detached signatures, make sure that the
program knows about it; either give both filenames on the command line
or use @samp{-} to specify STDIN.
For scripted or other unattended use of @command{gpg} make sure to use
the machine-parseable interface and not the default interface which is
intended for direct use by humans. The machine-parseable interface
provides a stable and well documented API independent of the locale or
future changes of @command{gpg}. To enable this interface use the
options @option{--with-colons} and @option{--status-fd}. For certain
operations the option @option{--command-fd} may come handy too. See
this man page and the file @file{DETAILS} for the specification of the
interface. Note that the GnuPG ``info'' pages as well as the PDF
version of the GnuPG manual features a chapter on unattended use of
GnuPG. As an alternative the library @command{GPGME} can be used as a
high-level abstraction on top of that interface.
@mansect interoperability
@chapheading INTEROPERABILITY WITH OTHER OPENPGP PROGRAMS
GnuPG tries to be a very flexible implementation of the OpenPGP
standard. In particular, GnuPG implements many of the optional parts
of the standard, such as the SHA-512 hash, and the ZLIB and BZIP2
compression algorithms. It is important to be aware that not all
OpenPGP programs implement these optional algorithms and that by
forcing their use via the @option{--cipher-algo},
@option{--digest-algo}, @option{--cert-digest-algo}, or
@option{--compress-algo} options in GnuPG, it is possible to create a
perfectly valid OpenPGP message, but one that cannot be read by the
intended recipient.
There are dozens of variations of OpenPGP programs available, and each
supports a slightly different subset of these optional algorithms.
For example, until recently, no (unhacked) version of PGP supported
the BLOWFISH cipher algorithm. A message using BLOWFISH simply could
not be read by a PGP user. By default, GnuPG uses the standard
OpenPGP preferences system that will always do the right thing and
create messages that are usable by all recipients, regardless of which
OpenPGP program they use. Only override this safe default if you
really know what you are doing.
If you absolutely must override the safe default, or if the preferences
on a given key are invalid for some reason, you are far better off using
the @option{--pgp6}, @option{--pgp7}, or @option{--pgp8} options. These
options are safe as they do not force any particular algorithms in
violation of OpenPGP, but rather reduce the available algorithms to a
"PGP-safe" list.
@mansect bugs
@chapheading BUGS
On older systems this program should be installed as setuid(root). This
is necessary to lock memory pages. Locking memory pages prevents the
operating system from writing memory pages (which may contain
passphrases or other sensitive material) to disk. If you get no
warning message about insecure memory your operating system supports
locking without being root. The program drops root privileges as soon
as locked memory is allocated.
Note also that some systems (especially laptops) have the ability to
``suspend to disk'' (also known as ``safe sleep'' or ``hibernate'').
This writes all memory to disk before going into a low power or even
powered off mode. Unless measures are taken in the operating system
to protect the saved memory, passphrases or other sensitive material
may be recoverable from it later.
Before you report a bug you should first search the mailing list
archives for similar problems and second check whether such a bug has
already been reported to our bug tracker at @url{https://bugs.gnupg.org}.
@c *******************************************
@c *************** **************
@c *************** UNATTENDED **************
@c *************** **************
@c *******************************************
@manpause
@node Unattended Usage of GPG
@section Unattended Usage
@command{@gpgname} is often used as a backend engine by other software. To help
with this a machine interface has been defined to have an unambiguous
way to do this. The options @option{--status-fd} and @option{--batch}
are almost always required for this.
@menu
* Programmatic use of GnuPG:: Programmatic use of GnuPG
* Ephemeral home directories:: Ephemeral home directories
* The quick key manipulation interface:: The quick key manipulation interface
* Unattended GPG key generation:: Unattended key generation
@end menu
@node Programmatic use of GnuPG
@subsection Programmatic use of GnuPG
Please consider using GPGME instead of calling @command{@gpgname}
directly. GPGME offers a stable, backend-independent interface for
many cryptographic operations. It supports OpenPGP and S/MIME, and
also allows interaction with various GnuPG components.
GPGME provides a C-API, and comes with bindings for C++, Qt, and
Python. Bindings for other languages are available.
@node Ephemeral home directories
@subsection Ephemeral home directories
Sometimes you want to contain effects of some operation, for example
you want to import a key to inspect it, but you do not want this key
to be added to your keyring. In earlier versions of GnuPG, it was
possible to specify alternate keyring files for both public and secret
keys. In modern GnuPG versions, however, we changed how secret keys
are stored in order to better protect secret key material, and it was
not possible to preserve this interface.
The preferred way to do this is to use ephemeral home directories.
This technique works across all versions of GnuPG.
Create a temporary directory, create (or copy) a configuration that
meets your needs, make @command{@gpgname} use this directory either
using the environment variable @var{GNUPGHOME}, or the option
@option{--homedir}. GPGME supports this too on a per-context basis,
by modifying the engine info of contexts. Now execute whatever
operation you like, import and export key material as necessary. Once
finished, you can delete the directory. All GnuPG backend services
that were started will detect this and shut down.
@node The quick key manipulation interface
@subsection The quick key manipulation interface
Recent versions of GnuPG have an interface to manipulate keys without
using the interactive command @option{--edit-key}. This interface was
added mainly for the benefit of GPGME (please consider using GPGME,
see the manual subsection ``Programmatic use of GnuPG''). This
interface is described in the subsection ``How to manage your keys''.
@node Unattended GPG key generation
@subsection Unattended key generation
The command @option{--generate-key} may be used along with the option
@option{--batch} for unattended key generation. This is the most
flexible way of generating keys, but it is also the most complex one.
Consider using the quick key manipulation interface described in the
previous subsection ``The quick key manipulation interface''.
The parameters for the key are either read from stdin or given as a
file on the command line. The format of the parameter file is as
follows:
@itemize @bullet
@item Text only, line length is limited to about 1000 characters.
@item UTF-8 encoding must be used to specify non-ASCII characters.
@item Empty lines are ignored.
@item Leading and trailing white space is ignored.
@item A hash sign as the first non white space character indicates
a comment line.
@item Control statements are indicated by a leading percent sign, the
arguments are separated by white space from the keyword.
@item Parameters are specified by a keyword, followed by a colon. Arguments
are separated by white space.
@item
The first parameter must be @samp{Key-Type}; control statements may be
placed anywhere.
@item
The order of the parameters does not matter except for @samp{Key-Type}
which must be the first parameter. The parameters are only used for
the generated keyblock (primary and subkeys); parameters from previous
sets are not used. Some syntactically checks may be performed.
@item
Key generation takes place when either the end of the parameter file
is reached, the next @samp{Key-Type} parameter is encountered or at the
control statement @samp{%commit} is encountered.
@end itemize
@noindent
Control statements:
@table @asis
@item %echo @var{text}
Print @var{text} as diagnostic.
@item %dry-run
Suppress actual key generation (useful for syntax checking).
@item %commit
Perform the key generation. Note that an implicit commit is done at
the next @asis{Key-Type} parameter.
@item %pubring @var{filename}
Do not write the key to the default or commandline given keyring but
to @var{filename}. This must be given before the first commit to take
place, duplicate specification of the same filename is ignored, the
last filename before a commit is used. The filename is used until a
new filename is used (at commit points) and all keys are written to
that file. If a new filename is given, this file is created (and
overwrites an existing one).
See the previous subsection ``Ephemeral home directories'' for a more
robust way to contain side-effects.
@item %secring @var{filename}
This option is a no-op for GnuPG 2.1 and later.
See the previous subsection ``Ephemeral home directories''.
@item %ask-passphrase
@itemx %no-ask-passphrase
This option is a no-op for GnuPG 2.1 and later.
@item %no-protection
Using this option allows the creation of keys without any passphrase
protection. This option is mainly intended for regression tests.
@item %transient-key
If given the keys are created using a faster and a somewhat less
secure random number generator. This option may be used for keys
which are only used for a short time and do not require full
cryptographic strength. It takes only effect if used together with
the control statement @samp{%no-protection}.
@end table
@noindent
General Parameters:
@table @asis
@item Key-Type: @var{algo}
Starts a new parameter block by giving the type of the primary
key. The algorithm must be capable of signing. This is a required
parameter. @var{algo} may either be an OpenPGP algorithm number or a
string with the algorithm name. The special value @samp{default} may
be used for @var{algo} to create the default key type; in this case a
@samp{Key-Usage} shall not be given and @samp{default} also be used
for @samp{Subkey-Type}.
@item Key-Length: @var{nbits}
The requested length of the generated key in bits. The default is
returned by running the command @samp{@gpgname --gpgconf-list}.
@item Key-Grip: @var{hexstring}
This is optional and used to generate a CSR or certificate for an
already existing key. Key-Length will be ignored when given.
@item Key-Usage: @var{usage-list}
Space or comma delimited list of key usages. Allowed values are
@samp{encrypt}, @samp{sign}, and @samp{auth}. This is used to
generate the key flags. Please make sure that the algorithm is
capable of this usage. Note that OpenPGP requires that all primary
keys are capable of certification, so no matter what usage is given
here, the @samp{cert} flag will be on. If no @samp{Key-Usage} is
specified and the @samp{Key-Type} is not @samp{default}, all allowed
usages for that particular algorithm are used; if it is not given but
@samp{default} is used the usage will be @samp{sign}.
@item Subkey-Type: @var{algo}
This generates a secondary key (subkey). Currently only one subkey
can be handled. See also @samp{Key-Type} above.
@item Subkey-Length: @var{nbits}
Length of the secondary key (subkey) in bits. The default is returned
by running the command @samp{@gpgname --gpgconf-list}.
@item Subkey-Usage: @var{usage-list}
Key usage lists for a subkey; similar to @samp{Key-Usage}.
@item Passphrase: @var{string}
If you want to specify a passphrase for the secret key, enter it here.
Default is to use the Pinentry dialog to ask for a passphrase.
@item Name-Real: @var{name}
@itemx Name-Comment: @var{comment}
@itemx Name-Email: @var{email}
The three parts of a user name. Remember to use UTF-8 encoding here.
If you don't give any of them, no user ID is created.
@item Expire-Date: @var{iso-date}|(@var{number}[d|w|m|y])
Set the expiration date for the key (and the subkey). It may either
be entered in ISO date format (e.g. "20000815T145012") or as number of
days, weeks, month or years after the creation date. The special
notation "seconds=N" is also allowed to specify a number of seconds
since creation. Without a letter days are assumed. Note that there
is no check done on the overflow of the type used by OpenPGP for
timestamps. Thus you better make sure that the given value make
sense. Although OpenPGP works with time intervals, GnuPG uses an
absolute value internally and thus the last year we can represent is
2105.
@item Creation-Date: @var{iso-date}
Set the creation date of the key as stored in the key information and
which is also part of the fingerprint calculation. Either a date like
"1986-04-26" or a full timestamp like "19860426T042640" may be used.
The time is considered to be UTC. The special notation "seconds=N"
may be used to directly specify a the number of seconds since Epoch
(Unix time). If it is not given the current time is used.
@item Preferences: @var{string}
Set the cipher, hash, and compression preference values for this key.
This expects the same type of string as the sub-command @samp{setpref}
in the @option{--edit-key} menu.
@item Revoker: @var{algo}:@var{fpr} [sensitive]
Add a designated revoker to the generated key. Algo is the public key
algorithm of the designated revoker (i.e. RSA=1, DSA=17, etc.)
@var{fpr} is the fingerprint of the designated revoker. The optional
@samp{sensitive} flag marks the designated revoker as sensitive
information. Only v4 keys may be designated revokers.
@item Keyserver: @var{string}
This is an optional parameter that specifies the preferred keyserver
URL for the key.
@item Handle: @var{string}
This is an optional parameter only used with the status lines
KEY_CREATED and KEY_NOT_CREATED. @var{string} may be up to 100
characters and should not contain spaces. It is useful for batch key
generation to associate a key parameter block with a status line.
@end table
@noindent
Here is an example on how to create a key in an ephemeral home directory:
@smallexample
$ export GNUPGHOME="$(mktemp -d)"
$ cat >foo <
ssb elg1024 2016-12-16 [E]
@end smallexample
@noindent
If you want to create a key with the default algorithms you would use
these parameters:
@smallexample
%echo Generating a default key
Key-Type: default
Subkey-Type: default
Name-Real: Joe Tester
Name-Comment: with stupid passphrase
Name-Email: joe@@foo.bar
Expire-Date: 0
Passphrase: abc
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
@end smallexample
@mansect see also
@ifset isman
@command{gpgv}(1),
@command{gpgsm}(1),
@command{gpg-agent}(1)
@end ifset
@include see-also-note.texi
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 7de07d234..04a9ab214 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -1,1203 +1,1203 @@
/* encrypt.c - Main encryption driver
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
* 2006, 2009 Free Software Foundation, Inc.
* 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
#include
#include
#include
#include "gpg.h"
#include "options.h"
#include "packet.h"
#include "../common/status.h"
#include "../common/iobuf.h"
#include "keydb.h"
#include "../common/util.h"
#include "main.h"
#include "filter.h"
#include "trustdb.h"
#include "../common/i18n.h"
#include "../common/status.h"
#include "pkglue.h"
#include "../common/compliance.h"
static int encrypt_simple( const char *filename, int mode, int use_seskey );
static int write_pubkey_enc_from_list (ctrl_t ctrl,
PK_LIST pk_list, DEK *dek, iobuf_t out);
/****************
* Encrypt FILENAME with only the symmetric cipher. Take input from
* stdin if FILENAME is NULL. If --force-aead is used we use an SKESK.
*/
int
encrypt_symmetric (const char *filename)
{
return encrypt_simple( filename, 1, opt.force_aead);
}
/****************
* Encrypt FILENAME as a literal data packet only. Take input from
* stdin if FILENAME is NULL.
*/
int
encrypt_store (const char *filename)
{
return encrypt_simple( filename, 0, 0 );
}
/* Encrypt a session key using DEK and store a pointer to the result
* at R_ENCKEY and its length at R_ENCKEYLEN.
*
* R_SESKEY points to the unencrypted session key (.KEY, .KEYLEN) and
* the algorithm that will be used to encrypt the contents of the
* SKESK packet (.ALGO). If R_SESKEY points to NULL, then a random
* session key that is appropriate for DEK->ALGO is generated and
* stored at R_SESKEY. If AEAD_ALGO is not 0 the given AEAD algorithm
* is used for encryption.
*/
gpg_error_t
encrypt_seskey (DEK *dek, aead_algo_t aead_algo,
DEK **r_seskey, void **r_enckey, size_t *r_enckeylen)
{
gpg_error_t err;
gcry_cipher_hd_t hd = NULL;
byte *buf = NULL;
DEK *seskey;
*r_enckey = NULL;
*r_enckeylen = 0;
if (*r_seskey)
seskey = *r_seskey;
else
{
seskey = xtrycalloc (1, sizeof(DEK));
if (!seskey)
{
err = gpg_error_from_syserror ();
goto leave;
}
seskey->algo = dek->algo;
make_session_key (seskey);
/*log_hexdump( "thekey", c->key, c->keylen );*/
}
if (aead_algo)
{
unsigned int noncelen;
enum gcry_cipher_modes ciphermode;
byte ad[4];
err = openpgp_aead_algo_info (aead_algo, &ciphermode, &noncelen);
if (err)
goto leave;
/* Allocate space for the nonce, the key, and the authentication
* tag (16). */
buf = xtrymalloc_secure (noncelen + seskey->keylen + 16);
if (!buf)
{
err = gpg_error_from_syserror ();
goto leave;
}
gcry_randomize (buf, noncelen, GCRY_STRONG_RANDOM);
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, buf, noncelen);
if (err)
goto leave;
ad[0] = (0xc0 | PKT_SYMKEY_ENC);
ad[1] = 5;
ad[2] = dek->algo;
ad[3] = aead_algo;
err = gcry_cipher_authenticate (hd, ad, 4);
if (err)
goto leave;
memcpy (buf + noncelen, seskey->key, seskey->keylen);
gcry_cipher_final (hd);
err = gcry_cipher_encrypt (hd, buf + noncelen, seskey->keylen, NULL,0);
if (err)
goto leave;
err = gcry_cipher_gettag (hd, buf + noncelen + seskey->keylen, 16);
if (err)
goto leave;
*r_enckeylen = noncelen + seskey->keylen + 16;
*r_enckey = buf;
buf = NULL;
}
else
{
/* In the old version 4 SKESK the encrypted session key is
* prefixed with a one-octet algorithm id. */
buf = xtrymalloc_secure (1 + seskey->keylen);
if (!buf)
{
err = gpg_error_from_syserror ();
goto leave;
}
buf[0] = seskey->algo;
memcpy (buf + 1, seskey->key, seskey->keylen);
err = openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1);
if (!err)
err = gcry_cipher_setkey (hd, dek->key, dek->keylen);
if (!err)
err = gcry_cipher_setiv (hd, NULL, 0);
if (!err)
err = gcry_cipher_encrypt (hd, buf, seskey->keylen + 1, NULL, 0);
if (err)
goto leave;
*r_enckeylen = seskey->keylen + 1;
*r_enckey = buf;
buf = NULL;
}
/* Return the session key in case we allocated it. */
*r_seskey = seskey;
seskey = NULL;
leave:
gcry_cipher_close (hd);
if (seskey != *r_seskey)
xfree (seskey);
xfree (buf);
return err;
}
/* Return the AEAD algo if we shall use AEAD mode. Returns 0 if AEAD
* shall not be used. */
aead_algo_t
use_aead (pk_list_t pk_list, int algo)
{
int can_use;
if (!opt.flags.rfc4880bis)
{
if (opt.force_aead)
log_info ("Warning: Option %s currently requires option '%s'\n",
"--force-aead", "--rfc4880bis");
return 0;
}
can_use = openpgp_cipher_get_algo_blklen (algo) == 16;
/* With --force-aead we want AEAD. */
if (opt.force_aead)
{
if (!can_use)
{
log_info ("Warning: request to use AEAD ignored for cipher '%s'\n",
openpgp_cipher_algo_name (algo));
return 0;
}
return default_aead_algo ();
}
/* AEAD does only work with 128 bit cipher blocklength. */
if (!can_use)
return 0;
/* Note the user which keys have no AEAD feature flag set. */
if (opt.verbose)
warn_missing_aead_from_pklist (pk_list);
/* If all keys support AEAD we can use it. */
return select_aead_from_pklist (pk_list);
}
/* Shall we use the MDC? Yes - unless rfc-2440 compatibility is
* requested. */
int
use_mdc (pk_list_t pk_list,int algo)
{
(void)pk_list;
(void)algo;
/* RFC-2440 don't has MDC - this is the only way to create a legacy
* non-MDC encryption packet. */
if (RFC2440)
return 0;
return 1; /* In all other cases we use the MDC */
}
/* We don't want to use use_seskey yet because older gnupg versions
can't handle it, and there isn't really any point unless we're
making a message that can be decrypted by a public key or
passphrase. */
static int
encrypt_simple (const char *filename, int mode, int use_seskey)
{
iobuf_t inp, out;
PACKET pkt;
PKT_plaintext *pt = NULL;
STRING2KEY *s2k = NULL;
void *enckey = NULL;
size_t enckeylen = 0;
int rc = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t *afx = NULL;
compress_filter_context_t zfx;
text_filter_context_t tfx;
progress_filter_context_t *pfx;
int do_compress = !!default_compress_algo();
if (!gnupg_rng_is_compliant (opt.compliance))
{
rc = gpg_error (GPG_ERR_FORBIDDEN);
log_error (_("%s is not compliant with %s mode\n"),
"RNG",
gnupg_compliance_option_string (opt.compliance));
write_status_error ("random-compliance", rc);
return rc;
}
pfx = new_progress_context ();
memset( &cfx, 0, sizeof cfx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
/* Prepare iobufs. */
inp = iobuf_open(filename);
if (inp)
iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
if (inp && is_secured_file (iobuf_get_fd (inp)))
{
iobuf_close (inp);
inp = NULL;
gpg_err_set_errno (EPERM);
}
if (!inp)
{
rc = gpg_error_from_syserror ();
log_error(_("can't open '%s': %s\n"), filename? filename: "[stdin]",
strerror(errno) );
release_progress_context (pfx);
return rc;
}
handle_progress (pfx, inp, filename);
if (opt.textmode)
iobuf_push_filter( inp, text_filter, &tfx );
cfx.dek = NULL;
if ( mode )
{
int canceled;
aead_algo_t aead_algo;
s2k = xmalloc_clear( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = S2K_DIGEST_ALGO;
cfx.dek = passphrase_to_dek (default_cipher_algo (), s2k, 1, 0,
NULL, &canceled);
if ( !cfx.dek || !cfx.dek->keylen )
{
rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE);
xfree (cfx.dek);
xfree (s2k);
iobuf_close (inp);
log_error (_("error creating passphrase: %s\n"), gpg_strerror (rc));
release_progress_context (pfx);
return rc;
}
if (use_seskey && s2k->mode != 1 && s2k->mode != 3)
{
use_seskey = 0;
log_info (_("can't use a symmetric ESK packet "
"due to the S2K mode\n"));
}
/* See whether we want to use AEAD. */
aead_algo = use_aead (NULL, cfx.dek->algo);
if ( use_seskey )
{
DEK *dek = NULL;
rc = encrypt_seskey (cfx.dek, aead_algo, &dek, &enckey, &enckeylen);
if (rc)
{
xfree (cfx.dek);
xfree (s2k);
iobuf_close (inp);
release_progress_context (pfx);
return rc;
}
/* Replace key in DEK. */
xfree (cfx.dek);
cfx.dek = dek;
}
if (aead_algo)
cfx.dek->use_aead = aead_algo;
else
cfx.dek->use_mdc = !!use_mdc (NULL, cfx.dek->algo);
if (opt.verbose)
log_info(_("using cipher %s.%s\n"),
openpgp_cipher_algo_name (cfx.dek->algo),
cfx.dek->use_aead? openpgp_aead_algo_name (cfx.dek->use_aead)
/**/ : "CFB");
}
if (do_compress
&& cfx.dek
&& (cfx.dek->use_mdc || cfx.dek->use_aead)
&& is_file_compressed(filename, &rc))
{
if (opt.verbose)
log_info(_("'%s' already compressed\n"), filename);
do_compress = 0;
}
if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out )))
{
iobuf_cancel (inp);
xfree (cfx.dek);
xfree (s2k);
release_progress_context (pfx);
return rc;
}
if ( opt.armor )
{
afx = new_armor_context ();
push_armor_filter (afx, out);
}
if ( s2k )
{
/* Fixme: This is quite similar to write_symkey_enc. */
PKT_symkey_enc *enc = xmalloc_clear (sizeof *enc + enckeylen);
enc->version = cfx.dek->use_aead ? 5 : 4;
enc->cipher_algo = cfx.dek->algo;
enc->aead_algo = cfx.dek->use_aead;
enc->s2k = *s2k;
if (enckeylen)
{
enc->seskeylen = enckeylen;
memcpy (enc->seskey, enckey, enckeylen);
}
pkt.pkttype = PKT_SYMKEY_ENC;
pkt.pkt.symkey_enc = enc;
if ((rc = build_packet( out, &pkt )))
log_error("build symkey packet failed: %s\n", gpg_strerror (rc) );
xfree (enc);
xfree (enckey);
enckey = NULL;
}
if (!opt.no_literal)
pt = setup_plaintext_name (filename, inp);
/* Note that PGP 5 has problems decrypting symmetrically encrypted
data if the file length is in the inner packet. It works when
only partial length headers are use. In the past, we always used
partial body length here, but since PGP 2, PGP 6, and PGP 7 need
the file length, and nobody should be using PGP 5 nowadays
anyway, this is now set to the file length. Note also that this
only applies to the RFC-1991 style symmetric messages, and not
the RFC-2440 style. PGP 6 and 7 work with either partial length
or fixed length with the new style messages. */
if ( !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
{
off_t tmpsize;
int overflow;
if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
&& !overflow && opt.verbose)
log_info(_("WARNING: '%s' is an empty file\n"), filename );
/* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the
size of a file is larger than 2^32 minus some bytes for
packet headers, we switch to partial length encoding. */
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
filesize = tmpsize;
else
filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
if (!opt.no_literal)
{
/* Note that PT has been initialized above in !no_literal mode. */
pt->timestamp = make_timestamp();
pt->mode = opt.mimemode? 'm' : opt.textmode? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
}
else
{
cfx.datalen = filesize && !do_compress ? filesize : 0;
pkt.pkttype = 0;
pkt.pkt.generic = NULL;
}
/* Register the cipher filter. */
if (mode)
iobuf_push_filter (out,
cfx.dek->use_aead? cipher_filter_aead
/**/ : cipher_filter_cfb,
&cfx );
/* Register the compress filter. */
if ( do_compress )
{
if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
zfx.new_ctb = 1;
push_compress_filter (out, &zfx, default_compress_algo());
}
/* Do the work. */
if (!opt.no_literal)
{
if ( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", gpg_strerror (rc) );
}
else
{
/* User requested not to create a literal packet, so we copy the
plain data. */
byte copy_buffer[4096];
int bytes_copied;
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
if ( (rc=iobuf_write(out, copy_buffer, bytes_copied)) ) {
log_error ("copying input to output failed: %s\n",
gpg_strerror (rc) );
break;
}
wipememory (copy_buffer, 4096); /* burn buffer */
}
/* Finish the stuff. */
iobuf_close (inp);
if (rc)
iobuf_cancel(out);
else
{
iobuf_close (out); /* fixme: check returncode */
if (mode)
write_status ( STATUS_END_ENCRYPTION );
}
if (pt)
pt->buf = NULL;
free_packet (&pkt, NULL);
xfree (enckey);
xfree (cfx.dek);
xfree (s2k);
release_armor_context (afx);
release_progress_context (pfx);
return rc;
}
int
setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek)
{
int canceled;
*symkey_s2k=xmalloc_clear(sizeof(STRING2KEY));
(*symkey_s2k)->mode = opt.s2k_mode;
(*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO;
*symkey_dek = passphrase_to_dek (opt.s2k_cipher_algo,
*symkey_s2k, 1, 0, NULL, &canceled);
if(!*symkey_dek || !(*symkey_dek)->keylen)
{
xfree(*symkey_dek);
xfree(*symkey_s2k);
return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE);
}
return 0;
}
static int
write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
DEK *symkey_dek, DEK *dek, iobuf_t out)
{
int rc;
void *enckey;
size_t enckeylen;
PKT_symkey_enc *enc;
PACKET pkt;
rc = encrypt_seskey (symkey_dek, aead_algo, &dek, &enckey, &enckeylen);
if (rc)
return rc;
enc = xtrycalloc (1, sizeof (PKT_symkey_enc) + enckeylen);
if (!enc)
{
rc = gpg_error_from_syserror ();
xfree (enckey);
return rc;
}
enc->version = aead_algo? 5 : 4;
enc->cipher_algo = opt.s2k_cipher_algo;
enc->aead_algo = aead_algo;
enc->s2k = *symkey_s2k;
enc->seskeylen = enckeylen;
memcpy (enc->seskey, enckey, enckeylen);
xfree (enckey);
pkt.pkttype = PKT_SYMKEY_ENC;
pkt.pkt.symkey_enc = enc;
if ((rc=build_packet(out,&pkt)))
log_error("build symkey_enc packet failed: %s\n",gpg_strerror (rc));
xfree (enc);
return rc;
}
/*
* Encrypt the file with the given userids (or ask if none is
* supplied). Either FILENAME or FILEFD must be given, but not both.
* The caller may provide a checked list of public keys in
* PROVIDED_PKS; if not the function builds a list of keys on its own.
*
* Note that FILEFD is currently only used by cmd_encrypt in the
* not yet finished server.c.
*/
int
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
int outputfd)
{
iobuf_t inp = NULL;
iobuf_t out = NULL;
PACKET pkt;
PKT_plaintext *pt = NULL;
DEK *symkey_dek = NULL;
STRING2KEY *symkey_s2k = NULL;
int rc = 0, rc2 = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t *afx = NULL;
compress_filter_context_t zfx;
text_filter_context_t tfx;
progress_filter_context_t *pfx;
PK_LIST pk_list;
int do_compress;
int compliant;
if (filefd != -1 && filename)
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
do_compress = !!opt.compress_algo;
pfx = new_progress_context ();
memset( &cfx, 0, sizeof cfx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
if (use_symkey
&& (rc=setup_symkey(&symkey_s2k,&symkey_dek)))
{
release_progress_context (pfx);
return rc;
}
if (provided_keys)
pk_list = provided_keys;
else
{
if ((rc = build_pk_list (ctrl, remusr, &pk_list)))
{
release_progress_context (pfx);
return rc;
}
}
/* Prepare iobufs. */
#ifdef HAVE_W32_SYSTEM
if (filefd == -1)
inp = iobuf_open (filename);
else
{
inp = NULL;
gpg_err_set_errno (ENOSYS);
}
#else
if (filefd == GNUPG_INVALID_FD)
inp = iobuf_open (filename);
else
inp = iobuf_fdopen_nc (FD2INT(filefd), "rb");
#endif
if (inp)
iobuf_ioctl (inp, IOBUF_IOCTL_NO_CACHE, 1, NULL);
if (inp && is_secured_file (iobuf_get_fd (inp)))
{
iobuf_close (inp);
inp = NULL;
gpg_err_set_errno (EPERM);
}
if (!inp)
{
char xname[64];
rc = gpg_error_from_syserror ();
if (filefd != -1)
snprintf (xname, sizeof xname, "[fd %d]", filefd);
else if (!filename)
strcpy (xname, "[stdin]");
else
*xname = 0;
log_error (_("can't open '%s': %s\n"),
*xname? xname : filename, gpg_strerror (rc) );
goto leave;
}
if (opt.verbose)
log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp));
handle_progress (pfx, inp, filename);
if (opt.textmode)
iobuf_push_filter (inp, text_filter, &tfx);
rc = open_outfile (outputfd, filename, opt.armor? 1:0, 0, &out);
if (rc)
goto leave;
if (opt.armor)
{
afx = new_armor_context ();
push_armor_filter (afx, out);
}
/* Create a session key. */
cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek);
if (!opt.def_cipher_algo)
{
/* Try to get it from the prefs. */
cfx.dek->algo = select_algo_from_prefs (pk_list, PREFTYPE_SYM, -1, NULL);
/* The only way select_algo_from_prefs can fail here is when
mixing v3 and v4 keys, as v4 keys have an implicit preference
entry for 3DES, and the pk_list cannot be empty. In this
case, use 3DES anyway as it's the safest choice - perhaps the
v3 key is being used in an OpenPGP implementation and we know
that the implementation behind any v4 key can handle 3DES. */
if (cfx.dek->algo == -1)
{
cfx.dek->algo = CIPHER_ALGO_3DES;
}
/* In case 3DES has been selected, print a warning if any key
does not have a preference for AES. This should help to
indentify why encrypting to several recipients falls back to
3DES. */
if (opt.verbose && cfx.dek->algo == CIPHER_ALGO_3DES)
warn_missing_aes_from_pklist (pk_list);
}
else
{
if (!opt.expert
&& (select_algo_from_prefs (pk_list, PREFTYPE_SYM,
opt.def_cipher_algo, NULL)
!= opt.def_cipher_algo))
{
log_info(_("WARNING: forcing symmetric cipher %s (%d)"
" violates recipient preferences\n"),
openpgp_cipher_algo_name (opt.def_cipher_algo),
opt.def_cipher_algo);
}
cfx.dek->algo = opt.def_cipher_algo;
}
/* Check compliance. */
if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo,
GCRY_CIPHER_MODE_CFB))
{
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
openpgp_cipher_algo_name (cfx.dek->algo),
gnupg_compliance_option_string (opt.compliance));
rc = gpg_error (GPG_ERR_CIPHER_ALGO);
goto leave;
}
if (!gnupg_rng_is_compliant (opt.compliance))
{
rc = gpg_error (GPG_ERR_FORBIDDEN);
log_error (_("%s is not compliant with %s mode\n"),
"RNG",
gnupg_compliance_option_string (opt.compliance));
write_status_error ("random-compliance", rc);
goto leave;
}
compliant = gnupg_cipher_is_compliant (CO_DE_VS, cfx.dek->algo,
GCRY_CIPHER_MODE_CFB);
{
pk_list_t pkr;
for (pkr = pk_list; pkr; pkr = pkr->next)
{
PKT_public_key *pk = pkr->pk;
unsigned int nbits = nbits_from_pk (pk);
if (!gnupg_pk_is_compliant (opt.compliance,
pk->pubkey_algo, pk->pkey, nbits, NULL))
log_info (_("WARNING: key %s is not suitable for encryption"
" in %s mode\n"),
keystr_from_pk (pk),
gnupg_compliance_option_string (opt.compliance));
if (compliant
&& !gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
nbits, NULL))
compliant = 0;
}
}
if (compliant)
write_status_strings (STATUS_ENCRYPTION_COMPLIANCE_MODE,
gnupg_status_compliance_flag (CO_DE_VS),
NULL);
cfx.dek->use_aead = use_aead (pk_list, cfx.dek->algo);
if (!cfx.dek->use_aead)
cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);
/* Only do the is-file-already-compressed check if we are using a
* MDC or AEAD. This forces compressed files to be re-compressed if
* we do not have a MDC to give some protection against chosen
* ciphertext attacks. */
if (do_compress
&& (cfx.dek->use_mdc || cfx.dek->use_aead)
&& is_file_compressed (filename, &rc2))
{
if (opt.verbose)
log_info(_("'%s' already compressed\n"), filename);
do_compress = 0;
}
if (rc2)
{
rc = rc2;
goto leave;
}
make_session_key (cfx.dek);
if (DBG_CRYPTO)
log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");
rc = write_pubkey_enc_from_list (ctrl, pk_list, cfx.dek, out);
if (rc)
goto leave;
/* We put the passphrase (if any) after any public keys as this
* seems to be the most useful on the recipient side - there is no
* point in prompting a user for a passphrase if they have the
* secret key needed to decrypt. */
if (use_symkey && (rc = write_symkey_enc (symkey_s2k, cfx.dek->use_aead,
symkey_dek, cfx.dek, out)))
goto leave;
if (!opt.no_literal)
pt = setup_plaintext_name (filename, inp);
/* Get the size of the file if possible, i.e., if it is a real file. */
if (filename && *filename
&& !iobuf_is_pipe_filename (filename) && !opt.textmode )
{
off_t tmpsize;
int overflow;
if ( !(tmpsize = iobuf_get_filelength(inp, &overflow))
&& !overflow && opt.verbose)
log_info(_("WARNING: '%s' is an empty file\n"), filename );
/* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the size
of a file is larger than 2^32 minus some bytes for packet
headers, we switch to partial length encoding. */
if (tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
filesize = tmpsize;
else
filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
if (!opt.no_literal)
{
pt->timestamp = make_timestamp();
pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
}
else
cfx.datalen = filesize && !do_compress ? filesize : 0;
/* Register the cipher filter. */
iobuf_push_filter (out,
cfx.dek->use_aead? cipher_filter_aead
/**/ : cipher_filter_cfb,
&cfx);
/* Register the compress filter. */
if (do_compress)
{
int compr_algo = opt.compress_algo;
if (compr_algo == -1)
{
compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, -1, NULL);
if (compr_algo == -1)
compr_algo = DEFAULT_COMPRESS_ALGO;
/* Theoretically impossible to get here since uncompressed
is implicit. */
}
else if (!opt.expert
&& select_algo_from_prefs(pk_list, PREFTYPE_ZIP,
compr_algo, NULL) != compr_algo)
{
log_info (_("WARNING: forcing compression algorithm %s (%d)"
" violates recipient preferences\n"),
compress_algo_to_string(compr_algo), compr_algo);
}
/* Algo 0 means no compression. */
if (compr_algo)
{
if (cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead))
zfx.new_ctb = 1;
push_compress_filter (out,&zfx,compr_algo);
}
}
/* Do the work. */
if (!opt.no_literal)
{
if ((rc = build_packet( out, &pkt )))
log_error ("build_packet failed: %s\n", gpg_strerror (rc));
}
else
{
/* User requested not to create a literal packet, so we copy the
plain data. */
byte copy_buffer[4096];
int bytes_copied;
while ((bytes_copied = iobuf_read (inp, copy_buffer, 4096)) != -1)
{
rc = iobuf_write (out, copy_buffer, bytes_copied);
if (rc)
{
log_error ("copying input to output failed: %s\n",
gpg_strerror (rc));
break;
}
}
wipememory (copy_buffer, 4096); /* Burn the buffer. */
}
/* Finish the stuff. */
leave:
iobuf_close (inp);
if (rc)
iobuf_cancel (out);
else
{
iobuf_close (out); /* fixme: check returncode */
write_status (STATUS_END_ENCRYPTION);
}
if (pt)
pt->buf = NULL;
free_packet (&pkt, NULL);
xfree (cfx.dek);
xfree (symkey_dek);
xfree (symkey_s2k);
if (!provided_keys)
release_pk_list (pk_list);
release_armor_context (afx);
release_progress_context (pfx);
return rc;
}
/*
* Filter to do a complete public key encryption.
*/
int
encrypt_filter (void *opaque, int control,
iobuf_t a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
encrypt_filter_context_t *efx = opaque;
int rc = 0;
if (control == IOBUFCTRL_UNDERFLOW) /* decrypt */
{
BUG(); /* not used */
}
else if ( control == IOBUFCTRL_FLUSH ) /* encrypt */
{
if ( !efx->header_okay )
{
efx->cfx.dek = xmalloc_secure_clear ( sizeof *efx->cfx.dek );
if ( !opt.def_cipher_algo )
{
/* Try to get it from the prefs. */
efx->cfx.dek->algo =
select_algo_from_prefs (efx->pk_list, PREFTYPE_SYM, -1, NULL);
if (efx->cfx.dek->algo == -1 )
{
/* Because 3DES is implicitly in the prefs, this can
only happen if we do not have any public keys in
the list. */
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
}
/* In case 3DES has been selected, print a warning if
any key does not have a preference for AES. This
should help to indentify why encrypting to several
recipients falls back to 3DES. */
if (opt.verbose
&& efx->cfx.dek->algo == CIPHER_ALGO_3DES)
warn_missing_aes_from_pklist (efx->pk_list);
}
else
{
if (!opt.expert
&& select_algo_from_prefs (efx->pk_list,PREFTYPE_SYM,
opt.def_cipher_algo,
NULL) != opt.def_cipher_algo)
log_info(_("forcing symmetric cipher %s (%d) "
"violates recipient preferences\n"),
openpgp_cipher_algo_name (opt.def_cipher_algo),
opt.def_cipher_algo);
efx->cfx.dek->algo = opt.def_cipher_algo;
}
efx->cfx.dek->use_aead = use_aead (efx->pk_list, efx->cfx.dek->algo);
if (!efx->cfx.dek->use_aead)
efx->cfx.dek->use_mdc = !!use_mdc (efx->pk_list,efx->cfx.dek->algo);
make_session_key ( efx->cfx.dek );
if (DBG_CRYPTO)
log_printhex (efx->cfx.dek->key, efx->cfx.dek->keylen, "DEK is: ");
rc = write_pubkey_enc_from_list (efx->ctrl,
efx->pk_list, efx->cfx.dek, a);
if (rc)
return rc;
if(efx->symkey_s2k && efx->symkey_dek)
{
rc = write_symkey_enc (efx->symkey_s2k, efx->cfx.dek->use_aead,
efx->symkey_dek, efx->cfx.dek, a);
if (rc)
return rc;
}
iobuf_push_filter (a,
efx->cfx.dek->use_aead? cipher_filter_aead
/**/ : cipher_filter_cfb,
&efx->cfx);
efx->header_okay = 1;
}
rc = iobuf_write (a, buf, size);
}
else if (control == IOBUFCTRL_FREE)
{
xfree (efx->symkey_dek);
xfree (efx->symkey_s2k);
}
else if ( control == IOBUFCTRL_DESC )
{
mem2str (buf, "encrypt_filter", *ret_len);
}
return rc;
}
/*
* Write a pubkey-enc packet for the public key PK to OUT.
*/
int
write_pubkey_enc (ctrl_t ctrl,
PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out)
{
PACKET pkt;
PKT_pubkey_enc *enc;
int rc;
gcry_mpi_t frame;
print_pubkey_algo_note ( pk->pubkey_algo );
enc = xmalloc_clear ( sizeof *enc );
enc->pubkey_algo = pk->pubkey_algo;
keyid_from_pk( pk, enc->keyid );
enc->throw_keyid = throw_keyid;
/* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in an
* integer value of n bits. pubkey_nbits gives us the number of
* bits we have to use. We then encode the session key in some
* way and we get it back in the big intger value FRAME. Then
* we use FRAME, the public key PK->PKEY and the algorithm
* number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which
* returns the encrypted value in the array ENC->DATA. This
* array has a size which depends on the used algorithm (e.g. 2
* for Elgamal). We don't need frame anymore because we have
* everything now in enc->data which is the passed to
* build_packet(). */
frame = encode_session_key (pk->pubkey_algo, dek,
pubkey_nbits (pk->pubkey_algo, pk->pkey));
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
gcry_mpi_release (frame);
if (rc)
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
else
{
if ( opt.verbose )
{
char *ustr = get_user_id_string_native (ctrl, enc->keyid);
log_info (_("%s/%s.%s encrypted for: \"%s\"\n"),
openpgp_pk_algo_name (enc->pubkey_algo),
openpgp_cipher_algo_name (dek->algo),
dek->use_aead? openpgp_aead_algo_name (dek->use_aead)
/**/ : "CFB",
ustr );
xfree (ustr);
}
/* And write it. */
init_packet (&pkt);
pkt.pkttype = PKT_PUBKEY_ENC;
pkt.pkt.pubkey_enc = enc;
rc = build_packet (out, &pkt);
if (rc)
log_error ("build_packet(pubkey_enc) failed: %s\n",
gpg_strerror (rc));
}
free_pubkey_enc(enc);
return rc;
}
/*
* Write pubkey-enc packets from the list of PKs to OUT.
*/
static int
write_pubkey_enc_from_list (ctrl_t ctrl, PK_LIST pk_list, DEK *dek, iobuf_t out)
{
- if (opt.throw_keyids && (PGP6 || PGP7 || PGP8))
+ if (opt.throw_keyids && (PGP7 || PGP8))
{
log_info(_("option '%s' may not be used in %s mode\n"),
"--throw-keyids",
gnupg_compliance_option_string (opt.compliance));
compliance_failure();
}
for ( ; pk_list; pk_list = pk_list->next )
{
PKT_public_key *pk = pk_list->pk;
int throw_keyid = (opt.throw_keyids || (pk_list->flags&1));
int rc = write_pubkey_enc (ctrl, pk, throw_keyid, dek, out);
if (rc)
return rc;
}
return 0;
}
void
encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
{
int rc = 0;
if (opt.outfile)
{
log_error(_("--output doesn't work for this command\n"));
return;
}
if (!nfiles)
{
char line[2048];
unsigned int lno = 0;
while ( fgets(line, DIM(line), stdin) )
{
lno++;
if (!*line || line[strlen(line)-1] != '\n')
{
log_error("input line %u too long or missing LF\n", lno);
return;
}
line[strlen(line)-1] = '\0';
print_file_status(STATUS_FILE_START, line, 2);
rc = encrypt_crypt (ctrl, -1, line, remusr, 0, NULL, -1);
if (rc)
log_error ("encryption of '%s' failed: %s\n",
print_fname_stdin(line), gpg_strerror (rc) );
write_status( STATUS_FILE_DONE );
}
}
else
{
while (nfiles--)
{
print_file_status(STATUS_FILE_START, *files, 2);
if ( (rc = encrypt_crypt (ctrl, -1, *files, remusr, 0, NULL, -1)) )
log_error("encryption of '%s' failed: %s\n",
print_fname_stdin(*files), gpg_strerror (rc) );
write_status( STATUS_FILE_DONE );
files++;
}
}
}
diff --git a/g10/getkey.c b/g10/getkey.c
index fe6483592..b111376c9 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,4537 +1,4537 @@
/* getkey.c - Get a key from the database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2008, 2010 Free Software Foundation, Inc.
* Copyright (C) 2015, 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
#include
#include
#include
#include "gpg.h"
#include "../common/util.h"
#include "packet.h"
#include "../common/iobuf.h"
#include "keydb.h"
#include "options.h"
#include "main.h"
#include "trustdb.h"
#include "../common/i18n.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "../common/host2net.h"
#include "../common/mbox-util.h"
#include "../common/status.h"
#define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE
#define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE
#if MAX_PK_CACHE_ENTRIES < 2
#error We need the cache for key creation
#endif
/* Flags values returned by the lookup code. Note that the values are
* directly used by the KEY_CONSIDERED status line. */
#define LOOKUP_NOT_SELECTED (1<<0)
#define LOOKUP_ALL_SUBKEYS_EXPIRED (1<<1) /* or revoked */
/* A context object used by the lookup functions. */
struct getkey_ctx_s
{
/* Part of the search criteria: whether the search is an exact
search or not. A search that is exact requires that a key or
subkey meet all of the specified criteria. A search that is not
exact allows selecting a different key or subkey from the
keyblock that matched the critera. Further, an exact search
returns the key or subkey that matched whereas a non-exact search
typically returns the primary key. See finish_lookup for
details. */
int exact;
/* Part of the search criteria: Whether the caller only wants keys
with an available secret key. This is used by getkey_next to get
the next result with the same initial criteria. */
int want_secret;
/* Part of the search criteria: The type of the requested key. A
mask of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT.
If non-zero, then for a key to match, it must implement one of
the required uses. */
int req_usage;
/* The database handle. */
KEYDB_HANDLE kr_handle;
/* Whether we should call xfree() on the context when the context is
released using getkey_end()). */
int not_allocated;
/* This variable is used as backing store for strings which have
their address used in ITEMS. */
strlist_t extra_list;
/* Part of the search criteria: The low-level search specification
as passed to keydb_search. */
int nitems;
/* This must be the last element in the structure. When we allocate
the structure, we allocate it so that ITEMS can hold NITEMS. */
KEYDB_SEARCH_DESC items[1];
};
#if 0
static struct
{
int any;
int okay_count;
int nokey_count;
int error_count;
} lkup_stats[21];
#endif
typedef struct keyid_list
{
struct keyid_list *next;
char fpr[MAX_FINGERPRINT_LEN];
u32 keyid[2];
} *keyid_list_t;
#if MAX_PK_CACHE_ENTRIES
typedef struct pk_cache_entry
{
struct pk_cache_entry *next;
u32 keyid[2];
PKT_public_key *pk;
} *pk_cache_entry_t;
static pk_cache_entry_t pk_cache;
static int pk_cache_entries; /* Number of entries in pk cache. */
static int pk_cache_disabled;
#endif
#if MAX_UID_CACHE_ENTRIES < 5
#error we really need the userid cache
#endif
typedef struct user_id_db
{
struct user_id_db *next;
keyid_list_t keyids;
int len;
char name[1];
} *user_id_db_t;
static user_id_db_t user_id_db;
static int uid_cache_entries; /* Number of entries in uid cache. */
static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock);
static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key);
static kbnode_t finish_lookup (kbnode_t keyblock,
unsigned int req_usage, int want_exact,
int want_secret, unsigned int *r_flags);
static void print_status_key_considered (kbnode_t keyblock, unsigned int flags);
#if 0
static void
print_stats ()
{
int i;
for (i = 0; i < DIM (lkup_stats); i++)
{
if (lkup_stats[i].any)
es_fprintf (es_stderr,
"lookup stats: mode=%-2d ok=%-6d nokey=%-6d err=%-6d\n",
i,
lkup_stats[i].okay_count,
lkup_stats[i].nokey_count, lkup_stats[i].error_count);
}
}
#endif
/* Cache a copy of a public key in the public key cache. PK is not
* cached if caching is disabled (via getkey_disable_caches), if
* PK->FLAGS.DONT_CACHE is set, we don't know how to derive a key id
* from the public key (e.g., unsupported algorithm), or a key with
* the key id is already in the cache.
*
* The public key packet is copied into the cache using
* copy_public_key. Thus, any secret parts are not copied, for
* instance.
*
* This cache is filled by get_pubkey and is read by get_pubkey and
* get_pubkey_fast. */
void
cache_public_key (PKT_public_key * pk)
{
#if MAX_PK_CACHE_ENTRIES
pk_cache_entry_t ce, ce2;
u32 keyid[2];
if (pk_cache_disabled)
return;
if (pk->flags.dont_cache)
return;
if (is_ELGAMAL (pk->pubkey_algo)
|| pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|| is_RSA (pk->pubkey_algo))
{
keyid_from_pk (pk, keyid);
}
else
return; /* Don't know how to get the keyid. */
for (ce = pk_cache; ce; ce = ce->next)
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
{
if (DBG_CACHE)
log_debug ("cache_public_key: already in cache\n");
return;
}
if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
{
int n;
/* Remove the last 50% of the entries. */
for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
ce = ce->next;
if (ce && ce != pk_cache && ce->next)
{
ce2 = ce->next;
ce->next = NULL;
ce = ce2;
for (; ce; ce = ce2)
{
ce2 = ce->next;
free_public_key (ce->pk);
xfree (ce);
pk_cache_entries--;
}
}
log_assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
}
pk_cache_entries++;
ce = xmalloc (sizeof *ce);
ce->next = pk_cache;
pk_cache = ce;
ce->pk = copy_public_key (NULL, pk);
ce->keyid[0] = keyid[0];
ce->keyid[1] = keyid[1];
#endif
}
/* Return a const utf-8 string with the text "[User ID not found]".
This function is required so that we don't need to switch gettext's
encoding temporary. */
static const char *
user_id_not_found_utf8 (void)
{
static char *text;
if (!text)
text = native_to_utf8 (_("[User ID not found]"));
return text;
}
/* Return the user ID from the given keyblock.
* We use the primary uid flag which has been set by the merge_selfsigs
* function. The returned value is only valid as long as the given
* keyblock is not changed. */
static const char *
get_primary_uid (KBNODE keyblock, size_t * uidlen)
{
KBNODE k;
const char *s;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->flags.primary)
{
*uidlen = k->pkt->pkt.user_id->len;
return k->pkt->pkt.user_id->name;
}
}
s = user_id_not_found_utf8 ();
*uidlen = strlen (s);
return s;
}
static void
release_keyid_list (keyid_list_t k)
{
while (k)
{
keyid_list_t k2 = k->next;
xfree (k);
k = k2;
}
}
/****************
* Store the association of keyid and userid
* Feed only public keys to this function.
*/
static void
cache_user_id (KBNODE keyblock)
{
user_id_db_t r;
const char *uid;
size_t uidlen;
keyid_list_t keyids = NULL;
KBNODE k;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
keyid_list_t a = xmalloc_clear (sizeof *a);
/* Hmmm: For a long list of keyids it might be an advantage
* to append the keys. */
fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
/* First check for duplicates. */
for (r = user_id_db; r; r = r->next)
{
keyid_list_t b;
for (b = r->keyids; b; b = b->next)
{
if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
{
if (DBG_CACHE)
log_debug ("cache_user_id: already in cache\n");
release_keyid_list (keyids);
xfree (a);
return;
}
}
}
/* Now put it into the cache. */
a->next = keyids;
keyids = a;
}
}
if (!keyids)
BUG (); /* No key no fun. */
uid = get_primary_uid (keyblock, &uidlen);
if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES)
{
/* fixme: use another algorithm to free some cache slots */
r = user_id_db;
user_id_db = r->next;
release_keyid_list (r->keyids);
xfree (r);
uid_cache_entries--;
}
r = xmalloc (sizeof *r + uidlen - 1);
r->keyids = keyids;
r->len = uidlen;
memcpy (r->name, uid, r->len);
r->next = user_id_db;
user_id_db = r;
uid_cache_entries++;
}
/* Disable and drop the public key cache (which is filled by
cache_public_key and get_pubkey). Note: there is currently no way
to re-enable this cache. */
void
getkey_disable_caches ()
{
#if MAX_PK_CACHE_ENTRIES
{
pk_cache_entry_t ce, ce2;
for (ce = pk_cache; ce; ce = ce2)
{
ce2 = ce->next;
free_public_key (ce->pk);
xfree (ce);
}
pk_cache_disabled = 1;
pk_cache_entries = 0;
pk_cache = NULL;
}
#endif
/* fixme: disable user id cache ? */
}
void
pubkey_free (pubkey_t key)
{
if (key)
{
xfree (key->pk);
release_kbnode (key->keyblock);
xfree (key);
}
}
void
pubkeys_free (pubkey_t keys)
{
while (keys)
{
pubkey_t next = keys->next;
pubkey_free (keys);
keys = next;
}
}
/* Returns all keys that match the search specification SEARCH_TERMS.
*
* This function also checks for and warns about duplicate entries in
* the keydb, which can occur if the user has configured multiple
* keyrings or keyboxes or if a keyring or keybox was corrupted.
*
* Note: SEARCH_TERMS will not be expanded (i.e., it may not be a
* group).
*
* USE is the operation for which the key is required. It must be
* either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or
* PUBKEY_USAGE_AUTH.
*
* INCLUDE_UNUSABLE indicates whether disabled keys are allowed.
* (Recipients specified with --encrypt-to and --hidden-encrypt-to may
* be disabled. It is possible to edit disabled keys.)
*
* SOURCE is the context in which SEARCH_TERMS was specified, e.g.,
* "--encrypt-to", etc. If this function is called interactively,
* then this should be NULL.
*
* If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user
* does not specify a long key id or a fingerprint.
*
* The results are placed in *KEYS. *KEYS must be NULL!
*
* Fixme: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
* implemented. */
gpg_error_t
get_pubkeys (ctrl_t ctrl,
char *search_terms, int use, int include_unusable, char *source,
int warn_possibly_ambiguous,
pubkey_t *r_keys)
{
/* We show a warning when a key appears multiple times in the DB.
* This can happen for two reasons:
*
* - The user has configured multiple keyrings or keyboxes.
*
* - The keyring or keybox has been corrupted in some way, e.g., a
* bug or a random process changing them.
*
* For each duplicate, we only want to show the key once. Hence,
* this list. */
static strlist_t key_dups;
gpg_error_t err;
char *use_str; /* USE transformed to a string. */
KEYDB_SEARCH_DESC desc;
GETKEY_CTX ctx;
pubkey_t results = NULL;
pubkey_t r;
int count;
char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
if (DBG_LOOKUP)
{
log_debug ("\n");
log_debug ("%s: Checking %s=%s\n",
__func__, source ? source : "user input", search_terms);
}
if (*r_keys)
log_bug ("%s: KEYS should be NULL!\n", __func__);
switch (use)
{
case PUBKEY_USAGE_ENC: use_str = "encrypt"; break;
case PUBKEY_USAGE_SIG: use_str = "sign"; break;
case PUBKEY_USAGE_CERT: use_str = "cetify"; break;
case PUBKEY_USAGE_AUTH: use_str = "authentication"; break;
default: log_bug ("%s: Bad value for USE (%d)\n", __func__, use);
}
if (use == PUBKEY_USAGE_CERT || use == PUBKEY_USAGE_AUTH)
log_bug ("%s: use=%s is unimplemented.\n", __func__, use_str);
err = classify_user_id (search_terms, &desc, 1);
if (err)
{
log_info (_("key \"%s\" not found: %s\n"),
search_terms, gpg_strerror (err));
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
goto leave;
}
if (warn_possibly_ambiguous
&& ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|| desc.mode == KEYDB_SEARCH_MODE_FPR))
{
log_info (_("Warning: '%s' should be a long key ID or a fingerprint\n"),
search_terms);
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
}
/* Gather all of the results. */
ctx = NULL;
count = 0;
do
{
PKT_public_key *pk;
KBNODE kb;
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
{
err = gpg_error_from_syserror ();
goto leave;
}
pk->req_usage = use;
if (! ctx)
err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
include_unusable, 1);
else
err = getkey_next (ctrl, ctx, pk, &kb);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) /* No more results. */
{
xfree (pk);
break;
}
else if (err) /* An error (other than "not found"). */
{
log_error (_("error looking up: %s\n"), gpg_strerror (err));
xfree (pk);
break;
}
/* Another result! */
count ++;
r = xtrycalloc (1, sizeof (*r));
if (!r)
{
err = gpg_error_from_syserror ();
xfree (pk);
goto leave;
}
r->pk = pk;
r->keyblock = kb;
r->next = results;
results = r;
}
while (ctx);
getkey_end (ctrl, ctx);
if (DBG_LOOKUP)
{
log_debug ("%s resulted in %d matches.\n", search_terms, count);
for (r = results; r; r = r->next)
log_debug (" %s\n",
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof (fingerprint)));
}
if (! results && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{ /* No match. */
if (DBG_LOOKUP)
log_debug ("%s: '%s' not found.\n", __func__, search_terms);
log_info (_("key \"%s\" not found\n"), search_terms);
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
goto leave;
}
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
; /* No more matches. */
else if (err)
{ /* Some other error. An error message was already printed out.
* Free RESULTS and continue. */
goto leave;
}
/* Check for duplicates. */
if (DBG_LOOKUP)
log_debug ("%s: Checking results of %s='%s' for dups\n",
__func__, source ? source : "user input", search_terms);
count = 0;
for (r = results; r; r = r->next)
{
pubkey_t *prevp;
pubkey_t next;
pubkey_t r2;
int dups = 0;
prevp = &r->next;
next = r->next;
while ((r2 = next))
{
if (cmp_public_keys (r->keyblock->pkt->pkt.public_key,
r2->keyblock->pkt->pkt.public_key) != 0)
{ /* Not a dup. */
prevp = &r2->next;
next = r2->next;
continue;
}
dups ++;
count ++;
/* Remove R2 from the list. */
*prevp = r2->next;
release_kbnode (r2->keyblock);
next = r2->next;
xfree (r2);
}
if (dups)
{
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof fingerprint);
if (! strlist_find (key_dups, fingerprint))
{
char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
log_info (_("Warning: %s appears in the keyring %d times\n"),
format_hexfingerprint (fingerprint,
fingerprint_formatted,
sizeof fingerprint_formatted),
1 + dups);
add_to_strlist (&key_dups, fingerprint);
}
}
}
if (DBG_LOOKUP && count)
{
log_debug ("After removing %d dups:\n", count);
for (r = results, count = 0; r; r = r->next)
log_debug (" %d: %s\n",
count,
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof fingerprint));
}
leave:
if (err)
pubkeys_free (results);
else
*r_keys = results;
return err;
}
static void
pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
{
kbnode_t a = found_key ? found_key : keyblock;
log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
|| a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
copy_public_key (pk, a->pkt->pkt.public_key);
}
/* Return the public key with the key id KEYID and store it at PK.
* The resources in *PK should be released using
* release_public_key_parts(). This function also stores a copy of
* the public key in the user id cache (see cache_public_key).
*
* If PK is NULL, this function just stores the public key in the
* cache and returns the usual return code.
*
* PK->REQ_USAGE (which is a mask of PUBKEY_USAGE_SIG,
* PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT) is passed through to the
* lookup function. If this is non-zero, only keys with the specified
* usage will be returned. As such, it is essential that
* PK->REQ_USAGE be correctly initialized!
*
* Returns 0 on success, GPG_ERR_NO_PUBKEY if there is no public key
* with the specified key id, or another error code if an error
* occurs.
*
* If the data was not read from the cache, then the self-signed data
* has definitely been merged into the public key using
* merge_selfsigs. */
int
get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
{
int internal = 0;
int rc = 0;
#if MAX_PK_CACHE_ENTRIES
if (pk)
{
/* Try to get it from the cache. We don't do this when pk is
NULL as it does not guarantee that the user IDs are
cached. */
pk_cache_entry_t ce;
for (ce = pk_cache; ce; ce = ce->next)
{
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
/* XXX: We don't check PK->REQ_USAGE here, but if we don't
read from the cache, we do check it! */
{
copy_public_key (pk, ce->pk);
return 0;
}
}
}
#endif
/* More init stuff. */
if (!pk)
{
internal++;
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
{
rc = gpg_error_from_syserror ();
goto leave;
}
}
/* Do a lookup. */
{
struct getkey_ctx_s ctx;
KBNODE kb = NULL;
KBNODE found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
if (ctrl && ctrl->cached_getkey_kdb)
{
ctx.kr_handle = ctrl->cached_getkey_kdb;
ctrl->cached_getkey_kdb = NULL;
keydb_search_reset (ctx.kr_handle);
}
else
{
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
{
rc = gpg_error_from_syserror ();
goto leave;
}
}
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
ctx.req_usage = pk->req_usage;
rc = lookup (ctrl, &ctx, 0, &kb, &found_key);
if (!rc)
{
pk_from_block (pk, kb, found_key);
}
getkey_end (ctrl, &ctx);
release_kbnode (kb);
}
if (!rc)
goto leave;
rc = GPG_ERR_NO_PUBKEY;
leave:
if (!rc)
cache_public_key (pk);
if (internal)
free_public_key (pk);
return rc;
}
/* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
* account nor does it merge in the self-signed data. This function
* also only considers primary keys. It is intended to be used as a
* quick check of the key to avoid recursion. It should only be used
* in very certain cases. Like get_pubkey and unlike any of the other
* lookup functions, this function also consults the user id cache
* (see cache_public_key).
*
* Return the public key in *PK. The resources in *PK should be
* released using release_public_key_parts(). */
int
get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
{
int rc = 0;
KEYDB_HANDLE hd;
KBNODE keyblock;
u32 pkid[2];
log_assert (pk);
#if MAX_PK_CACHE_ENTRIES
{
/* Try to get it from the cache */
pk_cache_entry_t ce;
for (ce = pk_cache; ce; ce = ce->next)
{
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]
/* Only consider primary keys. */
&& ce->pk->keyid[0] == ce->pk->main_keyid[0]
&& ce->pk->keyid[1] == ce->pk->main_keyid[1])
{
if (pk)
copy_public_key (pk, ce->pk);
return 0;
}
}
}
#endif
hd = keydb_new ();
if (!hd)
return gpg_error_from_syserror ();
rc = keydb_search_kid (hd, keyid);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
keydb_release (hd);
return GPG_ERR_NO_PUBKEY;
}
rc = keydb_get_keyblock (hd, &keyblock);
keydb_release (hd);
if (rc)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
return GPG_ERR_NO_PUBKEY;
}
log_assert (keyblock && keyblock->pkt
&& keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
/* We return the primary key. If KEYID matched a subkey, then we
return an error. */
keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
copy_public_key (pk, keyblock->pkt->pkt.public_key);
else
rc = GPG_ERR_NO_PUBKEY;
release_kbnode (keyblock);
/* Not caching key here since it won't have all of the fields
properly set. */
return rc;
}
/* Return the key block for the key with key id KEYID or NULL, if an
* error occurs. Use release_kbnode() to release the key block.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
kbnode_t
get_pubkeyblock (ctrl_t ctrl, u32 * keyid)
{
struct getkey_ctx_s ctx;
int rc = 0;
KBNODE keyblock = NULL;
memset (&ctx, 0, sizeof ctx);
/* No need to set exact here because we want the entire block. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return NULL;
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
rc = lookup (ctrl, &ctx, 0, &keyblock, NULL);
getkey_end (ctrl, &ctx);
return rc ? NULL : keyblock;
}
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. The resources should be released
* using release_public_key_parts().
*
* Unlike other lookup functions, PK may not be NULL. PK->REQ_USAGE
* is passed through to the lookup function and is a mask of
* PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. Thus, it
* must be valid! If this is non-zero, only keys with the specified
* usage will be returned.
*
* Returns 0 on success. If a public key with the specified key id is
* not found or a secret key is not available for that public key, an
* error code is returned. Note: this function ignores legacy keys.
* An error code is also return if an error occurs.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
gpg_error_t
get_seckey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid)
{
gpg_error_t err;
struct getkey_ctx_s ctx;
kbnode_t keyblock = NULL;
kbnode_t found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
ctx.req_usage = pk->req_usage;
err = lookup (ctrl, &ctx, 1, &keyblock, &found_key);
if (!err)
{
pk_from_block (pk, keyblock, found_key);
}
getkey_end (ctrl, &ctx);
release_kbnode (keyblock);
if (!err)
{
err = agent_probe_secret_key (/*ctrl*/NULL, pk);
if (err)
release_public_key_parts (pk);
}
return err;
}
/* Skip unusable keys. A key is unusable if it is revoked, expired or
disabled or if the selected user id is revoked or expired. */
static int
skip_unusable (void *opaque, u32 * keyid, int uid_no)
{
ctrl_t ctrl = opaque;
int unusable = 0;
KBNODE keyblock;
PKT_public_key *pk;
keyblock = get_pubkeyblock (ctrl, keyid);
if (!keyblock)
{
log_error ("error checking usability status of %s\n", keystr (keyid));
goto leave;
}
pk = keyblock->pkt->pkt.public_key;
/* Is the key revoked or expired? */
if (pk->flags.revoked || pk->has_expired)
unusable = 1;
/* Is the user ID in question revoked or expired? */
if (!unusable && uid_no)
{
KBNODE node;
int uids_seen = 0;
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *user_id = node->pkt->pkt.user_id;
uids_seen ++;
if (uids_seen != uid_no)
continue;
if (user_id->flags.revoked || user_id->flags.expired)
unusable = 1;
break;
}
}
/* If UID_NO is non-zero, then the keyblock better have at least
that many UIDs. */
log_assert (uids_seen == uid_no);
}
if (!unusable)
unusable = pk_is_disabled (pk);
leave:
release_kbnode (keyblock);
return unusable;
}
/* Search for keys matching some criteria.
If RETCTX is not NULL, then the constructed context is returned in
*RETCTX so that getpubkey_next can be used to get subsequent
results. In this case, getkey_end() must be used to free the
search context. If RETCTX is not NULL, then RET_KDBHD must be
NULL.
If NAMELIST is not NULL, then a search query is constructed using
classify_user_id on each of the strings in the list. (Recall: the
database does an OR of the terms, not an AND.) If NAMELIST is
NULL, then all results are returned.
If PK is not NULL, the public key of the first result is returned
in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
set, it is used to filter the search results. See the
documentation for finish_lookup to understand exactly how this is
used. Note: The self-signed data has already been merged into the
public key using merge_selfsigs. Free *PK by calling
release_public_key_parts (or, if PK was allocated using xfree, you
can use free_public_key, which calls release_public_key_parts(PK)
and then xfree(PK)).
If WANT_SECRET is set, then only keys with an available secret key
(either locally or via key registered on a smartcard) are returned.
If INCLUDE_UNUSABLE is set, then unusable keys (see the
documentation for skip_unusable for an exact definition) are
skipped unless they are looked up by key id or by fingerprint.
If RET_KB is not NULL, the keyblock is returned in *RET_KB. This
should be freed using release_kbnode().
If RET_KDBHD is not NULL, then the new database handle used to
conduct the search is returned in *RET_KDBHD. This can be used to
get subsequent results using keydb_search_next. Note: in this
case, no advanced filtering is done for subsequent results (e.g.,
WANT_SECRET and PK->REQ_USAGE are not respected).
This function returns 0 on success. Otherwise, an error code is
returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
(if want_secret is set) is returned if the key is not found. */
static int
key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
PKT_public_key *pk,
int want_secret, int include_unusable,
KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd)
{
int rc = 0;
int n;
strlist_t r;
GETKEY_CTX ctx;
KBNODE help_kb = NULL;
KBNODE found_key = NULL;
if (retctx)
{
/* Reset the returned context in case of error. */
log_assert (!ret_kdbhd); /* Not allowed because the handle is stored
in the context. */
*retctx = NULL;
}
if (ret_kdbhd)
*ret_kdbhd = NULL;
if (!namelist)
/* No search terms: iterate over the whole DB. */
{
ctx = xmalloc_clear (sizeof *ctx);
ctx->nitems = 1;
ctx->items[0].mode = KEYDB_SEARCH_MODE_FIRST;
if (!include_unusable)
{
ctx->items[0].skipfnc = skip_unusable;
ctx->items[0].skipfncvalue = ctrl;
}
}
else
{
/* Build the search context. */
for (n = 0, r = namelist; r; r = r->next)
n++;
/* CTX has space for a single search term at the end. Thus, we
need to allocate sizeof *CTX plus (n - 1) sizeof
CTX->ITEMS. */
ctx = xmalloc_clear (sizeof *ctx + (n - 1) * sizeof ctx->items);
ctx->nitems = n;
for (n = 0, r = namelist; r; r = r->next, n++)
{
gpg_error_t err;
err = classify_user_id (r->d, &ctx->items[n], 1);
if (ctx->items[n].exact)
ctx->exact = 1;
if (err)
{
xfree (ctx);
return gpg_err_code (err); /* FIXME: remove gpg_err_code. */
}
if (!include_unusable
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_LONG_KID
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR16
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR20
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR)
{
ctx->items[n].skipfnc = skip_unusable;
ctx->items[n].skipfncvalue = ctrl;
}
}
}
ctx->want_secret = want_secret;
ctx->kr_handle = keydb_new ();
if (!ctx->kr_handle)
{
rc = gpg_error_from_syserror ();
getkey_end (ctrl, ctx);
return rc;
}
if (!ret_kb)
ret_kb = &help_kb;
if (pk)
{
ctx->req_usage = pk->req_usage;
}
rc = lookup (ctrl, ctx, want_secret, ret_kb, &found_key);
if (!rc && pk)
{
pk_from_block (pk, *ret_kb, found_key);
}
release_kbnode (help_kb);
if (retctx) /* Caller wants the context. */
*retctx = ctx;
else
{
if (ret_kdbhd)
{
*ret_kdbhd = ctx->kr_handle;
ctx->kr_handle = NULL;
}
getkey_end (ctrl, ctx);
}
return rc;
}
/* Find a public key identified by NAME.
*
* If name appears to be a valid RFC822 mailbox (i.e., email
* address) and auto key lookup is enabled (no_akl == 0), then the
* specified auto key lookup methods (--auto-key-lookup) are used to
* import the key into the local keyring. Otherwise, just the local
* keyring is consulted.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! PK->REQ_USAGE is
* passed through to the lookup function and is a mask of
* PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this
* is non-zero, only keys with the specified usage will be returned.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* NAME is a string, which is turned into a search query using
* classify_user_id.
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* If RET_KDBHD is not NULL, then the new database handle used to
* conduct the search is returned in *RET_KDBHD. This can be used to
* get subsequent results using keydb_search_next or to modify the
* returned record. Note: in this case, no advanced filtering is done
* for subsequent results (e.g., PK->REQ_USAGE is not respected).
* Unlike RETCTX, this is always returned.
*
* If INCLUDE_UNUSABLE is set, then unusable keys (see the
* documentation for skip_unusable for an exact definition) are
* skipped unless they are looked up by key id or by fingerprint.
*
* If NO_AKL is set, then the auto key locate functionality is
* disabled and only the local key ring is considered. Note: the
* local key ring is consulted even if local is not in the
* --auto-key-locate option list!
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
int
get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
const char *name, KBNODE * ret_keyblock,
KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
{
int rc;
strlist_t namelist = NULL;
struct akl *akl;
int is_mbox;
int nodefault = 0;
int anylocalfirst = 0;
/* If RETCTX is not NULL, then RET_KDBHD must be NULL. */
log_assert (retctx == NULL || ret_kdbhd == NULL);
if (retctx)
*retctx = NULL;
/* Does NAME appear to be a mailbox (mail address)? */
is_mbox = is_valid_mailbox (name);
/* The auto-key-locate feature works as follows: there are a number
* of methods to look up keys. By default, the local keyring is
* tried first. Then, each method listed in the --auto-key-locate is
* tried in the order it appears.
*
* This can be changed as follows:
*
* - if nodefault appears anywhere in the list of options, then
* the local keyring is not tried first, or,
*
* - if local appears anywhere in the list of options, then the
* local keyring is not tried first, but in the order in which
* it was listed in the --auto-key-locate option.
*
* Note: we only save the search context in RETCTX if the local
* method is the first method tried (either explicitly or
* implicitly). */
if (!no_akl)
{
/* auto-key-locate is enabled. */
/* nodefault is true if "nodefault" or "local" appear. */
for (akl = opt.auto_key_locate; akl; akl = akl->next)
if (akl->type == AKL_NODEFAULT || akl->type == AKL_LOCAL)
{
nodefault = 1;
break;
}
/* anylocalfirst is true if "local" appears before any other
search methods (except "nodefault"). */
for (akl = opt.auto_key_locate; akl; akl = akl->next)
if (akl->type != AKL_NODEFAULT)
{
if (akl->type == AKL_LOCAL)
anylocalfirst = 1;
break;
}
}
if (!nodefault)
{
/* "nodefault" didn't occur. Thus, "local" is implicitly the
* first method to try. */
anylocalfirst = 1;
}
if (nodefault && is_mbox)
{
/* Either "nodefault" or "local" (explicitly) appeared in the
* auto key locate list and NAME appears to be an email address.
* Don't try the local keyring. */
rc = GPG_ERR_NO_PUBKEY;
}
else
{
/* Either "nodefault" and "local" don't appear in the auto key
* locate list (in which case we try the local keyring first) or
* NAME does not appear to be an email address (in which case we
* only try the local keyring). In this case, lookup NAME in
* the local keyring. */
add_to_strlist (&namelist, name);
rc = key_byname (ctrl, retctx, namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
}
/* If the requested name resembles a valid mailbox and automatic
retrieval has been enabled, we try to import the key. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox)
{
/* NAME wasn't present in the local keyring (or we didn't try
* the local keyring). Since the auto key locate feature is
* enabled and NAME appears to be an email address, try the auto
* locate feature. */
for (akl = opt.auto_key_locate; akl; akl = akl->next)
{
unsigned char *fpr = NULL;
size_t fpr_len;
int did_akl_local = 0;
int no_fingerprint = 0;
const char *mechanism = "?";
switch (akl->type)
{
case AKL_NODEFAULT:
/* This is a dummy mechanism. */
mechanism = "None";
rc = GPG_ERR_NO_PUBKEY;
break;
case AKL_LOCAL:
mechanism = "Local";
did_akl_local = 1;
if (retctx)
{
getkey_end (ctrl, *retctx);
*retctx = NULL;
}
add_to_strlist (&namelist, name);
rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
break;
case AKL_CERT:
mechanism = "DNS CERT";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_PKA:
mechanism = "PKA";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_DANE:
mechanism = "DANE";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_WKD:
mechanism = "WKD";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_wkd (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_LDAP:
mechanism = "LDAP";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_KEYSERVER:
/* Strictly speaking, we don't need to only use a valid
* mailbox for the getname search, but it helps cut down
* on the problem of searching for something like "john"
* and getting a whole lot of keys back. */
if (keyserver_any_configured (ctrl))
{
mechanism = "keyserver";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
opt.keyserver);
glo_ctrl.in_auto_key_retrieve--;
}
else
{
mechanism = "Unconfigured keyserver";
rc = GPG_ERR_NO_PUBKEY;
}
break;
case AKL_SPEC:
{
struct keyserver_spec *keyserver;
mechanism = akl->spec->uri;
keyserver = keyserver_match (akl->spec);
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl,
name, &fpr, &fpr_len, keyserver);
glo_ctrl.in_auto_key_retrieve--;
}
break;
}
/* Use the fingerprint of the key that we actually fetched.
* This helps prevent problems where the key that we fetched
* doesn't have the same name that we used to fetch it. In
* the case of CERT and PKA, this is an actual security
* requirement as the URL might point to a key put in by an
* attacker. By forcing the use of the fingerprint, we
* won't use the attacker's key here. */
if (!rc && fpr)
{
char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
free_strlist (namelist);
namelist = NULL;
bin2hex (fpr, fpr_len, fpr_string);
if (opt.verbose)
log_info ("auto-key-locate found fingerprint %s\n",
fpr_string);
add_to_strlist (&namelist, fpr_string);
}
else if (!rc && !fpr && !did_akl_local)
{ /* The acquisition method said no failure occurred, but
* it didn't return a fingerprint. That's a failure. */
no_fingerprint = 1;
rc = GPG_ERR_NO_PUBKEY;
}
xfree (fpr);
fpr = NULL;
if (!rc && !did_akl_local)
{ /* There was no error and we didn't do a local lookup.
* This means that we imported a key into the local
* keyring. Try to read the imported key from the
* keyring. */
if (retctx)
{
getkey_end (ctrl, *retctx);
*retctx = NULL;
}
rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
}
if (!rc)
{
/* Key found. */
if (opt.verbose)
log_info (_("automatically retrieved '%s' via %s\n"),
name, mechanism);
break;
}
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
|| opt.verbose || no_fingerprint)
log_info (_("error retrieving '%s' via %s: %s\n"),
name, mechanism,
no_fingerprint ? _("No fingerprint") : gpg_strerror (rc));
}
}
if (rc && retctx)
{
getkey_end (ctrl, *retctx);
*retctx = NULL;
}
if (retctx && *retctx)
{
log_assert (!(*retctx)->extra_list);
(*retctx)->extra_list = namelist;
}
else
free_strlist (namelist);
return rc;
}
/* Comparison machinery for get_best_pubkey_byname. */
/* First we have a struct to cache computed information about the key
* in question. */
struct pubkey_cmp_cookie
{
int valid; /* Is this cookie valid? */
PKT_public_key key; /* The key. */
PKT_user_id *uid; /* The matching UID packet. */
unsigned int validity; /* Computed validity of (KEY, UID). */
u32 creation_time; /* Creation time of the newest subkey
capable of encryption. */
};
/* Then we have a series of helper functions. */
static int
key_is_ok (const PKT_public_key *key)
{
return (! key->has_expired && ! key->flags.revoked
&& key->flags.valid && ! key->flags.disabled);
}
static int
uid_is_ok (const PKT_public_key *key, const PKT_user_id *uid)
{
return key_is_ok (key) && ! uid->flags.revoked;
}
static int
subkey_is_ok (const PKT_public_key *sub)
{
return ! sub->flags.revoked && sub->flags.valid && ! sub->flags.disabled;
}
/* Finally this function compares a NEW key to the former candidate
* OLD. Returns < 0 if the old key is worse, > 0 if the old key is
* better, == 0 if it is a tie. */
static int
pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old,
struct pubkey_cmp_cookie *new, KBNODE new_keyblock)
{
kbnode_t n;
new->creation_time = 0;
for (n = find_next_kbnode (new_keyblock, PKT_PUBLIC_SUBKEY);
n; n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY))
{
PKT_public_key *sub = n->pkt->pkt.public_key;
if ((sub->pubkey_usage & PUBKEY_USAGE_ENC) == 0)
continue;
if (! subkey_is_ok (sub))
continue;
if (sub->timestamp > new->creation_time)
new->creation_time = sub->timestamp;
}
for (n = find_next_kbnode (new_keyblock, PKT_USER_ID);
n; n = find_next_kbnode (n, PKT_USER_ID))
{
PKT_user_id *uid = n->pkt->pkt.user_id;
char *mbox = mailbox_from_userid (uid->name);
int match = mbox ? strcasecmp (name, mbox) == 0 : 0;
xfree (mbox);
if (! match)
continue;
new->uid = scopy_user_id (uid);
new->validity =
get_validity (ctrl, new_keyblock, &new->key, uid, NULL, 0) & TRUST_MASK;
new->valid = 1;
if (! old->valid)
return -1; /* No OLD key. */
if (! uid_is_ok (&old->key, old->uid) && uid_is_ok (&new->key, uid))
return -1; /* Validity of the NEW key is better. */
if (old->validity < new->validity)
return -1; /* Validity of the NEW key is better. */
if (old->validity == new->validity && uid_is_ok (&new->key, uid)
&& old->creation_time < new->creation_time)
return -1; /* Both keys are of the same validity, but the
NEW key is newer. */
}
/* Stick with the OLD key. */
return 1;
}
/* This function works like get_pubkey_byname, but if the name
* resembles a mail address, the results are ranked and only the best
* result is returned. */
gpg_error_t
get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable, int no_akl)
{
gpg_error_t err;
struct getkey_ctx_s *ctx = NULL;
if (retctx)
*retctx = NULL;
err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock,
NULL, include_unusable, no_akl);
if (err)
{
getkey_end (ctrl, ctx);
return err;
}
if (is_valid_mailbox (name) && ctx)
{
/* Rank results and return only the most relevant key. */
struct pubkey_cmp_cookie best = { 0 };
struct pubkey_cmp_cookie new = { 0 };
kbnode_t new_keyblock;
while (getkey_next (ctrl, ctx, &new.key, &new_keyblock) == 0)
{
int diff = pubkey_cmp (ctrl, name, &best, &new, new_keyblock);
release_kbnode (new_keyblock);
if (diff < 0)
{
/* New key is better. */
release_public_key_parts (&best.key);
free_user_id (best.uid);
best = new;
}
else if (diff > 0)
{
/* Old key is better. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
new.uid = NULL;
}
else
{
/* A tie. Keep the old key. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
new.uid = NULL;
}
}
getkey_end (ctrl, ctx);
ctx = NULL;
free_user_id (best.uid);
best.uid = NULL;
if (best.valid)
{
if (retctx || ret_keyblock)
{
ctx = xtrycalloc (1, sizeof **retctx);
if (! ctx)
err = gpg_error_from_syserror ();
else
{
ctx->kr_handle = keydb_new ();
if (! ctx->kr_handle)
{
err = gpg_error_from_syserror ();
xfree (ctx);
ctx = NULL;
if (retctx)
*retctx = NULL;
}
else
{
u32 *keyid = pk_keyid (&best.key);
ctx->exact = 1;
ctx->nitems = 1;
ctx->items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx->items[0].u.kid[0] = keyid[0];
ctx->items[0].u.kid[1] = keyid[1];
if (ret_keyblock)
{
release_kbnode (*ret_keyblock);
*ret_keyblock = NULL;
err = getkey_next (ctrl, ctx, NULL, ret_keyblock);
}
}
}
}
if (pk)
*pk = best.key;
else
release_public_key_parts (&best.key);
}
}
if (err && ctx)
{
getkey_end (ctrl, ctx);
ctx = NULL;
}
if (retctx && ctx)
*retctx = ctx;
else
getkey_end (ctrl, ctx);
return err;
}
/* Get a public key from a file.
*
* PK is the buffer to store the key. The caller needs to make sure
* that PK->REQ_USAGE is valid. PK->REQ_USAGE is passed through to
* the lookup function and is a mask of PUBKEY_USAGE_SIG,
* PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this is non-zero, only
* keys with the specified usage will be returned.
*
* FNAME is the file name. That file should contain exactly one
* keyblock.
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
* calling release_public_key_parts (or, if PK was malloced, using
* free_public_key).
*/
gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
err = read_key_from_file (ctrl, fname, &keyblock);
if (!err)
{
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. FIXME: Check whether this still holds. */
merge_selfsigs (ctrl, keyblock);
found_key = finish_lookup (keyblock, pk->req_usage, 0, 0, &infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
pk_from_block (pk, keyblock, found_key);
else
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
release_kbnode (keyblock);
return err;
}
/* Lookup a key with the specified fingerprint.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: this function does an exact search and thus the
* returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If PK->REQ_USAGE is set, it is used to filter the search results.
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
* documentation for finish_lookup to understand exactly how this is
* used.
*
* If R_KEYBLOCK is not NULL, then the first result's keyblock is
* returned in *R_KEYBLOCK. This should be freed using
* release_kbnode().
*
* FPRINT is a byte array whose contents is the fingerprint to use as
* the search term. FPRINT_LEN specifies the length of the
* fingerprint (in bytes). Currently, only 16 and 20-byte
* fingerprints are supported.
*
* FIXME: We should replace this with the _byname function. This can
* be done by creating a userID conforming to the unified fingerprint
* style. */
int
get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
const byte * fprint, size_t fprint_len)
{
int rc;
if (r_keyblock)
*r_keyblock = NULL;
if (fprint_len == 20 || fprint_len == 16)
{
struct getkey_ctx_s ctx;
KBNODE kb = NULL;
KBNODE found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1;
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
ctx.nitems = 1;
ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
: KEYDB_SEARCH_MODE_FPR20;
memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
if (pk)
ctx.req_usage = pk->req_usage;
rc = lookup (ctrl, &ctx, 0, &kb, &found_key);
if (!rc && pk)
pk_from_block (pk, kb, found_key);
if (!rc && r_keyblock)
{
*r_keyblock = kb;
kb = NULL;
}
release_kbnode (kb);
getkey_end (ctrl, &ctx);
}
else
rc = GPG_ERR_GENERAL; /* Oops */
return rc;
}
/* This function is similar to get_pubkey_byfprint, but it doesn't
* merge the self-signed data into the public key and subkeys or into
* the user ids. It also doesn't add the key to the user id cache.
* Further, this function ignores PK->REQ_USAGE.
*
* This function is intended to avoid recursion and, as such, should
* only be used in very specific situations.
*
* Like get_pubkey_byfprint, PK may be NULL. In that case, this
* function effectively just checks for the existence of the key. */
gpg_error_t
get_pubkey_byfprint_fast (PKT_public_key * pk,
const byte * fprint, size_t fprint_len)
{
gpg_error_t err;
KBNODE keyblock;
err = get_keyblock_byfprint_fast (&keyblock, NULL, fprint, fprint_len, 0);
if (!err)
{
if (pk)
copy_public_key (pk, keyblock->pkt->pkt.public_key);
release_kbnode (keyblock);
}
return err;
}
/* This function is similar to get_pubkey_byfprint_fast but returns a
* keydb handle at R_HD and the keyblock at R_KEYBLOCK. R_KEYBLOCK or
* R_HD may be NULL. If LOCK is set the handle has been opend in
* locked mode and keydb_disable_caching () has been called. On error
* R_KEYBLOCK is set to NULL but R_HD must be released by the caller;
* it may have a value of NULL, though. This allows to do an insert
* operation on a locked keydb handle. */
gpg_error_t
get_keyblock_byfprint_fast (kbnode_t *r_keyblock, KEYDB_HANDLE *r_hd,
const byte *fprint, size_t fprint_len, int lock)
{
gpg_error_t err;
KEYDB_HANDLE hd;
kbnode_t keyblock;
byte fprbuf[MAX_FINGERPRINT_LEN];
int i;
if (r_keyblock)
*r_keyblock = NULL;
if (r_hd)
*r_hd = NULL;
for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
fprbuf[i] = fprint[i];
while (i < MAX_FINGERPRINT_LEN)
fprbuf[i++] = 0;
hd = keydb_new ();
if (!hd)
return gpg_error_from_syserror ();
if (lock)
{
err = keydb_lock (hd);
if (err)
{
/* If locking did not work, we better don't return a handle
* at all - there was a reason that locking has been
* requested. */
keydb_release (hd);
return err;
}
keydb_disable_caching (hd);
}
/* Fo all other errors we return the handle. */
if (r_hd)
*r_hd = hd;
err = keydb_search_fpr (hd, fprbuf);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
if (!r_hd)
keydb_release (hd);
return gpg_error (GPG_ERR_NO_PUBKEY);
}
err = keydb_get_keyblock (hd, &keyblock);
if (err)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (err));
if (!r_hd)
keydb_release (hd);
return gpg_error (GPG_ERR_NO_PUBKEY);
}
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|| keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
/* Not caching key here since it won't have all of the fields
properly set. */
if (r_keyblock)
*r_keyblock = keyblock;
else
release_kbnode (keyblock);
if (!r_hd)
keydb_release (hd);
return 0;
}
const char *
parse_def_secret_key (ctrl_t ctrl)
{
KEYDB_HANDLE hd = NULL;
strlist_t t;
static int warned;
for (t = opt.def_secret_key; t; t = t->next)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
KBNODE kb;
KBNODE node;
err = classify_user_id (t->d, &desc, 1);
if (err)
{
log_error (_("secret key \"%s\" not found: %s\n"),
t->d, gpg_strerror (err));
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"), "--default-key");
continue;
}
if (! hd)
{
hd = keydb_new ();
if (!hd)
return NULL;
}
else
keydb_search_reset (hd);
err = keydb_search (hd, &desc, 1, NULL);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
continue;
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
t = NULL;
break;
}
err = keydb_get_keyblock (hd, &kb);
if (err)
{
log_error (_("error reading keyblock: %s\n"),
gpg_strerror (err));
continue;
}
merge_selfsigs (ctrl, kb);
err = gpg_error (GPG_ERR_NO_SECKEY);
node = kb;
do
{
PKT_public_key *pk = node->pkt->pkt.public_key;
/* Check that the key has the signing capability. */
if (! (pk->pubkey_usage & PUBKEY_USAGE_SIG))
continue;
/* Check if the key is valid. */
if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "revoked");
continue;
}
if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "expired");
continue;
}
if (pk_is_disabled (pk))
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "disabled");
continue;
}
err = agent_probe_secret_key (ctrl, pk);
if (! err)
/* This is a valid key. */
break;
}
while ((node = find_next_kbnode (node, PKT_PUBLIC_SUBKEY)));
release_kbnode (kb);
if (err)
{
if (! warned && ! opt.quiet)
{
log_info (_("Warning: not using '%s' as default key: %s\n"),
t->d, gpg_strerror (GPG_ERR_NO_SECKEY));
print_reported_error (err, GPG_ERR_NO_SECKEY);
}
}
else
{
if (! warned && ! opt.quiet)
log_info (_("using \"%s\" as default secret key for signing\n"),
t->d);
break;
}
}
if (! warned && opt.def_secret_key && ! t)
log_info (_("all values passed to '%s' ignored\n"),
"--default-key");
warned = 1;
if (hd)
keydb_release (hd);
if (t)
return t->d;
return NULL;
}
/* Look up a secret key.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If --default-key was set, then the specified key is looked up. (In
* this case, the default key is returned even if it is considered
* unusable. See the documentation for skip_unusable for exactly what
* this means.)
*
* Otherwise, this initiates a DB scan that returns all keys that are
* usable (see previous paragraph for exactly what usable means) and
* for which a secret key is available.
*
* This function returns the first match. Additional results can be
* returned using getkey_next. */
gpg_error_t
get_seckey_default (ctrl_t ctrl, PKT_public_key *pk)
{
gpg_error_t err;
strlist_t namelist = NULL;
int include_unusable = 1;
const char *def_secret_key = parse_def_secret_key (ctrl);
if (def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else
include_unusable = 0;
err = key_byname (ctrl, NULL, namelist, pk, 1, include_unusable, NULL, NULL);
free_strlist (namelist);
return err;
}
/* Search for keys matching some criteria.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If NAMES is not NULL, then a search query is constructed using
* classify_user_id on each of the strings in the list. (Recall: the
* database does an OR of the terms, not an AND.) If NAMES is
* NULL, then all results are returned.
*
* If WANT_SECRET is set, then only keys with an available secret key
* (either locally or via key registered on a smartcard) are returned.
*
* This function does not skip unusable keys (see the documentation
* for skip_unusable for an exact definition).
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
gpg_error_t
getkey_bynames (ctrl_t ctrl, getkey_ctx_t *retctx, PKT_public_key *pk,
strlist_t names, int want_secret, kbnode_t *ret_keyblock)
{
return key_byname (ctrl, retctx, names, pk, want_secret, 1,
ret_keyblock, NULL);
}
/* Search for one key matching some criteria.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If NAME is not NULL, then a search query is constructed using
* classify_user_id on the string. In this case, even unusable keys
* (see the documentation for skip_unusable for an exact definition of
* unusable) are returned. Otherwise, if --default-key was set, then
* that key is returned (even if it is unusable). If neither of these
* conditions holds, then the first usable key is returned.
*
* If WANT_SECRET is set, then only keys with an available secret key
* (either locally or via key registered on a smartcard) are returned.
*
* This function does not skip unusable keys (see the documentation
* for skip_unusable for an exact definition).
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found.
*
* FIXME: We also have the get_pubkey_byname function which has a
* different semantic. Should be merged with this one. */
gpg_error_t
getkey_byname (ctrl_t ctrl, getkey_ctx_t *retctx, PKT_public_key *pk,
const char *name, int want_secret, kbnode_t *ret_keyblock)
{
gpg_error_t err;
strlist_t namelist = NULL;
int with_unusable = 1;
const char *def_secret_key = NULL;
if (want_secret && !name)
def_secret_key = parse_def_secret_key (ctrl);
if (want_secret && !name && def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else if (name)
add_to_strlist (&namelist, name);
else
with_unusable = 0;
err = key_byname (ctrl, retctx, namelist, pk, want_secret, with_unusable,
ret_keyblock, NULL);
/* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
WANT_SECRET has been used. */
free_strlist (namelist);
return err;
}
/* Return the next search result.
*
* If PK is not NULL, the public key of the next result is returned in
* *PK. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xmalloc, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* RET_KEYBLOCK can be given as NULL; if it is not NULL it the entire
* found keyblock is returned which must be released with
* release_kbnode. If the function returns an error NULL is stored at
* RET_KEYBLOCK.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
gpg_error_t
getkey_next (ctrl_t ctrl, getkey_ctx_t ctx,
PKT_public_key *pk, kbnode_t *ret_keyblock)
{
int rc; /* Fixme: Make sure this is proper gpg_error */
KBNODE keyblock = NULL;
KBNODE found_key = NULL;
/* We need to disable the caching so that for an exact key search we
won't get the result back from the cache and thus end up in an
endless loop. The endless loop can occur, because the cache is
used without respecting the current file pointer! */
keydb_disable_caching (ctx->kr_handle);
/* FOUND_KEY is only valid as long as RET_KEYBLOCK is. If the
* caller wants PK, but not RET_KEYBLOCK, we need hand in our own
* keyblock. */
if (pk && ret_keyblock == NULL)
ret_keyblock = &keyblock;
rc = lookup (ctrl, ctx, ctx->want_secret,
ret_keyblock, pk ? &found_key : NULL);
if (!rc && pk)
{
log_assert (found_key);
pk_from_block (pk, NULL, found_key);
release_kbnode (keyblock);
}
return rc;
}
/* Release any resources used by a key listing context. This must be
* called on the context returned by, e.g., getkey_byname. */
void
getkey_end (ctrl_t ctrl, getkey_ctx_t ctx)
{
if (ctx)
{
#ifdef HAVE_W32_SYSTEM
/* FIXME: This creates a big regression for Windows because the
* keyring is only released after the global ctrl is released.
* So if an operation does a getkey and then tries to modify the
* keyring it will fail on Windows with a sharing violation. We
* need to modify all keyring write operations to also take the
* ctrl and close the cached_getkey_kdb handle to make writing
* work. See: GnuPG-bug-id: 3097 */
(void)ctrl;
keydb_release (ctx->kr_handle);
#else /*!HAVE_W32_SYSTEM*/
if (ctrl && !ctrl->cached_getkey_kdb)
ctrl->cached_getkey_kdb = ctx->kr_handle;
else
keydb_release (ctx->kr_handle);
#endif /*!HAVE_W32_SYSTEM*/
free_strlist (ctx->extra_list);
if (!ctx->not_allocated)
xfree (ctx);
}
}
/************************************************
************* Merging stuff ********************
************************************************/
/* Set the mainkey_id fields for all keys in KEYBLOCK. This is
* usually done by merge_selfsigs but at some places we only need the
* main_kid not a full merge. The function also guarantees that all
* pk->keyids are computed. */
void
setup_main_keyids (kbnode_t keyblock)
{
u32 kid[2], mainkid[2];
kbnode_t kbctx, node;
PKT_public_key *pk;
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
BUG ();
pk = keyblock->pkt->pkt.public_key;
keyid_from_pk (pk, mainkid);
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, kid); /* Make sure pk->keyid is set. */
if (!pk->main_keyid[0] && !pk->main_keyid[1])
{
pk->main_keyid[0] = mainkid[0];
pk->main_keyid[1] = mainkid[1];
}
}
}
/* KEYBLOCK corresponds to a public key block. This function merges
* much of the information from the self-signed data into the public
* key, public subkey and user id data structures. If you use the
* high-level search API (e.g., get_pubkey) for looking up key blocks,
* then you don't need to call this function. This function is
* useful, however, if you change the keyblock, e.g., by adding or
* removing a self-signed data packet. */
void
merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
{
if (!keyblock)
;
else if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
merge_selfsigs (ctrl, keyblock);
else
log_debug ("FIXME: merging secret key blocks is not anymore available\n");
}
static int
parse_key_usage (PKT_signature * sig)
{
int key_usage = 0;
const byte *p;
size_t n;
byte flags;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n);
if (p && n)
{
/* First octet of the keyflags. */
flags = *p;
if (flags & 1)
{
key_usage |= PUBKEY_USAGE_CERT;
flags &= ~1;
}
if (flags & 2)
{
key_usage |= PUBKEY_USAGE_SIG;
flags &= ~2;
}
/* We do not distinguish between encrypting communications and
encrypting storage. */
if (flags & (0x04 | 0x08))
{
key_usage |= PUBKEY_USAGE_ENC;
flags &= ~(0x04 | 0x08);
}
if (flags & 0x20)
{
key_usage |= PUBKEY_USAGE_AUTH;
flags &= ~0x20;
}
if (flags)
key_usage |= PUBKEY_USAGE_UNKNOWN;
if (!key_usage)
key_usage |= PUBKEY_USAGE_NONE;
}
else if (p) /* Key flags of length zero. */
key_usage |= PUBKEY_USAGE_NONE;
/* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
capability that we do not handle. This serves to distinguish
between a zero key usage which we handle as the default
capabilities for that algorithm, and a usage that we do not
handle. Likewise we use PUBKEY_USAGE_NONE to indicate that
key_flags have been given but they do not specify any usage. */
return key_usage;
}
/* Apply information from SIGNODE (which is the valid self-signature
* associated with that UID) to the UIDNODE:
* - weather the UID has been revoked
* - assumed creation date of the UID
* - temporary store the keyflags here
* - temporary store the key expiration time here
* - mark whether the primary user ID flag hat been set.
* - store the preferences
*/
static void
fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
{
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
PKT_signature *sig = signode->pkt->pkt.signature;
const byte *p, *sym, *aead, *hash, *zip;
size_t n, nsym, naead, nhash, nzip;
sig->flags.chosen_selfsig = 1;/* We chose this one. */
uid->created = 0; /* Not created == invalid. */
if (IS_UID_REV (sig))
{
uid->flags.revoked = 1;
return; /* Has been revoked. */
}
else
uid->flags.revoked = 0;
uid->expiredate = sig->expiredate;
if (sig->flags.expired)
{
uid->flags.expired = 1;
return; /* Has expired. */
}
else
uid->flags.expired = 0;
uid->created = sig->timestamp; /* This one is okay. */
uid->selfsigversion = sig->version;
/* If we got this far, it's not expired :) */
uid->flags.expired = 0;
/* Store the key flags in the helper variable for later processing. */
uid->help_key_usage = parse_key_usage (sig);
/* Ditto for the key expiration. */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
uid->help_key_expire = keycreated + buf32_to_u32 (p);
else
uid->help_key_expire = 0;
/* Set the primary user ID flag - we will later wipe out some
* of them to only have one in our keyblock. */
uid->flags.primary = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p)
uid->flags.primary = 2;
/* We could also query this from the unhashed area if it is not in
* the hased area and then later try to decide which is the better
* there should be no security problem with this.
* For now we only look at the hashed one. */
/* Now build the preferences list. These must come from the
hashed section so nobody can modify the ciphers a key is
willing to accept. */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
sym = p;
nsym = p ? n : 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n);
aead = p;
naead = p ? n : 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
hash = p;
nhash = p ? n : 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR, &n);
zip = p;
nzip = p ? n : 0;
if (uid->prefs)
xfree (uid->prefs);
n = nsym + naead + nhash + nzip;
if (!n)
uid->prefs = NULL;
else
{
uid->prefs = xmalloc (sizeof (*uid->prefs) * (n + 1));
n = 0;
for (; nsym; nsym--, n++)
{
uid->prefs[n].type = PREFTYPE_SYM;
uid->prefs[n].value = *sym++;
}
for (; naead; naead--, n++)
{
uid->prefs[n].type = PREFTYPE_AEAD;
uid->prefs[n].value = *aead++;
}
for (; nhash; nhash--, n++)
{
uid->prefs[n].type = PREFTYPE_HASH;
uid->prefs[n].value = *hash++;
}
for (; nzip; nzip--, n++)
{
uid->prefs[n].type = PREFTYPE_ZIP;
uid->prefs[n].value = *zip++;
}
uid->prefs[n].type = PREFTYPE_NONE; /* End of list marker */
uid->prefs[n].value = 0;
}
/* See whether we have the MDC feature. */
uid->flags.mdc = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x01))
uid->flags.mdc = 1;
/* See whether we have the AEAD feature. */
uid->flags.aead = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x02))
uid->flags.aead = 1;
/* And the keyserver modify flag. */
uid->flags.ks_modify = 1;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
if (p && n && (p[0] & 0x80))
uid->flags.ks_modify = 0;
}
static void
sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo)
{
rinfo->date = sig->timestamp;
rinfo->algo = sig->pubkey_algo;
rinfo->keyid[0] = sig->keyid[0];
rinfo->keyid[1] = sig->keyid[1];
}
/* Given a keyblock, parse the key block and extract various pieces of
* information and save them with the primary key packet and the user
* id packets. For instance, some information is stored in signature
* packets. We find the latest such valid packet (since the user can
* change that information) and copy its contents into the
* PKT_public_key.
*
* Note that R_REVOKED may be set to 0, 1 or 2.
*
* This function fills in the following fields in the primary key's
* keyblock:
*
* main_keyid (computed)
* revkey / numrevkeys (derived from self signed key data)
* flags.valid (whether we have at least 1 self-sig)
* flags.maybe_revoked (whether a designed revoked the key, but
* we are missing the key to check the sig)
* selfsigversion (highest version of any valid self-sig)
* pubkey_usage (derived from most recent self-sig or most
* recent user id)
* has_expired (various sources)
* expiredate (various sources)
*
* See the documentation for fixup_uidnode for how the user id packets
* are modified. In addition to that the primary user id's is_primary
* field is set to 1 and the other user id's is_primary are set to 0.
*/
static void
merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
struct revoke_info *rinfo)
{
PKT_public_key *pk = NULL;
KBNODE k;
u32 kid[2];
u32 sigdate, uiddate, uiddate2;
KBNODE signode, uidnode, uidnode2;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
u32 keytimestamp = 0;
u32 key_expire = 0;
int key_expire_seen = 0;
byte sigversion = 0;
*r_revoked = 0;
memset (rinfo, 0, sizeof (*rinfo));
/* Section 11.1 of RFC 4880 determines the order of packets within a
* message. There are three sections, which must occur in the
* following order: the public key, the user ids and user attributes
* and the subkeys. Within each section, each primary packet (e.g.,
* a user id packet) is followed by one or more signature packets,
* which modify that packet. */
/* According to Section 11.1 of RFC 4880, the public key must be the
first packet. Note that parse_keyblock_image ensures that the
first packet is the public key. */
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
BUG ();
pk = keyblock->pkt->pkt.public_key;
keytimestamp = pk->timestamp;
keyid_from_pk (pk, kid);
pk->main_keyid[0] = kid[0];
pk->main_keyid[1] = kid[1];
if (pk->version < 4)
{
/* Before v4 the key packet itself contains the expiration date
* and there was no way to change it, so we start with the one
* from the key packet. */
key_expire = pk->max_expiredate;
key_expire_seen = 1;
}
/* First pass:
*
* - Find the latest direct key self-signature. We assume that the
* newest one overrides all others.
*
* - Determine whether the key has been revoked.
*
* - Gather all revocation keys (unlike other data, we don't just
* take them from the latest self-signed packet).
*
* - Determine max (sig[...]->version).
*/
/* Reset this in case this key was already merged. */
xfree (pk->revkey);
pk->revkey = NULL;
pk->numrevkeys = 0;
signode = NULL;
sigdate = 0; /* Helper variable to find the latest signature. */
/* According to Section 11.1 of RFC 4880, the public key comes first
* and is immediately followed by any signature packets that modify
* it. */
for (k = keyblock;
k && k->pkt->pkttype != PKT_USER_ID
&& k->pkt->pkttype != PKT_ATTRIBUTE
&& k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
{ /* Self sig. */
if (check_key_signature (ctrl, keyblock, k, NULL))
; /* Signature did not verify. */
else if (IS_KEY_REV (sig))
{
/* Key has been revoked - there is no way to
* override such a revocation, so we theoretically
* can stop now. We should not cope with expiration
* times for revocations here because we have to
* assume that an attacker can generate all kinds of
* signatures. However due to the fact that the key
* has been revoked it does not harm either and by
* continuing we gather some more info on that
* key. */
*r_revoked = 1;
sig_to_revoke_info (sig, rinfo);
}
else if (IS_KEY_SIG (sig))
{
/* Add the indicated revocations keys from all
* signatures not just the latest. We do this
* because you need multiple 1F sigs to properly
* handle revocation keys (PGP does it this way, and
* a revocation key could be sensitive and hence in
* a different signature). */
if (sig->revkey)
{
int i;
pk->revkey =
xrealloc (pk->revkey, sizeof (struct revocation_key) *
(pk->numrevkeys + sig->numrevkeys));
for (i = 0; i < sig->numrevkeys; i++)
memcpy (&pk->revkey[pk->numrevkeys++],
&sig->revkey[i],
sizeof (struct revocation_key));
}
if (sig->timestamp >= sigdate)
{ /* This is the latest signature so far. */
if (sig->flags.expired)
; /* Signature has expired - ignore it. */
else
{
sigdate = sig->timestamp;
signode = k;
if (sig->version > sigversion)
sigversion = sig->version;
}
}
}
}
}
}
/* Remove dupes from the revocation keys. */
if (pk->revkey)
{
int i, j, x, changed = 0;
for (i = 0; i < pk->numrevkeys; i++)
{
for (j = i + 1; j < pk->numrevkeys; j++)
{
if (memcmp (&pk->revkey[i], &pk->revkey[j],
sizeof (struct revocation_key)) == 0)
{
/* remove j */
for (x = j; x < pk->numrevkeys - 1; x++)
pk->revkey[x] = pk->revkey[x + 1];
pk->numrevkeys--;
j--;
changed = 1;
}
}
}
if (changed)
pk->revkey = xrealloc (pk->revkey,
pk->numrevkeys *
sizeof (struct revocation_key));
}
/* SIGNODE is the 1F signature packet with the latest creation time.
* Extract some information from it. */
if (signode)
{
/* Some information from a direct key signature take precedence
* over the same information given in UID sigs. */
PKT_signature *sig = signode->pkt->pkt.signature;
const byte *p;
key_usage = parse_key_usage (sig);
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
{
key_expire = keytimestamp + buf32_to_u32 (p);
key_expire_seen = 1;
}
/* Mark that key as valid: One direct key signature should
* render a key as valid. */
pk->flags.valid = 1;
}
/* Pass 1.5: Look for key revocation signatures that were not made
* by the key (i.e. did a revocation key issue a revocation for
* us?). Only bother to do this if there is a revocation key in the
* first place and we're not revoked already. */
if (!*r_revoked && pk->revkey)
for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (IS_KEY_REV (sig) &&
(sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1]))
{
int rc = check_revocation_keys (ctrl, pk, sig);
if (rc == 0)
{
*r_revoked = 2;
sig_to_revoke_info (sig, rinfo);
/* Don't continue checking since we can't be any
* more revoked than this. */
break;
}
else if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
pk->flags.maybe_revoked = 1;
/* A failure here means the sig did not verify, was
* not issued by a revocation key, or a revocation
* key loop was broken. If a revocation key isn't
* findable, however, the key might be revoked and
* we don't know it. */
/* Fixme: In the future handle subkey and cert
* revocations? PGP doesn't, but it's in 2440. */
}
}
}
/* Second pass: Look at the self-signature of all user IDs. */
/* According to RFC 4880 section 11.1, user id and attribute packets
* are in the second section, after the public key packet and before
* the subkey packets. */
signode = uidnode = NULL;
sigdate = 0; /* Helper variable to find the latest signature in one UID. */
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID || k->pkt->pkttype == PKT_ATTRIBUTE)
{ /* New user id packet. */
/* Apply the data from the most recent self-signed packet to
* the preceding user id packet. */
if (uidnode && signode)
{
fixup_uidnode (uidnode, signode, keytimestamp);
pk->flags.valid = 1;
}
/* Clear SIGNODE. The only relevant self-signed data for
* UIDNODE follows it. */
if (k->pkt->pkttype == PKT_USER_ID)
uidnode = k;
else
uidnode = NULL;
signode = NULL;
sigdate = 0;
}
else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
{
if (check_key_signature (ctrl, keyblock, k, NULL))
; /* signature did not verify */
else if ((IS_UID_SIG (sig) || IS_UID_REV (sig))
&& sig->timestamp >= sigdate)
{
/* Note: we allow invalidation of cert revocations
* by a newer signature. An attacker can't use this
* because a key should be revoked with a key revocation.
* The reason why we have to allow for that is that at
* one time an email address may become invalid but later
* the same email address may become valid again (hired,
* fired, hired again). */
sigdate = sig->timestamp;
signode = k;
signode->pkt->pkt.signature->flags.chosen_selfsig = 0;
if (sig->version > sigversion)
sigversion = sig->version;
}
}
}
}
if (uidnode && signode)
{
fixup_uidnode (uidnode, signode, keytimestamp);
pk->flags.valid = 1;
}
/* If the key isn't valid yet, and we have
* --allow-non-selfsigned-uid set, then force it valid. */
if (!pk->flags.valid && opt.allow_non_selfsigned_uid)
{
if (opt.verbose)
log_info (_("Invalid key %s made valid by"
" --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
pk->flags.valid = 1;
}
/* The key STILL isn't valid, so try and find an ultimately
* trusted signature. */
if (!pk->flags.valid)
{
uidnode = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
uidnode = k;
else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1])
{
PKT_public_key *ultimate_pk;
ultimate_pk = xmalloc_clear (sizeof (*ultimate_pk));
/* We don't want to use the full get_pubkey to avoid
* infinite recursion in certain cases. There is no
* reason to check that an ultimately trusted key is
* still valid - if it has been revoked the user
* should also remove the ultimate trust flag. */
if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
&& check_key_signature2 (ctrl,
keyblock, k, ultimate_pk,
NULL, NULL, NULL, NULL) == 0
&& get_ownertrust (ctrl, ultimate_pk) == TRUST_ULTIMATE)
{
free_public_key (ultimate_pk);
pk->flags.valid = 1;
break;
}
free_public_key (ultimate_pk);
}
}
}
}
/* Record the highest selfsig version so we know if this is a v3 key
* through and through, or a v3 key with a v4 selfsig somewhere.
* This is useful in a few places to know if the key must be treated
* as PGP2-style or OpenPGP-style. Note that a selfsig revocation
* with a higher version number will also raise this value. This is
* okay since such a revocation must be issued by the user (i.e. it
* cannot be issued by someone else to modify the key behavior.) */
pk->selfsigversion = sigversion;
/* Now that we had a look at all user IDs we can now get some
* information from those user IDs. */
if (!key_usage)
{
/* Find the latest user ID with key flags set. */
uiddate = 0; /* Helper to find the latest user ID. */
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->help_key_usage && uid->created > uiddate)
{
key_usage = uid->help_key_usage;
uiddate = uid->created;
}
}
}
}
if (!key_usage)
{
/* No key flags at all: get it from the algo. */
key_usage = openpgp_pk_algo_usage (pk->pubkey_algo);
}
else
{
/* Check that the usage matches the usage as given by the algo. */
int x = openpgp_pk_algo_usage (pk->pubkey_algo);
if (x) /* Mask it down to the actual allowed usage. */
key_usage &= x;
}
/* Whatever happens, it's a primary key, so it can certify. */
pk->pubkey_usage = key_usage | PUBKEY_USAGE_CERT;
if (!key_expire_seen)
{
/* Find the latest valid user ID with a key expiration set
* Note, that this may be a different one from the above because
* some user IDs may have no expiration date set. */
uiddate = 0;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->help_key_expire && uid->created > uiddate)
{
key_expire = uid->help_key_expire;
uiddate = uid->created;
}
}
}
}
/* Currently only v3 keys have a maximum expiration date, but I'll
* bet v5 keys get this feature again. */
if (key_expire == 0
|| (pk->max_expiredate && key_expire > pk->max_expiredate))
key_expire = pk->max_expiredate;
pk->has_expired = key_expire >= curtime ? 0 : key_expire;
pk->expiredate = key_expire;
/* Fixme: we should see how to get rid of the expiretime fields but
* this needs changes at other places too. */
/* And now find the real primary user ID and delete all others. */
uiddate = uiddate2 = 0;
uidnode = uidnode2 = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->flags.primary)
{
if (uid->created > uiddate)
{
uiddate = uid->created;
uidnode = k;
}
else if (uid->created == uiddate && uidnode)
{
/* The dates are equal, so we need to do a different
* (and arbitrary) comparison. This should rarely,
* if ever, happen. It's good to try and guarantee
* that two different GnuPG users with two different
* keyrings at least pick the same primary. */
if (cmp_user_ids (uid, uidnode->pkt->pkt.user_id) > 0)
uidnode = k;
}
}
else
{
if (uid->created > uiddate2)
{
uiddate2 = uid->created;
uidnode2 = k;
}
else if (uid->created == uiddate2 && uidnode2)
{
if (cmp_user_ids (uid, uidnode2->pkt->pkt.user_id) > 0)
uidnode2 = k;
}
}
}
}
if (uidnode)
{
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID &&
!k->pkt->pkt.user_id->attrib_data)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (k != uidnode)
uid->flags.primary = 0;
}
}
}
else if (uidnode2)
{
/* None is flagged primary - use the latest user ID we have,
* and disambiguate with the arbitrary packet comparison. */
uidnode2->pkt->pkt.user_id->flags.primary = 1;
}
else
{
/* None of our uids were self-signed, so pick the one that
* sorts first to be the primary. This is the best we can do
* here since there are no self sigs to date the uids. */
uidnode = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data)
{
if (!uidnode)
{
uidnode = k;
uidnode->pkt->pkt.user_id->flags.primary = 1;
continue;
}
else
{
if (cmp_user_ids (k->pkt->pkt.user_id,
uidnode->pkt->pkt.user_id) > 0)
{
uidnode->pkt->pkt.user_id->flags.primary = 0;
uidnode = k;
uidnode->pkt->pkt.user_id->flags.primary = 1;
}
else
{
/* just to be safe: */
k->pkt->pkt.user_id->flags.primary = 0;
}
}
}
}
}
}
/* Convert a buffer to a signature. Useful for 0x19 embedded sigs.
* Caller must free the signature when they are done. */
static PKT_signature *
buf_to_sig (const byte * buf, size_t len)
{
PKT_signature *sig = xmalloc_clear (sizeof (PKT_signature));
IOBUF iobuf = iobuf_temp_with_content (buf, len);
int save_mode = set_packet_list_mode (0);
if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0)
{
xfree (sig);
sig = NULL;
}
set_packet_list_mode (save_mode);
iobuf_close (iobuf);
return sig;
}
/* Use the self-signed data to fill in various fields in subkeys.
*
* KEYBLOCK is the whole keyblock. SUBNODE is the subkey to fill in.
*
* Sets the following fields on the subkey:
*
* main_keyid
* flags.valid if the subkey has a valid self-sig binding
* flags.revoked
* flags.backsig
* pubkey_usage
* has_expired
* expired_date
*
* On this subkey's most revent valid self-signed packet, the
* following field is set:
*
* flags.chosen_selfsig
*/
static void
merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
{
PKT_public_key *mainpk = NULL, *subpk = NULL;
PKT_signature *sig;
KBNODE k;
u32 mainkid[2];
u32 sigdate = 0;
KBNODE signode;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
u32 keytimestamp = 0;
u32 key_expire = 0;
const byte *p;
if (subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY)
BUG ();
mainpk = keyblock->pkt->pkt.public_key;
if (mainpk->version < 4)
return;/* (actually this should never happen) */
keyid_from_pk (mainpk, mainkid);
subpk = subnode->pkt->pkt.public_key;
keytimestamp = subpk->timestamp;
subpk->flags.valid = 0;
subpk->flags.exact = 0;
subpk->main_keyid[0] = mainpk->main_keyid[0];
subpk->main_keyid[1] = mainpk->main_keyid[1];
/* Find the latest key binding self-signature. */
signode = NULL;
sigdate = 0; /* Helper to find the latest signature. */
for (k = subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
sig = k->pkt->pkt.signature;
if (sig->keyid[0] == mainkid[0] && sig->keyid[1] == mainkid[1])
{
if (check_key_signature (ctrl, keyblock, k, NULL))
; /* Signature did not verify. */
else if (IS_SUBKEY_REV (sig))
{
/* Note that this means that the date on a
* revocation sig does not matter - even if the
* binding sig is dated after the revocation sig,
* the subkey is still marked as revoked. This
* seems ok, as it is just as easy to make new
* subkeys rather than re-sign old ones as the
* problem is in the distribution. Plus, PGP (7)
* does this the same way. */
subpk->flags.revoked = 1;
sig_to_revoke_info (sig, &subpk->revoked);
/* Although we could stop now, we continue to
* figure out other information like the old expiration
* time. */
}
else if (IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate)
{
if (sig->flags.expired)
; /* Signature has expired - ignore it. */
else
{
sigdate = sig->timestamp;
signode = k;
signode->pkt->pkt.signature->flags.chosen_selfsig = 0;
}
}
}
}
}
/* No valid key binding. */
if (!signode)
return;
sig = signode->pkt->pkt.signature;
sig->flags.chosen_selfsig = 1; /* So we know which selfsig we chose later. */
key_usage = parse_key_usage (sig);
if (!key_usage)
{
/* No key flags at all: get it from the algo. */
key_usage = openpgp_pk_algo_usage (subpk->pubkey_algo);
}
else
{
/* Check that the usage matches the usage as given by the algo. */
int x = openpgp_pk_algo_usage (subpk->pubkey_algo);
if (x) /* Mask it down to the actual allowed usage. */
key_usage &= x;
}
subpk->pubkey_usage = key_usage;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
key_expire = keytimestamp + buf32_to_u32 (p);
else
key_expire = 0;
subpk->has_expired = key_expire >= curtime ? 0 : key_expire;
subpk->expiredate = key_expire;
/* Algo doesn't exist. */
if (openpgp_pk_test_algo (subpk->pubkey_algo))
return;
subpk->flags.valid = 1;
/* Find the most recent 0x19 embedded signature on our self-sig. */
if (!subpk->flags.backsig)
{
int seq = 0;
size_t n;
PKT_signature *backsig = NULL;
sigdate = 0;
/* We do this while() since there may be other embedded
* signatures in the future. We only want 0x19 here. */
while ((p = enum_sig_subpkt (sig->hashed,
SIGSUBPKT_SIGNATURE, &n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
PKT_signature *tempsig = buf_to_sig (p, n);
if (tempsig)
{
if (tempsig->timestamp > sigdate)
{
if (backsig)
free_seckey_enc (backsig);
backsig = tempsig;
sigdate = backsig->timestamp;
}
else
free_seckey_enc (tempsig);
}
}
seq = 0;
/* It is safe to have this in the unhashed area since the 0x19
* is located on the selfsig for convenience, not security. */
while ((p = enum_sig_subpkt (sig->unhashed, SIGSUBPKT_SIGNATURE,
&n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
PKT_signature *tempsig = buf_to_sig (p, n);
if (tempsig)
{
if (tempsig->timestamp > sigdate)
{
if (backsig)
free_seckey_enc (backsig);
backsig = tempsig;
sigdate = backsig->timestamp;
}
else
free_seckey_enc (tempsig);
}
}
if (backsig)
{
/* At this point, backsig contains the most recent 0x19 sig.
* Let's see if it is good. */
/* 2==valid, 1==invalid, 0==didn't check */
if (check_backsig (mainpk, subpk, backsig) == 0)
subpk->flags.backsig = 2;
else
subpk->flags.backsig = 1;
free_seckey_enc (backsig);
}
}
}
/* Merge information from the self-signatures with the public key,
* subkeys and user ids to make using them more easy.
*
* See documentation for merge_selfsigs_main, merge_selfsigs_subkey
* and fixup_uidnode for exactly which fields are updated. */
static void
merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
{
KBNODE k;
int revoked;
struct revoke_info rinfo;
PKT_public_key *main_pk;
prefitem_t *prefs;
unsigned int mdc_feature;
unsigned int aead_feature;
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
{
log_error ("expected public key but found secret key "
"- must stop\n");
/* We better exit here because a public key is expected at
* other places too. FIXME: Figure this out earlier and
* don't get to here at all */
g10_exit (1);
}
BUG ();
}
merge_selfsigs_main (ctrl, keyblock, &revoked, &rinfo);
/* Now merge in the data from each of the subkeys. */
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
merge_selfsigs_subkey (ctrl, keyblock, k);
}
}
main_pk = keyblock->pkt->pkt.public_key;
if (revoked || main_pk->has_expired || !main_pk->flags.valid)
{
/* If the primary key is revoked, expired, or invalid we
* better set the appropriate flags on that key and all
* subkeys. */
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
PKT_public_key *pk = k->pkt->pkt.public_key;
if (!main_pk->flags.valid)
pk->flags.valid = 0;
if (revoked && !pk->flags.revoked)
{
pk->flags.revoked = revoked;
memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
}
if (main_pk->has_expired)
pk->has_expired = main_pk->has_expired;
}
}
return;
}
/* Set the preference list of all keys to those of the primary real
* user ID. Note: we use these preferences when we don't know by
* which user ID the key has been selected.
* fixme: we should keep atoms of commonly used preferences or
* use reference counting to optimize the preference lists storage.
* FIXME: it might be better to use the intersection of
* all preferences.
* Do a similar thing for the MDC feature flag. */
prefs = NULL;
mdc_feature = aead_feature = 0;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->flags.primary)
{
prefs = k->pkt->pkt.user_id->prefs;
mdc_feature = k->pkt->pkt.user_id->flags.mdc;
aead_feature = k->pkt->pkt.user_id->flags.aead;
break;
}
}
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
PKT_public_key *pk = k->pkt->pkt.public_key;
if (pk->prefs)
xfree (pk->prefs);
pk->prefs = copy_prefs (prefs);
pk->flags.mdc = mdc_feature;
pk->flags.aead = aead_feature;
}
}
}
/* See whether the key satisfies any additional requirements specified
* in CTX. If so, return the node of an appropriate key or subkey.
* Otherwise, return NULL if there was no appropriate key.
*
* Note that we do not return a reference, i.e. the result must not be
* freed using 'release_kbnode'.
*
* In case the primary key is not required, select a suitable subkey.
* We need the primary key if PUBKEY_USAGE_CERT is set in REQ_USAGE or
- * we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG is set in
+ * we are in PGP7 mode and PUBKEY_USAGE_SIG is set in
* REQ_USAGE.
*
* If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
* are set in REQ_USAGE, we filter by the key's function. Concretely,
* if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then we only
* return a key if it is (at least) either a signing or a
* certification key.
*
* If REQ_USAGE is set, then we reject any keys that are not good
* (i.e., valid, not revoked, not expired, etc.). This allows the
* getkey functions to be used for plain key listings.
*
* Sets the matched key's user id field (pk->user_id) to the user id
* that matched the low-level search criteria or NULL.
*
* If R_FLAGS is not NULL set certain flags for more detailed error
* reporting. Used flags are:
*
* - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
* been revoked.
* - LOOKUP_NOT_SELECTED :: No suitable key found
*
* This function needs to handle several different cases:
*
* 1. No requested usage and no primary key requested
* Examples for this case are that we have a keyID to be used
* for decrytion or verification.
* 2. No usage but primary key requested
* This is the case for all functions which work on an
* entire keyblock, e.g. for editing or listing
* 3. Usage and primary key requested
* FIXME
* 4. Usage but no primary key requested
* FIXME
*
*/
static kbnode_t
finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
int want_secret, unsigned int *r_flags)
{
kbnode_t k;
/* If WANT_EXACT is set, the key or subkey that actually matched the
low-level search criteria. */
kbnode_t foundk = NULL;
/* The user id (if any) that matched the low-level search criteria. */
PKT_user_id *foundu = NULL;
u32 latest_date;
kbnode_t latest_key;
PKT_public_key *pk;
int req_prim;
u32 curtime = make_timestamp ();
if (r_flags)
*r_flags = 0;
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
req_usage &= USAGE_MASK;
/* Request the primary if we're certifying another key, and also if
- * signing data while --pgp6 or --pgp7 is on since pgp 6 and 7 do
+ * signing data while --pgp7 is on since pgp 7 do
* not understand signatures made by a signing subkey. PGP 8 does. */
req_prim = ((req_usage & PUBKEY_USAGE_CERT)
- || ((PGP6 || PGP7) && (req_usage & PUBKEY_USAGE_SIG)));
+ || (PGP7 && (req_usage & PUBKEY_USAGE_SIG)));
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
/* For an exact match mark the primary or subkey that matched the
low-level search criteria. */
if (want_exact)
{
for (k = keyblock; k; k = k->next)
{
if ((k->flag & 1))
{
log_assert (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY);
foundk = k;
pk = k->pkt->pkt.public_key;
pk->flags.exact = 1;
break;
}
}
}
/* Get the user id that matched that low-level search criteria. */
for (k = keyblock; k; k = k->next)
{
if ((k->flag & 2))
{
log_assert (k->pkt->pkttype == PKT_USER_ID);
foundu = k->pkt->pkt.user_id;
break;
}
}
if (DBG_LOOKUP)
log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
foundk ? "one" : "all", req_usage);
if (!req_usage)
{
latest_key = foundk ? foundk : keyblock;
goto found;
}
latest_date = 0;
latest_key = NULL;
/* Set LATEST_KEY to the latest (the one with the most recent
* timestamp) good (valid, not revoked, not expired, etc.) subkey.
*
* Don't bother if we are only looking for a primary key or we need
* an exact match and the exact match is not a subkey. */
if (req_prim || (foundk && foundk->pkt->pkttype != PKT_PUBLIC_SUBKEY))
;
else
{
kbnode_t nextk;
int n_subkeys = 0;
int n_revoked_or_expired = 0;
/* Either start a loop or check just this one subkey. */
for (k = foundk ? foundk : keyblock; k; k = nextk)
{
if (foundk)
{
/* If FOUNDK is not NULL, then only consider that exact
key, i.e., don't iterate. */
nextk = NULL;
}
else
nextk = k->next;
if (k->pkt->pkttype != PKT_PUBLIC_SUBKEY)
continue;
pk = k->pkt->pkt.public_key;
if (DBG_LOOKUP)
log_debug ("\tchecking subkey %08lX\n",
(ulong) keyid_from_pk (pk, NULL));
if (!pk->flags.valid)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not valid\n");
continue;
}
if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
{
if (DBG_LOOKUP)
log_debug ("\tusage does not match: want=%x have=%x\n",
req_usage, pk->pubkey_usage);
continue;
}
n_subkeys++;
if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has been revoked\n");
n_revoked_or_expired++;
continue;
}
if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has expired\n");
n_revoked_or_expired++;
continue;
}
if (pk->timestamp > curtime && !opt.ignore_valid_from)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not yet valid\n");
continue;
}
if (want_secret && agent_probe_secret_key (NULL, pk))
{
if (DBG_LOOKUP)
log_debug ("\tno secret key\n");
continue;
}
if (DBG_LOOKUP)
log_debug ("\tsubkey might be fine\n");
/* In case a key has a timestamp of 0 set, we make sure
that it is used. A better change would be to compare
">=" but that might also change the selected keys and
is as such a more intrusive change. */
if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date))
{
latest_date = pk->timestamp;
latest_key = k;
}
}
if (n_subkeys == n_revoked_or_expired && r_flags)
*r_flags |= LOOKUP_ALL_SUBKEYS_EXPIRED;
}
/* Check if the primary key is ok (valid, not revoke, not expire,
* matches requested usage) if:
*
* - we didn't find an appropriate subkey and we're not doing an
* exact search,
*
* - we're doing an exact match and the exact match was the
* primary key, or,
*
* - we're just considering the primary key. */
if ((!latest_key && !want_exact) || foundk == keyblock || req_prim)
{
if (DBG_LOOKUP && !foundk && !req_prim)
log_debug ("\tno suitable subkeys found - trying primary\n");
pk = keyblock->pkt->pkt.public_key;
if (!pk->flags.valid)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key not valid\n");
}
else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
{
if (DBG_LOOKUP)
log_debug ("\tprimary key usage does not match: "
"want=%x have=%x\n", req_usage, pk->pubkey_usage);
}
else if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has been revoked\n");
}
else if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
}
else /* Okay. */
{
if (DBG_LOOKUP)
log_debug ("\tprimary key may be used\n");
latest_key = keyblock;
}
}
if (!latest_key)
{
if (DBG_LOOKUP)
log_debug ("\tno suitable key found - giving up\n");
if (r_flags)
*r_flags |= LOOKUP_NOT_SELECTED;
return NULL; /* Not found. */
}
found:
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n",
(ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
if (latest_key)
{
pk = latest_key->pkt->pkt.public_key;
free_user_id (pk->user_id);
pk->user_id = scopy_user_id (foundu);
}
if (latest_key != keyblock && opt.verbose)
{
char *tempkeystr =
xstrdup (keystr_from_pk (latest_key->pkt->pkt.public_key));
log_info (_("using subkey %s instead of primary key %s\n"),
tempkeystr, keystr_from_pk (keyblock->pkt->pkt.public_key));
xfree (tempkeystr);
}
cache_user_id (keyblock);
return latest_key ? latest_key : keyblock; /* Found. */
}
/* Print a KEY_CONSIDERED status line. */
static void
print_status_key_considered (kbnode_t keyblock, unsigned int flags)
{
char hexfpr[2*MAX_FINGERPRINT_LEN + 1];
kbnode_t node;
char flagbuf[20];
if (!is_status_enabled ())
return;
for (node=keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY)
break;
if (!node)
{
log_error ("%s: keyblock w/o primary key\n", __func__);
return;
}
hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr);
snprintf (flagbuf, sizeof flagbuf, " %u", flags);
write_status_strings (STATUS_KEY_CONSIDERED, hexfpr, flagbuf, NULL);
}
/* A high-level function to lookup keys.
*
* This function builds on top of the low-level keydb API. It first
* searches the database using the description stored in CTX->ITEMS,
* then it filters the results using CTX and, finally, if WANT_SECRET
* is set, it ignores any keys for which no secret key is available.
*
* Unlike the low-level search functions, this function also merges
* all of the self-signed data into the keys, subkeys and user id
* packets (see the merge_selfsigs for details).
*
* On success the key's keyblock is stored at *RET_KEYBLOCK, and the
* specific subkey is stored at *RET_FOUND_KEY. Note that we do not
* return a reference in *RET_FOUND_KEY, i.e. the result must not be
* freed using 'release_kbnode', and it is only valid until
* *RET_KEYBLOCK is deallocated. Therefore, if RET_FOUND_KEY is not
* NULL, then RET_KEYBLOCK must not be NULL. */
static int
lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key)
{
int rc;
int no_suitable_key = 0;
KBNODE keyblock = NULL;
KBNODE found_key = NULL;
unsigned int infoflags;
log_assert (ret_found_key == NULL || ret_keyblock != NULL);
if (ret_keyblock)
*ret_keyblock = NULL;
for (;;)
{
rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL);
if (rc)
break;
/* If we are iterating over the entire database, then we need to
* change from KEYDB_SEARCH_MODE_FIRST, which does an implicit
* reset, to KEYDB_SEARCH_MODE_NEXT, which gets the next record. */
if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
ctx->items->mode = KEYDB_SEARCH_MODE_NEXT;
rc = keydb_get_keyblock (ctx->kr_handle, &keyblock);
if (rc)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
goto skip;
}
if (want_secret)
{
rc = agent_probe_any_secret_key (NULL, keyblock);
if (gpg_err_code(rc) == GPG_ERR_NO_SECKEY)
goto skip; /* No secret key available. */
if (rc)
goto found; /* Unexpected error. */
}
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. */
merge_selfsigs (ctrl, keyblock);
found_key = finish_lookup (keyblock, ctx->req_usage, ctx->exact,
want_secret, &infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
{
no_suitable_key = 0;
goto found;
}
else
{
no_suitable_key = 1;
}
skip:
/* Release resources and continue search. */
release_kbnode (keyblock);
keyblock = NULL;
/* The keyblock cache ignores the current "file position".
* Thus, if we request the next result and the cache matches
* (and it will since it is what we just looked for), we'll get
* the same entry back! We can avoid this infinite loop by
* disabling the cache. */
keydb_disable_caching (ctx->kr_handle);
}
found:
if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
if (!rc)
{
if (ret_keyblock)
{
*ret_keyblock = keyblock; /* Return the keyblock. */
keyblock = NULL;
}
}
else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
rc = want_secret? GPG_ERR_UNUSABLE_SECKEY : GPG_ERR_UNUSABLE_PUBKEY;
else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
rc = want_secret? GPG_ERR_NO_SECKEY : GPG_ERR_NO_PUBKEY;
release_kbnode (keyblock);
if (ret_found_key)
{
if (! rc)
*ret_found_key = found_key;
else
*ret_found_key = NULL;
}
return rc;
}
/* Enumerate some secret keys (specifically, those specified with
* --default-key and --try-secret-key). Use the following procedure:
*
* 1) Initialize a void pointer to NULL
* 2) Pass a reference to this pointer to this function (content)
* and provide space for the secret key (sk)
* 3) Call this function as long as it does not return an error (or
* until you are done). The error code GPG_ERR_EOF indicates the
* end of the listing.
* 4) Call this function a last time with SK set to NULL,
* so that can free it's context.
*
* In pseudo-code:
*
* void *ctx = NULL;
* PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
*
* while ((err = enum_secret_keys (&ctx, sk)))
* { // Process SK.
* if (done)
* break;
* free_public_key (sk);
* sk = xmalloc_clear (sizeof (*sk));
* }
*
* // Release any resources used by CTX.
* enum_secret_keys (&ctx, NULL);
* free_public_key (sk);
*
* if (gpg_err_code (err) != GPG_ERR_EOF)
* ; // An error occurred.
*/
gpg_error_t
enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
{
gpg_error_t err = 0;
const char *name;
kbnode_t keyblock;
struct
{
int eof;
int state;
strlist_t sl;
kbnode_t keyblock;
kbnode_t node;
getkey_ctx_t ctx;
} *c = *context;
if (!c)
{
/* Make a new context. */
c = xtrycalloc (1, sizeof *c);
if (!c)
return gpg_error_from_syserror ();
*context = c;
}
if (!sk)
{
/* Free the context. */
release_kbnode (c->keyblock);
getkey_end (ctrl, c->ctx);
xfree (c);
*context = NULL;
return 0;
}
if (c->eof)
return gpg_error (GPG_ERR_EOF);
for (;;)
{
/* Loop until we have a keyblock. */
while (!c->keyblock)
{
/* Loop over the list of secret keys. */
do
{
name = NULL;
keyblock = NULL;
switch (c->state)
{
case 0: /* First try to use the --default-key. */
name = parse_def_secret_key (ctrl);
c->state = 1;
break;
case 1: /* Init list of keys to try. */
c->sl = opt.secret_keys_to_try;
c->state++;
break;
case 2: /* Get next item from list. */
if (c->sl)
{
name = c->sl->d;
c->sl = c->sl->next;
}
else
c->state++;
break;
case 3: /* Init search context to enum all secret keys. */
err = getkey_bynames (ctrl, &c->ctx, NULL, NULL, 1,
&keyblock);
if (err)
{
release_kbnode (keyblock);
keyblock = NULL;
getkey_end (ctrl, c->ctx);
c->ctx = NULL;
}
c->state++;
break;
case 4: /* Get next item from the context. */
if (c->ctx)
{
err = getkey_next (ctrl, c->ctx, NULL, &keyblock);
if (err)
{
release_kbnode (keyblock);
keyblock = NULL;
getkey_end (ctrl, c->ctx);
c->ctx = NULL;
}
}
else
c->state++;
break;
default: /* No more names to check - stop. */
c->eof = 1;
return gpg_error (GPG_ERR_EOF);
}
}
while ((!name || !*name) && !keyblock);
if (keyblock)
c->node = c->keyblock = keyblock;
else
{
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
if (err)
{
/* getkey_byname might return a keyblock even in the
error case - I have not checked. Thus better release
it. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
}
else
c->node = c->keyblock;
}
}
/* Get the next key from the current keyblock. */
for (; c->node; c->node = c->node->next)
{
if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|| c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
copy_public_key (sk, c->node->pkt->pkt.public_key);
c->node = c->node->next;
return 0; /* Found. */
}
}
/* Dispose the keyblock and continue. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
}
}
gpg_error_t
get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
const byte *fpr_card, size_t fpr_len)
{
gpg_error_t err;
strlist_t namelist = NULL;
const char *def_secret_key = parse_def_secret_key (ctrl);
if (def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else if (fpr_card)
return get_pubkey_byfprint (ctrl, pk, NULL, fpr_card, fpr_len);
if (!fpr_card
|| (def_secret_key && def_secret_key[strlen (def_secret_key)-1] == '!'))
err = key_byname (ctrl, NULL, namelist, pk, 1, 0, NULL, NULL);
else
{ /* Default key is specified and card key is also available. */
kbnode_t k, keyblock = NULL;
err = key_byname (ctrl, NULL, namelist, pk, 1, 0, &keyblock, NULL);
if (!err)
for (k = keyblock; k; k = k->next)
{
PKT_public_key *pk_candidate;
char fpr[MAX_FINGERPRINT_LEN];
if (k->pkt->pkttype != PKT_PUBLIC_KEY
&&k->pkt->pkttype != PKT_PUBLIC_SUBKEY)
continue;
pk_candidate = k->pkt->pkt.public_key;
if (!pk_candidate->flags.valid)
continue;
if (!((pk_candidate->pubkey_usage & USAGE_MASK) & pk->req_usage))
continue;
fingerprint_from_pk (pk_candidate, fpr, NULL);
if (!memcmp (fpr_card, fpr, fpr_len))
{
release_public_key_parts (pk);
copy_public_key (pk, pk_candidate);
break;
}
}
release_kbnode (keyblock);
}
free_strlist (namelist);
return err;
}
/*********************************************
*********** User ID printing helpers *******
*********************************************/
/* Return a string with a printable representation of the user_id.
* this string must be freed by xfree. If R_NOUID is not NULL it is
* set to true if a user id was not found; otherwise to false. */
static char *
get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
int *r_nouid)
{
user_id_db_t r;
keyid_list_t a;
int pass = 0;
char *p;
if (r_nouid)
*r_nouid = 0;
/* Try it two times; second pass reads from the database. */
do
{
for (r = user_id_db; r; r = r->next)
{
for (a = r->keyids; a; a = a->next)
{
if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
{
if (mode == 2)
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and
does not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
if (r_len)
*r_len = r->len;
}
else
{
if (mode)
p = xasprintf ("%08lX%08lX %.*s",
(ulong) keyid[0], (ulong) keyid[1],
r->len, r->name);
else
p = xasprintf ("%s %.*s", keystr (keyid),
r->len, r->name);
if (r_len)
*r_len = strlen (p);
}
return p;
}
}
}
}
while (++pass < 2 && !get_pubkey (ctrl, NULL, keyid));
if (mode == 2)
p = xstrdup (user_id_not_found_utf8 ());
else if (mode)
p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
else
p = xasprintf ("%s [?]", keystr (keyid));
if (r_nouid)
*r_nouid = 1;
if (r_len)
*r_len = strlen (p);
return p;
}
char *
get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
{
char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL);
char *p2 = utf8_to_native (p, strlen (p), 0);
xfree (p);
return p2;
}
char *
get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
{
return get_user_id_string (ctrl, keyid, 1, NULL, NULL);
}
/* Please try to use get_user_byfpr instead of this one. */
char *
get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid)
{
return get_user_id_string (ctrl, keyid, 2, rn, r_nouid);
}
/* Please try to use get_user_id_byfpr_native instead of this one. */
char *
get_user_id_native (ctrl_t ctrl, u32 *keyid)
{
size_t rn;
char *p = get_user_id (ctrl, keyid, &rn, NULL);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;
}
/* Return the user id for a key designated by its fingerprint, FPR,
which must be MAX_FINGERPRINT_LEN bytes in size. Note: the
returned string, which must be freed using xfree, may not be NUL
terminated. To determine the length of the string, you must use
*RN. */
char *
get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn)
{
user_id_db_t r;
char *p;
int pass = 0;
/* Try it two times; second pass reads from the database. */
do
{
for (r = user_id_db; r; r = r->next)
{
keyid_list_t a;
for (a = r->keyids; a; a = a->next)
{
if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and does
not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
*rn = r->len;
return p;
}
}
}
}
while (++pass < 2
&& !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, MAX_FINGERPRINT_LEN));
p = xstrdup (user_id_not_found_utf8 ());
*rn = strlen (p);
return p;
}
/* Like get_user_id_byfpr, but convert the string to the native
encoding. The returned string needs to be freed. Unlike
get_user_id_byfpr, the returned string is NUL terminated. */
char *
get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr)
{
size_t rn;
char *p = get_user_id_byfpr (ctrl, fpr, &rn);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;
}
/* Return the database handle used by this context. The context still
owns the handle. */
KEYDB_HANDLE
get_ctx_handle (GETKEY_CTX ctx)
{
return ctx->kr_handle;
}
static void
free_akl (struct akl *akl)
{
if (! akl)
return;
if (akl->spec)
free_keyserver_spec (akl->spec);
xfree (akl);
}
void
release_akl (void)
{
while (opt.auto_key_locate)
{
struct akl *akl2 = opt.auto_key_locate;
opt.auto_key_locate = opt.auto_key_locate->next;
free_akl (akl2);
}
}
/* Returns false on error. */
int
parse_auto_key_locate (const char *options_arg)
{
char *tok;
char *options, *options_buf;
options = options_buf = xstrdup (options_arg);
while ((tok = optsep (&options)))
{
struct akl *akl, *check, *last = NULL;
int dupe = 0;
if (tok[0] == '\0')
continue;
akl = xmalloc_clear (sizeof (*akl));
if (ascii_strcasecmp (tok, "clear") == 0)
{
xfree (akl);
free_akl (opt.auto_key_locate);
opt.auto_key_locate = NULL;
continue;
}
else if (ascii_strcasecmp (tok, "nodefault") == 0)
akl->type = AKL_NODEFAULT;
else if (ascii_strcasecmp (tok, "local") == 0)
akl->type = AKL_LOCAL;
else if (ascii_strcasecmp (tok, "ldap") == 0)
akl->type = AKL_LDAP;
else if (ascii_strcasecmp (tok, "keyserver") == 0)
akl->type = AKL_KEYSERVER;
else if (ascii_strcasecmp (tok, "cert") == 0)
akl->type = AKL_CERT;
else if (ascii_strcasecmp (tok, "pka") == 0)
akl->type = AKL_PKA;
else if (ascii_strcasecmp (tok, "dane") == 0)
akl->type = AKL_DANE;
else if (ascii_strcasecmp (tok, "wkd") == 0)
akl->type = AKL_WKD;
else if ((akl->spec = parse_keyserver_uri (tok, 1)))
akl->type = AKL_SPEC;
else
{
free_akl (akl);
xfree (options_buf);
return 0;
}
/* We must maintain the order the user gave us */
for (check = opt.auto_key_locate; check;
last = check, check = check->next)
{
/* Check for duplicates */
if (check->type == akl->type
&& (akl->type != AKL_SPEC
|| (akl->type == AKL_SPEC
&& strcmp (check->spec->uri, akl->spec->uri) == 0)))
{
dupe = 1;
free_akl (akl);
break;
}
}
if (!dupe)
{
if (last)
last->next = akl;
else
opt.auto_key_locate = akl;
}
}
xfree (options_buf);
return 1;
}
/* The list of key origins. */
static struct {
const char *name;
int origin;
} key_origin_list[] =
{
{ "self", KEYORG_SELF },
{ "file", KEYORG_FILE },
{ "url", KEYORG_URL },
{ "wkd", KEYORG_WKD },
{ "dane", KEYORG_DANE },
{ "ks-pref", KEYORG_KS_PREF },
{ "ks", KEYORG_KS },
{ "unknown", KEYORG_UNKNOWN }
};
/* Parse the argument for --key-origin. Return false on error. */
int
parse_key_origin (char *string)
{
int i;
char *comma;
comma = strchr (string, ',');
if (comma)
*comma = 0;
if (!ascii_strcasecmp (string, "help"))
{
log_info (_("valid values for option '%s':\n"), "--key-origin");
for (i=0; i < DIM (key_origin_list); i++)
log_info (" %s\n", key_origin_list[i].name);
g10_exit (1);
}
for (i=0; i < DIM (key_origin_list); i++)
if (!ascii_strcasecmp (string, key_origin_list[i].name))
{
opt.key_origin = key_origin_list[i].origin;
xfree (opt.key_origin_url);
opt.key_origin_url = NULL;
if (comma && comma[1])
{
opt.key_origin_url = xstrdup (comma+1);
trim_spaces (opt.key_origin_url);
}
return 1;
}
if (comma)
*comma = ',';
return 0;
}
/* Return a string or "?" for the key ORIGIN. */
const char *
key_origin_string (int origin)
{
int i;
for (i=0; i < DIM (key_origin_list); i++)
if (key_origin_list[i].origin == origin)
return key_origin_list[i].name;
return "?";
}
/* Returns true if a secret key is available for the public key with
key id KEYID; returns false if not. This function ignores legacy
keys. Note: this is just a fast check and does not tell us whether
the secret key is valid; this check merely indicates whether there
is some secret key with the specified key id. */
int
have_secret_key_with_kid (u32 *keyid)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock;
kbnode_t node;
int result = 0;
kdbhd = keydb_new ();
if (!kdbhd)
return 0;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
desc.u.kid[0] = keyid[0];
desc.u.kid[1] = keyid[1];
while (!result)
{
err = keydb_search (kdbhd, &desc, 1, NULL);
if (err)
break;
err = keydb_get_keyblock (kdbhd, &keyblock);
if (err)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
break;
}
for (node = keyblock; node; node = node->next)
{
/* Bit 0 of the flags is set if the search found the key
using that key or subkey. Note: a search will only ever
match a single key or subkey. */
if ((node->flag & 1))
{
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
result = 1; /* Secret key available. */
else
result = 0;
break;
}
}
release_kbnode (keyblock);
}
keydb_release (kdbhd);
return result;
}
diff --git a/g10/gpg.c b/g10/gpg.c
index 1a419f7e7..af56f1256 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,5571 +1,5561 @@
/* gpg.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998-2011 Free Software Foundation, Inc.
* Copyright (C) 1997-2017 Werner Koch
* Copyright (C) 2015-2017 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
#include
#include
#include
#include
#include
#ifdef HAVE_STAT
#include /* for stat() */
#endif
#include
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include
# endif
# include
#endif
#define INCLUDED_BY_MAIN_MODULE 1
#include "gpg.h"
#include
#include "../common/iobuf.h"
#include "../common/util.h"
#include "packet.h"
#include "../common/membuf.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 "keyserver-internal.h"
#include "exec.h"
#include "../common/gc-opt-flags.h"
#include "../common/asshelp.h"
#include "call-dirmngr.h"
#include "tofu.h"
#include "../common/init.h"
#include "../common/mbox-util.h"
#include "../common/shareddefs.h"
#include "../common/compliance.h"
#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
#define MY_O_BINARY O_BINARY
#ifndef S_IRGRP
# define S_IRGRP 0
# define S_IWGRP 0
#endif
#else
#define MY_O_BINARY 0
#endif
#ifdef __MINGW32__
int _dowildcard = -1;
#endif
enum cmd_and_opt_values
{
aNull = 0,
oArmor = 'a',
aDetachedSign = 'b',
aSym = 'c',
aDecrypt = 'd',
aEncr = 'e',
oRecipientFile = 'f',
oHiddenRecipientFile = 'F',
oInteractive = 'i',
aListKeys = 'k',
oDryRun = 'n',
oOutput = 'o',
oQuiet = 'q',
oRecipient = 'r',
oHiddenRecipient = 'R',
aSign = 's',
oTextmodeShort= 't',
oLocalUser = 'u',
oVerbose = 'v',
oCompress = 'z',
oSetNotation = 'N',
aListSecretKeys = 'K',
oBatch = 500,
oMaxOutput,
oInputSizeHint,
oChunkSize,
oSigNotation,
oCertNotation,
oShowNotation,
oNoShowNotation,
aEncrFiles,
aEncrSym,
aDecryptFiles,
aClearsign,
aStore,
aQuickKeygen,
aFullKeygen,
aKeygen,
aSignEncr,
aSignEncrSym,
aSignSym,
aSignKey,
aLSignKey,
aQuickSignKey,
aQuickLSignKey,
aQuickAddUid,
aQuickAddKey,
aQuickRevUid,
aQuickSetExpire,
aQuickSetPrimaryUid,
aListConfig,
aListGcryptConfig,
aGPGConfList,
aGPGConfTest,
aListPackets,
aEditKey,
aDeleteKeys,
aDeleteSecretKeys,
aDeleteSecretAndPublicKeys,
aImport,
aFastImport,
aVerify,
aVerifyFiles,
aListSigs,
aSendKeys,
aRecvKeys,
aLocateKeys,
aSearchKeys,
aRefreshKeys,
aFetchKeys,
aExport,
aExportSecret,
aExportSecretSub,
aExportSshKey,
aCheckKeys,
aGenRevoke,
aDesigRevoke,
aPrimegen,
aPrintMD,
aPrintMDs,
aCheckTrustDB,
aUpdateTrustDB,
aFixTrustDB,
aListTrustDB,
aListTrustPath,
aExportOwnerTrust,
aImportOwnerTrust,
aDeArmor,
aEnArmor,
aGenRandom,
aRebuildKeydbCaches,
aCardStatus,
aCardEdit,
aChangePIN,
aPasswd,
aServer,
aTOFUPolicy,
oMimemode,
oTextmode,
oNoTextmode,
oExpert,
oNoExpert,
oDefSigExpire,
oAskSigExpire,
oNoAskSigExpire,
oDefCertExpire,
oAskCertExpire,
oNoAskCertExpire,
oDefCertLevel,
oMinCertLevel,
oAskCertLevel,
oNoAskCertLevel,
oFingerprint,
oWithFingerprint,
oWithSubkeyFingerprint,
oWithICAOSpelling,
oWithKeygrip,
oWithKeyScreening,
oWithSecret,
oWithWKDHash,
oWithColons,
oWithKeyData,
oWithKeyOrigin,
oWithTofuInfo,
oWithSigList,
oWithSigCheck,
oAnswerYes,
oAnswerNo,
oKeyring,
oPrimaryKeyring,
oSecretKeyring,
oShowKeyring,
oDefaultKey,
oDefRecipient,
oDefRecipientSelf,
oNoDefRecipient,
oTrySecretKey,
oOptions,
oDebug,
oDebugLevel,
oDebugAll,
oDebugIOLBF,
oDebugSetIobufSize,
oStatusFD,
oStatusFile,
oAttributeFD,
oAttributeFile,
oEmitVersion,
oNoEmitVersion,
oCompletesNeeded,
oMarginalsNeeded,
oMaxCertDepth,
oLoadExtension,
oCompliance,
oGnuPG,
oRFC2440,
oRFC4880,
oRFC4880bis,
oOpenPGP,
- oPGP6,
oPGP7,
oPGP8,
oDE_VS,
oRFC2440Text,
oNoRFC2440Text,
oCipherAlgo,
oAEADAlgo,
oDigestAlgo,
oCertDigestAlgo,
oCompressAlgo,
oCompressLevel,
oBZ2CompressLevel,
oBZ2DecompressLowmem,
oPassphrase,
oPassphraseFD,
oPassphraseFile,
oPassphraseRepeat,
oPinentryMode,
oCommandFD,
oCommandFile,
oQuickRandom,
oNoVerbose,
oTrustDBName,
oNoSecmemWarn,
oRequireSecmem,
oNoRequireSecmem,
oNoPermissionWarn,
oNoArmor,
oNoDefKeyring,
oNoKeyring,
oNoGreeting,
oNoTTY,
oNoOptions,
oNoBatch,
oHomedir,
oSkipVerify,
oSkipHiddenRecipients,
oNoSkipHiddenRecipients,
oAlwaysTrust,
oTrustModel,
oForceOwnertrust,
oSetFilename,
oForYourEyesOnly,
oNoForYourEyesOnly,
oSetPolicyURL,
oSigPolicyURL,
oCertPolicyURL,
oShowPolicyURL,
oNoShowPolicyURL,
oSigKeyserverURL,
oUseEmbeddedFilename,
oNoUseEmbeddedFilename,
oComment,
oDefaultComment,
oNoComments,
oThrowKeyids,
oNoThrowKeyids,
oShowPhotos,
oNoShowPhotos,
oPhotoViewer,
oForceAEAD,
oS2KMode,
oS2KDigest,
oS2KCipher,
oS2KCount,
oDisplayCharset,
oNotDashEscaped,
oEscapeFrom,
oNoEscapeFrom,
oLockOnce,
oLockMultiple,
oLockNever,
oKeyServer,
oKeyServerOptions,
oImportOptions,
oImportFilter,
oExportOptions,
oExportFilter,
oListOptions,
oVerifyOptions,
oTempDir,
oExecPath,
oEncryptTo,
oHiddenEncryptTo,
oNoEncryptTo,
oEncryptToDefaultKey,
oLoggerFD,
oLoggerFile,
oUtf8Strings,
oNoUtf8Strings,
oDisableCipherAlgo,
oDisablePubkeyAlgo,
oAllowNonSelfsignedUID,
oNoAllowNonSelfsignedUID,
oAllowFreeformUID,
oNoAllowFreeformUID,
oAllowSecretKeyImport,
oEnableSpecialFilenames,
oNoLiteral,
oSetFilesize,
oHonorHttpProxy,
oFastListMode,
oListOnly,
oIgnoreTimeConflict,
oIgnoreValidFrom,
oIgnoreCrcError,
oIgnoreMDCError,
oShowSessionKey,
oOverrideSessionKey,
oOverrideSessionKeyFD,
oNoRandomSeedFile,
oAutoKeyRetrieve,
oNoAutoKeyRetrieve,
oUseAgent,
oNoUseAgent,
oGpgAgentInfo,
oMergeOnly,
oTryAllSecrets,
oTrustedKey,
oNoExpensiveTrustChecks,
oFixedListMode,
oLegacyListMode,
oNoSigCache,
oAutoCheckTrustDB,
oNoAutoCheckTrustDB,
oPreservePermissions,
oDefaultPreferenceList,
oDefaultKeyserverURL,
oPersonalCipherPreferences,
oPersonalAEADPreferences,
oPersonalDigestPreferences,
oPersonalCompressPreferences,
oAgentProgram,
oDirmngrProgram,
oDisableDirmngr,
oDisplay,
oTTYname,
oTTYtype,
oLCctype,
oLCmessages,
oXauthority,
oGroup,
oUnGroup,
oNoGroups,
oStrict,
oNoStrict,
oMangleDosFilenames,
oNoMangleDosFilenames,
oEnableProgressFilter,
oMultifile,
oKeyidFormat,
oExitOnStatusWriteError,
oLimitCardInsertTries,
oReaderPort,
octapiDriver,
opcscDriver,
oDisableCCID,
oRequireCrossCert,
oNoRequireCrossCert,
oAutoKeyLocate,
oNoAutoKeyLocate,
oAllowMultisigVerification,
oEnableLargeRSA,
oDisableLargeRSA,
oEnableDSA2,
oDisableDSA2,
oAllowMultipleMessages,
oNoAllowMultipleMessages,
oAllowWeakDigestAlgos,
oFakedSystemTime,
oNoAutostart,
oPrintPKARecords,
oPrintDANERecords,
oTOFUDefaultPolicy,
oTOFUDBFormat,
oDefaultNewKeyAlgo,
oWeakDigest,
oUnwrap,
oOnlySignTextIDs,
oDisableSignerUID,
oSender,
oKeyOrigin,
oRequestOrigin,
oNoSymkeyCache,
oNoop
};
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (300, N_("@Commands:\n ")),
ARGPARSE_c (aSign, "sign", N_("make a signature")),
ARGPARSE_c (aClearsign, "clear-sign", N_("make a clear text signature")),
ARGPARSE_c (aClearsign, "clearsign", "@"),
ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")),
ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")),
ARGPARSE_c (aEncrFiles, "encrypt-files", "@"),
ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")),
ARGPARSE_c (aStore, "store", "@"),
ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")),
ARGPARSE_c (aDecryptFiles, "decrypt-files", "@"),
ARGPARSE_c (aVerify, "verify" , N_("verify a signature")),
ARGPARSE_c (aVerifyFiles, "verify-files" , "@" ),
ARGPARSE_c (aListKeys, "list-keys", N_("list keys")),
ARGPARSE_c (aListKeys, "list-public-keys", "@" ),
ARGPARSE_c (aListSigs, "list-signatures", N_("list keys and signatures")),
ARGPARSE_c (aListSigs, "list-sigs", "@"),
ARGPARSE_c (aCheckKeys, "check-signatures",
N_("list and check key signatures")),
ARGPARSE_c (aCheckKeys, "check-sigs", "@"),
ARGPARSE_c (oFingerprint, "fingerprint", N_("list keys and fingerprints")),
ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")),
ARGPARSE_c (aKeygen, "generate-key",
N_("generate a new key pair")),
ARGPARSE_c (aKeygen, "gen-key", "@"),
ARGPARSE_c (aQuickKeygen, "quick-generate-key" ,
N_("quickly generate a new key pair")),
ARGPARSE_c (aQuickKeygen, "quick-gen-key", "@"),
ARGPARSE_c (aQuickAddUid, "quick-add-uid",
N_("quickly add a new user-id")),
ARGPARSE_c (aQuickAddUid, "quick-adduid", "@"),
ARGPARSE_c (aQuickAddKey, "quick-add-key", "@"),
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
ARGPARSE_c (aQuickRevUid, "quick-revoke-uid",
N_("quickly revoke a user-id")),
ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"),
ARGPARSE_c (aQuickSetExpire, "quick-set-expire",
N_("quickly set a new expiration date")),
ARGPARSE_c (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"),
ARGPARSE_c (aFullKeygen, "full-generate-key" ,
N_("full featured key pair generation")),
ARGPARSE_c (aFullKeygen, "full-gen-key", "@"),
ARGPARSE_c (aGenRevoke, "generate-revocation",
N_("generate a revocation certificate")),
ARGPARSE_c (aGenRevoke, "gen-revoke", "@"),
ARGPARSE_c (aDeleteKeys,"delete-keys",
N_("remove keys from the public keyring")),
ARGPARSE_c (aDeleteSecretKeys, "delete-secret-keys",
N_("remove keys from the secret keyring")),
ARGPARSE_c (aQuickSignKey, "quick-sign-key" ,
N_("quickly sign a key")),
ARGPARSE_c (aQuickLSignKey, "quick-lsign-key",
N_("quickly sign a key locally")),
ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")),
ARGPARSE_c (aLSignKey, "lsign-key" ,N_("sign a key locally")),
ARGPARSE_c (aEditKey, "edit-key" ,N_("sign or edit a key")),
ARGPARSE_c (aEditKey, "key-edit" ,"@"),
ARGPARSE_c (aPasswd, "change-passphrase", N_("change a passphrase")),
ARGPARSE_c (aPasswd, "passwd", "@"),
ARGPARSE_c (aDesigRevoke, "generate-designated-revocation", "@"),
ARGPARSE_c (aDesigRevoke, "desig-revoke","@" ),
ARGPARSE_c (aExport, "export" , N_("export keys") ),
ARGPARSE_c (aSendKeys, "send-keys" , N_("export keys to a keyserver") ),
ARGPARSE_c (aRecvKeys, "receive-keys" , N_("import keys from a keyserver") ),
ARGPARSE_c (aRecvKeys, "recv-keys" , "@"),
ARGPARSE_c (aSearchKeys, "search-keys" ,
N_("search for keys on a keyserver") ),
ARGPARSE_c (aRefreshKeys, "refresh-keys",
N_("update all keys from a keyserver")),
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
ARGPARSE_c (aImport, "import", N_("import/merge keys")),
ARGPARSE_c (aFastImport, "fast-import", "@"),
#ifdef ENABLE_CARD_SUPPORT
ARGPARSE_c (aCardStatus, "card-status", N_("print the card status")),
ARGPARSE_c (aCardEdit, "edit-card", N_("change data on a card")),
ARGPARSE_c (aCardEdit, "card-edit", "@"),
ARGPARSE_c (aChangePIN, "change-pin", N_("change a card's PIN")),
#endif
ARGPARSE_c (aListConfig, "list-config", "@"),
ARGPARSE_c (aListGcryptConfig, "list-gcrypt-config", "@"),
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@" ),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@" ),
ARGPARSE_c (aListPackets, "list-packets","@"),
#ifndef NO_TRUST_MODELS
ARGPARSE_c (aExportOwnerTrust, "export-ownertrust", "@"),
ARGPARSE_c (aImportOwnerTrust, "import-ownertrust", "@"),
ARGPARSE_c (aUpdateTrustDB,"update-trustdb",
N_("update the trust database")),
ARGPARSE_c (aCheckTrustDB, "check-trustdb", "@"),
ARGPARSE_c (aFixTrustDB, "fix-trustdb", "@"),
#endif
ARGPARSE_c (aDeArmor, "dearmor", "@"),
ARGPARSE_c (aDeArmor, "dearmour", "@"),
ARGPARSE_c (aEnArmor, "enarmor", "@"),
ARGPARSE_c (aEnArmor, "enarmour", "@"),
ARGPARSE_c (aPrintMD, "print-md", N_("print message digests")),
ARGPARSE_c (aPrimegen, "gen-prime", "@" ),
ARGPARSE_c (aGenRandom,"gen-random", "@" ),
ARGPARSE_c (aServer, "server", N_("run in server mode")),
ARGPARSE_c (aTOFUPolicy, "tofu-policy",
N_("|VALUE|set the TOFU policy for a key")),
ARGPARSE_group (301, N_("@\nOptions:\n ")),
ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")),
ARGPARSE_s_n (oArmor, "armour", "@"),
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"),
ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"),
ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"),
ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */
ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"),
ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"),
ARGPARSE_s_n (oNoDefRecipient, "no-default-recipient", "@"),
ARGPARSE_s_s (oTempDir, "temp-directory", "@"),
ARGPARSE_s_s (oExecPath, "exec-path", "@"),
ARGPARSE_s_s (oEncryptTo, "encrypt-to", "@"),
ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"),
ARGPARSE_s_s (oHiddenEncryptTo, "hidden-encrypt-to", "@"),
ARGPARSE_s_n (oEncryptToDefaultKey, "encrypt-to-default-key", "@"),
ARGPARSE_s_s (oLocalUser, "local-user",
N_("|USER-ID|use USER-ID to sign or decrypt")),
ARGPARSE_s_s (oSender, "sender", "@"),
ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"),
ARGPARSE_s_i (oCompress, NULL,
N_("|N|set compress level to N (0 disables)")),
ARGPARSE_s_i (oCompressLevel, "compress-level", "@"),
ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"),
ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"),
ARGPARSE_s_n (oMimemode, "mimemode", "@"),
ARGPARSE_s_n (oTextmodeShort, NULL, "@"),
ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"),
ARGPARSE_s_n (oExpert, "expert", "@"),
ARGPARSE_s_n (oNoExpert, "no-expert", "@"),
ARGPARSE_s_s (oDefSigExpire, "default-sig-expire", "@"),
ARGPARSE_s_n (oAskSigExpire, "ask-sig-expire", "@"),
ARGPARSE_s_n (oNoAskSigExpire, "no-ask-sig-expire", "@"),
ARGPARSE_s_s (oDefCertExpire, "default-cert-expire", "@"),
ARGPARSE_s_n (oAskCertExpire, "ask-cert-expire", "@"),
ARGPARSE_s_n (oNoAskCertExpire, "no-ask-cert-expire", "@"),
ARGPARSE_s_i (oDefCertLevel, "default-cert-level", "@"),
ARGPARSE_s_i (oMinCertLevel, "min-cert-level", "@"),
ARGPARSE_s_n (oAskCertLevel, "ask-cert-level", "@"),
ARGPARSE_s_n (oNoAskCertLevel, "no-ask-cert-level", "@"),
ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
ARGPARSE_p_u (oMaxOutput, "max-output", "@"),
ARGPARSE_s_s (oInputSizeHint, "input-size-hint", "@"),
ARGPARSE_s_i (oChunkSize, "chunk-size", "@"),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", "@"),
ARGPARSE_s_n (oNoTTY, "no-tty", "@"),
ARGPARSE_s_n (oForceAEAD, "force-aead", "@"),
ARGPARSE_s_n (oDisableSignerUID, "disable-signer-uid", "@"),
ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
ARGPARSE_s_n (oInteractive, "interactive", N_("prompt before overwriting")),
ARGPARSE_s_n (oBatch, "batch", "@"),
ARGPARSE_s_n (oAnswerYes, "yes", "@"),
ARGPARSE_s_n (oAnswerNo, "no", "@"),
ARGPARSE_s_s (oKeyring, "keyring", "@"),
ARGPARSE_s_s (oPrimaryKeyring, "primary-keyring", "@"),
ARGPARSE_s_s (oSecretKeyring, "secret-keyring", "@"),
ARGPARSE_s_n (oShowKeyring, "show-keyring", "@"),
ARGPARSE_s_s (oDefaultKey, "default-key", "@"),
ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"),
ARGPARSE_s_s (oKeyOrigin, "key-origin", "@"),
ARGPARSE_s_s (oImportOptions, "import-options", "@"),
ARGPARSE_s_s (oImportFilter, "import-filter", "@"),
ARGPARSE_s_s (oExportOptions, "export-options", "@"),
ARGPARSE_s_s (oExportFilter, "export-filter", "@"),
ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
ARGPARSE_s_s (oDisplayCharset, "display-charset", "@"),
ARGPARSE_s_s (oDisplayCharset, "charset", "@"),
ARGPARSE_s_s (oOptions, "options", "@"),
ARGPARSE_s_s (oDebug, "debug", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"),
ARGPARSE_s_u (oDebugSetIobufSize, "debug-set-iobuf-size", "@"),
ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
ARGPARSE_s_s (oStatusFile, "status-file", "@"),
ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"),
ARGPARSE_s_s (oAttributeFile, "attribute-file", "@"),
ARGPARSE_s_i (oCompletesNeeded, "completes-needed", "@"),
ARGPARSE_s_i (oMarginalsNeeded, "marginals-needed", "@"),
ARGPARSE_s_i (oMaxCertDepth, "max-cert-depth", "@" ),
ARGPARSE_s_s (oTrustedKey, "trusted-key", "@"),
ARGPARSE_s_s (oLoadExtension, "load-extension", "@"), /* Dummy. */
ARGPARSE_s_s (oCompliance, "compliance", "@"),
ARGPARSE_s_n (oGnuPG, "gnupg", "@"),
ARGPARSE_s_n (oGnuPG, "no-pgp2", "@"),
ARGPARSE_s_n (oGnuPG, "no-pgp6", "@"),
ARGPARSE_s_n (oGnuPG, "no-pgp7", "@"),
ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"),
ARGPARSE_s_n (oRFC2440, "rfc2440", "@"),
ARGPARSE_s_n (oRFC4880, "rfc4880", "@"),
ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"),
ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")),
- ARGPARSE_s_n (oPGP6, "pgp6", "@"),
+ ARGPARSE_s_n (oPGP7, "pgp6", "@"),
ARGPARSE_s_n (oPGP7, "pgp7", "@"),
ARGPARSE_s_n (oPGP8, "pgp8", "@"),
ARGPARSE_s_n (oRFC2440Text, "rfc2440-text", "@"),
ARGPARSE_s_n (oNoRFC2440Text, "no-rfc2440-text", "@"),
ARGPARSE_s_i (oS2KMode, "s2k-mode", "@"),
ARGPARSE_s_s (oS2KDigest, "s2k-digest-algo", "@"),
ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"),
ARGPARSE_s_i (oS2KCount, "s2k-count", "@"),
ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
ARGPARSE_s_s (oAEADAlgo, "aead-algo", "@"),
ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"),
ARGPARSE_s_s (oCompressAlgo, "compression-algo", "@"), /* Alias */
ARGPARSE_s_n (oThrowKeyids, "throw-keyids", "@"),
ARGPARSE_s_n (oNoThrowKeyids, "no-throw-keyids", "@"),
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
ARGPARSE_s_s (oPhotoViewer, "photo-viewer", "@"),
ARGPARSE_s_s (oSetNotation, "set-notation", "@"),
ARGPARSE_s_s (oSigNotation, "sig-notation", "@"),
ARGPARSE_s_s (oCertNotation, "cert-notation", "@"),
ARGPARSE_group (302, N_(
"@\n(See the man page for a complete listing of all commands and options)\n"
)),
ARGPARSE_group (303, N_("@\nExamples:\n\n"
" -se -r Bob [file] sign and encrypt for user Bob\n"
" --clear-sign [file] make a clear text signature\n"
" --detach-sign [file] make a detached signature\n"
" --list-keys [names] show keys\n"
" --fingerprint [names] show fingerprints\n")),
/* More hidden commands and options. */
ARGPARSE_c (aPrintMDs, "print-mds", "@"), /* old */
#ifndef NO_TRUST_MODELS
ARGPARSE_c (aListTrustDB, "list-trustdb", "@"),
#endif
/* Not yet used:
ARGPARSE_c (aListTrustPath, "list-trust-path", "@"), */
ARGPARSE_c (aDeleteSecretAndPublicKeys,
"delete-secret-and-public-keys", "@"),
ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"),
ARGPARSE_s_s (oPassphrase, "passphrase", "@"),
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
ARGPARSE_s_s (oCommandFile, "command-file", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
#ifndef NO_TRUST_MODELS
ARGPARSE_s_s (oTrustDBName, "trustdb-name", "@"),
ARGPARSE_s_n (oAutoCheckTrustDB, "auto-check-trustdb", "@"),
ARGPARSE_s_n (oNoAutoCheckTrustDB, "no-auto-check-trustdb", "@"),
ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"),
#endif
ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
ARGPARSE_s_n (oRequireSecmem, "require-secmem", "@"),
ARGPARSE_s_n (oNoRequireSecmem, "no-require-secmem", "@"),
ARGPARSE_s_n (oNoPermissionWarn, "no-permission-warning", "@"),
ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_n (oNoBatch, "no-batch", "@"),
ARGPARSE_s_n (oWithColons, "with-colons", "@"),
ARGPARSE_s_n (oWithTofuInfo,"with-tofu-info", "@"),
ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"),
ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"),
ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"),
ARGPARSE_c (aListKeys, "list-key", "@"), /* alias */
ARGPARSE_c (aListSigs, "list-sig", "@"), /* alias */
ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */
ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
#ifndef NO_TRUST_MODELS
ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
#endif
ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
ARGPARSE_s_s (oSetFilename, "set-filename", "@"),
ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"),
ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"),
ARGPARSE_s_s (oSetPolicyURL, "set-policy-url", "@"),
ARGPARSE_s_s (oSigPolicyURL, "sig-policy-url", "@"),
ARGPARSE_s_s (oCertPolicyURL, "cert-policy-url", "@"),
ARGPARSE_s_n (oShowPolicyURL, "show-policy-url", "@"),
ARGPARSE_s_n (oNoShowPolicyURL, "no-show-policy-url", "@"),
ARGPARSE_s_s (oSigKeyserverURL, "sig-keyserver-url", "@"),
ARGPARSE_s_n (oShowNotation, "show-notation", "@"),
ARGPARSE_s_n (oNoShowNotation, "no-show-notation", "@"),
ARGPARSE_s_s (oComment, "comment", "@"),
ARGPARSE_s_n (oDefaultComment, "default-comment", "@"),
ARGPARSE_s_n (oNoComments, "no-comments", "@"),
ARGPARSE_s_n (oEmitVersion, "emit-version", "@"),
ARGPARSE_s_n (oNoEmitVersion, "no-emit-version", "@"),
ARGPARSE_s_n (oNoEmitVersion, "no-version", "@"), /* alias */
ARGPARSE_s_n (oNotDashEscaped, "not-dash-escaped", "@"),
ARGPARSE_s_n (oEscapeFrom, "escape-from-lines", "@"),
ARGPARSE_s_n (oNoEscapeFrom, "no-escape-from-lines", "@"),
ARGPARSE_s_n (oLockOnce, "lock-once", "@"),
ARGPARSE_s_n (oLockMultiple, "lock-multiple", "@"),
ARGPARSE_s_n (oLockNever, "lock-never", "@"),
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
ARGPARSE_s_s (oLoggerFile, "log-file", "@"),
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
ARGPARSE_s_n (oUseEmbeddedFilename, "use-embedded-filename", "@"),
ARGPARSE_s_n (oNoUseEmbeddedFilename, "no-use-embedded-filename", "@"),
ARGPARSE_s_n (oUtf8Strings, "utf8-strings", "@"),
ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"),
ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"),
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
ARGPARSE_s_n (oWithWKDHash, "with-wkd-hash", "@"),
ARGPARSE_s_n (oWithKeyOrigin, "with-key-origin", "@"),
ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"),
ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"),
ARGPARSE_s_n (oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", "@"),
ARGPARSE_s_n (oNoAllowNonSelfsignedUID, "no-allow-non-selfsigned-uid", "@"),
ARGPARSE_s_n (oAllowFreeformUID, "allow-freeform-uid", "@"),
ARGPARSE_s_n (oNoAllowFreeformUID, "no-allow-freeform-uid", "@"),
ARGPARSE_s_n (oNoLiteral, "no-literal", "@"),
ARGPARSE_p_u (oSetFilesize, "set-filesize", "@"),
ARGPARSE_s_n (oFastListMode, "fast-list-mode", "@"),
ARGPARSE_s_n (oFixedListMode, "fixed-list-mode", "@"),
ARGPARSE_s_n (oLegacyListMode, "legacy-list-mode", "@"),
ARGPARSE_s_n (oListOnly, "list-only", "@"),
ARGPARSE_s_n (oPrintPKARecords, "print-pka-records", "@"),
ARGPARSE_s_n (oPrintDANERecords, "print-dane-records", "@"),
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
ARGPARSE_s_n (oIgnoreValidFrom, "ignore-valid-from", "@"),
ARGPARSE_s_n (oIgnoreCrcError, "ignore-crc-error", "@"),
ARGPARSE_s_n (oIgnoreMDCError, "ignore-mdc-error", "@"),
ARGPARSE_s_n (oShowSessionKey, "show-session-key", "@"),
ARGPARSE_s_s (oOverrideSessionKey, "override-session-key", "@"),
ARGPARSE_s_i (oOverrideSessionKeyFD, "override-session-key-fd", "@"),
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
ARGPARSE_s_n (oAutoKeyRetrieve, "auto-key-retrieve", "@"),
ARGPARSE_s_n (oNoAutoKeyRetrieve, "no-auto-key-retrieve", "@"),
ARGPARSE_s_n (oNoSigCache, "no-sig-cache", "@"),
ARGPARSE_s_n (oMergeOnly, "merge-only", "@" ),
ARGPARSE_s_n (oAllowSecretKeyImport, "allow-secret-key-import", "@"),
ARGPARSE_s_n (oTryAllSecrets, "try-all-secrets", "@"),
ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
ARGPARSE_s_n (oNoExpensiveTrustChecks, "no-expensive-trust-checks", "@"),
ARGPARSE_s_n (oPreservePermissions, "preserve-permissions", "@"),
ARGPARSE_s_s (oDefaultPreferenceList, "default-preference-list", "@"),
ARGPARSE_s_s (oDefaultKeyserverURL, "default-keyserver-url", "@"),
ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"),
ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-preferences","@"),
ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"),
ARGPARSE_s_s (oPersonalCompressPreferences,
"personal-compress-preferences", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
ARGPARSE_s_s (oWeakDigest, "weak-digest","@"),
ARGPARSE_s_n (oUnwrap, "unwrap", "@"),
ARGPARSE_s_n (oOnlySignTextIDs, "only-sign-text-ids", "@"),
/* Aliases. I constantly mistype these, and assume other people do
as well. */
ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"),
ARGPARSE_s_s (oPersonalAEADPreferences, "personal-aead-prefs", "@"),
ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"),
ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"),
ARGPARSE_s_n (oDisableDirmngr, "disable-dirmngr", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"),
ARGPARSE_s_s (oTTYname, "ttyname", "@"),
ARGPARSE_s_s (oTTYtype, "ttytype", "@"),
ARGPARSE_s_s (oLCctype, "lc-ctype", "@"),
ARGPARSE_s_s (oLCmessages, "lc-messages","@"),
ARGPARSE_s_s (oXauthority, "xauthority", "@"),
ARGPARSE_s_s (oGroup, "group", "@"),
ARGPARSE_s_s (oUnGroup, "ungroup", "@"),
ARGPARSE_s_n (oNoGroups, "no-groups", "@"),
ARGPARSE_s_n (oStrict, "strict", "@"),
ARGPARSE_s_n (oNoStrict, "no-strict", "@"),
ARGPARSE_s_n (oMangleDosFilenames, "mangle-dos-filenames", "@"),
ARGPARSE_s_n (oNoMangleDosFilenames, "no-mangle-dos-filenames", "@"),
ARGPARSE_s_n (oEnableProgressFilter, "enable-progress-filter", "@"),
ARGPARSE_s_n (oMultifile, "multifile", "@"),
ARGPARSE_s_s (oKeyidFormat, "keyid-format", "@"),
ARGPARSE_s_n (oExitOnStatusWriteError, "exit-on-status-write-error", "@"),
ARGPARSE_s_i (oLimitCardInsertTries, "limit-card-insert-tries", "@"),
ARGPARSE_s_n (oAllowMultisigVerification,
"allow-multisig-verification", "@"),
ARGPARSE_s_n (oEnableLargeRSA, "enable-large-rsa", "@"),
ARGPARSE_s_n (oDisableLargeRSA, "disable-large-rsa", "@"),
ARGPARSE_s_n (oEnableDSA2, "enable-dsa2", "@"),
ARGPARSE_s_n (oDisableDSA2, "disable-dsa2", "@"),
ARGPARSE_s_n (oAllowMultipleMessages, "allow-multiple-messages", "@"),
ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"),
ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"),
ARGPARSE_s_s (oDefaultNewKeyAlgo, "default-new-key-algo", "@"),
/* These two are aliases to help users of the PGP command line
product use gpg with minimal pain. Many commands are common
already as they seem to have borrowed commands from us. Now I'm
returning the favor. */
ARGPARSE_s_s (oLocalUser, "sign-with", "@"),
ARGPARSE_s_s (oRecipient, "user", "@"),
ARGPARSE_s_n (oRequireCrossCert, "require-backsigs", "@"),
ARGPARSE_s_n (oRequireCrossCert, "require-cross-certification", "@"),
ARGPARSE_s_n (oNoRequireCrossCert, "no-require-backsigs", "@"),
ARGPARSE_s_n (oNoRequireCrossCert, "no-require-cross-certification", "@"),
/* New options. Fixme: Should go more to the top. */
ARGPARSE_s_s (oAutoKeyLocate, "auto-key-locate", "@"),
ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"),
ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"),
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
/* Dummy options with warnings. */
ARGPARSE_s_n (oUseAgent, "use-agent", "@"),
ARGPARSE_s_n (oNoUseAgent, "no-use-agent", "@"),
ARGPARSE_s_s (oGpgAgentInfo, "gpg-agent-info", "@"),
ARGPARSE_s_s (oReaderPort, "reader-port", "@"),
ARGPARSE_s_s (octapiDriver, "ctapi-driver", "@"),
ARGPARSE_s_s (opcscDriver, "pcsc-driver", "@"),
ARGPARSE_s_n (oDisableCCID, "disable-ccid", "@"),
ARGPARSE_s_n (oHonorHttpProxy, "honor-http-proxy", "@"),
ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
/* Dummy options. */
ARGPARSE_s_n (oNoop, "sk-comments", "@"),
ARGPARSE_s_n (oNoop, "no-sk-comments", "@"),
ARGPARSE_s_n (oNoop, "compress-keys", "@"),
ARGPARSE_s_n (oNoop, "compress-sigs", "@"),
ARGPARSE_s_n (oNoop, "force-v3-sigs", "@"),
ARGPARSE_s_n (oNoop, "no-force-v3-sigs", "@"),
ARGPARSE_s_n (oNoop, "force-v4-certs", "@"),
ARGPARSE_s_n (oNoop, "no-force-v4-certs", "@"),
ARGPARSE_s_n (oNoop, "no-mdc-warning", "@"),
ARGPARSE_s_n (oNoop, "force-mdc", "@"),
ARGPARSE_s_n (oNoop, "no-force-mdc", "@"),
ARGPARSE_s_n (oNoop, "disable-mdc", "@"),
ARGPARSE_s_n (oNoop, "no-disable-mdc", "@"),
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 }
};
#ifdef ENABLE_SELINUX_HACKS
#define ALWAYS_ADD_KEYRINGS 1
#else
#define ALWAYS_ADD_KEYRINGS 0
#endif
int g10_errors_seen = 0;
static int utf8_strings = 0;
static int maybe_setuid = 1;
static unsigned int opt_set_iobuf_size;
static unsigned int opt_set_iobuf_size_used;
static char *build_list( const char *text, char letter,
const char *(*mapf)(int), int (*chkf)(int) );
static void set_cmd( enum cmd_and_opt_values *ret_cmd,
enum cmd_and_opt_values new_cmd );
static void print_mds( const char *fname, int algo );
static void add_notation_data( const char *string, int which );
static void add_policy_url( const char *string, int which );
static void add_keyserver_url( const char *string, int which );
static void emergency_cleanup (void);
static void read_sessionkey_from_fd (int fd);
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
const char *s;
char *result;
if (maybe_setuid)
{
gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */
maybe_setuid = 0;
}
s = getfnc (NULL);
result = xmalloc (strlen (libname) + 1 + strlen (s) + 1);
strcpy (stpcpy (stpcpy (result, libname), " "), s);
return result;
}
static int
build_list_pk_test_algo (int algo)
{
/* Show only one "RSA" string. If RSA_E or RSA_S is available RSA
is also available. */
if (algo == PUBKEY_ALGO_RSA_E
|| algo == PUBKEY_ALGO_RSA_S)
return GPG_ERR_DIGEST_ALGO;
return openpgp_pk_test_algo (algo);
}
static const char *
build_list_pk_algo_name (int algo)
{
return openpgp_pk_algo_name (algo);
}
static int
build_list_cipher_test_algo (int algo)
{
return openpgp_cipher_test_algo (algo);
}
static const char *
build_list_cipher_algo_name (int algo)
{
return openpgp_cipher_algo_name (algo);
}
static int
build_list_aead_test_algo (int algo)
{
return openpgp_aead_test_algo (algo);
}
static const char *
build_list_aead_algo_name (int algo)
{
return openpgp_aead_algo_name (algo);
}
static int
build_list_md_test_algo (int algo)
{
/* By default we do not accept MD5 based signatures. To avoid
confusion we do not announce support for it either. */
if (algo == DIGEST_ALGO_MD5)
return GPG_ERR_DIGEST_ALGO;
return openpgp_md_test_algo (algo);
}
static const char *
build_list_md_algo_name (int algo)
{
return openpgp_md_algo_name (algo);
}
static const char *
my_strusage( int level )
{
static char *digests, *pubkeys, *ciphers, *zips, *aeads, *ver_gcry;
const char *p;
switch( level ) {
case 11: p = "@GPG@ (@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 20:
if (!ver_gcry)
ver_gcry = make_libversion ("libgcrypt", gcry_check_version);
p = ver_gcry;
break;
#ifdef IS_DEVELOPMENT_VERSION
case 25:
p="NOTE: THIS IS A DEVELOPMENT VERSION!";
break;
case 26:
p="It is only intended for test purposes and should NOT be";
break;
case 27:
p="used in a production environment or with production keys!";
break;
#endif
case 1:
case 40: p =
_("Usage: @GPG@ [options] [files] (-h for help)");
break;
case 41: p =
_("Syntax: @GPG@ [options] [files]\n"
"Sign, check, encrypt or decrypt\n"
"Default operation depends on the input data\n");
break;
case 31: p = "\nHome: "; break;
#ifndef __riscos__
case 32: p = gnupg_homedir (); break;
#else /* __riscos__ */
case 32: p = make_filename(gnupg_homedir (), NULL); break;
#endif /* __riscos__ */
case 33: p = _("\nSupported algorithms:\n"); break;
case 34:
if (!pubkeys)
pubkeys = build_list (_("Pubkey: "), 1,
build_list_pk_algo_name,
build_list_pk_test_algo );
p = pubkeys;
break;
case 35:
if( !ciphers )
ciphers = build_list(_("Cipher: "), 'S',
build_list_cipher_algo_name,
build_list_cipher_test_algo );
p = ciphers;
break;
case 36:
if (!aeads)
aeads = build_list ("AEAD: ", 'A',
build_list_aead_algo_name,
build_list_aead_test_algo);
p = aeads;
break;
case 37:
if( !digests )
digests = build_list(_("Hash: "), 'H',
build_list_md_algo_name,
build_list_md_test_algo );
p = digests;
break;
case 38:
if( !zips )
zips = build_list(_("Compression: "),'Z',
compress_algo_to_string,
check_compress_algo);
p = zips;
break;
default: p = NULL;
}
return p;
}
static char *
build_list (const char *text, char letter,
const char * (*mapf)(int), int (*chkf)(int))
{
membuf_t mb;
int indent;
int i, j, len;
int limit;
const char *s;
char *string;
if (maybe_setuid)
gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */
indent = utf8_charcount (text, -1);
len = 0;
init_membuf (&mb, 512);
limit = (letter == 'A')? 4 : 110;
for (i=0; i <= limit; i++ )
{
if (!chkf (i) && (s = mapf (i)))
{
if (mb.len - len > 60)
{
put_membuf_str (&mb, ",\n");
len = mb.len;
for (j=0; j < indent; j++)
put_membuf_str (&mb, " ");
}
else if (mb.len)
put_membuf_str (&mb, ", ");
else
put_membuf_str (&mb, text);
put_membuf_str (&mb, s);
if (opt.verbose && letter)
{
char num[20];
if (letter == 1)
snprintf (num, sizeof num, " (%d)", i);
else
snprintf (num, sizeof num, " (%c%d)", letter, i);
put_membuf_str (&mb, num);
}
}
}
if (mb.len)
put_membuf_str (&mb, "\n");
put_membuf (&mb, "", 1);
string = get_membuf (&mb, NULL);
return xrealloc (string, strlen (string)+1);
}
static void
wrong_args( const char *text)
{
es_fprintf (es_stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
log_inc_errorcount ();
g10_exit(2);
}
static char *
make_username( const char *string )
{
char *p;
if( utf8_strings )
p = xstrdup(string);
else
p = native_to_utf8( string );
return p;
}
static void
set_opt_session_env (const char *name, const char *value)
{
gpg_error_t err;
err = session_env_setenv (opt.session_env, name, value);
if (err)
log_fatal ("error setting session environment: %s\n",
gpg_strerror (err));
}
/* Setup the debugging. With a LEVEL of NULL only the active debug
flags are propagated to the subsystems. With LEVEL set, a specific
set of debug flags is set; thus overriding all flags already
set. */
static void
set_debug (const char *level)
{
int numok = (level && digitp (level));
int numlvl = numok? atoi (level) : 0;
if (!level)
;
else if (!strcmp (level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (level, "basic") || (numok && numlvl <= 2))
opt.debug = DBG_MEMSTAT_VALUE;
else if (!strcmp (level, "advanced") || (numok && numlvl <= 5))
opt.debug = DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE;
else if (!strcmp (level, "expert") || (numok && numlvl <= 8))
opt.debug = (DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE
|DBG_CACHE_VALUE|DBG_LOOKUP|DBG_FILTER_VALUE|DBG_PACKET_VALUE);
else if (!strcmp (level, "guru") || numok)
{
opt.debug = ~0;
/* Unless the "guru" string has been used we don't want to allow
hashing debugging. The rationale is that people tend to
select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */
if (numok)
opt.debug &= ~(DBG_HASHING_VALUE);
}
else
{
log_error (_("invalid debug-level '%s' given\n"), level);
g10_exit (2);
}
if ((opt.debug & DBG_MEMORY_VALUE))
memory_debug_mode = 1;
if ((opt.debug & DBG_MEMSTAT_VALUE))
memory_stat_debug_mode = 1;
if (DBG_MPI)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
if (DBG_CRYPTO)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
if ((opt.debug & DBG_IOBUF_VALUE))
iobuf_debug_mode = 1;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
parse_debug_flag (NULL, &opt.debug, debug_flags);
if (opt_set_iobuf_size || opt_set_iobuf_size_used)
log_debug ("iobuf buffer size is %uk\n",
iobuf_set_buffer_size (opt_set_iobuf_size));
}
/* We set the screen dimensions for UI purposes. Do not allow screens
smaller than 80x24 for the sake of simplicity. */
static void
set_screen_dimensions(void)
{
#ifndef HAVE_W32_SYSTEM
char *str;
str=getenv("COLUMNS");
if(str)
opt.screen_columns=atoi(str);
str=getenv("LINES");
if(str)
opt.screen_lines=atoi(str);
#endif
if(opt.screen_columns<80 || opt.screen_columns>255)
opt.screen_columns=80;
if(opt.screen_lines<24 || opt.screen_lines>255)
opt.screen_lines=24;
}
/* Helper to open a file FNAME either for reading or writing to be
used with --status-file etc functions. Not generally useful but it
avoids the riscos specific functions and well some Windows people
might like it too. Prints an error message and returns -1 on
error. On success the file descriptor is returned. */
static int
open_info_file (const char *fname, int for_write, int binary)
{
#ifdef __riscos__
return riscos_fdopenfile (fname, for_write);
#elif defined (ENABLE_SELINUX_HACKS)
/* We can't allow these even when testing for a secured filename
because files to be secured might not yet been secured. This is
similar to the option file but in that case it is unlikely that
sensitive information may be retrieved by means of error
messages. */
(void)fname;
(void)for_write;
(void)binary;
return -1;
#else
int fd;
if (binary)
binary = MY_O_BINARY;
/* if (is_secured_filename (fname)) */
/* { */
/* fd = -1; */
/* gpg_err_set_errno (EPERM); */
/* } */
/* else */
/* { */
do
{
if (for_write)
fd = open (fname, O_CREAT | O_TRUNC | O_WRONLY | binary,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
else
fd = open (fname, O_RDONLY | binary);
}
while (fd == -1 && errno == EINTR);
/* } */
if ( fd == -1)
log_error ( for_write? _("can't create '%s': %s\n")
: _("can't open '%s': %s\n"), fname, strerror(errno));
return fd;
#endif
}
static void
set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd )
{
enum cmd_and_opt_values cmd = *ret_cmd;
if( !cmd || cmd == new_cmd )
cmd = new_cmd;
else if( cmd == aSign && new_cmd == aEncr )
cmd = aSignEncr;
else if( cmd == aEncr && new_cmd == aSign )
cmd = aSignEncr;
else if( cmd == aSign && new_cmd == aSym )
cmd = aSignSym;
else if( cmd == aSym && new_cmd == aSign )
cmd = aSignSym;
else if( cmd == aSym && new_cmd == aEncr )
cmd = aEncrSym;
else if( cmd == aEncr && new_cmd == aSym )
cmd = aEncrSym;
else if (cmd == aSignEncr && new_cmd == aSym)
cmd = aSignEncrSym;
else if (cmd == aSignSym && new_cmd == aEncr)
cmd = aSignEncrSym;
else if (cmd == aEncrSym && new_cmd == aSign)
cmd = aSignEncrSym;
else if( ( cmd == aSign && new_cmd == aClearsign )
|| ( cmd == aClearsign && new_cmd == aSign ) )
cmd = aClearsign;
else {
log_error(_("conflicting commands\n"));
g10_exit(2);
}
*ret_cmd = cmd;
}
static void
add_group(char *string)
{
char *name,*value;
struct groupitem *item;
/* Break off the group name */
name=strsep(&string,"=");
if(string==NULL)
{
log_error(_("no = sign found in group definition '%s'\n"),name);
return;
}
trim_trailing_ws(name,strlen(name));
/* Does this group already exist? */
for(item=opt.grouplist;item;item=item->next)
if(strcasecmp(item->name,name)==0)
break;
if(!item)
{
item=xmalloc(sizeof(struct groupitem));
item->name=name;
item->next=opt.grouplist;
item->values=NULL;
opt.grouplist=item;
}
/* Break apart the values */
while ((value= strsep(&string," \t")))
{
if (*value)
add_to_strlist2(&item->values,value,utf8_strings);
}
}
static void
rm_group(char *name)
{
struct groupitem *item,*last=NULL;
trim_trailing_ws(name,strlen(name));
for(item=opt.grouplist;item;last=item,item=item->next)
{
if(strcasecmp(item->name,name)==0)
{
if(last)
last->next=item->next;
else
opt.grouplist=item->next;
free_strlist(item->values);
xfree(item);
break;
}
}
}
/* We need to check three things.
0) The homedir. It must be x00, a directory, and owned by the
user.
1) The options/gpg.conf file. Okay unless it or its containing
directory is group or other writable or not owned by us. Disable
exec in this case.
2) Extensions. Same as #1.
Returns true if the item is unsafe. */
static int
check_permissions (const char *path, int item)
{
#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
static int homedir_cache=-1;
char *tmppath,*dir;
struct stat statbuf,dirbuf;
int homedir=0,ret=0,checkonly=0;
int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0;
if(opt.no_perm_warn)
return 0;
log_assert(item==0 || item==1 || item==2);
/* extensions may attach a path */
if(item==2 && path[0]!=DIRSEP_C)
{
if(strchr(path,DIRSEP_C))
tmppath=make_filename(path,NULL);
else
tmppath=make_filename(gnupg_libdir (),path,NULL);
}
else
tmppath=xstrdup(path);
/* If the item is located in the homedir, but isn't the homedir,
don't continue if we already checked the homedir itself. This is
to avoid user confusion with an extra options file warning which
could be rectified if the homedir itself had proper
permissions. */
if(item!=0 && homedir_cache>-1
&& !ascii_strncasecmp (gnupg_homedir (), tmppath,
strlen (gnupg_homedir ())))
{
ret=homedir_cache;
goto end;
}
/* It's okay if the file or directory doesn't exist */
if(stat(tmppath,&statbuf)!=0)
{
ret=0;
goto end;
}
/* Now check the enclosing directory. Theoretically, we could walk
this test up to the root directory /, but for the sake of sanity,
I'm stopping at one level down. */
dir=make_dirname(tmppath);
if(stat(dir,&dirbuf)!=0 || !S_ISDIR(dirbuf.st_mode))
{
/* Weird error */
ret=1;
goto end;
}
xfree(dir);
/* Assume failure */
ret=1;
if(item==0)
{
/* The homedir must be x00, a directory, and owned by the user. */
if(S_ISDIR(statbuf.st_mode))
{
if(statbuf.st_uid==getuid())
{
if((statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
ret=0;
else
perm=1;
}
else
own=1;
homedir_cache=ret;
}
}
else if(item==1 || item==2)
{
/* The options or extension file. Okay unless it or its
containing directory is group or other writable or not owned
by us or root. */
if(S_ISREG(statbuf.st_mode))
{
if(statbuf.st_uid==getuid() || statbuf.st_uid==0)
{
if((statbuf.st_mode & (S_IWGRP|S_IWOTH))==0)
{
/* it's not writable, so make sure the enclosing
directory is also not writable */
if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0)
{
if((dirbuf.st_mode & (S_IWGRP|S_IWOTH))==0)
ret=0;
else
enc_dir_perm=1;
}
else
enc_dir_own=1;
}
else
{
/* it's writable, so the enclosing directory had
better not let people get to it. */
if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0)
{
if((dirbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
ret=0;
else
perm=enc_dir_perm=1; /* unclear which one to fix! */
}
else
enc_dir_own=1;
}
}
else
own=1;
}
}
else
BUG();
if(!checkonly)
{
if(own)
{
if(item==0)
log_info(_("WARNING: unsafe ownership on"
" homedir '%s'\n"),tmppath);
else if(item==1)
log_info(_("WARNING: unsafe ownership on"
" configuration file '%s'\n"),tmppath);
else
log_info(_("WARNING: unsafe ownership on"
" extension '%s'\n"),tmppath);
}
if(perm)
{
if(item==0)
log_info(_("WARNING: unsafe permissions on"
" homedir '%s'\n"),tmppath);
else if(item==1)
log_info(_("WARNING: unsafe permissions on"
" configuration file '%s'\n"),tmppath);
else
log_info(_("WARNING: unsafe permissions on"
" extension '%s'\n"),tmppath);
}
if(enc_dir_own)
{
if(item==0)
log_info(_("WARNING: unsafe enclosing directory ownership on"
" homedir '%s'\n"),tmppath);
else if(item==1)
log_info(_("WARNING: unsafe enclosing directory ownership on"
" configuration file '%s'\n"),tmppath);
else
log_info(_("WARNING: unsafe enclosing directory ownership on"
" extension '%s'\n"),tmppath);
}
if(enc_dir_perm)
{
if(item==0)
log_info(_("WARNING: unsafe enclosing directory permissions on"
" homedir '%s'\n"),tmppath);
else if(item==1)
log_info(_("WARNING: unsafe enclosing directory permissions on"
" configuration file '%s'\n"),tmppath);
else
log_info(_("WARNING: unsafe enclosing directory permissions on"
" extension '%s'\n"),tmppath);
}
}
end:
xfree(tmppath);
if(homedir)
homedir_cache=ret;
return ret;
#else /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/
(void)path;
(void)item;
return 0;
#endif /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/
}
/* Print the OpenPGP defined algo numbers. */
static void
print_algo_numbers(int (*checker)(int))
{
int i,first=1;
for(i=0;i<=110;i++)
{
if(!checker(i))
{
if(first)
first=0;
else
es_printf (";");
es_printf ("%d",i);
}
}
}
static void
print_algo_names(int (*checker)(int),const char *(*mapper)(int))
{
int i,first=1;
for(i=0;i<=110;i++)
{
if(!checker(i))
{
if(first)
first=0;
else
es_printf (";");
es_printf ("%s",mapper(i));
}
}
}
/* In the future, we can do all sorts of interesting configuration
output here. For now, just give "group" as the Enigmail folks need
it, and pubkey, cipher, hash, and compress as they may be useful
for frontends. */
static void
list_config(char *items)
{
int show_all = !items;
char *name = NULL;
const char *s;
struct groupitem *giter;
int first, iter;
if(!opt.with_colons)
return;
while(show_all || (name=strsep(&items," ")))
{
int any=0;
if(show_all || ascii_strcasecmp(name,"group")==0)
{
for (giter = opt.grouplist; giter; giter = giter->next)
{
strlist_t sl;
es_fprintf (es_stdout, "cfg:group:");
es_write_sanitized (es_stdout, giter->name, strlen(giter->name),
":", NULL);
es_putc (':', es_stdout);
for(sl=giter->values; sl; sl=sl->next)
{
es_write_sanitized (es_stdout, sl->d, strlen (sl->d),
":;", NULL);
if(sl->next)
es_printf(";");
}
es_printf("\n");
}
any=1;
}
if(show_all || ascii_strcasecmp(name,"version")==0)
{
es_printf("cfg:version:");
es_write_sanitized (es_stdout, VERSION, strlen(VERSION), ":", NULL);
es_printf ("\n");
any=1;
}
if(show_all || ascii_strcasecmp(name,"pubkey")==0)
{
es_printf ("cfg:pubkey:");
print_algo_numbers (build_list_pk_test_algo);
es_printf ("\n");
any=1;
}
if(show_all || ascii_strcasecmp(name,"pubkeyname")==0)
{
es_printf ("cfg:pubkeyname:");
print_algo_names (build_list_pk_test_algo,
build_list_pk_algo_name);
es_printf ("\n");
any=1;
}
if(show_all || ascii_strcasecmp(name,"cipher")==0)
{
es_printf ("cfg:cipher:");
print_algo_numbers (build_list_cipher_test_algo);
es_printf ("\n");
any=1;
}
if (show_all || !ascii_strcasecmp (name,"ciphername"))
{
es_printf ("cfg:ciphername:");
print_algo_names (build_list_cipher_test_algo,
build_list_cipher_algo_name);
es_printf ("\n");
any = 1;
}
if(show_all
|| ascii_strcasecmp(name,"digest")==0
|| ascii_strcasecmp(name,"hash")==0)
{
es_printf ("cfg:digest:");
print_algo_numbers (build_list_md_test_algo);
es_printf ("\n");
any=1;
}
if (show_all
|| !ascii_strcasecmp(name,"digestname")
|| !ascii_strcasecmp(name,"hashname"))
{
es_printf ("cfg:digestname:");
print_algo_names (build_list_md_test_algo,
build_list_md_algo_name);
es_printf ("\n");
any=1;
}
if(show_all || ascii_strcasecmp(name,"compress")==0)
{
es_printf ("cfg:compress:");
print_algo_numbers(check_compress_algo);
es_printf ("\n");
any=1;
}
if(show_all || ascii_strcasecmp (name, "compressname") == 0)
{
es_printf ("cfg:compressname:");
print_algo_names (check_compress_algo,
compress_algo_to_string);
es_printf ("\n");
any=1;
}
if (show_all || !ascii_strcasecmp(name,"ccid-reader-id"))
{
/* We ignore this for GnuPG 1.4 backward compatibility. */
any=1;
}
if (show_all || !ascii_strcasecmp (name,"curve"))
{
es_printf ("cfg:curve:");
for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first=0)
es_printf ("%s%s", first?"":";", s);
es_printf ("\n");
any=1;
}
/* Curve OIDs are rarely useful and thus only printed if requested. */
if (name && !ascii_strcasecmp (name,"curveoid"))
{
es_printf ("cfg:curveoid:");
for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first = 0)
{
s = openpgp_curve_to_oid (s, NULL);
es_printf ("%s%s", first?"":";", s? s:"[?]");
}
es_printf ("\n");
any=1;
}
if(show_all)
break;
if(!any)
log_error(_("unknown configuration item '%s'\n"),name);
}
}
/* List options and default values in the GPG Conf format. This is a
new tool distributed with gnupg 1.9.x but we also want some limited
support in older gpg versions. The output is the name of the
configuration file and a list of options available for editing by
gpgconf. */
static void
gpgconf_list (const char *configfile)
{
char *configfile_esc = percent_escape (configfile, NULL);
es_printf ("%s-%s.conf:%lu:\"%s\n",
GPGCONF_NAME, GPG_NAME,
GC_OPT_FLAG_DEFAULT,
configfile_esc ? configfile_esc : "/dev/null");
es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("auto-key-retrieve:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
es_printf ("group:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("compliance:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "gnupg");
es_printf ("default-new-key-algo:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("trust-model:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("disable-dirmngr:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("max-cert-depth:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("completes-needed:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("marginals-needed:%lu:\n", GC_OPT_FLAG_NONE);
/* The next one is an info only item and should match the macros at
the top of keygen.c */
es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT,
get_default_pubkey_algo ());
xfree (configfile_esc);
}
static int
parse_subpacket_list(char *list)
{
char *tok;
byte subpackets[128],i;
int count=0;
if(!list)
{
/* No arguments means all subpackets */
memset(subpackets+1,1,sizeof(subpackets)-1);
count=127;
}
else
{
memset(subpackets,0,sizeof(subpackets));
/* Merge with earlier copy */
if(opt.show_subpackets)
{
byte *in;
for(in=opt.show_subpackets;*in;in++)
{
if(*in>127 || *in<1)
BUG();
if(!subpackets[*in])
count++;
subpackets[*in]=1;
}
}
while((tok=strsep(&list," ,")))
{
if(!*tok)
continue;
i=atoi(tok);
if(i>127 || i<1)
return 0;
if(!subpackets[i])
count++;
subpackets[i]=1;
}
}
xfree(opt.show_subpackets);
opt.show_subpackets=xmalloc(count+1);
opt.show_subpackets[count--]=0;
for(i=1;i<128 && count>=0;i++)
if(subpackets[i])
opt.show_subpackets[count--]=i;
return 1;
}
static int
parse_list_options(char *str)
{
char *subpackets=""; /* something that isn't NULL */
struct parse_options lopts[]=
{
{"show-photos",LIST_SHOW_PHOTOS,NULL,
N_("display photo IDs during key listings")},
{"show-usage",LIST_SHOW_USAGE,NULL,
N_("show key usage information during key listings")},
{"show-policy-urls",LIST_SHOW_POLICY_URLS,NULL,
N_("show policy URLs during signature listings")},
{"show-notations",LIST_SHOW_NOTATIONS,NULL,
N_("show all notations during signature listings")},
{"show-std-notations",LIST_SHOW_STD_NOTATIONS,NULL,
N_("show IETF standard notations during signature listings")},
{"show-standard-notations",LIST_SHOW_STD_NOTATIONS,NULL,
NULL},
{"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL,
N_("show user-supplied notations during signature listings")},
{"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL,
N_("show preferred keyserver URLs during signature listings")},
{"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL,
N_("show user ID validity during key listings")},
{"show-unusable-uids",LIST_SHOW_UNUSABLE_UIDS,NULL,
N_("show revoked and expired user IDs in key listings")},
{"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL,
N_("show revoked and expired subkeys in key listings")},
{"show-keyring",LIST_SHOW_KEYRING,NULL,
N_("show the keyring name in key listings")},
{"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL,
N_("show expiration dates during signature listings")},
{"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL,
NULL},
{NULL,0,NULL,NULL}
};
/* C99 allows for non-constant initializers, but we'd like to
compile everywhere, so fill in the show-sig-subpackets argument
here. Note that if the parse_options array changes, we'll have
to change the subscript here. */
lopts[13].value=&subpackets;
if(parse_options(str,&opt.list_options,lopts,1))
{
if(opt.list_options&LIST_SHOW_SIG_SUBPACKETS)
{
/* Unset so users can pass multiple lists in. */
opt.list_options&=~LIST_SHOW_SIG_SUBPACKETS;
if(!parse_subpacket_list(subpackets))
return 0;
}
else if(subpackets==NULL && opt.show_subpackets)
{
/* User did 'no-show-subpackets' */
xfree(opt.show_subpackets);
opt.show_subpackets=NULL;
}
return 1;
}
else
return 0;
}
/* Collapses argc/argv into a single string that must be freed */
static char *
collapse_args(int argc,char *argv[])
{
char *str=NULL;
int i,first=1,len=0;
for(i=0;imagic = SERVER_CONTROL_MAGIC;
}
/* This function is called to deinitialize a control object. It is
not deallocated. */
static void
gpg_deinit_default_ctrl (ctrl_t ctrl)
{
#ifdef USE_TOFU
tofu_closedbs (ctrl);
#endif
gpg_dirmngr_deinit_session_data (ctrl);
keydb_release (ctrl->cached_getkey_kdb);
}
char *
get_default_configname (void)
{
char *configname = NULL;
char *name = xstrdup (GPG_NAME EXTSEP_S "conf-" SAFE_VERSION);
char *ver = &name[strlen (GPG_NAME EXTSEP_S "conf-")];
do
{
if (configname)
{
char *tok;
xfree (configname);
configname = NULL;
if ((tok = strrchr (ver, SAFE_VERSION_DASH)))
*tok='\0';
else if ((tok = strrchr (ver, SAFE_VERSION_DOT)))
*tok='\0';
else
break;
}
configname = make_filename (gnupg_homedir (), name, NULL);
}
while (access (configname, R_OK));
xfree(name);
if (! configname)
configname = make_filename (gnupg_homedir (),
GPG_NAME EXTSEP_S "conf", NULL);
if (! access (configname, R_OK))
{
/* Print a warning when both config files are present. */
char *p = make_filename (gnupg_homedir (), "options", NULL);
if (! access (p, R_OK))
log_info (_("Note: old default options file '%s' ignored\n"), p);
xfree (p);
}
else
{
/* Use the old default only if it exists. */
char *p = make_filename (gnupg_homedir (), "options", NULL);
if (!access (p, R_OK))
{
xfree (configname);
configname = p;
}
else
xfree (p);
}
return configname;
}
int
main (int argc, char **argv)
{
ARGPARSE_ARGS pargs;
IOBUF a;
int rc=0;
int orig_argc;
char **orig_argv;
const char *fname;
char *username;
int may_coredump;
strlist_t sl;
strlist_t remusr = NULL;
strlist_t locusr = NULL;
strlist_t nrings = NULL;
armor_filter_context_t *afx = NULL;
int detached_sig = 0;
FILE *configfp = NULL;
char *configname = NULL;
char *save_configname = NULL;
char *default_configname = NULL;
unsigned configlineno;
int parse_debug = 0;
int default_config = 1;
int default_keyring = 1;
int greeting = 0;
int nogreeting = 0;
char *logfile = NULL;
int use_random_seed = 1;
enum cmd_and_opt_values cmd = 0;
const char *debug_level = NULL;
#ifndef NO_TRUST_MODELS
const char *trustdb_name = NULL;
#endif /*!NO_TRUST_MODELS*/
char *def_cipher_string = NULL;
char *def_aead_string = NULL;
char *def_digest_string = NULL;
char *compress_algo_string = NULL;
char *cert_digest_string = NULL;
char *s2k_cipher_string = NULL;
char *s2k_digest_string = NULL;
char *pers_cipher_list = NULL;
char *pers_aead_list = NULL;
char *pers_digest_list = NULL;
char *pers_compress_list = NULL;
int eyes_only=0;
int multifile=0;
int pwfd = -1;
int ovrseskeyfd = -1;
int fpr_maybe_cmd = 0; /* --fingerprint maybe a command. */
int any_explicit_recipient = 0;
int default_akl = 1;
int require_secmem = 0;
int got_secmem = 0;
struct assuan_malloc_hooks malloc_hooks;
ctrl_t ctrl;
static int print_dane_records;
static int print_pka_records;
#ifdef __riscos__
opt.lock_once = 1;
#endif /* __riscos__ */
/* Please note that we may running SUID(ROOT), so be very CAREFUL
when adding any stuff between here and the call to
secmem_init() somewhere after the option parsing. */
early_system_init ();
gnupg_reopen_std (GPG_NAME);
trap_unaligned ();
gnupg_rl_initialize ();
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
log_set_prefix (GPG_NAME, GPGRT_LOG_WITH_PREFIX);
/* Make sure that our subsystems are ready. */
i18n_init();
init_common_subsystems (&argc, &argv);
/* Use our own logging handler for Libcgrypt. */
setup_libgcrypt_logging ();
/* Put random number into secure memory */
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
may_coredump = disable_core_dumps();
gnupg_init_signals (0, emergency_cleanup);
dotlock_create (NULL, 0); /* Register lock file cleanup. */
/* Tell the compliance module who we are. */
gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG);
opt.autostart = 1;
opt.session_env = session_env_new ();
if (!opt.session_env)
log_fatal ("error allocating session environment block: %s\n",
strerror (errno));
opt.command_fd = -1; /* no command fd */
opt.compress_level = -1; /* defaults to standard compress level */
opt.bz2_compress_level = -1; /* defaults to standard compress level */
/* note: if you change these lines, look at oOpenPGP */
opt.def_cipher_algo = 0;
opt.def_aead_algo = 0;
opt.def_digest_algo = 0;
opt.cert_digest_algo = 0;
opt.compress_algo = -1; /* defaults to DEFAULT_COMPRESS_ALGO */
opt.s2k_mode = 3; /* iterated+salted */
opt.s2k_count = 0; /* Auto-calibrate when needed. */
opt.s2k_cipher_algo = DEFAULT_CIPHER_ALGO;
opt.completes_needed = 1;
opt.marginals_needed = 3;
opt.max_cert_depth = 5;
opt.escape_from = 1;
opt.flags.require_cross_cert = 1;
opt.import_options = IMPORT_REPAIR_KEYS;
opt.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
| IMPORT_REPAIR_PKS_SUBKEY_BUG);
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
opt.verify_options = (LIST_SHOW_UID_VALIDITY
| VERIFY_SHOW_POLICY_URLS
| VERIFY_SHOW_STD_NOTATIONS
| VERIFY_SHOW_KEYSERVER_URLS);
opt.list_options = (LIST_SHOW_UID_VALIDITY
| LIST_SHOW_USAGE);
#ifdef NO_TRUST_MODELS
opt.trust_model = TM_ALWAYS;
#else
opt.trust_model = TM_AUTO;
#endif
opt.tofu_default_policy = TOFU_POLICY_AUTO;
opt.mangle_dos_filenames = 0;
opt.min_cert_level = 2;
set_screen_dimensions ();
opt.keyid_format = KF_NONE;
opt.def_sig_expire = "0";
opt.def_cert_expire = "0";
gnupg_set_homedir (NULL);
opt.passphrase_repeat = 1;
opt.emit_version = 0;
opt.weak_digests = NULL;
/* Check whether we have a config file on the command line. */
orig_argc = argc;
orig_argv = argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
while( arg_parse( &pargs, opts) ) {
if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
parse_debug++;
else if (pargs.r_opt == oDebugIOLBF)
es_setvbuf (es_stdout, NULL, _IOLBF, 0);
else if( pargs.r_opt == oOptions ) {
/* yes there is one, so we do not try the default one, but
* read the option file when it is encountered at the commandline
*/
default_config = 0;
}
else if( pargs.r_opt == oNoOptions )
{
default_config = 0; /* --no-options */
opt.no_homedir_creation = 1;
}
else if( pargs.r_opt == oHomedir )
gnupg_set_homedir (pargs.r.ret_str);
else if( pargs.r_opt == oNoPermissionWarn )
opt.no_perm_warn=1;
else if (pargs.r_opt == oStrict )
{
/* Not used */
}
else if (pargs.r_opt == oNoStrict )
{
/* Not used */
}
}
#ifdef HAVE_DOSISH_SYSTEM
if ( strchr (gnupg_homedir (), '\\') ) {
char *d, *buf = xmalloc (strlen (gnupg_homedir ())+1);
const char *s;
for (d=buf, s = gnupg_homedir (); *s; s++)
{
*d++ = *s == '\\'? '/': *s;
#ifdef HAVE_W32_SYSTEM
if (s[1] && IsDBCSLeadByte (*s))
*d++ = *++s;
#endif
}
*d = 0;
gnupg_set_homedir (buf);
}
#endif
/* Initialize the secure memory. */
if (!gcry_control (GCRYCTL_INIT_SECMEM, SECMEM_BUFFER_SIZE, 0))
got_secmem = 1;
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
/* There should be no way to get to this spot while still carrying
setuid privs. Just in case, bomb out if we are. */
if ( getuid () != geteuid () )
BUG ();
#endif
maybe_setuid = 0;
/* Okay, we are now working under our real uid */
/* malloc hooks go here ... */
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
setup_libassuan_logging (&opt.debug, NULL);
/* Set default options which require that malloc stuff is ready. */
additional_weak_digest ("MD5");
parse_auto_key_locate ("local,wkd");
/* Try for a version specific config file first */
default_configname = get_default_configname ();
if (default_config)
configname = xstrdup (default_configname);
argc = orig_argc;
argv = orig_argv;
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= ARGPARSE_FLAG_KEEP;
/* By this point we have a homedir, and cannot change it. */
check_permissions (gnupg_homedir (), 0);
next_pass:
if( configname ) {
if(check_permissions(configname,1))
{
/* If any options file is unsafe, then disable any external
programs for keyserver calls or photo IDs. Since the
external program to call is set in the options file, a
unsafe options file can lead to an arbitrary program
being run. */
opt.exec_disable=1;
}
configlineno = 0;
configfp = fopen( configname, "r" );
if (configfp && is_secured_file (fileno (configfp)))
{
fclose (configfp);
configfp = NULL;
gpg_err_set_errno (EPERM);
}
if( !configfp ) {
if( default_config ) {
if( parse_debug )
log_info(_("Note: no default option file '%s'\n"),
configname );
}
else {
log_error(_("option file '%s': %s\n"),
configname, strerror(errno) );
g10_exit(2);
}
xfree(configname); configname = NULL;
}
if( parse_debug && configname )
log_info(_("reading options from '%s'\n"), configname );
default_config = 0;
}
while( optfile_parse( configfp, configname, &configlineno,
&pargs, opts) )
{
switch( pargs.r_opt )
{
case aListConfig:
case aListGcryptConfig:
case aGPGConfList:
case aGPGConfTest:
set_cmd (&cmd, pargs.r_opt);
/* Do not register a keyring for these commands. */
default_keyring = -1;
break;
case aCheckKeys:
case aListPackets:
case aImport:
case aFastImport:
case aSendKeys:
case aRecvKeys:
case aSearchKeys:
case aRefreshKeys:
case aFetchKeys:
case aExport:
#ifdef ENABLE_CARD_SUPPORT
case aCardStatus:
case aCardEdit:
case aChangePIN:
#endif /* ENABLE_CARD_SUPPORT*/
case aListKeys:
case aLocateKeys:
case aListSigs:
case aExportSecret:
case aExportSecretSub:
case aExportSshKey:
case aSym:
case aClearsign:
case aGenRevoke:
case aDesigRevoke:
case aPrimegen:
case aGenRandom:
case aPrintMD:
case aPrintMDs:
case aListTrustDB:
case aCheckTrustDB:
case aUpdateTrustDB:
case aFixTrustDB:
case aListTrustPath:
case aDeArmor:
case aEnArmor:
case aSign:
case aQuickSignKey:
case aQuickLSignKey:
case aSignKey:
case aLSignKey:
case aStore:
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickRevUid:
case aQuickSetExpire:
case aQuickSetPrimaryUid:
case aExportOwnerTrust:
case aImportOwnerTrust:
case aRebuildKeydbCaches:
set_cmd (&cmd, pargs.r_opt);
break;
case aKeygen:
case aFullKeygen:
case aEditKey:
case aDeleteSecretKeys:
case aDeleteSecretAndPublicKeys:
case aDeleteKeys:
case aPasswd:
set_cmd (&cmd, pargs.r_opt);
greeting=1;
break;
case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
case aDecryptFiles: multifile=1; /* fall through */
case aDecrypt: set_cmd( &cmd, aDecrypt); break;
case aEncrFiles: multifile=1; /* fall through */
case aEncr: set_cmd( &cmd, aEncr); break;
case aVerifyFiles: multifile=1; /* fall through */
case aVerify: set_cmd( &cmd, aVerify); break;
case aServer:
set_cmd (&cmd, pargs.r_opt);
opt.batch = 1;
break;
case aTOFUPolicy:
set_cmd (&cmd, pargs.r_opt);
break;
case oArmor: opt.armor = 1; opt.no_armor=0; break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
case oMaxOutput: opt.max_output = pargs.r.ret_ulong; break;
case oInputSizeHint:
opt.input_size_hint = string_to_u64 (pargs.r.ret_str);
break;
case oChunkSize:
opt.chunk_size = pargs.r.ret_int;
break;
case oQuiet: opt.quiet = 1; break;
case oNoTTY: tty_no_terminal(1); break;
case oDryRun: opt.dry_run = 1; break;
case oInteractive: opt.interactive = 1; break;
case oVerbose:
opt.verbose++;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
opt.list_options|=LIST_SHOW_UNUSABLE_UIDS;
opt.list_options|=LIST_SHOW_UNUSABLE_SUBKEYS;
break;
case oBatch:
opt.batch = 1;
nogreeting = 1;
break;
case oUseAgent: /* Dummy. */
break;
case oNoUseAgent:
obsolete_option (configname, configlineno, "no-use-agent");
break;
case oGpgAgentInfo:
obsolete_option (configname, configlineno, "gpg-agent-info");
break;
case oReaderPort:
obsolete_scdaemon_option (configname, configlineno, "reader-port");
break;
case octapiDriver:
obsolete_scdaemon_option (configname, configlineno, "ctapi-driver");
break;
case opcscDriver:
obsolete_scdaemon_option (configname, configlineno, "pcsc-driver");
break;
case oDisableCCID:
obsolete_scdaemon_option (configname, configlineno, "disable-ccid");
break;
case oHonorHttpProxy:
obsolete_option (configname, configlineno, "honor-http-proxy");
break;
case oAnswerYes: opt.answer_yes = 1; break;
case oAnswerNo: opt.answer_no = 1; break;
case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
case oPrimaryKeyring:
sl = append_to_strlist (&nrings, pargs.r.ret_str);
sl->flags = KEYDB_RESOURCE_FLAG_PRIMARY;
break;
case oShowKeyring:
deprecated_warning(configname,configlineno,"--show-keyring",
"--list-options ","show-keyring");
opt.list_options|=LIST_SHOW_KEYRING;
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 oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break;
case oDebugIOLBF: break; /* Already set in pre-parse step. */
case oDebugSetIobufSize:
opt_set_iobuf_size = pargs.r.ret_ulong;
opt_set_iobuf_size_used = 1;
break;
case oStatusFD:
set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
break;
case oStatusFile:
set_status_fd ( open_info_file (pargs.r.ret_str, 1, 0) );
break;
case oAttributeFD:
set_attrib_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
break;
case oAttributeFile:
set_attrib_fd ( open_info_file (pargs.r.ret_str, 1, 1) );
break;
case oLoggerFD:
log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1));
break;
case oLoggerFile:
logfile = pargs.r.ret_str;
break;
case oWithFingerprint:
opt.with_fingerprint = 1;
opt.fingerprint++;
break;
case oWithSubkeyFingerprint:
opt.with_subkey_fingerprint = 1;
break;
case oWithICAOSpelling:
opt.with_icao_spelling = 1;
break;
case oFingerprint:
opt.fingerprint++;
fpr_maybe_cmd = 1;
break;
case oWithKeygrip:
opt.with_keygrip = 1;
break;
case oWithKeyScreening:
opt.with_key_screening = 1;
break;
case oWithSecret:
opt.with_secret = 1;
break;
case oWithWKDHash:
opt.with_wkd_hash = 1;
break;
case oWithKeyOrigin:
opt.with_key_origin = 1;
break;
case oSecretKeyring:
/* Ignore this old option. */
break;
case oOptions:
/* config files may not be nested (silently ignore them) */
if( !configfp ) {
xfree(configname);
configname = xstrdup(pargs.r.ret_str);
goto next_pass;
}
break;
case oNoArmor: opt.no_armor=1; opt.armor=0; break;
case oNoDefKeyring:
if (default_keyring > 0)
default_keyring = 0;
break;
case oNoKeyring:
default_keyring = -1;
break;
case oNoGreeting: nogreeting = 1; break;
case oNoVerbose:
opt.verbose = 0;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
opt.list_sigs=0;
break;
case oQuickRandom:
gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
break;
case oEmitVersion: opt.emit_version++; break;
case oNoEmitVersion: opt.emit_version=0; break;
case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break;
case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break;
case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break;
#ifndef NO_TRUST_MODELS
case oTrustDBName: trustdb_name = pargs.r.ret_str; break;
#endif /*!NO_TRUST_MODELS*/
case oDefaultKey:
sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oDefRecipient:
if( *pargs.r.ret_str )
{
xfree (opt.def_recipient);
opt.def_recipient = make_username(pargs.r.ret_str);
}
break;
case oDefRecipientSelf:
xfree(opt.def_recipient); opt.def_recipient = NULL;
opt.def_recipient_self = 1;
break;
case oNoDefRecipient:
xfree(opt.def_recipient); opt.def_recipient = NULL;
opt.def_recipient_self = 0;
break;
case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */
case oHomedir: break;
case oNoBatch: opt.batch = 0; break;
case oWithTofuInfo: opt.with_tofu_info = 1; break;
case oWithKeyData: opt.with_key_data=1; /*FALLTHRU*/
case oWithColons: opt.with_colons=':'; break;
case oWithSigCheck: opt.check_sigs = 1; /*FALLTHRU*/
case oWithSigList: opt.list_sigs = 1; break;
case oSkipVerify: opt.skip_verify=1; break;
case oSkipHiddenRecipients: opt.skip_hidden_recipients = 1; break;
case oNoSkipHiddenRecipients: opt.skip_hidden_recipients = 0; break;
case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break;
#ifndef NO_TRUST_MODELS
/* There are many programs (like mutt) that call gpg with
--always-trust so keep this option around for a long
time. */
case oAlwaysTrust: opt.trust_model=TM_ALWAYS; break;
case oTrustModel:
parse_trust_model(pargs.r.ret_str);
break;
#endif /*!NO_TRUST_MODELS*/
case oTOFUDefaultPolicy:
opt.tofu_default_policy = parse_tofu_policy (pargs.r.ret_str);
break;
case oTOFUDBFormat:
obsolete_option (configname, configlineno, "tofu-db-format");
break;
case oForceOwnertrust:
log_info(_("Note: %s is not for normal use!\n"),
"--force-ownertrust");
opt.force_ownertrust=string_to_trust_value(pargs.r.ret_str);
if(opt.force_ownertrust==-1)
{
log_error("invalid ownertrust '%s'\n",pargs.r.ret_str);
opt.force_ownertrust=0;
}
break;
case oLoadExtension:
/* Dummy so that gpg 1.4 conf files can work. Should
eventually be removed. */
break;
case oCompliance:
{
int compliance = gnupg_parse_compliance_option
(pargs.r.ret_str,
compliance_options, DIM (compliance_options),
opt.quiet);
if (compliance < 0)
g10_exit (1);
set_compliance_option (compliance);
}
break;
case oOpenPGP:
case oRFC2440:
case oRFC4880:
case oRFC4880bis:
- case oPGP6:
case oPGP7:
case oPGP8:
case oGnuPG:
set_compliance_option (pargs.r_opt);
break;
case oRFC2440Text: opt.rfc2440_text=1; break;
case oNoRFC2440Text: opt.rfc2440_text=0; break;
case oSetFilename:
if(utf8_strings)
opt.set_filename = pargs.r.ret_str;
else
opt.set_filename = native_to_utf8(pargs.r.ret_str);
break;
case oForYourEyesOnly: eyes_only = 1; break;
case oNoForYourEyesOnly: eyes_only = 0; break;
case oSetPolicyURL:
add_policy_url(pargs.r.ret_str,0);
add_policy_url(pargs.r.ret_str,1);
break;
case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break;
case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break;
case oShowPolicyURL:
deprecated_warning(configname,configlineno,"--show-policy-url",
"--list-options ","show-policy-urls");
deprecated_warning(configname,configlineno,"--show-policy-url",
"--verify-options ","show-policy-urls");
opt.list_options|=LIST_SHOW_POLICY_URLS;
opt.verify_options|=VERIFY_SHOW_POLICY_URLS;
break;
case oNoShowPolicyURL:
deprecated_warning(configname,configlineno,"--no-show-policy-url",
"--list-options ","no-show-policy-urls");
deprecated_warning(configname,configlineno,"--no-show-policy-url",
"--verify-options ","no-show-policy-urls");
opt.list_options&=~LIST_SHOW_POLICY_URLS;
opt.verify_options&=~VERIFY_SHOW_POLICY_URLS;
break;
case oSigKeyserverURL: add_keyserver_url(pargs.r.ret_str,0); break;
case oUseEmbeddedFilename:
opt.flags.use_embedded_filename=1;
break;
case oNoUseEmbeddedFilename:
opt.flags.use_embedded_filename=0;
break;
case oComment:
if(pargs.r.ret_str[0])
append_to_strlist(&opt.comments,pargs.r.ret_str);
break;
case oDefaultComment:
deprecated_warning(configname,configlineno,
"--default-comment","--no-comments","");
/* fall through */
case oNoComments:
free_strlist(opt.comments);
opt.comments=NULL;
break;
case oThrowKeyids: opt.throw_keyids = 1; break;
case oNoThrowKeyids: opt.throw_keyids = 0; break;
case oShowPhotos:
deprecated_warning(configname,configlineno,"--show-photos",
"--list-options ","show-photos");
deprecated_warning(configname,configlineno,"--show-photos",
"--verify-options ","show-photos");
opt.list_options|=LIST_SHOW_PHOTOS;
opt.verify_options|=VERIFY_SHOW_PHOTOS;
break;
case oNoShowPhotos:
deprecated_warning(configname,configlineno,"--no-show-photos",
"--list-options ","no-show-photos");
deprecated_warning(configname,configlineno,"--no-show-photos",
"--verify-options ","no-show-photos");
opt.list_options&=~LIST_SHOW_PHOTOS;
opt.verify_options&=~VERIFY_SHOW_PHOTOS;
break;
case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break;
case oForceAEAD: opt.force_aead = 1; break;
case oDisableSignerUID: opt.flags.disable_signer_uid = 1; break;
case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break;
case oS2KDigest: s2k_digest_string = xstrdup(pargs.r.ret_str); break;
case oS2KCipher: s2k_cipher_string = xstrdup(pargs.r.ret_str); break;
case oS2KCount:
if (pargs.r.ret_int)
opt.s2k_count = encode_s2k_iterations (pargs.r.ret_int);
else
opt.s2k_count = 0; /* Auto-calibrate when needed. */
break;
case oRecipient:
case oHiddenRecipient:
case oRecipientFile:
case oHiddenRecipientFile:
/* Store the recipient. Note that we also store the
* option as private data in the flags. This is achieved
* by shifting the option value to the left so to keep
* enough space for the flags. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenRecipient
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_HIDDEN;
if (pargs.r_opt == oRecipientFile
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_FROM_FILE;
any_explicit_recipient = 1;
break;
case oEncryptTo:
case oHiddenEncryptTo:
/* Store an additional recipient. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenEncryptTo)
sl->flags |= PK_LIST_HIDDEN;
break;
case oNoEncryptTo:
opt.no_encrypt_to = 1;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
pargs.r.ret_str, utf8_strings);
break;
case oMimemode: opt.mimemode = opt.textmode = 1; break;
case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break;
case oNoTextmode: opt.textmode=opt.mimemode=0; break;
case oExpert: opt.expert = 1; break;
case oNoExpert: opt.expert = 0; break;
case oDefSigExpire:
if(*pargs.r.ret_str!='\0')
{
if(parse_expire_string(pargs.r.ret_str)==(u32)-1)
log_error(_("'%s' is not a valid signature expiration\n"),
pargs.r.ret_str);
else
opt.def_sig_expire=pargs.r.ret_str;
}
break;
case oAskSigExpire: opt.ask_sig_expire = 1; break;
case oNoAskSigExpire: opt.ask_sig_expire = 0; break;
case oDefCertExpire:
if(*pargs.r.ret_str!='\0')
{
if(parse_expire_string(pargs.r.ret_str)==(u32)-1)
log_error(_("'%s' is not a valid signature expiration\n"),
pargs.r.ret_str);
else
opt.def_cert_expire=pargs.r.ret_str;
}
break;
case oAskCertExpire: opt.ask_cert_expire = 1; break;
case oNoAskCertExpire: opt.ask_cert_expire = 0; break;
case oDefCertLevel: opt.def_cert_level=pargs.r.ret_int; break;
case oMinCertLevel: opt.min_cert_level=pargs.r.ret_int; break;
case oAskCertLevel: opt.ask_cert_level = 1; break;
case oNoAskCertLevel: opt.ask_cert_level = 0; break;
case oLocalUser: /* store the local users */
sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oSender:
{
char *mbox = mailbox_from_userid (pargs.r.ret_str);
if (!mbox)
log_error (_("\"%s\" is not a proper mail address\n"),
pargs.r.ret_str);
else
{
add_to_strlist (&opt.sender_list, mbox);
xfree (mbox);
}
}
break;
case oCompress:
/* this is the -z command line option */
opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int;
break;
case oCompressLevel: opt.compress_level = pargs.r.ret_int; break;
case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break;
case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break;
case oPassphrase:
set_passphrase_from_string(pargs.r.ret_str);
break;
case oPassphraseFD:
pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
break;
case oPassphraseFile:
pwfd = open_info_file (pargs.r.ret_str, 0, 1);
break;
case oPassphraseRepeat:
opt.passphrase_repeat = pargs.r.ret_int;
break;
case oPinentryMode:
opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
if (opt.pinentry_mode == -1)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break;
case oRequestOrigin:
opt.request_origin = parse_request_origin (pargs.r.ret_str);
if (opt.request_origin == -1)
log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
break;
case oCommandFD:
opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
if (! gnupg_fd_valid (opt.command_fd))
log_error ("command-fd is invalid: %s\n", strerror (errno));
break;
case oCommandFile:
opt.command_fd = open_info_file (pargs.r.ret_str, 0, 1);
break;
case oCipherAlgo:
def_cipher_string = xstrdup(pargs.r.ret_str);
break;
case oAEADAlgo:
def_aead_string = xstrdup (pargs.r.ret_str);
break;
case oDigestAlgo:
def_digest_string = xstrdup(pargs.r.ret_str);
break;
case oCompressAlgo:
/* If it is all digits, stick a Z in front of it for
later. This is for backwards compatibility with
versions that took the compress algorithm number. */
{
char *pt=pargs.r.ret_str;
while(*pt)
{
if (!isascii (*pt) || !isdigit (*pt))
break;
pt++;
}
if(*pt=='\0')
{
compress_algo_string=xmalloc(strlen(pargs.r.ret_str)+2);
strcpy(compress_algo_string,"Z");
strcat(compress_algo_string,pargs.r.ret_str);
}
else
compress_algo_string = xstrdup(pargs.r.ret_str);
}
break;
case oCertDigestAlgo:
cert_digest_string = xstrdup(pargs.r.ret_str);
break;
case oNoSecmemWarn:
gcry_control (GCRYCTL_DISABLE_SECMEM_WARN);
break;
case oRequireSecmem: require_secmem=1; break;
case oNoRequireSecmem: require_secmem=0; break;
case oNoPermissionWarn: opt.no_perm_warn=1; break;
case oDisplayCharset:
if( set_native_charset( pargs.r.ret_str ) )
log_error(_("'%s' is not a valid character set\n"),
pargs.r.ret_str);
break;
case oNotDashEscaped: opt.not_dash_escaped = 1; break;
case oEscapeFrom: opt.escape_from = 1; break;
case oNoEscapeFrom: opt.escape_from = 0; break;
case oLockOnce: opt.lock_once = 1; break;
case oLockNever:
dotlock_disable ();
break;
case oLockMultiple:
#ifndef __riscos__
opt.lock_once = 0;
#else /* __riscos__ */
riscos_not_implemented("lock-multiple");
#endif /* __riscos__ */
break;
case oKeyServer:
{
keyserver_spec_t keyserver;
keyserver = parse_keyserver_uri (pargs.r.ret_str, 0);
if (!keyserver)
log_error (_("could not parse keyserver URL\n"));
else
{
/* We only support a single keyserver. Later ones
override earlier ones. (Since we parse the
config file first and then the command line
arguments, the command line takes
precedence.) */
if (opt.keyserver)
free_keyserver_spec (opt.keyserver);
opt.keyserver = keyserver;
}
}
break;
case oKeyServerOptions:
if(!parse_keyserver_options(pargs.r.ret_str))
{
if(configname)
log_error(_("%s:%d: invalid keyserver options\n"),
configname,configlineno);
else
log_error(_("invalid keyserver options\n"));
}
break;
case oImportOptions:
if(!parse_import_options(pargs.r.ret_str,&opt.import_options,1))
{
if(configname)
log_error(_("%s:%d: invalid import options\n"),
configname,configlineno);
else
log_error(_("invalid import options\n"));
}
break;
case oImportFilter:
rc = parse_and_set_import_filter (pargs.r.ret_str);
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oExportOptions:
if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1))
{
if(configname)
log_error(_("%s:%d: invalid export options\n"),
configname,configlineno);
else
log_error(_("invalid export options\n"));
}
break;
case oExportFilter:
rc = parse_and_set_export_filter (pargs.r.ret_str);
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oListOptions:
if(!parse_list_options(pargs.r.ret_str))
{
if(configname)
log_error(_("%s:%d: invalid list options\n"),
configname,configlineno);
else
log_error(_("invalid list options\n"));
}
break;
case oVerifyOptions:
{
struct parse_options vopts[]=
{
{"show-photos",VERIFY_SHOW_PHOTOS,NULL,
N_("display photo IDs during signature verification")},
{"show-policy-urls",VERIFY_SHOW_POLICY_URLS,NULL,
N_("show policy URLs during signature verification")},
{"show-notations",VERIFY_SHOW_NOTATIONS,NULL,
N_("show all notations during signature verification")},
{"show-std-notations",VERIFY_SHOW_STD_NOTATIONS,NULL,
N_("show IETF standard notations during signature verification")},
{"show-standard-notations",VERIFY_SHOW_STD_NOTATIONS,NULL,
NULL},
{"show-user-notations",VERIFY_SHOW_USER_NOTATIONS,NULL,
N_("show user-supplied notations during signature verification")},
{"show-keyserver-urls",VERIFY_SHOW_KEYSERVER_URLS,NULL,
N_("show preferred keyserver URLs during signature verification")},
{"show-uid-validity",VERIFY_SHOW_UID_VALIDITY,NULL,
N_("show user ID validity during signature verification")},
{"show-unusable-uids",VERIFY_SHOW_UNUSABLE_UIDS,NULL,
N_("show revoked and expired user IDs in signature verification")},
{"show-primary-uid-only",VERIFY_SHOW_PRIMARY_UID_ONLY,NULL,
N_("show only the primary user ID in signature verification")},
{"pka-lookups",VERIFY_PKA_LOOKUPS,NULL,
N_("validate signatures with PKA data")},
{"pka-trust-increase",VERIFY_PKA_TRUST_INCREASE,NULL,
N_("elevate the trust of signatures with valid PKA data")},
{NULL,0,NULL,NULL}
};
if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts,1))
{
if(configname)
log_error(_("%s:%d: invalid verify options\n"),
configname,configlineno);
else
log_error(_("invalid verify options\n"));
}
}
break;
case oTempDir: opt.temp_dir=pargs.r.ret_str; break;
case oExecPath:
if(set_exec_path(pargs.r.ret_str))
log_error(_("unable to set exec-path to %s\n"),pargs.r.ret_str);
else
opt.exec_path_set=1;
break;
case oSetNotation:
add_notation_data( pargs.r.ret_str, 0 );
add_notation_data( pargs.r.ret_str, 1 );
break;
case oSigNotation: add_notation_data( pargs.r.ret_str, 0 ); break;
case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break;
case oShowNotation:
deprecated_warning(configname,configlineno,"--show-notation",
"--list-options ","show-notations");
deprecated_warning(configname,configlineno,"--show-notation",
"--verify-options ","show-notations");
opt.list_options|=LIST_SHOW_NOTATIONS;
opt.verify_options|=VERIFY_SHOW_NOTATIONS;
break;
case oNoShowNotation:
deprecated_warning(configname,configlineno,"--no-show-notation",
"--list-options ","no-show-notations");
deprecated_warning(configname,configlineno,"--no-show-notation",
"--verify-options ","no-show-notations");
opt.list_options&=~LIST_SHOW_NOTATIONS;
opt.verify_options&=~VERIFY_SHOW_NOTATIONS;
break;
case oUtf8Strings: utf8_strings = 1; break;
case oNoUtf8Strings: utf8_strings = 0; break;
case oDisableCipherAlgo:
{
int algo = string_to_cipher_algo (pargs.r.ret_str);
gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo);
}
break;
case oDisablePubkeyAlgo:
{
int algo = gcry_pk_map_name (pargs.r.ret_str);
gcry_pk_ctl (GCRYCTL_DISABLE_ALGO, &algo, sizeof algo);
}
break;
case oNoSigCache: opt.no_sig_cache = 1; break;
case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
case oNoAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid=0; break;
case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break;
case oNoLiteral: opt.no_literal = 1; break;
case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
case oFastListMode: opt.fast_list_mode = 1; break;
case oFixedListMode: /* Dummy */ break;
case oLegacyListMode: opt.legacy_list_mode = 1; break;
case oPrintPKARecords: print_pka_records = 1; break;
case oPrintDANERecords: print_dane_records = 1; break;
case oListOnly: opt.list_only=1; break;
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
case oIgnoreValidFrom: opt.ignore_valid_from = 1; break;
case oIgnoreCrcError: opt.ignore_crc_error = 1; break;
case oIgnoreMDCError: opt.ignore_mdc_error = 1; break;
case oNoRandomSeedFile: use_random_seed = 0; break;
case oAutoKeyRetrieve:
opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE;
break;
case oNoAutoKeyRetrieve:
opt.keyserver_options.options &= ~KEYSERVER_AUTO_KEY_RETRIEVE;
break;
case oShowSessionKey: opt.show_session_key = 1; break;
case oOverrideSessionKey:
opt.override_session_key = pargs.r.ret_str;
break;
case oOverrideSessionKeyFD:
ovrseskeyfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
break;
case oMergeOnly:
deprecated_warning(configname,configlineno,"--merge-only",
"--import-options ","merge-only");
opt.import_options|=IMPORT_MERGE_ONLY;
break;
case oAllowSecretKeyImport: /* obsolete */ break;
case oTryAllSecrets: opt.try_all_secrets = 1; break;
case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
case oEnableSpecialFilenames:
enable_special_filenames ();
break;
case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break;
case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break;
case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break;
case oPreservePermissions: opt.preserve_permissions=1; break;
case oDefaultPreferenceList:
opt.def_preference_list = pargs.r.ret_str;
break;
case oDefaultKeyserverURL:
{
keyserver_spec_t keyserver;
keyserver = parse_keyserver_uri (pargs.r.ret_str,1 );
if (!keyserver)
log_error (_("could not parse keyserver URL\n"));
else
free_keyserver_spec (keyserver);
opt.def_keyserver_url = pargs.r.ret_str;
}
break;
case oPersonalCipherPreferences:
pers_cipher_list=pargs.r.ret_str;
break;
case oPersonalAEADPreferences:
pers_aead_list = pargs.r.ret_str;
break;
case oPersonalDigestPreferences:
pers_digest_list=pargs.r.ret_str;
break;
case oPersonalCompressPreferences:
pers_compress_list=pargs.r.ret_str;
break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break;
case oDisableDirmngr: opt.disable_dirmngr = 1; break;
case oWeakDigest:
additional_weak_digest(pargs.r.ret_str);
break;
case oUnwrap:
opt.unwrap_encryption = 1;
break;
case oOnlySignTextIDs:
opt.only_sign_text_ids = 1;
break;
case oDisplay:
set_opt_session_env ("DISPLAY", pargs.r.ret_str);
break;
case oTTYname:
set_opt_session_env ("GPG_TTY", pargs.r.ret_str);
break;
case oTTYtype:
set_opt_session_env ("TERM", pargs.r.ret_str);
break;
case oXauthority:
set_opt_session_env ("XAUTHORITY", pargs.r.ret_str);
break;
case oLCctype: opt.lc_ctype = pargs.r.ret_str; break;
case oLCmessages: opt.lc_messages = pargs.r.ret_str; break;
case oGroup: add_group(pargs.r.ret_str); break;
case oUnGroup: rm_group(pargs.r.ret_str); break;
case oNoGroups:
while(opt.grouplist)
{
struct groupitem *iter=opt.grouplist;
free_strlist(iter->values);
opt.grouplist=opt.grouplist->next;
xfree(iter);
}
break;
case oStrict:
case oNoStrict:
/* Not used */
break;
case oMangleDosFilenames: opt.mangle_dos_filenames = 1; break;
case oNoMangleDosFilenames: opt.mangle_dos_filenames = 0; break;
case oEnableProgressFilter: opt.enable_progress_filter = 1; break;
case oMultifile: multifile=1; break;
case oKeyidFormat:
if(ascii_strcasecmp(pargs.r.ret_str,"short")==0)
opt.keyid_format=KF_SHORT;
else if(ascii_strcasecmp(pargs.r.ret_str,"long")==0)
opt.keyid_format=KF_LONG;
else if(ascii_strcasecmp(pargs.r.ret_str,"0xshort")==0)
opt.keyid_format=KF_0xSHORT;
else if(ascii_strcasecmp(pargs.r.ret_str,"0xlong")==0)
opt.keyid_format=KF_0xLONG;
else if(ascii_strcasecmp(pargs.r.ret_str,"none")==0)
opt.keyid_format = KF_NONE;
else
log_error("unknown keyid-format '%s'\n",pargs.r.ret_str);
break;
case oExitOnStatusWriteError:
opt.exit_on_status_write_error = 1;
break;
case oLimitCardInsertTries:
opt.limit_card_insert_tries = pargs.r.ret_int;
break;
case oRequireCrossCert: opt.flags.require_cross_cert=1; break;
case oNoRequireCrossCert: opt.flags.require_cross_cert=0; break;
case oAutoKeyLocate:
if (default_akl)
{
/* This is the first time --aito-key-locate is seen.
* We need to reset the default akl. */
default_akl = 0;
release_akl();
}
if(!parse_auto_key_locate(pargs.r.ret_str))
{
if(configname)
log_error(_("%s:%d: invalid auto-key-locate list\n"),
configname,configlineno);
else
log_error(_("invalid auto-key-locate list\n"));
}
break;
case oNoAutoKeyLocate:
release_akl();
break;
case oKeyOrigin:
if(!parse_key_origin (pargs.r.ret_str))
log_error (_("invalid argument for option \"%.50s\"\n"),
"--key-origin");
break;
case oEnableLargeRSA:
#if SECMEM_BUFFER_SIZE >= 65536
opt.flags.large_rsa=1;
#else
if (configname)
log_info("%s:%d: WARNING: gpg not built with large secure "
"memory buffer. Ignoring enable-large-rsa\n",
configname,configlineno);
else
log_info("WARNING: gpg not built with large secure "
"memory buffer. Ignoring --enable-large-rsa\n");
#endif /* SECMEM_BUFFER_SIZE >= 65536 */
break;
case oDisableLargeRSA: opt.flags.large_rsa=0;
break;
case oEnableDSA2: opt.flags.dsa2=1; break;
case oDisableDSA2: opt.flags.dsa2=0; break;
case oAllowMultisigVerification:
case oAllowMultipleMessages:
opt.flags.allow_multiple_messages=1;
break;
case oNoAllowMultipleMessages:
opt.flags.allow_multiple_messages=0;
break;
case oAllowWeakDigestAlgos:
opt.flags.allow_weak_digest_algos = 1;
break;
case oFakedSystemTime:
{
size_t len = strlen (pargs.r.ret_str);
int freeze = 0;
time_t faked_time;
if (len > 0 && pargs.r.ret_str[len-1] == '!')
{
freeze = 1;
pargs.r.ret_str[len-1] = '\0';
}
faked_time = isotime2epoch (pargs.r.ret_str);
if (faked_time == (time_t)(-1))
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
gnupg_set_time (faked_time, freeze);
}
break;
case oNoAutostart: opt.autostart = 0; break;
case oNoSymkeyCache: opt.no_symkey_cache = 1; break;
case oDefaultNewKeyAlgo:
opt.def_new_key_algo = pargs.r.ret_str;
break;
case oNoop: break;
default:
if (configfp)
pargs.err = ARGPARSE_PRINT_WARNING;
else
{
pargs.err = ARGPARSE_PRINT_ERROR;
/* The argparse fucntion calls a plain exit and thus
* we need to print a status here. */
write_status_failure ("option-parser",
gpg_error(GPG_ERR_GENERAL));
}
break;
}
}
if (configfp)
{
fclose( configfp );
configfp = NULL;
/* Remember the first config file name. */
if (!save_configname)
save_configname = configname;
else
xfree(configname);
configname = NULL;
goto next_pass;
}
xfree(configname); configname = NULL;
if (log_get_errorcount (0))
{
write_status_failure ("option-parser", gpg_error(GPG_ERR_GENERAL));
g10_exit(2);
}
/* The command --gpgconf-list is pretty simple and may be called
directly after the option parsing. */
if (cmd == aGPGConfList)
{
gpgconf_list (save_configname ? save_configname : default_configname);
g10_exit (0);
}
xfree (save_configname);
xfree (default_configname);
if (print_dane_records)
log_error ("invalid option \"%s\"; use \"%s\" instead\n",
"--print-dane-records",
"--export-options export-dane");
if (print_pka_records)
log_error ("invalid option \"%s\"; use \"%s\" instead\n",
"--print-pks-records",
"--export-options export-pka");
if (log_get_errorcount (0))
{
write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
g10_exit(2);
}
if( nogreeting )
greeting = 0;
if( greeting )
{
es_fprintf (es_stderr, "%s %s; %s\n",
strusage(11), strusage(13), strusage(14) );
es_fprintf (es_stderr, "%s\n", strusage(15) );
}
#ifdef IS_DEVELOPMENT_VERSION
if (!opt.batch)
{
const char *s;
if((s=strusage(25)))
log_info("%s\n",s);
if((s=strusage(26)))
log_info("%s\n",s);
if((s=strusage(27)))
log_info("%s\n",s);
}
#endif
/* FIXME: We should use logging to a file only in server mode;
however we have not yet implemetyed that. Thus we try to get
away with --batch as indication for logging to file
required. */
if (logfile && opt.batch)
{
log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
}
if (opt.verbose > 2)
log_info ("using character set '%s'\n", get_native_charset ());
if( may_coredump && !opt.quiet )
log_info(_("WARNING: program may create a core file!\n"));
if (opt.flags.rfc4880bis)
log_info ("WARNING: using experimental features from RFC4880bis!\n");
else
{
opt.mimemode = 0; /* This will use text mode instead. */
}
if (eyes_only) {
if (opt.set_filename)
log_info(_("WARNING: %s overrides %s\n"),
"--for-your-eyes-only","--set-filename");
opt.set_filename="_CONSOLE";
}
if (opt.no_literal) {
log_info(_("Note: %s is not for normal use!\n"), "--no-literal");
if (opt.textmode)
log_error(_("%s not allowed with %s!\n"),
"--textmode", "--no-literal" );
if (opt.set_filename)
log_error(_("%s makes no sense with %s!\n"),
eyes_only?"--for-your-eyes-only":"--set-filename",
"--no-literal" );
}
if (opt.set_filesize)
log_info(_("Note: %s is not for normal use!\n"), "--set-filesize");
if( opt.batch )
tty_batchmode( 1 );
if (gnupg_faked_time_p ())
{
gnupg_isotime_t tbuf;
log_info (_("WARNING: running with faked system time: "));
gnupg_get_isotime (tbuf);
dump_isotime (tbuf);
log_printf ("\n");
}
/* Print a warning if an argument looks like an option. */
if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
{
int i;
for (i=0; i < argc; i++)
if (argv[i][0] == '-' && argv[i][1] == '-')
log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
}
gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
if(require_secmem && !got_secmem)
{
log_info(_("will not run with insecure memory due to %s\n"),
"--require-secmem");
write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
g10_exit(2);
}
set_debug (debug_level);
if (DBG_CLOCK)
log_clock ("start");
/* Do these after the switch(), so they can override settings. */
- if(PGP6)
- {
- /* That does not anymore work because we have no more support
- for v3 signatures. */
- opt.escape_from=1;
- opt.ask_sig_expire=0;
- }
- else if(PGP7)
+ if (PGP7)
{
/* That does not anymore work because we have no more support
for v3 signatures. */
opt.escape_from=1;
opt.ask_sig_expire=0;
}
else if(PGP8)
{
opt.escape_from=1;
}
if( def_cipher_string ) {
opt.def_cipher_algo = string_to_cipher_algo (def_cipher_string);
xfree(def_cipher_string); def_cipher_string = NULL;
if ( openpgp_cipher_test_algo (opt.def_cipher_algo) )
log_error(_("selected cipher algorithm is invalid\n"));
}
if (def_aead_string)
{
opt.def_aead_algo = string_to_aead_algo (def_aead_string);
xfree (def_aead_string); def_aead_string = NULL;
if (openpgp_aead_test_algo (opt.def_aead_algo))
log_error(_("selected AEAD algorithm is invalid\n"));
}
if( def_digest_string ) {
opt.def_digest_algo = string_to_digest_algo (def_digest_string);
xfree(def_digest_string); def_digest_string = NULL;
if ( openpgp_md_test_algo (opt.def_digest_algo) )
log_error(_("selected digest algorithm is invalid\n"));
}
if( compress_algo_string ) {
opt.compress_algo = string_to_compress_algo(compress_algo_string);
xfree(compress_algo_string); compress_algo_string = NULL;
if( check_compress_algo(opt.compress_algo) )
log_error(_("selected compression algorithm is invalid\n"));
}
if( cert_digest_string ) {
opt.cert_digest_algo = string_to_digest_algo (cert_digest_string);
xfree(cert_digest_string); cert_digest_string = NULL;
if (openpgp_md_test_algo(opt.cert_digest_algo))
log_error(_("selected certification digest algorithm is invalid\n"));
}
if( s2k_cipher_string ) {
opt.s2k_cipher_algo = string_to_cipher_algo (s2k_cipher_string);
xfree(s2k_cipher_string); s2k_cipher_string = NULL;
if (openpgp_cipher_test_algo (opt.s2k_cipher_algo))
log_error(_("selected cipher algorithm is invalid\n"));
}
if( s2k_digest_string ) {
opt.s2k_digest_algo = string_to_digest_algo (s2k_digest_string);
xfree(s2k_digest_string); s2k_digest_string = NULL;
if (openpgp_md_test_algo(opt.s2k_digest_algo))
log_error(_("selected digest algorithm is invalid\n"));
}
if( opt.completes_needed < 1 )
log_error(_("completes-needed must be greater than 0\n"));
if( opt.marginals_needed < 2 )
log_error(_("marginals-needed must be greater than 1\n"));
if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 )
log_error(_("max-cert-depth must be in the range from 1 to 255\n"));
if(opt.def_cert_level<0 || opt.def_cert_level>3)
log_error(_("invalid default-cert-level; must be 0, 1, 2, or 3\n"));
if( opt.min_cert_level < 1 || opt.min_cert_level > 3 )
log_error(_("invalid min-cert-level; must be 1, 2, or 3\n"));
switch( opt.s2k_mode ) {
case 0:
log_info(_("Note: simple S2K mode (0) is strongly discouraged\n"));
break;
case 1: case 3: break;
default:
log_error(_("invalid S2K mode; must be 0, 1 or 3\n"));
}
/* This isn't actually needed, but does serve to error out if the
string is invalid. */
if(opt.def_preference_list &&
keygen_set_std_prefs(opt.def_preference_list,0))
log_error(_("invalid default preferences\n"));
if(pers_cipher_list &&
keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM))
log_error(_("invalid personal cipher preferences\n"));
if (pers_aead_list && keygen_set_std_prefs (pers_aead_list, PREFTYPE_AEAD))
log_error(_("invalid personal AEAD preferences\n"));
if(pers_digest_list &&
keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH))
log_error(_("invalid personal digest preferences\n"));
if(pers_compress_list &&
keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP))
log_error(_("invalid personal compress preferences\n"));
/* Check chunk size. Please fix also the man page if you chnage
* the default. The limits are given by the specs. */
if (!opt.chunk_size)
opt.chunk_size = 30; /* Default to 1 GiB chunks. */
else if (opt.chunk_size < 6)
{
opt.chunk_size = 6;
log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
}
else if (opt.chunk_size > 62)
{
opt.chunk_size = 62;
log_info (_("chunk size invalid - using %d\n"), opt.chunk_size);
}
/* We don't support all possible commands with multifile yet */
if(multifile)
{
char *cmdname;
switch(cmd)
{
case aSign:
cmdname="--sign";
break;
case aSignEncr:
cmdname="--sign --encrypt";
break;
case aClearsign:
cmdname="--clear-sign";
break;
case aDetachedSign:
cmdname="--detach-sign";
break;
case aSym:
cmdname="--symmetric";
break;
case aEncrSym:
cmdname="--symmetric --encrypt";
break;
case aStore:
cmdname="--store";
break;
default:
cmdname=NULL;
break;
}
if(cmdname)
log_error(_("%s does not yet work with %s\n"),cmdname,"--multifile");
}
if( log_get_errorcount(0) )
{
write_status_failure ("option-postprocessing",
gpg_error(GPG_ERR_GENERAL));
g10_exit (2);
}
if(opt.compress_level==0)
opt.compress_algo=COMPRESS_ALGO_NONE;
/* Check our chosen algorithms against the list of legal
algorithms. */
if(!GNUPG && !opt.flags.rfc4880bis)
{
const char *badalg=NULL;
preftype_t badtype=PREFTYPE_NONE;
if(opt.def_cipher_algo
&& !algo_available(PREFTYPE_SYM,opt.def_cipher_algo,NULL))
{
badalg = openpgp_cipher_algo_name (opt.def_cipher_algo);
badtype = PREFTYPE_SYM;
}
else if(opt.def_aead_algo
&& !algo_available(PREFTYPE_AEAD, opt.def_aead_algo, NULL))
{
badalg = openpgp_aead_algo_name (opt.def_aead_algo);
badtype = PREFTYPE_AEAD;
}
else if(opt.def_digest_algo
&& !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL))
{
badalg = gcry_md_algo_name (opt.def_digest_algo);
badtype = PREFTYPE_HASH;
}
else if(opt.cert_digest_algo
&& !algo_available(PREFTYPE_HASH,opt.cert_digest_algo,NULL))
{
badalg = gcry_md_algo_name (opt.cert_digest_algo);
badtype = PREFTYPE_HASH;
}
else if(opt.compress_algo!=-1
&& !algo_available(PREFTYPE_ZIP,opt.compress_algo,NULL))
{
badalg = compress_algo_to_string(opt.compress_algo);
badtype = PREFTYPE_ZIP;
}
if(badalg)
{
switch(badtype)
{
case PREFTYPE_SYM:
log_info (_("cipher algorithm '%s'"
" may not be used in %s mode\n"),
badalg,
gnupg_compliance_option_string (opt.compliance));
break;
case PREFTYPE_AEAD:
log_info (_("AEAD algorithm '%s'"
" may not be used in %s mode\n"),
badalg,
gnupg_compliance_option_string (opt.compliance));
break;
case PREFTYPE_HASH:
log_info (_("digest algorithm '%s'"
" may not be used in %s mode\n"),
badalg,
gnupg_compliance_option_string (opt.compliance));
break;
case PREFTYPE_ZIP:
log_info (_("compression algorithm '%s'"
" may not be used in %s mode\n"),
badalg,
gnupg_compliance_option_string (opt.compliance));
break;
default:
BUG();
}
compliance_failure();
}
}
/* Check our chosen algorithms against the list of allowed
* algorithms in the current compliance mode, and fail hard if it
* is not. This is us being nice to the user informing her early
* that the chosen algorithms are not available. We also check
* and enforce this right before the actual operation. */
/* FIXME: We also need to check the AEAD algo. */
if (opt.def_cipher_algo
&& ! gnupg_cipher_is_allowed (opt.compliance,
cmd == aEncr
|| cmd == aSignEncr
|| cmd == aEncrSym
|| cmd == aSym
|| cmd == aSignSym
|| cmd == aSignEncrSym,
opt.def_cipher_algo,
GCRY_CIPHER_MODE_NONE))
log_error (_("cipher algorithm '%s' may not be used in %s mode\n"),
openpgp_cipher_algo_name (opt.def_cipher_algo),
gnupg_compliance_option_string (opt.compliance));
if (opt.def_digest_algo
&& ! gnupg_digest_is_allowed (opt.compliance,
cmd == aSign
|| cmd == aSignEncr
|| cmd == aSignEncrSym
|| cmd == aSignSym
|| cmd == aClearsign,
opt.def_digest_algo))
log_error (_("digest algorithm '%s' may not be used in %s mode\n"),
gcry_md_algo_name (opt.def_digest_algo),
gnupg_compliance_option_string (opt.compliance));
/* Fail hard. */
if (log_get_errorcount (0))
{
write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
g10_exit (2);
}
/* Set the random seed file. */
if( use_random_seed ) {
char *p = make_filename (gnupg_homedir (), "random_seed", NULL );
gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
if (!access (p, F_OK))
register_secured_file (p);
xfree(p);
}
/* If there is no command but the --fingerprint is given, default
to the --list-keys command. */
if (!cmd && fpr_maybe_cmd)
{
set_cmd (&cmd, aListKeys);
}
if( opt.verbose > 1 )
set_packet_list_mode(1);
/* Add the keyrings, but not for some special commands. We always
* need to add the keyrings if we are running under SELinux, this
* is so that the rings are added to the list of secured files.
* We do not add any keyring if --no-keyring has been used. */
if (default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
if (!nrings || default_keyring > 0) /* Add default ring. */
keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
KEYDB_RESOURCE_FLAG_DEFAULT);
for (sl = nrings; sl; sl = sl->next )
keydb_add_resource (sl->d, sl->flags);
}
FREE_STRLIST(nrings);
if (opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)
/* In loopback mode, never ask for the password multiple
times. */
{
opt.passphrase_repeat = 0;
}
if (cmd == aGPGConfTest)
g10_exit(0);
if (pwfd != -1) /* Read the passphrase now. */
read_passphrase_from_fd (pwfd);
if (ovrseskeyfd != -1 ) /* Read the sessionkey now. */
read_sessionkey_from_fd (ovrseskeyfd);
fname = argc? *argv : NULL;
if(fname && utf8_strings)
opt.flags.utf8_filename=1;
ctrl = xcalloc (1, sizeof *ctrl);
gpg_init_default_ctrl (ctrl);
#ifndef NO_TRUST_MODELS
switch (cmd)
{
case aPrimegen:
case aPrintMD:
case aPrintMDs:
case aGenRandom:
case aDeArmor:
case aEnArmor:
case aListConfig:
case aListGcryptConfig:
break;
case aFixTrustDB:
case aExportOwnerTrust:
rc = setup_trustdb (0, trustdb_name);
break;
case aListTrustDB:
rc = setup_trustdb (argc? 1:0, trustdb_name);
break;
case aKeygen:
case aFullKeygen:
case aQuickKeygen:
rc = setup_trustdb (1, trustdb_name);
break;
default:
/* If we are using TM_ALWAYS, we do not need to create the
trustdb. */
rc = setup_trustdb (opt.trust_model != TM_ALWAYS, trustdb_name);
break;
}
if (rc)
log_error (_("failed to initialize the TrustDB: %s\n"),
gpg_strerror (rc));
#endif /*!NO_TRUST_MODELS*/
switch (cmd)
{
case aStore:
case aSym:
case aSign:
case aSignSym:
case aClearsign:
if (!opt.quiet && any_explicit_recipient)
log_info (_("WARNING: recipients (-r) given "
"without using public key encryption\n"));
break;
default:
break;
}
/* Check for certain command whether we need to migrate a
secring.gpg to the gpg-agent. */
switch (cmd)
{
case aListSecretKeys:
case aSign:
case aSignEncr:
case aSignEncrSym:
case aSignSym:
case aClearsign:
case aDecrypt:
case aSignKey:
case aLSignKey:
case aEditKey:
case aPasswd:
case aDeleteSecretKeys:
case aDeleteSecretAndPublicKeys:
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickRevUid:
case aQuickSetPrimaryUid:
case aFullKeygen:
case aKeygen:
case aImport:
case aExportSecret:
case aExportSecretSub:
case aGenRevoke:
case aDesigRevoke:
case aCardEdit:
case aChangePIN:
migrate_secring (ctrl);
break;
case aListKeys:
if (opt.with_secret)
migrate_secring (ctrl);
break;
default:
break;
}
/* The command dispatcher. */
switch( cmd )
{
case aServer:
gpg_server (ctrl);
break;
case aStore: /* only store the file */
if( argc > 1 )
wrong_args("--store [filename]");
if( (rc = encrypt_store(fname)) )
{
write_status_failure ("store", rc);
log_error ("storing '%s' failed: %s\n",
print_fname_stdin(fname),gpg_strerror (rc) );
}
break;
case aSym: /* encrypt the given file only with the symmetric cipher */
if( argc > 1 )
wrong_args("--symmetric [filename]");
if( (rc = encrypt_symmetric(fname)) )
{
write_status_failure ("symencrypt", rc);
log_error (_("symmetric encryption of '%s' failed: %s\n"),
print_fname_stdin(fname),gpg_strerror (rc) );
}
break;
case aEncr: /* encrypt the given file */
if(multifile)
encrypt_crypt_files (ctrl, argc, argv, remusr);
else
{
if( argc > 1 )
wrong_args("--encrypt [filename]");
if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) )
{
write_status_failure ("encrypt", rc);
log_error("%s: encryption failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
}
break;
case aEncrSym:
/* This works with PGP 8 in the sense that it acts just like a
symmetric message. It doesn't work at all with 2 or 6. It
might work with 7, but alas, I don't have a copy to test
with right now. */
if( argc > 1 )
wrong_args("--symmetric --encrypt [filename]");
else if(opt.s2k_mode==0)
log_error(_("you cannot use --symmetric --encrypt"
" with --s2k-mode 0\n"));
- else if(PGP6 || PGP7)
+ else if (PGP7)
log_error(_("you cannot use --symmetric --encrypt"
" in %s mode\n"),
gnupg_compliance_option_string (opt.compliance));
else
{
if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) )
{
write_status_failure ("encrypt", rc);
log_error ("%s: encryption failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
}
break;
case aSign: /* sign the given file */
sl = NULL;
if( detached_sig ) { /* sign all files */
for( ; argc; argc--, argv++ )
add_to_strlist( &sl, *argv );
}
else {
if( argc > 1 )
wrong_args("--sign [filename]");
if( argc ) {
sl = xmalloc_clear( sizeof *sl + strlen(fname));
strcpy(sl->d, fname);
}
}
if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL)))
{
write_status_failure ("sign", rc);
log_error ("signing failed: %s\n", gpg_strerror (rc) );
}
free_strlist(sl);
break;
case aSignEncr: /* sign and encrypt the given file */
if( argc > 1 )
wrong_args("--sign --encrypt [filename]");
if( argc ) {
sl = xmalloc_clear( sizeof *sl + strlen(fname));
strcpy(sl->d, fname);
}
else
sl = NULL;
if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 1, remusr, NULL)))
{
write_status_failure ("sign-encrypt", rc);
log_error("%s: sign+encrypt failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
free_strlist(sl);
break;
case aSignEncrSym: /* sign and encrypt the given file */
if( argc > 1 )
wrong_args("--symmetric --sign --encrypt [filename]");
else if(opt.s2k_mode==0)
log_error(_("you cannot use --symmetric --sign --encrypt"
" with --s2k-mode 0\n"));
- else if(PGP6 || PGP7)
+ else if (PGP7)
log_error(_("you cannot use --symmetric --sign --encrypt"
" in %s mode\n"),
gnupg_compliance_option_string (opt.compliance));
else
{
if( argc )
{
sl = xmalloc_clear( sizeof *sl + strlen(fname));
strcpy(sl->d, fname);
}
else
sl = NULL;
if ((rc = sign_file (ctrl, sl, detached_sig, locusr,
2, remusr, NULL)))
{
write_status_failure ("sign-encrypt", rc);
log_error("%s: symmetric+sign+encrypt failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
free_strlist(sl);
}
break;
case aSignSym: /* sign and conventionally encrypt the given file */
if (argc > 1)
wrong_args("--sign --symmetric [filename]");
rc = sign_symencrypt_file (ctrl, fname, locusr);
if (rc)
{
write_status_failure ("sign-symencrypt", rc);
log_error("%s: sign+symmetric failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
break;
case aClearsign: /* make a clearsig */
if( argc > 1 )
wrong_args("--clear-sign [filename]");
if( (rc = clearsign_file (ctrl, fname, locusr, NULL)) )
{
write_status_failure ("sign", rc);
log_error("%s: clear-sign failed: %s\n",
print_fname_stdin(fname), gpg_strerror (rc) );
}
break;
case aVerify:
if (multifile)
{
if ((rc = verify_files (ctrl, argc, argv)))
log_error("verify files failed: %s\n", gpg_strerror (rc) );
}
else
{
if ((rc = verify_signatures (ctrl, argc, argv)))
log_error("verify signatures failed: %s\n", gpg_strerror (rc) );
}
if (rc)
write_status_failure ("verify", rc);
break;
case aDecrypt:
if (multifile)
decrypt_messages (ctrl, argc, argv);
else
{
if( argc > 1 )
wrong_args("--decrypt [filename]");
if( (rc = decrypt_message (ctrl, fname) ))
{
write_status_failure ("decrypt", rc);
log_error("decrypt_message failed: %s\n", gpg_strerror (rc) );
}
}
break;
case aQuickSignKey:
case aQuickLSignKey:
{
const char *fpr;
if (argc < 1)
wrong_args ("--quick-[l]sign-key fingerprint [userids]");
fpr = *argv++; argc--;
sl = NULL;
for( ; argc; argc--, argv++)
append_to_strlist2 (&sl, *argv, utf8_strings);
keyedit_quick_sign (ctrl, fpr, sl, locusr, (cmd == aQuickLSignKey));
free_strlist (sl);
}
break;
case aSignKey:
if( argc != 1 )
wrong_args("--sign-key user-id");
/* fall through */
case aLSignKey:
if( argc != 1 )
wrong_args("--lsign-key user-id");
/* fall through */
sl=NULL;
if(cmd==aSignKey)
append_to_strlist(&sl,"sign");
else if(cmd==aLSignKey)
append_to_strlist(&sl,"lsign");
else
BUG();
append_to_strlist( &sl, "save" );
username = make_username( fname );
keyedit_menu (ctrl, username, locusr, sl, 0, 0 );
xfree(username);
free_strlist(sl);
break;
case aEditKey: /* Edit a key signature */
if( !argc )
wrong_args("--edit-key user-id [commands]");
username = make_username( fname );
if( argc > 1 ) {
sl = NULL;
for( argc--, argv++ ; argc; argc--, argv++ )
append_to_strlist( &sl, *argv );
keyedit_menu (ctrl, username, locusr, sl, 0, 1 );
free_strlist(sl);
}
else
keyedit_menu (ctrl, username, locusr, NULL, 0, 1 );
xfree(username);
break;
case aPasswd:
if (argc != 1)
wrong_args("--change-passphrase ");
else
{
username = make_username (fname);
keyedit_passwd (ctrl, username);
xfree (username);
}
break;
case aDeleteKeys:
case aDeleteSecretKeys:
case aDeleteSecretAndPublicKeys:
sl = NULL;
/* I'm adding these in reverse order as add_to_strlist2
reverses them again, and it's easier to understand in the
proper order :) */
for( ; argc; argc-- )
add_to_strlist2( &sl, argv[argc-1], utf8_strings );
delete_keys (ctrl, sl,
cmd==aDeleteSecretKeys, cmd==aDeleteSecretAndPublicKeys);
free_strlist(sl);
break;
case aCheckKeys:
opt.check_sigs = 1; /* fall through */
case aListSigs:
opt.list_sigs = 1; /* fall through */
case aListKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
public_key_list (ctrl, sl, 0);
free_strlist(sl);
break;
case aListSecretKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
secret_key_list (ctrl, sl);
free_strlist(sl);
break;
case aLocateKeys:
sl = NULL;
for (; argc; argc--, argv++)
add_to_strlist2( &sl, *argv, utf8_strings );
public_key_list (ctrl, sl, 1);
free_strlist (sl);
break;
case aQuickKeygen:
{
const char *x_algo, *x_usage, *x_expire;
if (argc < 1 || argc > 4)
wrong_args("--quick-generate-key USER-ID [ALGO [USAGE [EXPIRE]]]");
username = make_username (fname);
argv++, argc--;
x_algo = "";
x_usage = "";
x_expire = "";
if (argc)
{
x_algo = *argv++; argc--;
if (argc)
{
x_usage = *argv++; argc--;
if (argc)
{
x_expire = *argv++; argc--;
}
}
}
quick_generate_keypair (ctrl, username, x_algo, x_usage, x_expire);
xfree (username);
}
break;
case aKeygen: /* generate a key */
if( opt.batch ) {
if( argc > 1 )
wrong_args("--generate-key [parameterfile]");
generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
}
else {
if (opt.command_fd != -1 && argc)
{
if( argc > 1 )
wrong_args("--generate-key [parameterfile]");
opt.batch = 1;
generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0);
}
else if (argc)
wrong_args ("--generate-key");
else
generate_keypair (ctrl, 0, NULL, NULL, 0);
}
break;
case aFullKeygen: /* Generate a key with all options. */
if (opt.batch)
{
if (argc > 1)
wrong_args ("--full-generate-key [parameterfile]");
generate_keypair (ctrl, 1, argc? *argv : NULL, NULL, 0);
}
else
{
if (argc)
wrong_args("--full-generate-key");
generate_keypair (ctrl, 1, NULL, NULL, 0);
}
break;
case aQuickAddUid:
{
const char *uid, *newuid;
if (argc != 2)
wrong_args ("--quick-add-uid USER-ID NEW-USER-ID");
uid = *argv++; argc--;
newuid = *argv++; argc--;
keyedit_quick_adduid (ctrl, uid, newuid);
}
break;
case aQuickAddKey:
{
const char *x_fpr, *x_algo, *x_usage, *x_expire;
if (argc < 1 || argc > 4)
wrong_args ("--quick-add-key FINGERPRINT [ALGO [USAGE [EXPIRE]]]");
x_fpr = *argv++; argc--;
x_algo = "";
x_usage = "";
x_expire = "";
if (argc)
{
x_algo = *argv++; argc--;
if (argc)
{
x_usage = *argv++; argc--;
if (argc)
{
x_expire = *argv++; argc--;
}
}
}
keyedit_quick_addkey (ctrl, x_fpr, x_algo, x_usage, x_expire);
}
break;
case aQuickRevUid:
{
const char *uid, *uidtorev;
if (argc != 2)
wrong_args ("--quick-revoke-uid USER-ID USER-ID-TO-REVOKE");
uid = *argv++; argc--;
uidtorev = *argv++; argc--;
keyedit_quick_revuid (ctrl, uid, uidtorev);
}
break;
case aQuickSetExpire:
{
const char *x_fpr, *x_expire;
if (argc < 2)
wrong_args ("--quick-set-exipre FINGERPRINT EXPIRE [SUBKEY-FPRS]");
x_fpr = *argv++; argc--;
x_expire = *argv++; argc--;
keyedit_quick_set_expire (ctrl, x_fpr, x_expire, argv);
}
break;
case aQuickSetPrimaryUid:
{
const char *uid, *primaryuid;
if (argc != 2)
wrong_args ("--quick-set-primary-uid USER-ID PRIMARY-USER-ID");
uid = *argv++; argc--;
primaryuid = *argv++; argc--;
keyedit_quick_set_primary (ctrl, uid, primaryuid);
}
break;
case aFastImport:
opt.import_options |= IMPORT_FAST; /* fall through */
case aImport:
import_keys (ctrl, argc? argv:NULL, argc, NULL,
opt.import_options, opt.key_origin, opt.key_origin_url);
break;
/* TODO: There are a number of command that use this same
"make strlist, call function, report error, free strlist"
pattern. Join them together here and avoid all that
duplicated code. */
case aExport:
case aSendKeys:
case aRecvKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
append_to_strlist2( &sl, *argv, utf8_strings );
if( cmd == aSendKeys )
rc = keyserver_export (ctrl, sl );
else if( cmd == aRecvKeys )
rc = keyserver_import (ctrl, sl );
else
{
export_stats_t stats = export_new_stats ();
rc = export_pubkeys (ctrl, sl, opt.export_options, stats);
export_print_stats (stats);
export_release_stats (stats);
}
if(rc)
{
if(cmd==aSendKeys)
{
write_status_failure ("send-keys", rc);
log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc));
}
else if(cmd==aRecvKeys)
{
write_status_failure ("recv-keys", rc);
log_error (_("keyserver receive failed: %s\n"),
gpg_strerror (rc));
}
else
{
write_status_failure ("export", rc);
log_error (_("key export failed: %s\n"), gpg_strerror (rc));
}
}
free_strlist(sl);
break;
case aExportSshKey:
if (argc != 1)
wrong_args ("--export-ssh-key ");
rc = export_ssh_key (ctrl, argv[0]);
if (rc)
{
write_status_failure ("export-ssh-key", rc);
log_error (_("export as ssh key failed: %s\n"), gpg_strerror (rc));
}
break;
case aSearchKeys:
sl = NULL;
for (; argc; argc--, argv++)
append_to_strlist2 (&sl, *argv, utf8_strings);
rc = keyserver_search (ctrl, sl);
if (rc)
{
write_status_failure ("search-keys", rc);
log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc));
}
free_strlist (sl);
break;
case aRefreshKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
append_to_strlist2( &sl, *argv, utf8_strings );
rc = keyserver_refresh (ctrl, sl);
if(rc)
{
write_status_failure ("refresh-keys", rc);
log_error (_("keyserver refresh failed: %s\n"),gpg_strerror (rc));
}
free_strlist(sl);
break;
case aFetchKeys:
sl = NULL;
for( ; argc; argc--, argv++ )
append_to_strlist2( &sl, *argv, utf8_strings );
rc = keyserver_fetch (ctrl, sl, opt.key_origin);
if(rc)
{
write_status_failure ("fetch-keys", rc);
log_error ("key fetch failed: %s\n",gpg_strerror (rc));
}
free_strlist(sl);
break;
case aExportSecret:
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
{
export_stats_t stats = export_new_stats ();
export_seckeys (ctrl, sl, opt.export_options, stats);
export_print_stats (stats);
export_release_stats (stats);
}
free_strlist(sl);
break;
case aExportSecretSub:
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
{
export_stats_t stats = export_new_stats ();
export_secsubkeys (ctrl, sl, opt.export_options, stats);
export_print_stats (stats);
export_release_stats (stats);
}
free_strlist(sl);
break;
case aGenRevoke:
if( argc != 1 )
wrong_args("--generate-revocation user-id");
username = make_username(*argv);
gen_revoke (ctrl, username );
xfree( username );
break;
case aDesigRevoke:
if (argc != 1)
wrong_args ("--generate-designated-revocation user-id");
username = make_username (*argv);
gen_desig_revoke (ctrl, username, locusr);
xfree (username);
break;
case aDeArmor:
if( argc > 1 )
wrong_args("--dearmor [file]");
rc = dearmor_file( argc? *argv: NULL );
if( rc )
{
write_status_failure ("dearmor", rc);
log_error (_("dearmoring failed: %s\n"), gpg_strerror (rc));
}
break;
case aEnArmor:
if( argc > 1 )
wrong_args("--enarmor [file]");
rc = enarmor_file( argc? *argv: NULL );
if( rc )
{
write_status_failure ("enarmor", rc);
log_error (_("enarmoring failed: %s\n"), gpg_strerror (rc));
}
break;
case aPrimegen:
#if 0 /*FIXME*/
{ int mode = argc < 2 ? 0 : atoi(*argv);
if( mode == 1 && argc == 2 ) {
mpi_print (es_stdout,
generate_public_prime( atoi(argv[1]) ), 1);
}
else if( mode == 2 && argc == 3 ) {
mpi_print (es_stdout, generate_elg_prime(
0, atoi(argv[1]),
atoi(argv[2]), NULL,NULL ), 1);
}
else if( mode == 3 && argc == 3 ) {
MPI *factors;
mpi_print (es_stdout, generate_elg_prime(
1, atoi(argv[1]),
atoi(argv[2]), NULL,&factors ), 1);
es_putc ('\n', es_stdout);
mpi_print (es_stdout, factors[0], 1 ); /* print q */
}
else if( mode == 4 && argc == 3 ) {
MPI g = mpi_alloc(1);
mpi_print (es_stdout, generate_elg_prime(
0, atoi(argv[1]),
atoi(argv[2]), g, NULL ), 1);
es_putc ('\n', es_stdout);
mpi_print (es_stdout, g, 1 );
mpi_free (g);
}
else
wrong_args("--gen-prime mode bits [qbits] ");
es_putc ('\n', es_stdout);
}
#endif
wrong_args("--gen-prime not yet supported ");
break;
case aGenRandom:
{
int level = argc ? atoi(*argv):0;
int count = argc > 1 ? atoi(argv[1]): 0;
int endless = !count;
if( argc < 1 || argc > 2 || level < 0 || level > 2 || count < 0 )
wrong_args("--gen-random 0|1|2 [count]");
while( endless || count ) {
byte *p;
/* Wee need a multiple of 3, so that in case of
armored output we get a correct string. No
linefolding is done, as it is best to levae this to
other tools */
size_t n = !endless && count < 99? count : 99;
p = gcry_random_bytes (n, level);
#ifdef HAVE_DOSISH_SYSTEM
setmode ( fileno(stdout), O_BINARY );
#endif
if (opt.armor) {
char *tmp = make_radix64_string (p, n);
es_fputs (tmp, es_stdout);
xfree (tmp);
if (n%3 == 1)
es_putc ('=', es_stdout);
if (n%3)
es_putc ('=', es_stdout);
} else {
es_fwrite( p, n, 1, es_stdout );
}
xfree(p);
if( !endless )
count -= n;
}
if (opt.armor)
es_putc ('\n', es_stdout);
}
break;
case aPrintMD:
if( argc < 1)
wrong_args("--print-md algo [files]");
{
int all_algos = (**argv=='*' && !(*argv)[1]);
int algo = all_algos? 0 : gcry_md_map_name (*argv);
if( !algo && !all_algos )
log_error(_("invalid hash algorithm '%s'\n"), *argv );
else {
argc--; argv++;
if( !argc )
print_mds(NULL, algo);
else {
for(; argc; argc--, argv++ )
print_mds(*argv, algo);
}
}
}
break;
case aPrintMDs: /* old option */
if( !argc )
print_mds(NULL,0);
else {
for(; argc; argc--, argv++ )
print_mds(*argv,0);
}
break;
#ifndef NO_TRUST_MODELS
case aListTrustDB:
if( !argc )
list_trustdb (ctrl, es_stdout, NULL);
else {
for( ; argc; argc--, argv++ )
list_trustdb (ctrl, es_stdout, *argv );
}
break;
case aUpdateTrustDB:
if( argc )
wrong_args("--update-trustdb");
update_trustdb (ctrl);
break;
case aCheckTrustDB:
/* Old versions allowed for arguments - ignore them */
check_trustdb (ctrl);
break;
case aFixTrustDB:
how_to_fix_the_trustdb ();
break;
case aListTrustPath:
if( !argc )
wrong_args("--list-trust-path ");
for( ; argc; argc--, argv++ ) {
username = make_username( *argv );
list_trust_path( username );
xfree(username);
}
break;
case aExportOwnerTrust:
if( argc )
wrong_args("--export-ownertrust");
export_ownertrust (ctrl);
break;
case aImportOwnerTrust:
if( argc > 1 )
wrong_args("--import-ownertrust [file]");
import_ownertrust (ctrl, argc? *argv:NULL );
break;
#endif /*!NO_TRUST_MODELS*/
case aRebuildKeydbCaches:
if (argc)
wrong_args ("--rebuild-keydb-caches");
keydb_rebuild_caches (ctrl, 1);
break;
#ifdef ENABLE_CARD_SUPPORT
case aCardStatus:
if (argc == 0)
card_status (ctrl, es_stdout, NULL);
else if (argc == 1)
card_status (ctrl, es_stdout, *argv);
else
wrong_args ("--card-status [serialno]");
break;
case aCardEdit:
if (argc) {
sl = NULL;
for (argc--, argv++ ; argc; argc--, argv++)
append_to_strlist (&sl, *argv);
card_edit (ctrl, sl);
free_strlist (sl);
}
else
card_edit (ctrl, NULL);
break;
case aChangePIN:
if (!argc)
change_pin (0,1);
else if (argc == 1)
change_pin (atoi (*argv),1);
else
wrong_args ("--change-pin [no]");
break;
#endif /* ENABLE_CARD_SUPPORT*/
case aListConfig:
{
char *str=collapse_args(argc,argv);
list_config(str);
xfree(str);
}
break;
case aListGcryptConfig:
/* Fixme: It would be nice to integrate that with
--list-config but unfortunately there is no way yet to have
libgcrypt print it to an estream for further parsing. */
gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
break;
case aTOFUPolicy:
#ifdef USE_TOFU
{
int policy;
int i;
KEYDB_HANDLE hd;
if (argc < 2)
wrong_args ("--tofu-policy POLICY KEYID [KEYID...]");
policy = parse_tofu_policy (argv[0]);
hd = keydb_new ();
if (! hd)
{
write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));
g10_exit (1);
}
tofu_begin_batch_update (ctrl);
for (i = 1; i < argc; i ++)
{
KEYDB_SEARCH_DESC desc;
kbnode_t kb;
rc = classify_user_id (argv[i], &desc, 0);
if (rc)
{
log_error (_("error parsing key specification '%s': %s\n"),
argv[i], gpg_strerror (rc));
write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
if (! (desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
|| desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|| desc.mode == KEYDB_SEARCH_MODE_FPR
|| desc.mode == KEYDB_SEARCH_MODE_KEYGRIP))
{
log_error (_("'%s' does not appear to be a valid"
" key ID, fingerprint or keygrip\n"),
argv[i]);
write_status_failure ("tofu-driver",
gpg_error(GPG_ERR_GENERAL));
g10_exit (1);
}
rc = keydb_search_reset (hd);
if (rc)
{
/* This should not happen, thus no need to tranalate
the string. */
log_error ("keydb_search_reset failed: %s\n",
gpg_strerror (rc));
write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
rc = keydb_search (hd, &desc, 1, NULL);
if (rc)
{
log_error (_("key \"%s\" not found: %s\n"), argv[i],
gpg_strerror (rc));
write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
rc = keydb_get_keyblock (hd, &kb);
if (rc)
{
log_error (_("error reading keyblock: %s\n"),
gpg_strerror (rc));
write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
merge_keys_and_selfsig (ctrl, kb);
if (tofu_set_policy (ctrl, kb, policy))
{
write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
release_kbnode (kb);
}
tofu_end_batch_update (ctrl);
keydb_release (hd);
}
#endif /*USE_TOFU*/
break;
default:
if (!opt.quiet)
log_info (_("WARNING: no command supplied."
" Trying to guess what you mean ...\n"));
/*FALLTHRU*/
case aListPackets:
if( argc > 1 )
wrong_args("[filename]");
/* Issue some output for the unix newbie */
if (!fname && !opt.outfile
&& gnupg_isatty (fileno (stdin))
&& gnupg_isatty (fileno (stdout))
&& gnupg_isatty (fileno (stderr)))
log_info(_("Go ahead and type your message ...\n"));
a = iobuf_open(fname);
if (a && is_secured_file (iobuf_get_fd (a)))
{
iobuf_close (a);
a = NULL;
gpg_err_set_errno (EPERM);
}
if( !a )
log_error(_("can't open '%s'\n"), print_fname_stdin(fname));
else {
if( !opt.no_armor ) {
if( use_armor_filter( a ) ) {
afx = new_armor_context ();
push_armor_filter (afx, a);
}
}
if( cmd == aListPackets ) {
opt.list_packets=1;
set_packet_list_mode(1);
}
rc = proc_packets (ctrl, NULL, a );
if( rc )
{
write_status_failure ("-", rc);
log_error ("processing message failed: %s\n",
gpg_strerror (rc));
}
iobuf_close(a);
}
break;
}
/* cleanup */
gpg_deinit_default_ctrl (ctrl);
xfree (ctrl);
release_armor_context (afx);
FREE_STRLIST(remusr);
FREE_STRLIST(locusr);
g10_exit(0);
return 8; /*NEVER REACHED*/
}
/* Note: This function is used by signal handlers!. */
static void
emergency_cleanup (void)
{
gcry_control (GCRYCTL_TERM_SECMEM );
}
void
g10_exit( int rc )
{
/* If we had an error but not printed an error message, do it now.
* Note that write_status_failure will never print a second failure
* status line. */
if (rc)
write_status_failure ("gpg-exit", gpg_error (GPG_ERR_GENERAL));
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
if (DBG_CLOCK)
log_clock ("stop");
if ( (opt.debug & DBG_MEMSTAT_VALUE) )
{
keydb_dump_stats ();
sig_check_dump_stats ();
gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
emergency_cleanup ();
rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
exit (rc);
}
/* Pretty-print hex hashes. This assumes at least an 80-character
display, but there are a few other similar assumptions in the
display code. */
static void
print_hex (gcry_md_hd_t md, int algo, const char *fname)
{
int i,n,count,indent=0;
const byte *p;
if (fname)
indent = es_printf("%s: ",fname);
if (indent>40)
{
es_printf ("\n");
indent=0;
}
if (algo==DIGEST_ALGO_RMD160)
indent += es_printf("RMD160 = ");
else if (algo>0)
indent += es_printf("%6s = ", gcry_md_algo_name (algo));
else
algo = abs(algo);
count = indent;
p = gcry_md_read (md, algo);
n = gcry_md_get_algo_dlen (algo);
count += es_printf ("%02X",*p++);
for(i=1;i79)
{
es_printf ("\n%*s",indent," ");
count = indent;
}
else
count += es_printf(" ");
if (!(i%8))
count += es_printf(" ");
}
else if (n==20)
{
if(!(i%2))
{
if(count+4>79)
{
es_printf ("\n%*s",indent," ");
count=indent;
}
else
count += es_printf(" ");
}
if (!(i%10))
count += es_printf(" ");
}
else
{
if(!(i%4))
{
if (count+8>79)
{
es_printf ("\n%*s",indent," ");
count=indent;
}
else
count += es_printf(" ");
}
}
count += es_printf("%02X",*p);
}
es_printf ("\n");
}
static void
print_hashline( gcry_md_hd_t md, int algo, const char *fname )
{
int i, n;
const byte *p;
if ( fname )
{
for (p = fname; *p; p++ )
{
if ( *p <= 32 || *p > 127 || *p == ':' || *p == '%' )
es_printf ("%%%02X", *p );
else
es_putc (*p, es_stdout);
}
}
es_putc (':', es_stdout);
es_printf ("%d:", algo);
p = gcry_md_read (md, algo);
n = gcry_md_get_algo_dlen (algo);
for(i=0; i < n ; i++, p++ )
es_printf ("%02X", *p);
es_fputs (":\n", es_stdout);
}
static void
print_mds( const char *fname, int algo )
{
estream_t fp;
char buf[1024];
size_t n;
gcry_md_hd_t md;
if (!fname)
{
fp = es_stdin;
es_set_binary (fp);
}
else
{
fp = es_fopen (fname, "rb" );
if (fp && is_secured_file (es_fileno (fp)))
{
es_fclose (fp);
fp = NULL;
gpg_err_set_errno (EPERM);
}
}
if (!fp)
{
log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) );
return;
}
gcry_md_open (&md, 0, 0);
if (algo)
gcry_md_enable (md, algo);
else
{
if (!gcry_md_test_algo (GCRY_MD_MD5))
gcry_md_enable (md, GCRY_MD_MD5);
gcry_md_enable (md, GCRY_MD_SHA1);
if (!gcry_md_test_algo (GCRY_MD_RMD160))
gcry_md_enable (md, GCRY_MD_RMD160);
if (!gcry_md_test_algo (GCRY_MD_SHA224))
gcry_md_enable (md, GCRY_MD_SHA224);
if (!gcry_md_test_algo (GCRY_MD_SHA256))
gcry_md_enable (md, GCRY_MD_SHA256);
if (!gcry_md_test_algo (GCRY_MD_SHA384))
gcry_md_enable (md, GCRY_MD_SHA384);
if (!gcry_md_test_algo (GCRY_MD_SHA512))
gcry_md_enable (md, GCRY_MD_SHA512);
}
while ((n=es_fread (buf, 1, DIM(buf), fp)))
gcry_md_write (md, buf, n);
if (es_ferror(fp))
log_error ("%s: %s\n", fname?fname:"[stdin]", strerror(errno));
else
{
gcry_md_final (md);
if (opt.with_colons)
{
if ( algo )
print_hashline (md, algo, fname);
else
{
if (!gcry_md_test_algo (GCRY_MD_MD5))
print_hashline( md, GCRY_MD_MD5, fname );
print_hashline( md, GCRY_MD_SHA1, fname );
if (!gcry_md_test_algo (GCRY_MD_RMD160))
print_hashline( md, GCRY_MD_RMD160, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA224))
print_hashline (md, GCRY_MD_SHA224, fname);
if (!gcry_md_test_algo (GCRY_MD_SHA256))
print_hashline( md, GCRY_MD_SHA256, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA384))
print_hashline ( md, GCRY_MD_SHA384, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA512))
print_hashline ( md, GCRY_MD_SHA512, fname );
}
}
else
{
if (algo)
print_hex (md, -algo, fname);
else
{
if (!gcry_md_test_algo (GCRY_MD_MD5))
print_hex (md, GCRY_MD_MD5, fname);
print_hex (md, GCRY_MD_SHA1, fname );
if (!gcry_md_test_algo (GCRY_MD_RMD160))
print_hex (md, GCRY_MD_RMD160, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA224))
print_hex (md, GCRY_MD_SHA224, fname);
if (!gcry_md_test_algo (GCRY_MD_SHA256))
print_hex (md, GCRY_MD_SHA256, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA384))
print_hex (md, GCRY_MD_SHA384, fname );
if (!gcry_md_test_algo (GCRY_MD_SHA512))
print_hex (md, GCRY_MD_SHA512, fname );
}
}
}
gcry_md_close (md);
if (fp != es_stdin)
es_fclose (fp);
}
/****************
* Check the supplied name,value string and add it to the notation
* data to be used for signatures. which==0 for sig notations, and 1
* for cert notations.
*/
static void
add_notation_data( const char *string, int which )
{
struct notation *notation;
notation=string_to_notation(string,utf8_strings);
if(notation)
{
if(which)
{
notation->next=opt.cert_notations;
opt.cert_notations=notation;
}
else
{
notation->next=opt.sig_notations;
opt.sig_notations=notation;
}
}
}
static void
add_policy_url( const char *string, int which )
{
unsigned int i,critical=0;
strlist_t sl;
if(*string=='!')
{
string++;
critical=1;
}
for(i=0;iflags |= 1;
}
static void
add_keyserver_url( const char *string, int which )
{
unsigned int i,critical=0;
strlist_t sl;
if(*string=='!')
{
string++;
critical=1;
}
for(i=0;iflags |= 1;
}
static void
read_sessionkey_from_fd (int fd)
{
int i, len;
char *line;
if (! gnupg_fd_valid (fd))
log_fatal ("override-session-key-fd is invalid: %s\n", strerror (errno));
for (line = NULL, i = len = 100; ; i++ )
{
if (i >= len-1 )
{
char *tmp = line;
len += 100;
line = xmalloc_secure (len);
if (tmp)
{
memcpy (line, tmp, i);
xfree (tmp);
}
else
i=0;
}
if (read (fd, line + i, 1) != 1 || line[i] == '\n')
break;
}
line[i] = 0;
log_debug ("seskey: %s\n", line);
gpgrt_annotate_leaked_object (line);
opt.override_session_key = line;
}
diff --git a/g10/misc.c b/g10/misc.c
index 1e6df5f67..d7a3ee3f2 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -1,1882 +1,1878 @@
/* misc.c - miscellaneous functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
* 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 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
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include
#include
#endif
#ifdef HAVE_SETRLIMIT
#include
#include
#include
#endif
#ifdef ENABLE_SELINUX_HACKS
#include
#endif
#ifdef HAVE_W32_SYSTEM
#include
#include
#ifdef HAVE_WINSOCK2_H
# define WIN32_LEAN_AND_MEAN 1
# include
#endif
#include
#include
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE 0x8000
#endif
#endif /*HAVE_W32_SYSTEM*/
#include "gpg.h"
#ifdef HAVE_W32_SYSTEM
# include "../common/status.h"
#endif /*HAVE_W32_SYSTEM*/
#include "../common/util.h"
#include "main.h"
#include "photoid.h"
#include "options.h"
#include "call-agent.h"
#include "../common/i18n.h"
#include "../common/zb32.h"
/* FIXME: Libgcrypt 1.9 will support EAX. Until we kame this a
* requirement we hardwire the enum used for EAX. */
#define MY_GCRY_CIPHER_MODE_EAX 14
#ifdef ENABLE_SELINUX_HACKS
/* A object and a global variable to keep track of files marked as
secured. */
struct secured_file_item
{
struct secured_file_item *next;
ino_t ino;
dev_t dev;
};
static struct secured_file_item *secured_files;
#endif /*ENABLE_SELINUX_HACKS*/
/* For the sake of SELinux we want to restrict access through gpg to
certain files we keep under our own control. This function
registers such a file and is_secured_file may then be used to
check whether a file has ben registered as secured. */
void
register_secured_file (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
/* Note that we stop immediately if something goes wrong here. */
if (stat (fname, &buf))
log_fatal (_("fstat of '%s' failed in %s: %s\n"), fname,
"register_secured_file", strerror (errno));
/* log_debug ("registering '%s' i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return; /* Already registered. */
}
sf = xmalloc (sizeof *sf);
sf->ino = buf.st_ino;
sf->dev = buf.st_dev;
sf->next = secured_files;
secured_files = sf;
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
}
/* Remove a file registered as secure. */
void
unregister_secured_file (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf, *sfprev;
if (stat (fname, &buf))
{
log_error (_("fstat of '%s' failed in %s: %s\n"), fname,
"unregister_secured_file", strerror (errno));
return;
}
/* log_debug ("unregistering '%s' i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sfprev=NULL,sf=secured_files; sf; sfprev=sf, sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
{
if (sfprev)
sfprev->next = sf->next;
else
secured_files = sf->next;
xfree (sf);
return;
}
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
}
/* Return true if FD is corresponds to a secured file. Using -1 for
FS is allowed and will return false. */
int
is_secured_file (int fd)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
if (fd == -1)
return 0; /* No file descriptor so it can't be secured either. */
/* Note that we print out a error here and claim that a file is
secure if something went wrong. */
if (fstat (fd, &buf))
{
log_error (_("fstat(%d) failed in %s: %s\n"), fd,
"is_secured_file", strerror (errno));
return 1;
}
/* log_debug ("is_secured_file (%d) i=%lu.%lu\n", fd, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return 1; /* Yes. */
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fd;
#endif /*!ENABLE_SELINUX_HACKS*/
return 0; /* No. */
}
/* Return true if FNAME is corresponds to a secured file. Using NULL,
"" or "-" for FS is allowed and will return false. This function is
used before creating a file, thus it won't fail if the file does
not exist. */
int
is_secured_filename (const char *fname)
{
#ifdef ENABLE_SELINUX_HACKS
struct stat buf;
struct secured_file_item *sf;
if (iobuf_is_pipe_filename (fname) || !*fname)
return 0;
/* Note that we print out a error here and claim that a file is
secure if something went wrong. */
if (stat (fname, &buf))
{
if (errno == ENOENT || errno == EPERM || errno == EACCES)
return 0;
log_error (_("fstat of '%s' failed in %s: %s\n"), fname,
"is_secured_filename", strerror (errno));
return 1;
}
/* log_debug ("is_secured_filename (%s) i=%lu.%lu\n", fname, */
/* (unsigned long)buf.st_dev, (unsigned long)buf.st_ino); */
for (sf=secured_files; sf; sf = sf->next)
{
if (sf->ino == buf.st_ino && sf->dev == buf.st_dev)
return 1; /* Yes. */
}
#else /*!ENABLE_SELINUX_HACKS*/
(void)fname;
#endif /*!ENABLE_SELINUX_HACKS*/
return 0; /* No. */
}
u16
checksum_u16( unsigned n )
{
u16 a;
a = (n >> 8) & 0xff;
a += n & 0xff;
return a;
}
u16
checksum( byte *p, unsigned n )
{
u16 a;
for(a=0; n; n-- )
a += *p++;
return a;
}
u16
checksum_mpi (gcry_mpi_t a)
{
u16 csum;
byte *buffer;
size_t nbytes;
if ( gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, a) )
BUG ();
/* Fixme: For numbers not in secure memory we should use a stack
* based buffer and only allocate a larger one if mpi_print returns
* an error. */
buffer = (gcry_is_secure(a)?
gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes));
if ( gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, NULL, a) )
BUG ();
csum = checksum (buffer, nbytes);
xfree (buffer);
return csum;
}
void
print_pubkey_algo_note (pubkey_algo_t algo)
{
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
es_fflush (es_stdout);
log_info (_("WARNING: using experimental public key algorithm %s\n"),
openpgp_pk_algo_name (algo));
}
}
else if (algo == PUBKEY_ALGO_ELGAMAL)
{
es_fflush (es_stdout);
log_info (_("WARNING: Elgamal sign+encrypt keys are deprecated\n"));
}
}
void
print_cipher_algo_note (cipher_algo_t algo)
{
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
es_fflush (es_stdout);
log_info (_("WARNING: using experimental cipher algorithm %s\n"),
openpgp_cipher_algo_name (algo));
}
}
}
void
print_digest_algo_note (digest_algo_t algo)
{
const enum gcry_md_algos galgo = map_md_openpgp_to_gcry (algo);
const struct weakhash *weak;
if(algo >= 100 && algo <= 110)
{
static int warn=0;
if(!warn)
{
warn=1;
es_fflush (es_stdout);
log_info (_("WARNING: using experimental digest algorithm %s\n"),
gcry_md_algo_name (galgo));
}
}
else
for (weak = opt.weak_digests; weak != NULL; weak = weak->next)
if (weak->algo == galgo)
{
es_fflush (es_stdout);
log_info (_("WARNING: digest algorithm %s is deprecated\n"),
gcry_md_algo_name (galgo));
}
}
void
print_digest_rejected_note (enum gcry_md_algos algo)
{
struct weakhash* weak;
int show = 1;
for (weak = opt.weak_digests; weak; weak = weak->next)
if (weak->algo == algo)
{
if (weak->rejection_shown)
show = 0;
else
weak->rejection_shown = 1;
break;
}
if (show)
{
es_fflush (es_stdout);
log_info
(_("Note: signatures using the %s algorithm are rejected\n"),
gcry_md_algo_name(algo));
}
}
/* Print a message
* "(reported error: %s)\n
* in verbose mode to further explain an error. If the error code has
* the value IGNORE_EC no message is printed. A message is also not
* printed if ERR is 0. */
void
print_reported_error (gpg_error_t err, gpg_err_code_t ignore_ec)
{
if (!opt.verbose)
return;
if (!gpg_err_code (err))
;
else if (gpg_err_code (err) == ignore_ec)
;
else if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
log_info (_("(reported error: %s)\n"),
gpg_strerror (err));
else
log_info (_("(reported error: %s <%s>)\n"),
gpg_strerror (err), gpg_strsource (err));
}
/* Print a message
* "(further info: %s)\n
* in verbose mode to further explain an error. That message is
* intended to help debug a problem and should not be translated.
*/
void
print_further_info (const char *format, ...)
{
va_list arg_ptr;
if (!opt.verbose)
return;
log_info (_("(further info: "));
va_start (arg_ptr, format);
log_logv (GPGRT_LOGLVL_CONT, format, arg_ptr);
va_end (arg_ptr);
log_printf (")\n");
}
/* Map OpenPGP algo numbers to those used by Libgcrypt. We need to do
this for algorithms we implemented in Libgcrypt after they become
part of OpenPGP. */
enum gcry_cipher_algos
map_cipher_openpgp_to_gcry (cipher_algo_t algo)
{
switch (algo)
{
case CIPHER_ALGO_NONE: return GCRY_CIPHER_NONE;
#ifdef GPG_USE_IDEA
case CIPHER_ALGO_IDEA: return GCRY_CIPHER_IDEA;
#else
case CIPHER_ALGO_IDEA: return 0;
#endif
case CIPHER_ALGO_3DES: return GCRY_CIPHER_3DES;
#ifdef GPG_USE_CAST5
case CIPHER_ALGO_CAST5: return GCRY_CIPHER_CAST5;
#else
case CIPHER_ALGO_CAST5: return 0;
#endif
#ifdef GPG_USE_BLOWFISH
case CIPHER_ALGO_BLOWFISH: return GCRY_CIPHER_BLOWFISH;
#else
case CIPHER_ALGO_BLOWFISH: return 0;
#endif
#ifdef GPG_USE_AES128
case CIPHER_ALGO_AES: return GCRY_CIPHER_AES;
#else
case CIPHER_ALGO_AES: return 0;
#endif
#ifdef GPG_USE_AES192
case CIPHER_ALGO_AES192: return GCRY_CIPHER_AES192;
#else
case CIPHER_ALGO_AES192: return 0;
#endif
#ifdef GPG_USE_AES256
case CIPHER_ALGO_AES256: return GCRY_CIPHER_AES256;
#else
case CIPHER_ALGO_AES256: return 0;
#endif
#ifdef GPG_USE_TWOFISH
case CIPHER_ALGO_TWOFISH: return GCRY_CIPHER_TWOFISH;
#else
case CIPHER_ALGO_TWOFISH: return 0;
#endif
#ifdef GPG_USE_CAMELLIA128
case CIPHER_ALGO_CAMELLIA128: return GCRY_CIPHER_CAMELLIA128;
#else
case CIPHER_ALGO_CAMELLIA128: return 0;
#endif
#ifdef GPG_USE_CAMELLIA192
case CIPHER_ALGO_CAMELLIA192: return GCRY_CIPHER_CAMELLIA192;
#else
case CIPHER_ALGO_CAMELLIA192: return 0;
#endif
#ifdef GPG_USE_CAMELLIA256
case CIPHER_ALGO_CAMELLIA256: return GCRY_CIPHER_CAMELLIA256;
#else
case CIPHER_ALGO_CAMELLIA256: return 0;
#endif
default: return 0;
}
}
/* The inverse function of above. */
static cipher_algo_t
map_cipher_gcry_to_openpgp (enum gcry_cipher_algos algo)
{
switch (algo)
{
case GCRY_CIPHER_NONE: return CIPHER_ALGO_NONE;
case GCRY_CIPHER_IDEA: return CIPHER_ALGO_IDEA;
case GCRY_CIPHER_3DES: return CIPHER_ALGO_3DES;
case GCRY_CIPHER_CAST5: return CIPHER_ALGO_CAST5;
case GCRY_CIPHER_BLOWFISH: return CIPHER_ALGO_BLOWFISH;
case GCRY_CIPHER_AES: return CIPHER_ALGO_AES;
case GCRY_CIPHER_AES192: return CIPHER_ALGO_AES192;
case GCRY_CIPHER_AES256: return CIPHER_ALGO_AES256;
case GCRY_CIPHER_TWOFISH: return CIPHER_ALGO_TWOFISH;
case GCRY_CIPHER_CAMELLIA128: return CIPHER_ALGO_CAMELLIA128;
case GCRY_CIPHER_CAMELLIA192: return CIPHER_ALGO_CAMELLIA192;
case GCRY_CIPHER_CAMELLIA256: return CIPHER_ALGO_CAMELLIA256;
default: return 0;
}
}
/* Map Gcrypt public key algorithm numbers to those used by OpenPGP.
FIXME: This mapping is used at only two places - we should get rid
of it. */
pubkey_algo_t
map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
{
switch (algo)
{
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
default: return algo < 110 ? (pubkey_algo_t)algo : 0;
}
}
/* Return the block length of an OpenPGP cipher algorithm. */
int
openpgp_cipher_blocklen (cipher_algo_t algo)
{
/* We use the numbers from OpenPGP to be sure that we get the right
block length. This is so that the packet parsing code works even
for unknown algorithms (for which we assume 8 due to tradition).
NOTE: If you change the returned blocklen above 16, check
the callers because they may use a fixed size buffer of that
size. */
switch (algo)
{
case CIPHER_ALGO_AES:
case CIPHER_ALGO_AES192:
case CIPHER_ALGO_AES256:
case CIPHER_ALGO_TWOFISH:
case CIPHER_ALGO_CAMELLIA128:
case CIPHER_ALGO_CAMELLIA192:
case CIPHER_ALGO_CAMELLIA256:
return 16;
default:
return 8;
}
}
/****************
* Wrapper around the libgcrypt function with additional checks on
* the OpenPGP contraints for the algo ID.
*/
int
openpgp_cipher_test_algo (cipher_algo_t algo)
{
enum gcry_cipher_algos ga;
ga = map_cipher_openpgp_to_gcry (algo);
if (!ga)
return gpg_error (GPG_ERR_CIPHER_ALGO);
return gcry_cipher_test_algo (ga);
}
/* Map the OpenPGP cipher algorithm whose ID is contained in ALGORITHM to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_cipher_algo_name (cipher_algo_t algo)
{
switch (algo)
{
case CIPHER_ALGO_IDEA: return "IDEA";
case CIPHER_ALGO_3DES: return "3DES";
case CIPHER_ALGO_CAST5: return "CAST5";
case CIPHER_ALGO_BLOWFISH: return "BLOWFISH";
case CIPHER_ALGO_AES: return "AES";
case CIPHER_ALGO_AES192: return "AES192";
case CIPHER_ALGO_AES256: return "AES256";
case CIPHER_ALGO_TWOFISH: return "TWOFISH";
case CIPHER_ALGO_CAMELLIA128: return "CAMELLIA128";
case CIPHER_ALGO_CAMELLIA192: return "CAMELLIA192";
case CIPHER_ALGO_CAMELLIA256: return "CAMELLIA256";
case CIPHER_ALGO_NONE:
default: return "?";
}
}
/* Return 0 if ALGO is supported. Return an error if not. */
gpg_error_t
openpgp_aead_test_algo (aead_algo_t algo)
{
/* FIXME: We currently have no easy way to test whether libgcrypt
* implements a mode. The only way we can do this is to open a
* cipher context with that mode and close it immediately. That is
* a bit costly. So we look at the libgcrypt version and assume
* nothing has been patched out. */
switch (algo)
{
case AEAD_ALGO_NONE:
break;
case AEAD_ALGO_EAX:
#if GCRYPT_VERSION_NUMBER < 0x010900
break;
#else
return 0;
#endif
case AEAD_ALGO_OCB:
return 0;
}
return gpg_error (GPG_ERR_INV_CIPHER_MODE);
}
/* Map the OpenPGP AEAD algorithm with ID ALGO to a string
* representation of the algorithm name. For unknown algorithm IDs
* this function returns "?". */
const char *
openpgp_aead_algo_name (aead_algo_t algo)
{
switch (algo)
{
case AEAD_ALGO_NONE: break;
case AEAD_ALGO_EAX: return "EAX";
case AEAD_ALGO_OCB: return "OCB";
}
return "?";
}
/* Return information for the AEAD algorithm ALGO. The corresponding
* Libgcrypt ciphermode is stored at R_MODE and the required number of
* octets for the nonce at R_NONCELEN. On error and error code is
* returned. Note that the taglen is always 128 bits. */
gpg_error_t
openpgp_aead_algo_info (aead_algo_t algo, enum gcry_cipher_modes *r_mode,
unsigned int *r_noncelen)
{
switch (algo)
{
case AEAD_ALGO_OCB:
*r_mode = GCRY_CIPHER_MODE_OCB;
*r_noncelen = 15;
break;
case AEAD_ALGO_EAX:
*r_mode = MY_GCRY_CIPHER_MODE_EAX;
*r_noncelen = 16;
break;
default:
log_error ("unsupported AEAD algo %d\n", algo);
return gpg_error (GPG_ERR_INV_CIPHER_MODE);
}
return 0;
}
/* Return 0 if ALGO is a supported OpenPGP public key algorithm. */
int
openpgp_pk_test_algo (pubkey_algo_t algo)
{
return openpgp_pk_test_algo2 (algo, 0);
}
/* Return 0 if ALGO is a supported OpenPGP public key algorithm and
allows the usage USE. */
int
openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use)
{
enum gcry_pk_algos ga = 0;
size_t use_buf = use;
switch (algo)
{
#ifdef GPG_USE_RSA
case PUBKEY_ALGO_RSA: ga = GCRY_PK_RSA; break;
case PUBKEY_ALGO_RSA_E: ga = GCRY_PK_RSA_E; break;
case PUBKEY_ALGO_RSA_S: ga = GCRY_PK_RSA_S; break;
#else
case PUBKEY_ALGO_RSA: break;
case PUBKEY_ALGO_RSA_E: break;
case PUBKEY_ALGO_RSA_S: break;
#endif
case PUBKEY_ALGO_ELGAMAL_E: ga = GCRY_PK_ELG; break;
case PUBKEY_ALGO_DSA: ga = GCRY_PK_DSA; break;
#ifdef GPG_USE_ECDH
case PUBKEY_ALGO_ECDH: ga = GCRY_PK_ECC; break;
#else
case PUBKEY_ALGO_ECDH: break;
#endif
#ifdef GPG_USE_ECDSA
case PUBKEY_ALGO_ECDSA: ga = GCRY_PK_ECC; break;
#else
case PUBKEY_ALGO_ECDSA: break;
#endif
#ifdef GPG_USE_EDDSA
case PUBKEY_ALGO_EDDSA: ga = GCRY_PK_ECC; break;
#else
case PUBKEY_ALGO_EDDSA: break;
#endif
case PUBKEY_ALGO_ELGAMAL:
/* Dont't allow type 20 keys unless in rfc2440 mode. */
if (RFC2440)
ga = GCRY_PK_ELG;
break;
default:
break;
}
if (!ga)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
/* Now check whether Libgcrypt has support for the algorithm. */
return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf);
}
int
openpgp_pk_algo_usage ( int algo )
{
int use = 0;
/* They are hardwired in gpg 1.0. */
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
if (RFC2440)
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
break;
case PUBKEY_ALGO_ECDSA:
case PUBKEY_ALGO_EDDSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
default:
break;
}
return use;
}
/* Map the OpenPGP pubkey algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_pk_algo_name (pubkey_algo_t algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return "RSA";
case PUBKEY_ALGO_ELGAMAL:
case PUBKEY_ALGO_ELGAMAL_E: return "ELG";
case PUBKEY_ALGO_DSA: return "DSA";
case PUBKEY_ALGO_ECDH: return "ECDH";
case PUBKEY_ALGO_ECDSA: return "ECDSA";
case PUBKEY_ALGO_EDDSA: return "EDDSA";
default: return "?";
}
}
/* Explicit mapping of OpenPGP digest algos to Libgcrypt. */
/* FIXME: We do not yes use it everywhere. */
enum gcry_md_algos
map_md_openpgp_to_gcry (digest_algo_t algo)
{
switch (algo)
{
#ifdef GPG_USE_MD5
case DIGEST_ALGO_MD5: return GCRY_MD_MD5;
#else
case DIGEST_ALGO_MD5: return 0;
#endif
case DIGEST_ALGO_SHA1: return GCRY_MD_SHA1;
#ifdef GPG_USE_RMD160
case DIGEST_ALGO_RMD160: return GCRY_MD_RMD160;
#else
case DIGEST_ALGO_RMD160: return 0;
#endif
#ifdef GPG_USE_SHA224
case DIGEST_ALGO_SHA224: return GCRY_MD_SHA224;
#else
case DIGEST_ALGO_SHA224: return 0;
#endif
case DIGEST_ALGO_SHA256: return GCRY_MD_SHA256;
#ifdef GPG_USE_SHA384
case DIGEST_ALGO_SHA384: return GCRY_MD_SHA384;
#else
case DIGEST_ALGO_SHA384: return 0;
#endif
#ifdef GPG_USE_SHA512
case DIGEST_ALGO_SHA512: return GCRY_MD_SHA512;
#else
case DIGEST_ALGO_SHA512: return 0;
#endif
default: return 0;
}
}
/* Return 0 if ALGO is suitable and implemented OpenPGP hash
algorithm. */
int
openpgp_md_test_algo (digest_algo_t algo)
{
enum gcry_md_algos ga;
ga = map_md_openpgp_to_gcry (algo);
if (!ga)
return gpg_error (GPG_ERR_DIGEST_ALGO);
return gcry_md_test_algo (ga);
}
/* Map the OpenPGP digest algorithm whose ID is contained in ALGO to a
string representation of the algorithm name. For unknown algorithm
IDs this function returns "?". */
const char *
openpgp_md_algo_name (int algo)
{
switch (algo)
{
case DIGEST_ALGO_MD5: return "MD5";
case DIGEST_ALGO_SHA1: return "SHA1";
case DIGEST_ALGO_RMD160: return "RIPEMD160";
case DIGEST_ALGO_SHA256: return "SHA256";
case DIGEST_ALGO_SHA384: return "SHA384";
case DIGEST_ALGO_SHA512: return "SHA512";
case DIGEST_ALGO_SHA224: return "SHA224";
}
return "?";
}
static unsigned long
get_signature_count (PKT_public_key *pk)
{
#ifdef ENABLE_CARD_SUPPORT
struct agent_card_info_s info;
(void)pk;
if (!agent_scd_getattr ("SIG-COUNTER",&info))
return info.sig_counter;
else
return 0;
#else
(void)pk;
return 0;
#endif
}
/* Expand %-strings. Returns a string which must be xfreed. Returns
NULL if the string cannot be expanded (too large). */
char *
pct_expando(const char *string,struct expando_args *args)
{
const char *ch=string;
int idx=0,maxlen=0,done=0;
u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
char *ret=NULL;
if(args->pk)
keyid_from_pk(args->pk,pk_keyid);
if(args->pksk)
keyid_from_pk (args->pksk, sk_keyid);
/* This is used so that %k works in photoid command strings in
--list-secret-keys (which of course has a sk, but no pk). */
if(!args->pk && args->pksk)
keyid_from_pk (args->pksk, pk_keyid);
while(*ch!='\0')
{
if(!done)
{
/* 8192 is way bigger than we'll need here */
if(maxlen>=8192)
goto fail;
maxlen+=1024;
ret=xrealloc(ret,maxlen);
}
done=0;
if(*ch=='%')
{
switch(*(ch+1))
{
case 's': /* short key id */
if(idx+8namehash)
{
char *tmp = zb32_encode (args->namehash, 8*20);
if (tmp)
{
if (idx + strlen (tmp) < maxlen)
{
strcpy (ret+idx, tmp);
idx += strlen (tmp);
}
xfree (tmp);
done = 1;
}
}
break;
case 'c': /* signature count from card, if any. */
if(idx+10pksk));
idx+=strlen(&ret[idx]);
done=1;
}
break;
case 'f': /* Fingerprint of key being signed */
case 'p': /* Fingerprint of the primary key making the signature. */
case 'g': /* Fingerprint of the key making the signature. */
{
byte array[MAX_FINGERPRINT_LEN];
size_t len;
int i;
if ((*(ch+1))=='f' && args->pk)
fingerprint_from_pk (args->pk, array, &len);
else if ((*(ch+1))=='p' && args->pksk)
{
if(args->pksk->flags.primary)
fingerprint_from_pk (args->pksk, array, &len);
else if (args->pksk->main_keyid[0]
|| args->pksk->main_keyid[1])
{
/* Not the primary key: Find the fingerprint
of the primary key. */
PKT_public_key *pk=
xmalloc_clear(sizeof(PKT_public_key));
if (!get_pubkey_fast (pk,args->pksk->main_keyid))
fingerprint_from_pk (pk, array, &len);
else
memset (array, 0, (len=MAX_FINGERPRINT_LEN));
free_public_key (pk);
}
else /* Oops: info about the primary key missing. */
memset(array,0,(len=MAX_FINGERPRINT_LEN));
}
else if((*(ch+1))=='g' && args->pksk)
fingerprint_from_pk (args->pksk, array, &len);
else
memset(array,0,(len=MAX_FINGERPRINT_LEN));
if(idx+(len*2)validity_info && idx+1validity_info;
ret[idx]='\0';
done=1;
}
break;
/* The text string types */
case 't':
case 'T':
case 'V':
{
const char *str=NULL;
switch(*(ch+1))
{
case 't': /* e.g. "jpg" */
str=image_type_to_string(args->imagetype,0);
break;
case 'T': /* e.g. "image/jpeg" */
str=image_type_to_string(args->imagetype,2);
break;
case 'V': /* e.g. "full", "expired", etc. */
str=args->validity_string;
break;
}
if(str && idx+strlen(str) 2)
result = 0;
}
else
result = 0;
return result;
}
/*
* Wrapper around gcry_md_map_name to provide a fallback using the
* "Hn" syntax as used by the preference strings.
*/
int
string_to_digest_algo (const char *string)
{
int val;
/* FIXME: We should make use of our wrapper function and not assume
that there is a 1 to 1 mapping between OpenPGP and Libgcrypt. */
val = gcry_md_map_name (string);
if (!val && string && (string[0]=='H' || string[0]=='h'))
{
char *endptr;
string++;
val = strtol (string, &endptr, 10);
if (!*string || *endptr || openpgp_md_test_algo (val))
val = 0;
}
return val;
}
const char *
compress_algo_to_string(int algo)
{
const char *s=NULL;
switch(algo)
{
case COMPRESS_ALGO_NONE:
s=_("Uncompressed");
break;
case COMPRESS_ALGO_ZIP:
s="ZIP";
break;
case COMPRESS_ALGO_ZLIB:
s="ZLIB";
break;
#ifdef HAVE_BZIP2
case COMPRESS_ALGO_BZIP2:
s="BZIP2";
break;
#endif
}
return s;
}
int
string_to_compress_algo(const char *string)
{
/* TRANSLATORS: See doc/TRANSLATE about this string. */
if(match_multistr(_("uncompressed|none"),string))
return 0;
else if(ascii_strcasecmp(string,"uncompressed")==0)
return 0;
else if(ascii_strcasecmp(string,"none")==0)
return 0;
else if(ascii_strcasecmp(string,"zip")==0)
return 1;
else if(ascii_strcasecmp(string,"zlib")==0)
return 2;
#ifdef HAVE_BZIP2
else if(ascii_strcasecmp(string,"bzip2")==0)
return 3;
#endif
else if(ascii_strcasecmp(string,"z0")==0)
return 0;
else if(ascii_strcasecmp(string,"z1")==0)
return 1;
else if(ascii_strcasecmp(string,"z2")==0)
return 2;
#ifdef HAVE_BZIP2
else if(ascii_strcasecmp(string,"z3")==0)
return 3;
#endif
else
return -1;
}
int
check_compress_algo(int algo)
{
switch (algo)
{
case 0: return 0;
#ifdef HAVE_ZIP
case 1:
case 2: return 0;
#endif
#ifdef HAVE_BZIP2
case 3: return 0;
#endif
default: return GPG_ERR_COMPR_ALGO;
}
}
int
default_cipher_algo(void)
{
if(opt.def_cipher_algo)
return opt.def_cipher_algo;
else if(opt.personal_cipher_prefs)
return opt.personal_cipher_prefs[0].value;
else
return opt.s2k_cipher_algo;
}
aead_algo_t
default_aead_algo(void)
{
if(opt.def_aead_algo)
return opt.def_aead_algo;
else if(opt.personal_aead_prefs)
return opt.personal_aead_prefs[0].value;
else
return DEFAULT_AEAD_ALGO;
}
/* There is no default_digest_algo function, but see
sign.c:hash_for() */
int
default_compress_algo(void)
{
if(opt.compress_algo!=-1)
return opt.compress_algo;
else if(opt.personal_compress_prefs)
return opt.personal_compress_prefs[0].value;
else
return DEFAULT_COMPRESS_ALGO;
}
void
compliance_failure(void)
{
char *ver="???";
switch(opt.compliance)
{
case CO_GNUPG:
ver="GnuPG";
break;
case CO_RFC4880:
ver="OpenPGP";
break;
case CO_RFC2440:
ver="OpenPGP (older)";
break;
- case CO_PGP6:
- ver="PGP 6.x";
- break;
-
case CO_PGP7:
ver="PGP 7.x";
break;
case CO_PGP8:
ver="PGP 8.x";
break;
case CO_DE_VS:
ver="DE-VS applications";
break;
}
log_info(_("this message may not be usable by %s\n"),ver);
opt.compliance=CO_GNUPG;
}
/* Break a string into successive option pieces. Accepts single word
options and key=value argument options. */
char *
optsep(char **stringp)
{
char *tok,*end;
tok=*stringp;
if(tok)
{
end=strpbrk(tok," ,=");
if(end)
{
int sawequals=0;
char *ptr=end;
/* what we need to do now is scan along starting with *end,
If the next character we see (ignoring spaces) is an =
sign, then there is an argument. */
while(*ptr)
{
if(*ptr=='=')
sawequals=1;
else if(*ptr!=' ')
break;
ptr++;
}
/* There is an argument, so grab that too. At this point,
ptr points to the first character of the argument. */
if(sawequals)
{
/* Is it a quoted argument? */
if(*ptr=='"')
{
ptr++;
end=strchr(ptr,'"');
if(end)
end++;
}
else
end=strpbrk(ptr," ,");
}
if(end && *end)
{
*end='\0';
*stringp=end+1;
}
else
*stringp=NULL;
}
else
*stringp=NULL;
}
return tok;
}
/* Breaks an option value into key and value. Returns NULL if there
is no value. Note that "string" is modified to remove the =value
part. */
char *
argsplit(char *string)
{
char *equals,*arg=NULL;
equals=strchr(string,'=');
if(equals)
{
char *quote,*space;
*equals='\0';
arg=equals+1;
/* Quoted arg? */
quote=strchr(arg,'"');
if(quote)
{
arg=quote+1;
quote=strchr(arg,'"');
if(quote)
*quote='\0';
}
else
{
size_t spaces;
/* Trim leading spaces off of the arg */
spaces=strspn(arg," ");
arg+=spaces;
}
/* Trim tailing spaces off of the tag */
space=strchr(string,' ');
if(space)
*space='\0';
}
return arg;
}
/* Return the length of the initial token, leaving off any
argument. */
static size_t
optlen(const char *s)
{
char *end=strpbrk(s," =");
if(end)
return end-s;
else
return strlen(s);
}
int
parse_options(char *str,unsigned int *options,
struct parse_options *opts,int noisy)
{
char *tok;
if (str && !strcmp (str, "help"))
{
int i,maxlen=0;
/* Figure out the longest option name so we can line these up
neatly. */
for(i=0;opts[i].name;i++)
if(opts[i].help && maxlen='A' && file[0]<='Z')
|| (file[0]>='a' && file[0]<='z'))
&& file[1]==':')
#else
|| file[0]=='/'
#endif
)
return access(file,mode);
else
{
/* At least as large as, but most often larger than we need. */
char *buffer=xmalloc(strlen(envpath)+1+strlen(file)+1);
char *split,*item,*path=xstrdup(envpath);
split=path;
while((item=strsep(&split,PATHSEP_S)))
{
strcpy(buffer,item);
strcat(buffer,"/");
strcat(buffer,file);
ret=access(buffer,mode);
if(ret==0)
break;
}
xfree(path);
xfree(buffer);
}
return ret;
}
/* Return the number of public key parameters as used by OpenPGP. */
int
pubkey_get_npkey (pubkey_algo_t algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return 2;
case PUBKEY_ALGO_ELGAMAL_E: return 3;
case PUBKEY_ALGO_DSA: return 4;
case PUBKEY_ALGO_ECDH: return 3;
case PUBKEY_ALGO_ECDSA: return 2;
case PUBKEY_ALGO_ELGAMAL: return 3;
case PUBKEY_ALGO_EDDSA: return 2;
default: return 0;
}
}
/* Return the number of secret key parameters as used by OpenPGP. */
int
pubkey_get_nskey (pubkey_algo_t algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return 6;
case PUBKEY_ALGO_ELGAMAL_E: return 4;
case PUBKEY_ALGO_DSA: return 5;
case PUBKEY_ALGO_ECDH: return 4;
case PUBKEY_ALGO_ECDSA: return 3;
case PUBKEY_ALGO_ELGAMAL: return 4;
case PUBKEY_ALGO_EDDSA: return 3;
default: return 0;
}
}
/* Temporary helper. */
int
pubkey_get_nsig (pubkey_algo_t algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return 1;
case PUBKEY_ALGO_ELGAMAL_E: return 0;
case PUBKEY_ALGO_DSA: return 2;
case PUBKEY_ALGO_ECDH: return 0;
case PUBKEY_ALGO_ECDSA: return 2;
case PUBKEY_ALGO_ELGAMAL: return 2;
case PUBKEY_ALGO_EDDSA: return 2;
default: return 0;
}
}
/* Temporary helper. */
int
pubkey_get_nenc (pubkey_algo_t algo)
{
switch (algo)
{
case PUBKEY_ALGO_RSA:
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_RSA_S: return 1;
case PUBKEY_ALGO_ELGAMAL_E: return 2;
case PUBKEY_ALGO_DSA: return 0;
case PUBKEY_ALGO_ECDH: return 2;
case PUBKEY_ALGO_ECDSA: return 0;
case PUBKEY_ALGO_ELGAMAL: return 2;
case PUBKEY_ALGO_EDDSA: return 0;
default: return 0;
}
}
/* Temporary helper. */
unsigned int
pubkey_nbits( int algo, gcry_mpi_t *key )
{
int rc, nbits;
gcry_sexp_t sexp;
if (algo == PUBKEY_ALGO_DSA
&& key[0] && key[1] && key[2] && key[3])
{
rc = gcry_sexp_build (&sexp, NULL,
"(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
key[0], key[1], key[2], key[3] );
}
else if ((algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
&& key[0] && key[1] && key[2])
{
rc = gcry_sexp_build (&sexp, NULL,
"(public-key(elg(p%m)(g%m)(y%m)))",
key[0], key[1], key[2] );
}
else if (is_RSA (algo)
&& key[0] && key[1])
{
rc = gcry_sexp_build (&sexp, NULL,
"(public-key(rsa(n%m)(e%m)))",
key[0], key[1] );
}
else if ((algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH
|| algo == PUBKEY_ALGO_EDDSA)
&& key[0] && key[1])
{
char *curve = openpgp_oid_to_str (key[0]);
if (!curve)
rc = gpg_error_from_syserror ();
else
{
rc = gcry_sexp_build (&sexp, NULL,
"(public-key(ecc(curve%s)(q%m)))",
curve, key[1]);
xfree (curve);
}
}
else
return 0;
if (rc)
BUG ();
nbits = gcry_pk_get_nbits (sexp);
gcry_sexp_release (sexp);
return nbits;
}
int
mpi_print (estream_t fp, gcry_mpi_t a, int mode)
{
int n = 0;
size_t nwritten;
if (!a)
return es_fprintf (fp, "[MPI_NULL]");
if (!mode)
{
unsigned int n1;
n1 = gcry_mpi_get_nbits(a);
n += es_fprintf (fp, "[%u bits]", n1);
}
else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
unsigned int nbits;
unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
if (!p)
n += es_fprintf (fp, "[invalid opaque value]");
else
{
if (!es_write_hexstring (fp, p, (nbits + 7)/8, 0, &nwritten))
n += nwritten;
}
}
else
{
unsigned char *buffer;
size_t buflen;
if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &buflen, a))
BUG ();
if (!es_write_hexstring (fp, buffer, buflen, 0, &nwritten))
n += nwritten;
gcry_free (buffer);
}
return n;
}
/* pkey[1] or skey[1] is Q for ECDSA, which is an uncompressed point,
i.e. 04 */
unsigned int
ecdsa_qbits_from_Q (unsigned int qbits)
{
if ((qbits%8) > 3)
{
log_error (_("ECDSA public key is expected to be in SEC encoding "
"multiple of 8 bits\n"));
return 0;
}
qbits -= qbits%8;
qbits /= 2;
return qbits;
}
/* Ignore signatures and certifications made over certain digest
* algorithms by default, MD5 is considered weak. This allows users
* to deprecate support for other algorithms as well.
*/
void
additional_weak_digest (const char* digestname)
{
struct weakhash *weak = NULL;
const enum gcry_md_algos algo = string_to_digest_algo(digestname);
if (algo == GCRY_MD_NONE)
{
log_error (_("unknown weak digest '%s'\n"), digestname);
return;
}
/* Check to ensure it's not already present. */
for (weak = opt.weak_digests; weak; weak = weak->next)
if (algo == weak->algo)
return;
/* Add it to the head of the list. */
weak = xmalloc(sizeof(*weak));
weak->algo = algo;
weak->rejection_shown = 0;
weak->next = opt.weak_digests;
opt.weak_digests = weak;
}
diff --git a/g10/options.h b/g10/options.h
index 09d4e4435..3754687ae 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -1,410 +1,409 @@
/* options.h
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2010, 2011 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_OPTIONS_H
#define G10_OPTIONS_H
#include
#include "../common/types.h"
#include
#include "main.h"
#include "packet.h"
#include "tofu.h"
#include "../common/session-env.h"
#include "../common/compliance.h"
#ifndef EXTERN_UNLESS_MAIN_MODULE
/* Norcraft can't cope with common symbols */
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
#define EXTERN_UNLESS_MAIN_MODULE extern
#else
#define EXTERN_UNLESS_MAIN_MODULE
#endif
#endif
/* Declaration of a keyserver spec type. The definition is found in
../common/keyserver.h. */
struct keyserver_spec;
typedef struct keyserver_spec *keyserver_spec_t;
/* Global options for GPG. */
EXTERN_UNLESS_MAIN_MODULE
struct
{
int verbose;
int quiet;
unsigned debug;
int armor;
char *outfile;
estream_t outfp; /* Hack, sometimes used in place of outfile. */
off_t max_output;
/* If > 0 a hint with the expected number of input data bytes. This
* is not necessary an exact number but intended to be used for
* progress info and to decide on how to allocate buffers. */
uint64_t input_size_hint;
/* The AEAD chunk size expressed as a power of 2. */
int chunk_size;
int dry_run;
int autostart;
int list_only;
int mimemode;
int textmode;
int expert;
const char *def_sig_expire;
int ask_sig_expire;
const char *def_cert_expire;
int ask_cert_expire;
int batch; /* run in batch mode */
int answer_yes; /* answer yes on most questions */
int answer_no; /* answer no on most questions */
int check_sigs; /* check key signatures */
int with_colons;
int with_key_data;
int with_icao_spelling; /* Print ICAO spelling with fingerprints. */
int with_fingerprint; /* Option --with-fingerprint active. */
int with_subkey_fingerprint; /* Option --with-subkey-fingerprint active. */
int with_keygrip; /* Option --with-keygrip active. */
int with_key_screening;/* Option --with-key-screening active. */
int with_tofu_info; /* Option --with-tofu_info active. */
int with_secret; /* Option --with-secret active. */
int with_wkd_hash; /* Option --with-wkd-hash. */
int with_key_origin; /* Option --with-key-origin. */
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
int no_armor;
int list_packets; /* Option --list-packets active. */
int def_cipher_algo;
int def_aead_algo;
int force_mdc;
int disable_mdc;
int force_aead;
int def_digest_algo;
int cert_digest_algo;
int compress_algo;
int compress_level;
int bz2_compress_level;
int bz2_decompress_lowmem;
strlist_t def_secret_key;
char *def_recipient;
int def_recipient_self;
strlist_t secret_keys_to_try;
/* A list of mail addresses (addr-spec) provided by the user with
* the option --sender. */
strlist_t sender_list;
int def_cert_level;
int min_cert_level;
int ask_cert_level;
int emit_version; /* 0 = none,
1 = major only,
2 = major and minor,
3 = full version,
4 = full version plus OS string. */
int marginals_needed;
int completes_needed;
int max_cert_depth;
const char *agent_program;
const char *dirmngr_program;
int disable_dirmngr;
const char *def_new_key_algo;
/* Options to be passed to the gpg-agent */
session_env_t session_env;
char *lc_ctype;
char *lc_messages;
int skip_verify;
int skip_hidden_recipients;
/* TM_CLASSIC must be zero to accommodate trustdbsg generated before
we started storing the trust model inside the trustdb. */
enum
{
TM_CLASSIC=0, TM_PGP=1, TM_EXTERNAL=2,
TM_ALWAYS, TM_DIRECT, TM_AUTO, TM_TOFU, TM_TOFU_PGP
} trust_model;
enum tofu_policy tofu_default_policy;
int force_ownertrust;
enum gnupg_compliance_mode compliance;
enum
{
KF_DEFAULT, KF_NONE, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
} keyid_format;
const char *set_filename;
strlist_t comments;
int throw_keyids;
const char *photo_viewer;
int s2k_mode;
int s2k_digest_algo;
int s2k_cipher_algo;
unsigned char s2k_count; /* This is the encoded form, not the raw
count */
int not_dash_escaped;
int escape_from;
int lock_once;
keyserver_spec_t keyserver; /* The list of configured keyservers. */
struct
{
unsigned int options;
unsigned int import_options;
unsigned int export_options;
char *http_proxy;
} keyserver_options;
int exec_disable;
int exec_path_set;
unsigned int import_options;
unsigned int export_options;
unsigned int list_options;
unsigned int verify_options;
const char *def_preference_list;
const char *def_keyserver_url;
prefitem_t *personal_cipher_prefs;
prefitem_t *personal_aead_prefs;
prefitem_t *personal_digest_prefs;
prefitem_t *personal_compress_prefs;
struct weakhash *weak_digests;
int no_perm_warn;
char *temp_dir;
int no_encrypt_to;
int encrypt_to_default_key;
int interactive;
struct notation *sig_notations;
struct notation *cert_notations;
strlist_t sig_policy_url;
strlist_t cert_policy_url;
strlist_t sig_keyserver_url;
strlist_t cert_subpackets;
strlist_t sig_subpackets;
int allow_non_selfsigned_uid;
int allow_freeform_uid;
int no_literal;
ulong set_filesize;
int fast_list_mode;
int legacy_list_mode;
int ignore_time_conflict;
int ignore_valid_from;
int ignore_crc_error;
int ignore_mdc_error;
int command_fd;
const char *override_session_key;
int show_session_key;
const char *gpg_agent_info;
int try_all_secrets;
int no_expensive_trust_checks;
int no_sig_cache;
int no_auto_check_trustdb;
int preserve_permissions;
int no_homedir_creation;
struct groupitem *grouplist;
int mangle_dos_filenames;
int enable_progress_filter;
unsigned int screen_columns;
unsigned int screen_lines;
byte *show_subpackets;
int rfc2440_text;
/* If true, let write failures on the status-fd exit the process. */
int exit_on_status_write_error;
/* If > 0, limit the number of card insertion prompts to this
value. */
int limit_card_insert_tries;
struct
{
/* If set, require an 0x19 backsig to be present on signatures
made by signing subkeys. If not set, a missing backsig is not
an error (but an invalid backsig still is). */
unsigned int require_cross_cert:1;
unsigned int use_embedded_filename:1;
unsigned int utf8_filename:1;
unsigned int dsa2:1;
unsigned int allow_multiple_messages:1;
unsigned int allow_weak_digest_algos:1;
unsigned int large_rsa:1;
unsigned int disable_signer_uid:1;
/* Flag to enable experimental features from RFC4880bis. */
unsigned int rfc4880bis:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
keyring. */
struct akl
{
enum {
AKL_NODEFAULT,
AKL_LOCAL,
AKL_CERT,
AKL_PKA,
AKL_DANE,
AKL_WKD,
AKL_LDAP,
AKL_KEYSERVER,
AKL_SPEC
} type;
keyserver_spec_t spec;
struct akl *next;
} *auto_key_locate;
/* The value of --key-origin. See parse_key_origin(). */
int key_origin;
char *key_origin_url;
int passphrase_repeat;
int pinentry_mode;
int request_origin;
int unwrap_encryption;
int only_sign_text_ids;
int no_symkey_cache; /* Disable the cache used for --symmetric. */
} opt;
/* CTRL is used to keep some global variables we currently can't
avoid. Future concurrent versions of gpg will put it into a per
request structure CTRL. */
EXTERN_UNLESS_MAIN_MODULE
struct {
int in_auto_key_retrieve; /* True if we are doing an
auto_key_retrieve. */
/* Hack to store the last error. We currently need it because the
proc_packet machinery is not able to reliabale return error
codes. Thus for the --server purposes we store some of the error
codes here. FIXME! */
gpg_error_t lasterr;
} glo_ctrl;
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug crypto handling */
/* (may reveal sensitive data) */
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
#define DBG_IPC_VALUE 1024 /* debug assuan communication */
#define DBG_CLOCK_VALUE 4096
#define DBG_LOOKUP_VALUE 8192 /* debug the key lookup */
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
/* Tests for the debugging flags. */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
#define DBG_MPI (opt.debug & DBG_MPI_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
#define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE)
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
/* FIXME: We need to check why we did not put this into opt. */
#define DBG_MEMORY memory_debug_mode
#define DBG_MEMSTAT memory_stat_debug_mode
EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode;
EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
/* Compatibility flags. */
#define GNUPG (opt.compliance==CO_GNUPG || opt.compliance==CO_DE_VS)
#define RFC2440 (opt.compliance==CO_RFC2440)
#define RFC4880 (opt.compliance==CO_RFC4880)
-#define PGP6 (opt.compliance==CO_PGP6)
#define PGP7 (opt.compliance==CO_PGP7)
#define PGP8 (opt.compliance==CO_PGP8)
-#define PGPX (PGP6 || PGP7 || PGP8)
+#define PGPX (PGP7 || PGP8)
/* Various option flags. Note that there should be no common string
names between the IMPORT_ and EXPORT_ flags as they can be mixed in
the keyserver-options option. */
#define IMPORT_LOCAL_SIGS (1<<0)
#define IMPORT_REPAIR_PKS_SUBKEY_BUG (1<<1)
#define IMPORT_FAST (1<<2)
#define IMPORT_SHOW (1<<3)
#define IMPORT_MERGE_ONLY (1<<4)
#define IMPORT_MINIMAL (1<<5)
#define IMPORT_CLEAN (1<<6)
#define IMPORT_NO_SECKEY (1<<7)
#define IMPORT_KEEP_OWNERTTRUST (1<<8)
#define IMPORT_EXPORT (1<<9)
#define IMPORT_RESTORE (1<<10)
#define IMPORT_REPAIR_KEYS (1<<11)
#define IMPORT_DRY_RUN (1<<12)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)
#define EXPORT_SENSITIVE_REVKEYS (1<<2)
#define EXPORT_RESET_SUBKEY_PASSWD (1<<3)
#define EXPORT_MINIMAL (1<<4)
#define EXPORT_CLEAN (1<<5)
#define EXPORT_PKA_FORMAT (1<<6)
#define EXPORT_DANE_FORMAT (1<<7)
#define EXPORT_BACKUP (1<<10)
#define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1)
#define LIST_SHOW_STD_NOTATIONS (1<<2)
#define LIST_SHOW_USER_NOTATIONS (1<<3)
#define LIST_SHOW_NOTATIONS (LIST_SHOW_STD_NOTATIONS|LIST_SHOW_USER_NOTATIONS)
#define LIST_SHOW_KEYSERVER_URLS (1<<4)
#define LIST_SHOW_UID_VALIDITY (1<<5)
#define LIST_SHOW_UNUSABLE_UIDS (1<<6)
#define LIST_SHOW_UNUSABLE_SUBKEYS (1<<7)
#define LIST_SHOW_KEYRING (1<<8)
#define LIST_SHOW_SIG_EXPIRE (1<<9)
#define LIST_SHOW_SIG_SUBPACKETS (1<<10)
#define LIST_SHOW_USAGE (1<<11)
#define VERIFY_SHOW_PHOTOS (1<<0)
#define VERIFY_SHOW_POLICY_URLS (1<<1)
#define VERIFY_SHOW_STD_NOTATIONS (1<<2)
#define VERIFY_SHOW_USER_NOTATIONS (1<<3)
#define VERIFY_SHOW_NOTATIONS (VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_USER_NOTATIONS)
#define VERIFY_SHOW_KEYSERVER_URLS (1<<4)
#define VERIFY_SHOW_UID_VALIDITY (1<<5)
#define VERIFY_SHOW_UNUSABLE_UIDS (1<<6)
#define VERIFY_PKA_LOOKUPS (1<<7)
#define VERIFY_PKA_TRUST_INCREASE (1<<8)
#define VERIFY_SHOW_PRIMARY_UID_ONLY (1<<9)
#define KEYSERVER_HTTP_PROXY (1<<0)
#define KEYSERVER_TIMEOUT (1<<1)
#define KEYSERVER_ADD_FAKE_V3 (1<<2)
#define KEYSERVER_AUTO_KEY_RETRIEVE (1<<3)
#define KEYSERVER_HONOR_KEYSERVER_URL (1<<4)
#define KEYSERVER_HONOR_PKA_RECORD (1<<5)
#endif /*G10_OPTIONS_H*/
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 05bbea52d..6aec13882 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1,1724 +1,1719 @@
/* pkclist.c - create a list of public keys
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
* 2008, 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
#include "gpg.h"
#include "options.h"
#include "packet.h"
#include "../common/status.h"
#include "keydb.h"
#include "../common/util.h"
#include "main.h"
#include "trustdb.h"
#include "../common/ttyio.h"
#include "../common/status.h"
#include "photoid.h"
#include "../common/i18n.h"
#include "tofu.h"
#define CONTROL_D ('D' - 'A' + 1)
static void
send_status_inv_recp (int reason, const char *name)
{
char buf[40];
snprintf (buf, sizeof buf, "%d ", reason);
write_status_text_and_buffer (STATUS_INV_RECP, buf,
name, strlen (name),
-1);
}
/****************
* Show the revocation reason as it is stored with the given signature
*/
static void
do_show_revocation_reason( PKT_signature *sig )
{
size_t n, nn;
const byte *p, *pp;
int seq = 0;
const char *text;
while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
&n, &seq, NULL )) ) {
if( !n )
continue; /* invalid - just skip it */
if( *p == 0 )
text = _("No reason specified");
else if( *p == 0x01 )
text = _("Key is superseded");
else if( *p == 0x02 )
text = _("Key has been compromised");
else if( *p == 0x03 )
text = _("Key is no longer used");
else if( *p == 0x20 )
text = _("User ID is no longer valid");
else
text = NULL;
log_info ( _("reason for revocation: "));
if (text)
log_printf ("%s\n", text);
else
log_printf ("code=%02x\n", *p );
n--; p++;
pp = NULL;
do {
/* We don't want any empty lines, so skip them */
while( n && *p == '\n' ) {
p++;
n--;
}
if( n ) {
pp = memchr( p, '\n', n );
nn = pp? pp - p : n;
log_info ( _("revocation comment: ") );
es_write_sanitized (log_get_stream(), p, nn, NULL, NULL);
log_printf ("\n");
p += nn; n -= nn;
}
} while( pp );
}
}
/* Mode 0: try and find the revocation based on the pk (i.e. check
subkeys, etc.) Mode 1: use only the revocation on the main pk */
void
show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode)
{
/* Hmmm, this is not so easy because we have to duplicate the code
* used in the trustbd to calculate the keyflags. We need to find
* a clean way to check revocation certificates on keys and
* signatures. And there should be no duplicate code. Because we
* enter this function only when the trustdb told us that we have
* a revoked key, we could simply look for a revocation cert and
* display this one, when there is only one. Let's try to do this
* until we have a better solution. */
KBNODE node, keyblock = NULL;
byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
int rc;
/* get the keyblock */
fingerprint_from_pk( pk, fingerprint, &fingerlen );
rc = get_pubkey_byfprint (ctrl, NULL, &keyblock, fingerprint, fingerlen);
if( rc ) { /* that should never happen */
log_debug( "failed to get the keyblock\n");
return;
}
for( node=keyblock; node; node = node->next ) {
if( (mode && node->pkt->pkttype == PKT_PUBLIC_KEY) ||
( ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
&& !cmp_public_keys( node->pkt->pkt.public_key, pk ) ) )
break;
}
if( !node ) {
log_debug("Oops, PK not in keyblock\n");
release_kbnode( keyblock );
return;
}
/* now find the revocation certificate */
for( node = node->next; node ; node = node->next ) {
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
break;
if( node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class == 0x20
|| node->pkt->pkt.signature->sig_class == 0x28 ) ) {
/* FIXME: we should check the signature here */
do_show_revocation_reason ( node->pkt->pkt.signature );
break;
}
}
/* We didn't find it, so check if the whole key is revoked */
if(!node && !mode)
show_revocation_reason (ctrl, pk, 1);
release_kbnode( keyblock );
}
/****************
* mode: 0 = standard
* 1 = Without key info and additional menu option 'm'
* this does also add an option to set the key to ultimately trusted.
* Returns:
* -2 = nothing changed - caller should show some additional info
* -1 = quit operation
* 0 = nothing changed
* 1 = new ownertrust now in new_trust
*/
#ifndef NO_TRUST_MODELS
static int
do_edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode,
unsigned *new_trust, int defer_help )
{
char *p;
u32 keyid[2];
int changed=0;
int quit=0;
int show=0;
int min_num;
int did_help=defer_help;
unsigned int minimum = tdb_get_min_ownertrust (ctrl, pk, 0);
switch(minimum)
{
default:
case TRUST_UNDEFINED: min_num=1; break;
case TRUST_NEVER: min_num=2; break;
case TRUST_MARGINAL: min_num=3; break;
case TRUST_FULLY: min_num=4; break;
}
keyid_from_pk (pk, keyid);
for(;;) {
/* A string with valid answers.
TRANSLATORS: These are the allowed answers in lower and
uppercase. Below you will find the matching strings which
should be translated accordingly and the letter changed to
match the one in the answer string.
i = please show me more information
m = back to the main menu
s = skip this key
q = quit
*/
const char *ans = _("iImMqQsS");
if( !did_help )
{
if( !mode )
{
KBNODE keyblock, un;
tty_printf (_("No trust value assigned to:\n"));
print_key_line (ctrl, NULL, pk, 0);
p = get_user_id_native (ctrl, keyid);
tty_printf (_(" \"%s\"\n"),p);
xfree (p);
keyblock = get_pubkeyblock (ctrl, keyid);
if (!keyblock)
BUG ();
for (un=keyblock; un; un = un->next)
{
if (un->pkt->pkttype != PKT_USER_ID )
continue;
if (un->pkt->pkt.user_id->flags.revoked)
continue;
if (un->pkt->pkt.user_id->flags.expired)
continue;
/* Only skip textual primaries */
if (un->pkt->pkt.user_id->flags.primary
&& !un->pkt->pkt.user_id->attrib_data )
continue;
if((opt.verify_options&VERIFY_SHOW_PHOTOS)
&& un->pkt->pkt.user_id->attrib_data)
show_photos (ctrl,
un->pkt->pkt.user_id->attribs,
un->pkt->pkt.user_id->numattribs, pk,
un->pkt->pkt.user_id);
p=utf8_to_native(un->pkt->pkt.user_id->name,
un->pkt->pkt.user_id->len,0);
tty_printf(_(" aka \"%s\"\n"),p);
}
print_fingerprint (ctrl, NULL, pk, 2);
tty_printf("\n");
release_kbnode (keyblock);
}
if(opt.trust_model==TM_DIRECT)
{
tty_printf(_("How much do you trust that this key actually "
"belongs to the named user?\n"));
tty_printf("\n");
}
else
{
/* This string also used in keyedit.c:trustsig_prompt */
tty_printf(_("Please decide how far you trust this user to"
" correctly verify other users' keys\n"
"(by looking at passports, checking fingerprints from"
" different sources, etc.)\n"));
tty_printf("\n");
}
if(min_num<=1)
tty_printf (_(" %d = I don't know or won't say\n"), 1);
if(min_num<=2)
tty_printf (_(" %d = I do NOT trust\n"), 2);
if(min_num<=3)
tty_printf (_(" %d = I trust marginally\n"), 3);
if(min_num<=4)
tty_printf (_(" %d = I trust fully\n"), 4);
if (mode)
tty_printf (_(" %d = I trust ultimately\n"), 5);
#if 0
/* not yet implemented */
tty_printf (" i = please show me more information\n");
#endif
if( mode )
tty_printf(_(" m = back to the main menu\n"));
else
{
tty_printf(_(" s = skip this key\n"));
tty_printf(_(" q = quit\n"));
}
tty_printf("\n");
if(minimum)
tty_printf(_("The minimum trust level for this key is: %s\n\n"),
trust_value_to_string(minimum));
did_help = 1;
}
if( strlen(ans) != 8 )
BUG();
p = cpr_get("edit_ownertrust.value",_("Your decision? "));
trim_spaces(p);
cpr_kill_prompt();
if( !*p )
did_help = 0;
else if( *p && p[1] )
;
else if( !p[1] && ((*p >= '0'+min_num) && *p <= (mode?'5':'4')) )
{
unsigned int trust;
switch( *p )
{
case '1': trust = TRUST_UNDEFINED; break;
case '2': trust = TRUST_NEVER ; break;
case '3': trust = TRUST_MARGINAL ; break;
case '4': trust = TRUST_FULLY ; break;
case '5': trust = TRUST_ULTIMATE ; break;
default: BUG();
}
if (trust == TRUST_ULTIMATE
&& !cpr_get_answer_is_yes ("edit_ownertrust.set_ultimate.okay",
_("Do you really want to set this key"
" to ultimate trust? (y/N) ")))
; /* no */
else
{
*new_trust = trust;
changed = 1;
break;
}
}
#if 0
/* not yet implemented */
else if( *p == ans[0] || *p == ans[1] )
{
tty_printf(_("Certificates leading to an ultimately trusted key:\n"));
show = 1;
break;
}
#endif
else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) )
{
break ; /* back to the menu */
}
else if( !mode && (*p == ans[6] || *p == ans[7] ) )
{
break; /* skip */
}
else if( !mode && (*p == ans[4] || *p == ans[5] ) )
{
quit = 1;
break ; /* back to the menu */
}
xfree(p); p = NULL;
}
xfree(p);
return show? -2: quit? -1 : changed;
}
#endif /*!NO_TRUST_MODELS*/
/*
* Display a menu to change the ownertrust of the key PK (which should
* be a primary key).
* For mode values see do_edit_ownertrust ()
*/
#ifndef NO_TRUST_MODELS
int
edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode )
{
unsigned int trust = 0;
int no_help = 0;
for(;;)
{
switch ( do_edit_ownertrust (ctrl, pk, mode, &trust, no_help ) )
{
case -1: /* quit */
return -1;
case -2: /* show info */
no_help = 1;
break;
case 1: /* trust value set */
trust &= ~TRUST_FLAG_DISABLED;
trust |= get_ownertrust (ctrl, pk) & TRUST_FLAG_DISABLED;
update_ownertrust (ctrl, pk, trust );
return 1;
default:
return 0;
}
}
}
#endif /*!NO_TRUST_MODELS*/
/****************
* Check whether we can trust this pk which has a trustlevel of TRUSTLEVEL
* Returns: true if we trust.
*/
static int
do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
{
/* We should not be able to get here with a revoked or expired
key */
if(trustlevel & TRUST_FLAG_REVOKED
|| trustlevel & TRUST_FLAG_SUB_REVOKED
|| (trustlevel & TRUST_MASK) == TRUST_EXPIRED)
BUG();
if( opt.trust_model==TM_ALWAYS )
{
if( opt.verbose )
log_info("No trust check due to '--trust-model always' option\n");
return 1;
}
switch(trustlevel & TRUST_MASK)
{
default:
log_error ("invalid trustlevel %u returned from validation layer\n",
trustlevel);
/* fall through */
case TRUST_UNKNOWN:
case TRUST_UNDEFINED:
log_info(_("%s: There is no assurance this key belongs"
" to the named user\n"),keystr_from_pk(pk));
return 0; /* no */
case TRUST_MARGINAL:
log_info(_("%s: There is limited assurance this key belongs"
" to the named user\n"),keystr_from_pk(pk));
return 1; /* yes */
case TRUST_FULLY:
if( opt.verbose )
log_info(_("This key probably belongs to the named user\n"));
return 1; /* yes */
case TRUST_ULTIMATE:
if( opt.verbose )
log_info(_("This key belongs to us\n"));
return 1; /* yes */
case TRUST_NEVER:
/* This can be returned by TOFU, which can return negative
assertions. */
log_info(_("%s: This key is bad! It has been marked as untrusted!\n"),
keystr_from_pk(pk));
return 0; /* no */
}
return 1; /*NOTREACHED*/
}
/****************
* wrapper around do_we_trust, so we can ask whether to use the
* key anyway.
*/
static int
do_we_trust_pre (ctrl_t ctrl, PKT_public_key *pk, unsigned int trustlevel )
{
int rc;
rc = do_we_trust( pk, trustlevel );
if( !opt.batch && !rc )
{
print_pubkey_info (ctrl, NULL,pk);
print_fingerprint (ctrl, NULL, pk, 2);
tty_printf("\n");
if ((trustlevel & TRUST_MASK) == TRUST_NEVER)
tty_printf(
_("This key is bad! It has been marked as untrusted! If you\n"
"*really* know what you are doing, you may answer the next\n"
"question with yes.\n"));
else
tty_printf(
_("It is NOT certain that the key belongs to the person named\n"
"in the user ID. If you *really* know what you are doing,\n"
"you may answer the next question with yes.\n"));
tty_printf("\n");
if (is_status_enabled ())
{
u32 kid[2];
char *hint_str;
keyid_from_pk (pk, kid);
hint_str = get_long_user_id_string (ctrl, kid);
write_status_text ( STATUS_USERID_HINT, hint_str );
xfree (hint_str);
}
if( cpr_get_answer_is_yes("untrusted_key.override",
_("Use this key anyway? (y/N) ")) )
rc = 1;
/* Hmmm: Should we set a flag to tell the user about
* his decision the next time he encrypts for this recipient?
*/
}
return rc;
}
/* Write a TRUST_foo status line inclduing the validation model. */
static void
write_trust_status (int statuscode, int trustlevel)
{
#ifdef NO_TRUST_MODELS
write_status (statuscode);
#else /* NO_TRUST_MODELS */
int tm;
/* For the combined tofu+pgp method, we return the trust model which
* was responsible for the trustlevel. */
if (opt.trust_model == TM_TOFU_PGP)
tm = (trustlevel & TRUST_FLAG_TOFU_BASED)? TM_TOFU : TM_PGP;
else
tm = opt.trust_model;
write_status_strings (statuscode, "0 ", trust_model_string (tm), NULL);
#endif /* NO_TRUST_MODELS */
}
/****************
* Check whether we can trust this signature.
* Returns an error code if we should not trust this signature.
*/
int
check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
{
PKT_public_key *pk = xmalloc_clear( sizeof *pk );
unsigned int trustlevel = TRUST_UNKNOWN;
int rc=0;
rc = get_pubkey (ctrl, pk, sig->keyid );
if (rc)
{ /* this should not happen */
log_error("Ooops; the key vanished - can't check the trust\n");
rc = GPG_ERR_NO_PUBKEY;
goto leave;
}
if ( opt.trust_model==TM_ALWAYS )
{
if( !opt.quiet )
log_info(_("WARNING: Using untrusted key!\n"));
if (opt.with_fingerprint)
print_fingerprint (ctrl, NULL, pk, 1);
goto leave;
}
if(pk->flags.maybe_revoked && !pk->flags.revoked)
log_info(_("WARNING: this key might be revoked (revocation key"
" not present)\n"));
trustlevel = get_validity (ctrl, NULL, pk, NULL, sig, 1);
if ( (trustlevel & TRUST_FLAG_REVOKED) )
{
write_status( STATUS_KEYREVOKED );
if(pk->flags.revoked == 2)
log_info(_("WARNING: This key has been revoked by its"
" designated revoker!\n"));
else
log_info(_("WARNING: This key has been revoked by its owner!\n"));
log_info(_(" This could mean that the signature is forged.\n"));
show_revocation_reason (ctrl, pk, 0);
}
else if ((trustlevel & TRUST_FLAG_SUB_REVOKED) )
{
write_status( STATUS_KEYREVOKED );
log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
show_revocation_reason (ctrl, pk, 0);
}
if ((trustlevel & TRUST_FLAG_DISABLED))
log_info (_("Note: This key has been disabled.\n"));
/* If we have PKA information adjust the trustlevel. */
if (sig->pka_info && sig->pka_info->valid)
{
unsigned char fpr[MAX_FINGERPRINT_LEN];
PKT_public_key *primary_pk;
size_t fprlen;
int okay;
primary_pk = xmalloc_clear (sizeof *primary_pk);
get_pubkey (ctrl, primary_pk, pk->main_keyid);
fingerprint_from_pk (primary_pk, fpr, &fprlen);
free_public_key (primary_pk);
if ( fprlen == 20 && !memcmp (sig->pka_info->fpr, fpr, 20) )
{
okay = 1;
write_status_text (STATUS_PKA_TRUST_GOOD, sig->pka_info->email);
log_info (_("Note: Verified signer's address is '%s'\n"),
sig->pka_info->email);
}
else
{
okay = 0;
write_status_text (STATUS_PKA_TRUST_BAD, sig->pka_info->email);
log_info (_("Note: Signer's address '%s' "
"does not match DNS entry\n"), sig->pka_info->email);
}
switch ( (trustlevel & TRUST_MASK) )
{
case TRUST_UNKNOWN:
case TRUST_UNDEFINED:
case TRUST_MARGINAL:
if (okay && opt.verify_options&VERIFY_PKA_TRUST_INCREASE)
{
trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_FULLY);
log_info (_("trustlevel adjusted to FULL"
" due to valid PKA info\n"));
}
/* fall through */
case TRUST_FULLY:
if (!okay)
{
trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_NEVER);
log_info (_("trustlevel adjusted to NEVER"
" due to bad PKA info\n"));
}
break;
}
}
/* Now let the user know what up with the trustlevel. */
switch ( (trustlevel & TRUST_MASK) )
{
case TRUST_EXPIRED:
log_info(_("Note: This key has expired!\n"));
print_fingerprint (ctrl, NULL, pk, 1);
break;
default:
log_error ("invalid trustlevel %u returned from validation layer\n",
trustlevel);
/* fall through */
case TRUST_UNKNOWN:
case TRUST_UNDEFINED:
write_trust_status (STATUS_TRUST_UNDEFINED, trustlevel);
log_info(_("WARNING: This key is not certified with"
" a trusted signature!\n"));
log_info(_(" There is no indication that the "
"signature belongs to the owner.\n" ));
print_fingerprint (ctrl, NULL, pk, 1);
break;
case TRUST_NEVER:
/* This level can be returned by TOFU, which supports negative
* assertions. */
write_trust_status (STATUS_TRUST_NEVER, trustlevel);
log_info(_("WARNING: We do NOT trust this key!\n"));
log_info(_(" The signature is probably a FORGERY.\n"));
if (opt.with_fingerprint)
print_fingerprint (ctrl, NULL, pk, 1);
rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
break;
case TRUST_MARGINAL:
write_trust_status (STATUS_TRUST_MARGINAL, trustlevel);
log_info(_("WARNING: This key is not certified with"
" sufficiently trusted signatures!\n"));
log_info(_(" It is not certain that the"
" signature belongs to the owner.\n" ));
print_fingerprint (ctrl, NULL, pk, 1);
break;
case TRUST_FULLY:
write_trust_status (STATUS_TRUST_FULLY, trustlevel);
if (opt.with_fingerprint)
print_fingerprint (ctrl, NULL, pk, 1);
break;
case TRUST_ULTIMATE:
write_trust_status (STATUS_TRUST_ULTIMATE, trustlevel);
if (opt.with_fingerprint)
print_fingerprint (ctrl, NULL, pk, 1);
break;
}
leave:
free_public_key( pk );
return rc;
}
void
release_pk_list (pk_list_t pk_list)
{
PK_LIST pk_rover;
for ( ; pk_list; pk_list = pk_rover)
{
pk_rover = pk_list->next;
free_public_key ( pk_list->pk );
xfree ( pk_list );
}
}
static int
key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
{
for( ; pk_list; pk_list = pk_list->next)
if (cmp_public_keys(pk_list->pk, pk) == 0)
return 0;
return -1;
}
/*
* Return a malloced string with a default recipient if there is any
* Fixme: We don't distinguish between malloc failure and no-default-recipient.
*/
static char *
default_recipient (ctrl_t ctrl)
{
PKT_public_key *pk;
char *result;
if (opt.def_recipient)
return xtrystrdup (opt.def_recipient);
if (!opt.def_recipient_self)
return NULL;
pk = xtrycalloc (1, sizeof *pk );
if (!pk)
return NULL;
if (get_seckey_default (ctrl, pk))
{
free_public_key (pk);
return NULL;
}
result = hexfingerprint (pk, NULL, 0);
free_public_key (pk);
return result;
}
static int
expand_id(const char *id,strlist_t *into,unsigned int flags)
{
struct groupitem *groups;
int count=0;
for(groups=opt.grouplist;groups;groups=groups->next)
{
/* need strcasecmp() here, as this should be localized */
if(strcasecmp(groups->name,id)==0)
{
strlist_t each,sl;
/* this maintains the current utf8-ness */
for(each=groups->values;each;each=each->next)
{
sl=add_to_strlist(into,each->d);
sl->flags=flags;
count++;
}
break;
}
}
return count;
}
/* For simplicity, and to avoid potential loops, we only expand once -
* you can't make an alias that points to an alias. */
static strlist_t
expand_group (strlist_t input)
{
strlist_t output = NULL;
strlist_t sl, rover;
for (rover = input; rover; rover = rover->next)
if (!(rover->flags & PK_LIST_FROM_FILE)
&& !expand_id(rover->d,&output,rover->flags))
{
/* Didn't find any groups, so use the existing string */
sl=add_to_strlist(&output,rover->d);
sl->flags=rover->flags;
}
return output;
}
/* Helper for build_pk_list to find and check one key. This helper is
* also used directly in server mode by the RECIPIENTS command. On
* success the new key is added to PK_LIST_ADDR. NAME is the user id
* of the key. USE the requested usage and a set MARK_HIDDEN will
* mark the key in the updated list as a hidden recipient. If
* FROM_FILE is true, NAME is not a user ID but the name of a file
* holding a key. */
gpg_error_t
find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int mark_hidden, int from_file, pk_list_t *pk_list_addr)
{
int rc;
PKT_public_key *pk;
KBNODE keyblock = NULL;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
pk = xtrycalloc (1, sizeof *pk);
if (!pk)
return gpg_error_from_syserror ();
pk->req_usage = use;
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
else
rc = get_best_pubkey_byname (ctrl, NULL, pk, name, &keyblock, 0, 0);
if (rc)
{
int code;
/* Key not found or other error. */
log_error (_("%s: skipped: %s\n"), name, gpg_strerror (rc) );
switch (gpg_err_code (rc))
{
case GPG_ERR_NO_SECKEY:
case GPG_ERR_NO_PUBKEY: code = 1; break;
case GPG_ERR_INV_USER_ID: code = 14; break;
default: code = 0; break;
}
send_status_inv_recp (code, name);
free_public_key (pk);
return rc;
}
rc = openpgp_pk_test_algo2 (pk->pubkey_algo, use);
if (rc)
{
/* Key found but not usable for us (e.g. sign-only key). */
release_kbnode (keyblock);
send_status_inv_recp (3, name); /* Wrong key usage */
log_error (_("%s: skipped: %s\n"), name, gpg_strerror (rc) );
free_public_key (pk);
return rc;
}
/* Key found and usable. Check validity. */
if (!from_file)
{
int trustlevel;
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
release_kbnode (keyblock);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
{
/* We don't trust this key. */
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
}
/* Skip the actual key if the key is already present in the
list. */
if (!key_present_in_pk_list (*pk_list_addr, pk))
{
if (!opt.quiet)
log_info (_("%s: skipped: public key already present\n"), name);
free_public_key (pk);
}
else
{
pk_list_t r;
r = xtrymalloc (sizeof *r);
if (!r)
{
rc = gpg_error_from_syserror ();
free_public_key (pk);
return rc;
}
r->pk = pk;
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0;
*pk_list_addr = r;
}
return 0;
}
/* This is the central function to collect the keys for recipients.
* It is thus used to prepare a public key encryption. encrypt-to
* keys, default keys and the keys for the actual recipients are all
* collected here. When not in batch mode and no recipient has been
* passed on the commandline, the function will also ask for
* recipients.
*
* RCPTS is a string list with the recipients; NULL is an allowed
* value but not very useful. Group expansion is done on these names;
* they may be in any of the user Id formats we can handle. The flags
* bits for each string in the string list are used for:
*
* - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
* - PK_LIST_HIDDEN :: This is a hidden recipient.
* - PK_LIST_FROM_FILE :: The argument is a file with a key.
*
* On success a list of keys is stored at the address RET_PK_LIST; the
* caller must free this list. On error the value at this address is
* not changed.
*/
int
build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
{
PK_LIST pk_list = NULL;
PKT_public_key *pk=NULL;
int rc=0;
int any_recipients=0;
strlist_t rov,remusr;
char *def_rec = NULL;
char pkstrbuf[PUBKEY_STRING_SIZE];
/* Try to expand groups if any have been defined. */
if (opt.grouplist)
remusr = expand_group (rcpts);
else
remusr = rcpts;
/* XXX: Change this function to use get_pubkeys instead of
get_pubkey_byname to detect ambiguous key specifications and warn
about duplicate keyblocks. For ambiguous key specifications on
the command line or provided interactively, prompt the user to
select the best key. If a key specification is ambiguous and we
are in batch mode, die. */
if (opt.encrypt_to_default_key)
{
static int warned;
const char *default_key = parse_def_secret_key (ctrl);
if (default_key)
{
PK_LIST r = xmalloc_clear (sizeof *r);
r->pk = xmalloc_clear (sizeof *r->pk);
r->pk->req_usage = PUBKEY_USAGE_ENC;
rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key,
NULL, NULL, 0, 1);
if (rc)
{
xfree (r->pk);
xfree (r);
log_error (_("can't encrypt to '%s'\n"), default_key);
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"),
"--default-key");
}
else
{
r->next = pk_list;
r->flags = 0;
pk_list = r;
}
}
else if (opt.def_secret_key)
{
if (! warned)
log_info (_("option '%s' given, but no valid default keys given\n"),
"--encrypt-to-default-key");
warned = 1;
}
else
{
if (! warned)
log_info (_("option '%s' given, but option '%s' not given\n"),
"--encrypt-to-default-key", "--default-key");
warned = 1;
}
}
/* Check whether there are any recipients in the list and build the
* list of the encrypt-to ones (we always trust them). */
for ( rov = remusr; rov; rov = rov->next )
{
if ( !(rov->flags & PK_LIST_ENCRYPT_TO) )
{
/* This is a regular recipient; i.e. not an encrypt-to
one. */
any_recipients = 1;
/* Hidden recipients are not allowed while in PGP mode,
issue a warning and switch into GnuPG mode. */
- if ((rov->flags & PK_LIST_HIDDEN) && (PGP6 || PGP7 || PGP8))
+ if ((rov->flags & PK_LIST_HIDDEN) && (PGP7 || PGP8))
{
log_info(_("option '%s' may not be used in %s mode\n"),
"--hidden-recipient",
gnupg_compliance_option_string (opt.compliance));
compliance_failure();
}
}
else if (!opt.no_encrypt_to)
{
/* --encrypt-to has not been disabled. Check this
encrypt-to key. */
pk = xmalloc_clear( sizeof *pk );
pk->req_usage = PUBKEY_USAGE_ENC;
/* We explicitly allow encrypt-to to an disabled key; thus
we pass 1 for the second last argument and 1 as the last
argument to disable AKL. */
if ( (rc = get_pubkey_byname (ctrl,
NULL, pk, rov->d, NULL, NULL, 1, 1)) )
{
free_public_key ( pk ); pk = NULL;
log_error (_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
send_status_inv_recp (0, rov->d);
goto fail;
}
else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
PUBKEY_USAGE_ENC)) )
{
/* Skip the actual key if the key is already present
* in the list. Add it to our list if not. */
if (key_present_in_pk_list(pk_list, pk) == 0)
{
free_public_key (pk); pk = NULL;
if (!opt.quiet)
log_info (_("%s: skipped: public key already present\n"),
rov->d);
}
else
{
PK_LIST r;
r = xmalloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->flags = (rov->flags&PK_LIST_HIDDEN)?1:0;
pk_list = r;
/* Hidden encrypt-to recipients are not allowed while
in PGP mode, issue a warning and switch into
GnuPG mode. */
- if ((r->flags&PK_LIST_ENCRYPT_TO) && (PGP6 || PGP7 || PGP8))
+ if ((r->flags&PK_LIST_ENCRYPT_TO) && (PGP7 || PGP8))
{
log_info(_("option '%s' may not be used in %s mode\n"),
"--hidden-encrypt-to",
gnupg_compliance_option_string (opt.compliance));
compliance_failure();
}
}
}
else
{
/* The public key is not usable for encryption. */
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
send_status_inv_recp (3, rov->d); /* Wrong key usage */
goto fail;
}
}
}
/* If we don't have any recipients yet and we are not in batch mode
drop into interactive selection mode. */
if ( !any_recipients && !opt.batch )
{
int have_def_rec;
char *answer = NULL;
strlist_t backlog = NULL;
if (pk_list)
any_recipients = 1;
def_rec = default_recipient(ctrl);
have_def_rec = !!def_rec;
if ( !have_def_rec )
tty_printf(_("You did not specify a user ID. (you may use \"-r\")\n"));
for (;;)
{
rc = 0;
xfree(answer);
if ( have_def_rec )
{
/* A default recipient is taken as the first entry. */
answer = def_rec;
def_rec = NULL;
}
else if (backlog)
{
/* This is part of our trick to expand and display groups. */
answer = strlist_pop (&backlog);
}
else
{
/* Show the list of already collected recipients and ask
for more. */
PK_LIST iter;
tty_printf("\n");
tty_printf(_("Current recipients:\n"));
for (iter=pk_list;iter;iter=iter->next)
{
u32 keyid[2];
keyid_from_pk(iter->pk,keyid);
tty_printf ("%s/%s %s \"",
pubkey_string (iter->pk,
pkstrbuf, sizeof pkstrbuf),
keystr(keyid),
datestr_from_pk (iter->pk));
if (iter->pk->user_id)
tty_print_utf8_string(iter->pk->user_id->name,
iter->pk->user_id->len);
else
{
size_t n;
char *p = get_user_id (ctrl, keyid, &n, NULL);
tty_print_utf8_string ( p, n );
xfree(p);
}
tty_printf("\"\n");
}
answer = cpr_get_utf8("pklist.user_id.enter",
_("\nEnter the user ID. "
"End with an empty line: "));
trim_spaces(answer);
cpr_kill_prompt();
}
if ( !answer || !*answer )
{
xfree(answer);
break; /* No more recipients entered - get out of loop. */
}
/* Do group expand here too. The trick here is to continue
the loop if any expansion occurred. The code above will
then list all expanded keys. */
if (expand_id(answer,&backlog,0))
continue;
/* Get and check key for the current name. */
free_public_key (pk);
pk = xmalloc_clear( sizeof *pk );
pk->req_usage = PUBKEY_USAGE_ENC;
rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 );
if (rc)
tty_printf(_("No such user ID.\n"));
else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
PUBKEY_USAGE_ENC)) )
{
if ( have_def_rec )
{
/* No validation for a default recipient. */
if (!key_present_in_pk_list(pk_list, pk))
{
free_public_key (pk);
pk = NULL;
log_info (_("skipped: public key "
"already set as default recipient\n") );
}
else
{
PK_LIST r = xmalloc (sizeof *r);
r->pk = pk; pk = NULL;
r->next = pk_list;
r->flags = 0; /* No throwing default ids. */
pk_list = r;
}
any_recipients = 1;
continue;
}
else
{ /* Check validity of this key. */
int trustlevel;
trustlevel =
get_validity (ctrl, NULL, pk, pk->user_id, NULL, 1);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
tty_printf (_("Public key is disabled.\n") );
}
else if ( do_we_trust_pre (ctrl, pk, trustlevel) )
{
/* Skip the actual key if the key is already
* present in the list */
if (!key_present_in_pk_list(pk_list, pk))
{
free_public_key (pk);
pk = NULL;
log_info(_("skipped: public key already set\n") );
}
else
{
PK_LIST r;
r = xmalloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->flags = 0; /* No throwing interactive ids. */
pk_list = r;
}
any_recipients = 1;
continue;
}
}
}
xfree(def_rec); def_rec = NULL;
have_def_rec = 0;
}
if ( pk )
{
free_public_key( pk );
pk = NULL;
}
}
else if ( !any_recipients && (def_rec = default_recipient(ctrl)) )
{
/* We are in batch mode and have only a default recipient. */
pk = xmalloc_clear( sizeof *pk );
pk->req_usage = PUBKEY_USAGE_ENC;
/* The default recipient is allowed to be disabled; thus pass 1
as second last argument. We also don't want an AKL. */
rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1);
if (rc)
log_error(_("unknown default recipient \"%s\"\n"), def_rec );
else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo,
PUBKEY_USAGE_ENC)) )
{
/* Mark any_recipients here since the default recipient
would have been used if it wasn't already there. It
doesn't really matter if we got this key from the default
recipient or an encrypt-to. */
any_recipients = 1;
if (!key_present_in_pk_list(pk_list, pk))
log_info (_("skipped: public key already set "
"as default recipient\n"));
else
{
PK_LIST r = xmalloc( sizeof *r );
r->pk = pk; pk = NULL;
r->next = pk_list;
r->flags = 0; /* No throwing default ids. */
pk_list = r;
}
}
if ( pk )
{
free_public_key( pk );
pk = NULL;
}
xfree(def_rec); def_rec = NULL;
}
else
{
/* General case: Check all keys. */
any_recipients = 0;
for (; remusr; remusr = remusr->next )
{
if ( (remusr->flags & PK_LIST_ENCRYPT_TO) )
continue; /* encrypt-to keys are already handled. */
rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
!!(remusr->flags&PK_LIST_HIDDEN),
!!(remusr->flags&PK_LIST_FROM_FILE),
&pk_list);
if (rc)
goto fail;
any_recipients = 1;
}
}
if ( !rc && !any_recipients )
{
log_error(_("no valid addressees\n"));
write_status_text (STATUS_NO_RECP, "0");
rc = GPG_ERR_NO_USER_ID;
}
#ifdef USE_TOFU
if (! rc && (opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU))
{
PK_LIST iter;
for (iter = pk_list; iter; iter = iter->next)
{
int rc2;
/* Note: we already resolved any conflict when looking up
the key. Don't annoy the user again if she selected
accept once. */
rc2 = tofu_register_encryption (ctrl, iter->pk, NULL, 0);
if (rc2)
log_info ("WARNING: Failed to register encryption to %s"
" with TOFU engine\n",
keystr (pk_main_keyid (iter->pk)));
else if (DBG_TRUST)
log_debug ("Registered encryption to %s with TOFU DB.\n",
keystr (pk_main_keyid (iter->pk)));
}
}
#endif /*USE_TOFU*/
fail:
if ( rc )
release_pk_list( pk_list );
else
*ret_pk_list = pk_list;
if (opt.grouplist)
free_strlist(remusr);
return rc;
}
/* In pgp6 mode, disallow all ciphers except IDEA (1), 3DES (2), and
CAST5 (3), all hashes except MD5 (1), SHA1 (2), and RIPEMD160 (3),
and all compressions except none (0) and ZIP (1). pgp7 and pgp8
mode expands the cipher list to include AES128 (7), AES192 (8),
AES256 (9), and TWOFISH (10). pgp8 adds the SHA-256 hash (8). For
a true PGP key all of this is unneeded as they are the only items
present in the preferences subpacket, but checking here covers the
weird case of encrypting to a key that had preferences from a
different implementation which was then used with PGP. I am not
completely comfortable with this as the right thing to do, as it
slightly alters the list of what the user is supposedly requesting.
It is not against the RFC however, as the preference chosen will
never be one that the user didn't specify somewhere ("The
implementation may use any mechanism to pick an algorithm in the
intersection"), and PGP has no mechanism to fix such a broken
preference list, so I'm including it. -dms */
int
algo_available( preftype_t preftype, int algo, const union pref_hint *hint)
{
if( preftype == PREFTYPE_SYM )
{
- if(PGP6 && (algo != CIPHER_ALGO_IDEA
- && algo != CIPHER_ALGO_3DES
- && algo != CIPHER_ALGO_CAST5))
- return 0;
-
if(PGP7 && (algo != CIPHER_ALGO_IDEA
&& algo != CIPHER_ALGO_3DES
&& algo != CIPHER_ALGO_CAST5
&& algo != CIPHER_ALGO_AES
&& algo != CIPHER_ALGO_AES192
&& algo != CIPHER_ALGO_AES256
&& algo != CIPHER_ALGO_TWOFISH))
return 0;
/* PGP8 supports all the ciphers we do.. */
return algo && !openpgp_cipher_test_algo ( algo );
}
else if( preftype == PREFTYPE_HASH )
{
if (hint && hint->digest_length)
{
if (hint->digest_length!=20 || opt.flags.dsa2)
{
/* If --enable-dsa2 is set or the hash isn't 160 bits
(which implies DSA2), then we'll accept a hash that
is larger than we need. Otherwise we won't accept
any hash that isn't exactly the right size. */
if (hint->digest_length > gcry_md_get_algo_dlen (algo))
return 0;
}
else if (hint->digest_length != gcry_md_get_algo_dlen (algo))
return 0;
}
- if((PGP6 || PGP7) && (algo != DIGEST_ALGO_MD5
- && algo != DIGEST_ALGO_SHA1
- && algo != DIGEST_ALGO_RMD160))
+ if (PGP7 && (algo != DIGEST_ALGO_MD5
+ && algo != DIGEST_ALGO_SHA1
+ && algo != DIGEST_ALGO_RMD160))
return 0;
if(PGP8 && (algo != DIGEST_ALGO_MD5
&& algo != DIGEST_ALGO_SHA1
&& algo != DIGEST_ALGO_RMD160
&& algo != DIGEST_ALGO_SHA256))
return 0;
return algo && !openpgp_md_test_algo (algo);
}
else if( preftype == PREFTYPE_ZIP )
{
- if((PGP6 || PGP7) && (algo != COMPRESS_ALGO_NONE
- && algo != COMPRESS_ALGO_ZIP))
+ if (PGP7 && (algo != COMPRESS_ALGO_NONE
+ && algo != COMPRESS_ALGO_ZIP))
return 0;
/* PGP8 supports all the compression algos we do */
return !check_compress_algo( algo );
}
else
return 0;
}
/****************
* Return -1 if we could not find an algorithm.
*/
int
select_algo_from_prefs(PK_LIST pk_list, int preftype,
int request, const union pref_hint *hint)
{
PK_LIST pkr;
u32 bits[8];
const prefitem_t *prefs;
int result=-1,i;
u16 scores[256];
if( !pk_list )
return -1;
memset(bits,0xFF,sizeof(bits));
memset(scores,0,sizeof(scores));
for( pkr = pk_list; pkr; pkr = pkr->next )
{
u32 mask[8];
int rank=1,implicit=-1;
memset(mask,0,sizeof(mask));
switch(preftype)
{
case PREFTYPE_SYM:
/* IDEA is implicitly there for v3 keys with v3 selfsigs if
--pgp2 mode is on. This was a 2440 thing that was
dropped from 4880 but is still relevant to GPG's 1991
support. All this doesn't mean IDEA is actually
available, of course. */
implicit=CIPHER_ALGO_3DES;
break;
case PREFTYPE_AEAD:
/* No implicit algo. */
break;
case PREFTYPE_HASH:
/* While I am including this code for completeness, note
that currently --pgp2 mode locks the hash at MD5, so this
code will never even be called. Even if the hash wasn't
locked at MD5, we don't support sign+encrypt in --pgp2
mode, and that's the only time PREFTYPE_HASH is used
anyway. -dms */
implicit=DIGEST_ALGO_SHA1;
break;
case PREFTYPE_ZIP:
/* Uncompressed is always an option. */
implicit=COMPRESS_ALGO_NONE;
}
if (pkr->pk->user_id) /* selected by user ID */
prefs = pkr->pk->user_id->prefs;
else
prefs = pkr->pk->prefs;
if( prefs )
{
for (i=0; prefs[i].type; i++ )
{
if( prefs[i].type == preftype )
{
/* Make sure all scores don't add up past 0xFFFF
(and roll around) */
if(rank+scores[prefs[i].value]<=0xFFFF)
scores[prefs[i].value]+=rank;
else
scores[prefs[i].value]=0xFFFF;
mask[prefs[i].value/32] |= 1<<(prefs[i].value%32);
rank++;
/* We saw the implicit algorithm, so we don't need
tack it on the end ourselves. */
if(implicit==prefs[i].value)
implicit=-1;
}
}
}
if(rank==1 && preftype==PREFTYPE_ZIP)
{
/* If the compression preferences are not present, they are
assumed to be ZIP, Uncompressed (RFC4880:13.3.1) */
scores[1]=1; /* ZIP is first choice */
scores[0]=2; /* Uncompressed is second choice */
mask[0]|=3;
}
/* If the key didn't have the implicit algorithm listed
explicitly, add it here at the tail of the list. */
if(implicit>-1)
{
scores[implicit]+=rank;
mask[implicit/32] |= 1<<(implicit%32);
}
for(i=0;i<8;i++)
bits[i]&=mask[i];
}
/* We've now scored all of the algorithms, and the usable ones have
bits set. Let's pick the winner. */
/* The caller passed us a request. Can we use it? */
if(request>-1 && (bits[request/32] & (1<<(request%32))) &&
algo_available(preftype,request,hint))
result=request;
if(result==-1)
{
/* If we have personal prefs set, use them. */
prefs=NULL;
if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs)
prefs=opt.personal_cipher_prefs;
else if(preftype==PREFTYPE_AEAD && opt.personal_aead_prefs)
prefs=opt.personal_aead_prefs;
else if(preftype==PREFTYPE_HASH && opt.personal_digest_prefs)
prefs=opt.personal_digest_prefs;
else if(preftype==PREFTYPE_ZIP && opt.personal_compress_prefs)
prefs=opt.personal_compress_prefs;
if( prefs )
for(i=0; prefs[i].type; i++ )
{
if(bits[prefs[i].value/32] & (1<<(prefs[i].value%32))
&& algo_available( preftype, prefs[i].value, hint))
{
result = prefs[i].value;
break;
}
}
}
if(result==-1)
{
unsigned int best=-1;
/* At this point, we have not selected an algorithm due to a
special request or via personal prefs. Pick the highest
ranked algorithm (i.e. the one with the lowest score). */
if(preftype==PREFTYPE_HASH && scores[DIGEST_ALGO_MD5])
{
/* "If you are building an authentication system, the recipient
may specify a preferred signing algorithm. However, the
signer would be foolish to use a weak algorithm simply
because the recipient requests it." (RFC4880:14). If any
other hash algorithm is available, pretend that MD5 isn't.
Note that if the user intentionally chose MD5 by putting it
in their personal prefs, then we do what the user said (as we
never reach this code). */
for(i=DIGEST_ALGO_MD5+1;i<256;i++)
if(scores[i])
{
scores[DIGEST_ALGO_MD5]=0;
break;
}
}
for(i=0;i<256;i++)
{
/* Note the '<' here. This means in case of a tie, we will
favor the lower algorithm number. We have a choice
between the lower number (probably an older algorithm
with more time in use), or the higher number (probably a
newer algorithm with less time in use). Older is
probably safer here, even though the newer algorithms
tend to be "stronger". */
if(scores[i] && scores[i]next)
{
int mdc;
if (pkr->pk->user_id) /* selected by user ID */
mdc = pkr->pk->user_id->flags.mdc;
else
mdc = pkr->pk->flags.mdc;
if (!mdc)
return 0; /* At least one recipient does not support it. */
}
return 1; /* Can be used. */
}
/* Select the AEAD flag from the pk_list. We can only use AEAD if all
* recipients support this feature. Returns the AEAD to be used or 0
* if AEAD shall not be used. */
aead_algo_t
select_aead_from_pklist (PK_LIST pk_list)
{
pk_list_t pkr;
int aead;
if (!pk_list)
return 0;
for (pkr = pk_list; pkr; pkr = pkr->next)
{
if (pkr->pk->user_id) /* selected by user ID */
aead = pkr->pk->user_id->flags.aead;
else
aead = pkr->pk->flags.aead;
if (!aead)
return 0; /* At least one recipient does not support it. */
}
return default_aead_algo (); /* Yes, AEAD can be used. */
}
/* Print a warning for all keys in PK_LIST missing the AEAD feature
* flag or AEAD algorithms. */
void
warn_missing_aead_from_pklist (PK_LIST pk_list)
{
PK_LIST pkr;
for (pkr = pk_list; pkr; pkr = pkr->next)
{
int mdc;
if (pkr->pk->user_id) /* selected by user ID */
mdc = pkr->pk->user_id->flags.aead;
else
mdc = pkr->pk->flags.aead;
if (!mdc)
log_info (_("Note: key %s has no %s feature\n"),
keystr_from_pk (pkr->pk), "AEAD");
}
}
void
warn_missing_aes_from_pklist (PK_LIST pk_list)
{
PK_LIST pkr;
for (pkr = pk_list; pkr; pkr = pkr->next)
{
const prefitem_t *prefs;
int i;
int gotit = 0;
prefs = pkr->pk->user_id? pkr->pk->user_id->prefs : pkr->pk->prefs;
if (prefs)
{
for (i=0; !gotit && prefs[i].type; i++ )
if (prefs[i].type == PREFTYPE_SYM
&& prefs[i].value == CIPHER_ALGO_AES)
gotit++;
}
if (!gotit)
log_info (_("Note: key %s has no preference for %s\n"),
keystr_from_pk (pkr->pk), "AES");
}
}
diff --git a/g10/revoke.c b/g10/revoke.c
index 3a089725c..b778684b0 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -1,901 +1,901 @@
/* revoke.c - Create recovation certificates.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
* 2004 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 "gpg.h"
#include "options.h"
#include "packet.h"
#include "../common/status.h"
#include "keydb.h"
#include "../common/util.h"
#include "main.h"
#include "../common/ttyio.h"
#include "../common/i18n.h"
#include "call-agent.h"
struct revocation_reason_info {
int code;
char *desc;
};
int
revocation_reason_build_cb( PKT_signature *sig, void *opaque )
{
struct revocation_reason_info *reason = opaque;
char *ud = NULL;
byte *buffer;
size_t buflen = 1;
if(!reason)
return 0;
if( reason->desc ) {
ud = native_to_utf8( reason->desc );
buflen += strlen(ud);
}
buffer = xmalloc( buflen );
*buffer = reason->code;
if( ud ) {
memcpy(buffer+1, ud, strlen(ud) );
xfree( ud );
}
build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
xfree( buffer );
return 0;
}
/* Outputs a minimal pk (as defined by 2440) from a keyblock. A
minimal pk consists of the public key packet and a user ID. We try
and pick a user ID that has a uid signature, and include it if
possible. */
static int
export_minimal_pk(IOBUF out,KBNODE keyblock,
PKT_signature *revsig,PKT_signature *revkey)
{
KBNODE node;
PACKET pkt;
PKT_user_id *uid=NULL;
PKT_signature *selfsig=NULL;
u32 keyid[2];
int rc;
node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
if(!node)
{
log_error("key incomplete\n");
return GPG_ERR_GENERAL;
}
keyid_from_pk(node->pkt->pkt.public_key,keyid);
pkt=*node->pkt;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
return rc;
}
init_packet(&pkt);
pkt.pkttype=PKT_SIGNATURE;
/* the revocation itself, if any. 2440 likes this to come first. */
if(revsig)
{
pkt.pkt.signature=revsig;
rc=build_packet(out,&pkt);
if(rc)
{
log_error("build_packet failed: %s\n", gpg_strerror (rc) );
return rc;
}
}
/* If a revkey in a 1F sig is present, include it too */
if(revkey)
{
pkt.pkt.signature=revkey;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
return rc;
}
}
while(!selfsig)
{
KBNODE signode;
node=find_next_kbnode(node,PKT_USER_ID);
if(!node)
{
/* We're out of user IDs - none were self-signed. */
if(uid)
break;
else
{
log_error(_("key %s has no user IDs\n"),keystr(keyid));
return GPG_ERR_GENERAL;
}
}
if(node->pkt->pkt.user_id->attrib_data)
continue;
uid=node->pkt->pkt.user_id;
signode=node;
while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
{
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
IS_UID_SIG(signode->pkt->pkt.signature))
{
selfsig=signode->pkt->pkt.signature;
break;
}
}
}
pkt.pkttype=PKT_USER_ID;
pkt.pkt.user_id=uid;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
return rc;
}
if(selfsig)
{
pkt.pkttype=PKT_SIGNATURE;
pkt.pkt.signature=selfsig;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
return rc;
}
}
return 0;
}
/****************
* Generate a revocation certificate for UNAME via a designated revoker
*/
int
gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
{
int rc = 0;
armor_filter_context_t *afx;
PKT_public_key *pk = NULL;
PKT_public_key *pk2 = NULL;
PKT_signature *sig = NULL;
IOBUF out = NULL;
struct revocation_reason_info *reason = NULL;
KEYDB_HANDLE kdbhd;
KEYDB_SEARCH_DESC desc;
KBNODE keyblock=NULL,node;
u32 keyid[2];
int i,any=0;
SK_LIST sk_list=NULL;
if( opt.batch )
{
log_error(_("can't do this in batch mode\n"));
return GPG_ERR_GENERAL;
}
afx = new_armor_context ();
kdbhd = keydb_new ();
if (!kdbhd)
{
rc = gpg_error_from_syserror ();
goto leave;
}
rc = classify_user_id (uname, &desc, 1);
if (!rc)
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (rc) {
log_error (_("key \"%s\" not found: %s\n"),uname, gpg_strerror (rc));
goto leave;
}
rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
goto leave;
}
/* To parse the revkeys */
merge_keys_and_selfsig (ctrl, keyblock);
/* get the key from the keyblock */
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
if( !node )
BUG ();
pk=node->pkt->pkt.public_key;
keyid_from_pk(pk,keyid);
if(locusr)
{
rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
if(rc)
goto leave;
}
/* Are we a designated revoker for this key? */
if(!pk->revkey && pk->numrevkeys)
BUG();
for(i=0;inumrevkeys;i++)
{
SK_LIST list;
free_public_key (pk2);
pk2 = NULL;
if(sk_list)
{
for(list=sk_list;list;list=list->next)
{
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
fingerprint_from_pk (list->pk, fpr, &fprlen);
/* Don't get involved with keys that don't have 160
bit fingerprints */
if(fprlen!=20)
continue;
if(memcmp(fpr,pk->revkey[i].fpr,20)==0)
break;
}
if (list)
pk2 = copy_public_key (NULL, list->pk);
else
continue;
}
else
{
pk2 = xmalloc_clear (sizeof *pk2);
rc = get_pubkey_byfprint (ctrl, pk2, NULL,
pk->revkey[i].fpr, MAX_FINGERPRINT_LEN);
}
/* We have the revocation key. */
if(!rc)
{
PKT_signature *revkey = NULL;
any = 1;
print_pubkey_info (ctrl, NULL, pk);
tty_printf ("\n");
tty_printf (_("To be revoked by:\n"));
print_seckey_info (ctrl, pk2);
if(pk->revkey[i].class&0x40)
tty_printf(_("(This is a sensitive revocation key)\n"));
tty_printf("\n");
rc = agent_probe_secret_key (ctrl, pk2);
if (rc)
{
tty_printf (_("Secret key is not available.\n"));
continue;
}
if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
_("Create a designated revocation certificate for this key? (y/N) ")))
continue;
/* get the reason for the revocation (this is always v4) */
reason = ask_revocation_reason( 1, 0, 1 );
if( !reason )
continue;
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
if( (rc = open_outfile (-1, NULL, 0, 1, &out )) )
goto leave;
afx->what = 1;
afx->hdrlines = "Comment: A designated revocation certificate"
" should follow\n";
push_armor_filter (afx, out);
/* create it */
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0,
0, 0,
revocation_reason_build_cb, reason,
NULL);
if( rc ) {
log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
goto leave;
}
/* Spit out a minimal pk as well, since otherwise there is
no way to know which key to attach this revocation to.
Also include the direct key signature that contains
this revocation key. We're allowed to include
sensitive revocation keys along with a revocation, as
this may be the only time the recipient has seen it.
Note that this means that if we have multiple different
sensitive revocation keys in a given direct key
signature, we're going to include them all here. This
is annoying, but the good outweighs the bad, since
without including this a sensitive revoker can't really
do their job. People should not include multiple
sensitive revocation keys in one signature: 2440 says
"Note that it may be appropriate to isolate this
subpacket within a separate signature so that it is not
combined with other subpackets that need to be
exported." -dms */
while(!revkey)
{
KBNODE signode;
signode=find_next_kbnode(node,PKT_SIGNATURE);
if(!signode)
break;
node=signode;
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
IS_KEY_SIG(signode->pkt->pkt.signature))
{
int j;
for(j=0;jpkt->pkt.signature->numrevkeys;j++)
{
if(pk->revkey[i].class==
signode->pkt->pkt.signature->revkey[j].class &&
pk->revkey[i].algid==
signode->pkt->pkt.signature->revkey[j].algid &&
memcmp(pk->revkey[i].fpr,
signode->pkt->pkt.signature->revkey[j].fpr,
MAX_FINGERPRINT_LEN)==0)
{
revkey=signode->pkt->pkt.signature;
break;
}
}
}
}
if(!revkey)
BUG();
rc=export_minimal_pk(out,keyblock,sig,revkey);
if(rc)
goto leave;
/* and issue a usage notice */
tty_printf(_("Revocation certificate created.\n"));
break;
}
}
if(!any)
log_error(_("no revocation keys found for \"%s\"\n"),uname);
leave:
free_public_key (pk);
free_public_key (pk2);
if( sig )
free_seckey_enc( sig );
release_sk_list(sk_list);
if( rc )
iobuf_cancel(out);
else
iobuf_close(out);
release_revocation_reason_info( reason );
release_armor_context (afx);
return rc;
}
/* Common core to create the revocation. FILENAME may be NULL to write
to stdout or the filename given by --output. REASON describes the
revocation reason. PSK is the public primary key - we expect that
a corresponding secret key is available. KEYBLOCK is the entire
KEYBLOCK which is used in PGP mode to write a minimal key and not
just the naked revocation signature; it may be NULL. If LEADINTEXT
is not NULL, it is written right before the (armored) output.*/
static int
create_revocation (ctrl_t ctrl,
const char *filename,
struct revocation_reason_info *reason,
PKT_public_key *psk,
kbnode_t keyblock,
const char *leadintext, int suffix,
const char *cache_nonce)
{
int rc;
iobuf_t out = NULL;
armor_filter_context_t *afx;
PKT_signature *sig = NULL;
PACKET pkt;
afx = new_armor_context ();
if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
goto leave;
if (leadintext )
iobuf_writestr (out, leadintext);
afx->what = 1;
afx->hdrlines = "Comment: This is a revocation certificate\n";
push_armor_filter (afx, out);
rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0,
0, 0,
revocation_reason_build_cb, reason, cache_nonce);
if (rc)
{
log_error (_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
goto leave;
}
- if (keyblock && (PGP6 || PGP7 || PGP8))
+ if (keyblock && (PGP7 || PGP8))
{
/* Use a minimal pk for PGPx mode, since PGP can't import bare
revocation certificates. */
rc = export_minimal_pk (out, keyblock, sig, NULL);
if (rc)
goto leave;
}
else
{
init_packet (&pkt);
pkt.pkttype = PKT_SIGNATURE;
pkt.pkt.signature = sig;
rc = build_packet (out, &pkt);
if (rc)
{
log_error (_("build_packet failed: %s\n"), gpg_strerror (rc));
goto leave;
}
}
leave:
if (sig)
free_seckey_enc (sig);
if (rc)
iobuf_cancel (out);
else
iobuf_close (out);
release_armor_context (afx);
return rc;
}
/* This function is used to generate a standard revocation certificate
by gpg's interactive key generation function. The certificate is
stored at a dedicated place in a slightly modified form to avoid an
accidental import. PSK is the primary key; a corresponding secret
key must be available. CACHE_NONCE is optional but can be used to
help gpg-agent to avoid an extra passphrase prompt. */
int
gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce)
{
int rc;
estream_t memfp;
struct revocation_reason_info reason;
char *dir, *tmpstr, *fname;
void *leadin;
size_t len;
u32 keyid[2];
int kl;
char *orig_codeset;
char *old_outfile;
dir = get_openpgp_revocdir (gnupg_homedir ());
tmpstr = hexfingerprint (psk, NULL, 0);
if (!tmpstr)
{
rc = gpg_error_from_syserror ();
xfree (dir);
return rc;
}
fname = strconcat (dir, DIRSEP_S, tmpstr, NULL);
if (!fname)
{
rc = gpg_error_from_syserror ();
xfree (tmpstr);
xfree (dir);
return rc;
}
xfree (tmpstr);
xfree (dir);
keyid_from_pk (psk, keyid);
memfp = es_fopenmem (0, "r+");
if (!memfp)
log_fatal ("error creating memory stream\n");
orig_codeset = i18n_switchto_utf8 ();
es_fprintf (memfp, "%s\n\n",
_("This is a revocation certificate for the OpenPGP key:"));
print_key_line (ctrl, memfp, psk, 0);
if (opt.keyid_format != KF_NONE)
print_fingerprint (ctrl, memfp, psk, 3);
kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
tmpstr = get_user_id (ctrl, keyid, &len, NULL);
es_fprintf (memfp, "uid%*s%.*s\n\n",
kl + 10, "",
(int)len, tmpstr);
xfree (tmpstr);
es_fprintf (memfp, "%s\n\n%s\n\n%s\n\n:",
_("A revocation certificate is a kind of \"kill switch\" to publicly\n"
"declare that a key shall not anymore be used. It is not possible\n"
"to retract such a revocation certificate once it has been published."),
_("Use it to revoke this key in case of a compromise or loss of\n"
"the secret key. However, if the secret key is still accessible,\n"
"it is better to generate a new revocation certificate and give\n"
"a reason for the revocation. For details see the description of\n"
"of the gpg command \"--generate-revocation\" in the "
"GnuPG manual."),
_("To avoid an accidental use of this file, a colon has been inserted\n"
"before the 5 dashes below. Remove this colon with a text editor\n"
"before importing and publishing this revocation certificate."));
es_putc (0, memfp);
i18n_switchback (orig_codeset);
if (es_fclose_snatch (memfp, &leadin, NULL))
log_fatal ("error snatching memory stream\n");
reason.code = 0x00; /* No particular reason. */
reason.desc = NULL;
old_outfile = opt.outfile;
opt.outfile = NULL;
rc = create_revocation (ctrl,
fname, &reason, psk, NULL, leadin, 3, cache_nonce);
opt.outfile = old_outfile;
if (!rc && !opt.quiet)
log_info (_("revocation certificate stored as '%s.rev'\n"), fname);
xfree (leadin);
xfree (fname);
return rc;
}
/****************
* Generate a revocation certificate for UNAME
*/
int
gen_revoke (ctrl_t ctrl, const char *uname)
{
int rc = 0;
PKT_public_key *psk;
u32 keyid[2];
kbnode_t keyblock = NULL;
kbnode_t node;
KEYDB_HANDLE kdbhd;
struct revocation_reason_info *reason = NULL;
KEYDB_SEARCH_DESC desc;
if( opt.batch )
{
log_error(_("can't do this in batch mode\n"));
return GPG_ERR_GENERAL;
}
/* Search the userid; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
if (!kdbhd)
{
rc = gpg_error_from_syserror ();
goto leave;
}
rc = classify_user_id (uname, &desc, 1);
if (!rc)
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (rc)
{
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
log_error (_("secret key \"%s\" not found\n"), uname);
else
log_error (_("secret key \"%s\" not found: %s\n"),
uname, gpg_strerror (rc));
goto leave;
}
rc = keydb_get_keyblock (kdbhd, &keyblock );
if (rc)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
goto leave;
}
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
/* Not ambiguous. */
{
}
else if (rc == 0)
/* Ambiguous. */
{
char *info;
/* TRANSLATORS: The %s prints a key specification which
for example has been given at the command line. Several lines
lines with secret key infos are printed after this message. */
log_error (_("'%s' matches multiple secret keys:\n"), uname);
info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
log_error (" %s\n", info);
xfree (info);
release_kbnode (keyblock);
rc = keydb_get_keyblock (kdbhd, &keyblock);
while (! rc)
{
info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
log_info (" %s\n", info);
xfree (info);
release_kbnode (keyblock);
keyblock = NULL;
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (! rc)
rc = keydb_get_keyblock (kdbhd, &keyblock);
}
rc = GPG_ERR_AMBIGUOUS_NAME;
goto leave;
}
else
{
log_error (_("error searching the keyring: %s\n"), gpg_strerror (rc));
goto leave;
}
/* Get the keyid from the keyblock. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node)
BUG ();
psk = node->pkt->pkt.public_key;
rc = agent_probe_secret_key (NULL, psk);
if (rc)
{
log_error (_("secret key \"%s\" not found: %s\n"),
uname, gpg_strerror (rc));
goto leave;
}
keyid_from_pk (psk, keyid );
print_seckey_info (ctrl, psk);
tty_printf("\n");
if (!cpr_get_answer_is_yes ("gen_revoke.okay",
_("Create a revocation certificate for this key? (y/N) ")))
{
rc = 0;
goto leave;
}
/* Get the reason for the revocation. */
reason = ask_revocation_reason (1, 0, 1);
if (!reason)
{
/* User decided to cancel. */
rc = 0;
goto leave;
}
if (!opt.armor)
tty_printf (_("ASCII armored output forced.\n"));
rc = create_revocation (ctrl, NULL, reason, psk, keyblock, NULL, 0, NULL);
if (rc)
goto leave;
/* and issue a usage notice */
tty_printf (_(
"Revocation certificate created.\n\n"
"Please move it to a medium which you can hide away; if Mallory gets\n"
"access to this certificate he can use it to make your key unusable.\n"
"It is smart to print this certificate and store it away, just in case\n"
"your media become unreadable. But have some caution: The print system of\n"
"your machine might store the data and make it available to others!\n"));
leave:
release_kbnode (keyblock);
keydb_release (kdbhd);
release_revocation_reason_info( reason );
return rc;
}
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint )
{
int code=-1;
char *description = NULL;
struct revocation_reason_info *reason;
const char *text_0 = _("No reason specified");
const char *text_1 = _("Key has been compromised");
const char *text_2 = _("Key is superseded");
const char *text_3 = _("Key is no longer used");
const char *text_4 = _("User ID is no longer valid");
const char *code_text = NULL;
do {
code=-1;
xfree(description);
description = NULL;
tty_printf(_("Please select the reason for the revocation:\n"));
tty_printf( " 0 = %s\n", text_0 );
if( key_rev )
tty_printf(" 1 = %s\n", text_1 );
if( key_rev )
tty_printf(" 2 = %s\n", text_2 );
if( key_rev )
tty_printf(" 3 = %s\n", text_3 );
if( cert_rev )
tty_printf(" 4 = %s\n", text_4 );
tty_printf( " Q = %s\n", _("Cancel") );
if( hint )
tty_printf(_("(Probably you want to select %d here)\n"), hint );
while(code==-1) {
int n;
char *answer = cpr_get("ask_revocation_reason.code",
_("Your decision? "));
trim_spaces( answer );
cpr_kill_prompt();
if( *answer == 'q' || *answer == 'Q')
return NULL; /* cancel */
if( hint && !*answer )
n = hint;
else if(!digitp( answer ) )
n = -1;
else
n = atoi(answer);
xfree(answer);
if( n == 0 ) {
code = 0x00; /* no particular reason */
code_text = text_0;
}
else if( key_rev && n == 1 ) {
code = 0x02; /* key has been compromised */
code_text = text_1;
}
else if( key_rev && n == 2 ) {
code = 0x01; /* key is superseded */
code_text = text_2;
}
else if( key_rev && n == 3 ) {
code = 0x03; /* key is no longer used */
code_text = text_3;
}
else if( cert_rev && n == 4 ) {
code = 0x20; /* uid is no longer valid */
code_text = text_4;
}
else
tty_printf(_("Invalid selection.\n"));
}
tty_printf(_("Enter an optional description; "
"end it with an empty line:\n") );
for(;;) {
char *answer = cpr_get("ask_revocation_reason.text", "> " );
trim_trailing_ws( answer, strlen(answer) );
cpr_kill_prompt();
if( !*answer ) {
xfree(answer);
break;
}
{
char *p = make_printable_string( answer, strlen(answer), 0 );
xfree(answer);
answer = p;
}
if( !description )
description = xstrdup(answer);
else {
char *p = xmalloc( strlen(description) + strlen(answer) + 2 );
strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
xfree(description);
description = p;
}
xfree(answer);
}
tty_printf(_("Reason for revocation: %s\n"), code_text );
if( !description )
tty_printf(_("(No description given)\n") );
else
tty_printf("%s\n", description );
} while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
_("Is this okay? (y/N) ")) );
reason = xmalloc( sizeof *reason );
reason->code = code;
reason->desc = description;
return reason;
}
struct revocation_reason_info *
get_default_uid_revocation_reason(void)
{
struct revocation_reason_info *reason;
reason = xmalloc( sizeof *reason );
reason->code = 0x20; /* uid is no longer valid */
reason->desc = strdup(""); /* no text */
return reason;
}
void
release_revocation_reason_info( struct revocation_reason_info *reason )
{
if( reason ) {
xfree( reason->desc );
xfree( reason );
}
}