aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/call-agent.h15
-rw-r--r--g10/card-util.c370
-rw-r--r--g10/cpr.c6
-rw-r--r--g10/getkey.c2
-rw-r--r--g10/gpg.c56
-rw-r--r--g10/keydb.h5
-rw-r--r--g10/keyedit.c8
-rw-r--r--g10/keygen.c53
-rw-r--r--g10/main.h1
-rw-r--r--g10/sig-check.c690
10 files changed, 684 insertions, 522 deletions
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 8de0d13fd..7314ae87b 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -19,6 +19,13 @@
#ifndef GNUPG_G10_CALL_AGENT_H
#define GNUPG_G10_CALL_AGENT_H
+struct key_attr {
+ int algo; /* Algorithm identifier. */
+ union {
+ unsigned int nbits; /* Supported keysize. */
+ const char *curve; /* Name of curve. */
+ };
+};
struct agent_card_info_s
{
@@ -57,13 +64,7 @@ struct agent_card_info_s
int is_v2; /* True if this is a v2 card. */
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
int chvretry[3]; /* Allowed retries for the CHV; 0 = blocked. */
- struct { /* Array with key attributes. */
- int algo; /* Algorithm identifier. */
- union {
- unsigned int nbits; /* Supported keysize. */
- const char *curve; /* Name of curve. */
- };
- } key_attr[3];
+ struct key_attr key_attr[3];
struct {
unsigned int ki:1; /* Key import available. */
unsigned int aac:1; /* Algorithm attributes are changeable. */
diff --git a/g10/card-util.c b/g10/card-util.c
index 9b99751ee..ffb94dae4 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -216,6 +216,7 @@ get_manufacturer (unsigned int no)
case 0x1337: return "Warsaw Hackerspace";
case 0x2342: return "warpzone"; /* hackerspace Muenster. */
+ case 0x63AF: return "Trustica";
case 0xBD0E: return "Paranoidlabs";
case 0xF517: return "FSIJ";
@@ -1356,11 +1357,10 @@ show_keysize_warning (void)
/* Ask for the size of a card key. NBITS is the current size
- configured for the card. KEYNO is the number of the key used to
- select the prompt. Returns 0 to use the default size (i.e. NBITS)
- or the selected size. */
+ configured for the card. Returns 0 to use the default size
+ (i.e. NBITS) or the selected size. */
static unsigned int
-ask_card_keyattr (int keyno, unsigned int nbits)
+ask_card_rsa_keysize (unsigned int nbits)
{
unsigned int min_nbits = 1024;
unsigned int max_nbits = 4096;
@@ -1369,93 +1369,236 @@ ask_card_keyattr (int keyno, unsigned int nbits)
for (;;)
{
- prompt = xasprintf
- (keyno == 0?
- _("What keysize do you want for the Signature key? (%u) "):
- keyno == 1?
- _("What keysize do you want for the Encryption key? (%u) "):
- _("What keysize do you want for the Authentication key? (%u) "),
- nbits);
+ prompt = xasprintf (_("What keysize do you want? (%u) "), nbits);
answer = cpr_get ("cardedit.genkeys.size", prompt);
cpr_kill_prompt ();
req_nbits = *answer? atoi (answer): nbits;
xfree (prompt);
xfree (answer);
- if (req_nbits == 25519)
+ if (req_nbits != nbits && (req_nbits % 32) )
{
- if (req_nbits == nbits)
- return 0; /* Use default. */
-
- tty_printf (_("The card will now be re-configured"
- " to generate a key of type: %s\n"),
- keyno==1? "cv25519":"ed25519");
- show_keysize_warning ();
- return req_nbits;
+ req_nbits = ((req_nbits + 31) / 32) * 32;
+ tty_printf (_("rounded up to %u bits\n"), req_nbits);
}
- else
+
+ if (req_nbits == nbits)
+ return 0; /* Use default. */
+
+ if (req_nbits < min_nbits || req_nbits > max_nbits)
{
- if (req_nbits != nbits && (req_nbits % 32) )
- {
- req_nbits = ((req_nbits + 31) / 32) * 32;
- tty_printf (_("rounded up to %u bits\n"), req_nbits);
- }
+ tty_printf (_("%s keysizes must be in the range %u-%u\n"),
+ "RSA", min_nbits, max_nbits);
+ }
+ else
+ return req_nbits;
+ }
+}
- if (req_nbits == nbits)
- return 0; /* Use default. */
+/* Ask for the key attribute of a card key. CURRENT is the current
+ attribute configured for the card. KEYNO is the number of the key
+ used to select the prompt. Returns NULL to use the default
+ attribute or the selected attribute structure. */
+static struct key_attr *
+ask_card_keyattr (int keyno, const struct key_attr *current)
+{
+ struct key_attr *key_attr = NULL;
+ char *answer = NULL;
+ int algo;
+
+ tty_printf (_("Changing card key attribute for: "));
+ if (keyno == 0)
+ tty_printf (_("Signature key\n"));
+ else if (keyno == 1)
+ tty_printf (_("Encryption key\n"));
+ else
+ tty_printf (_("Authentication key\n"));
- if (req_nbits < min_nbits || req_nbits > max_nbits)
+ tty_printf (_("Please select what kind of key you want:\n"));
+ tty_printf (_(" (%d) RSA\n"), 1 );
+ tty_printf (_(" (%d) ECC\n"), 2 );
+
+ for (;;)
+ {
+ xfree (answer);
+ answer = cpr_get ("cardedit.genkeys.algo", _("Your selection? "));
+ cpr_kill_prompt ();
+ algo = *answer? atoi (answer) : 0;
+
+ if (!*answer || algo == 1 || algo == 2)
+ break;
+ else
+ tty_printf (_("Invalid selection.\n"));
+ }
+
+ if (algo == 0)
+ goto leave;
+
+ key_attr = xmalloc (sizeof (struct key_attr));
+
+ if (algo == 1)
+ {
+ unsigned int nbits, result_nbits;
+
+ if (current->algo == PUBKEY_ALGO_RSA)
+ nbits = current->nbits;
+ else
+ nbits = 2048;
+
+ result_nbits = ask_card_rsa_keysize (nbits);
+ if (result_nbits == 0)
+ {
+ if (current->algo == PUBKEY_ALGO_RSA)
{
- tty_printf (_("%s keysizes must be in the range %u-%u\n"),
- "RSA", min_nbits, max_nbits);
+ xfree (key_attr);
+ key_attr = NULL;
}
else
- {
- char name[30];
-
- snprintf (name, sizeof name, "rsa%u", req_nbits);
- tty_printf (_("The card will now be re-configured"
- " to generate a key of type: %s\n"),
- name);
- show_keysize_warning ();
- return req_nbits;
- }
+ result_nbits = nbits;
+ }
+
+ if (key_attr)
+ {
+ key_attr->algo = PUBKEY_ALGO_RSA;
+ key_attr->nbits = result_nbits;
+ }
+ }
+ else
+ {
+ const char *curve;
+ const char *oid_str;
+
+ if (current->algo == PUBKEY_ALGO_RSA)
+ {
+ if (keyno == 1)
+ /* Encryption key */
+ algo = PUBKEY_ALGO_ECDH;
+ else /* Signature key or Authentication key */
+ algo = PUBKEY_ALGO_ECDSA;
+ curve = NULL;
+ }
+ else
+ {
+ algo = current->algo;
+ curve = current->curve;
+ }
+
+ curve = ask_curve (&algo, NULL, curve);
+ if (curve)
+ {
+ key_attr->algo = algo;
+ oid_str = openpgp_curve_to_oid (curve, NULL);
+ key_attr->curve = openpgp_oid_to_curve (oid_str, 0);
+ }
+ else
+ {
+ xfree (key_attr);
+ key_attr = NULL;
}
}
+
+ leave:
+ if (key_attr)
+ {
+ if (key_attr->algo == PUBKEY_ALGO_RSA)
+ tty_printf (_("The card will now be re-configured"
+ " to generate a key of %u bits\n"), key_attr->nbits);
+ else if (key_attr->algo == PUBKEY_ALGO_ECDH
+ || key_attr->algo == PUBKEY_ALGO_ECDSA
+ || key_attr->algo == PUBKEY_ALGO_EDDSA)
+ tty_printf (_("The card will now be re-configured"
+ " to generate a key of type: %s\n"), key_attr->curve),
+
+ show_keysize_warning ();
+ }
+
+ return key_attr;
}
-/* Change the size of key KEYNO (0..2) to NBITS and show an error
- * message if that fails. Using the magic value 25519 for NBITS
- * switches to ed25519 or cv25519 depending on the KEYNO. */
+
+/* Change the key attribute of key KEYNO (0..2) and show an error
+ * message if that fails. */
static gpg_error_t
-do_change_keyattr (int keyno, unsigned int nbits)
+do_change_keyattr (int keyno, const struct key_attr *key_attr)
{
- gpg_error_t err;
+ gpg_error_t err = 0;
char args[100];
- if (nbits == 25519)
+ if (key_attr->algo == PUBKEY_ALGO_RSA)
+ snprintf (args, sizeof args, "--force %d 1 rsa%u", keyno+1,
+ key_attr->nbits);
+ else if (key_attr->algo == PUBKEY_ALGO_ECDH
+ || key_attr->algo == PUBKEY_ALGO_ECDSA
+ || key_attr->algo == PUBKEY_ALGO_EDDSA)
snprintf (args, sizeof args, "--force %d %d %s",
- keyno+1,
- keyno == 1? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_EDDSA,
- keyno == 1? "cv25519" : "ed25519");
+ keyno+1, key_attr->algo, key_attr->curve);
else
- snprintf (args, sizeof args, "--force %d 1 rsa%u", keyno+1, nbits);
+ {
+ log_error (_("public key algorithm %d (%s) is not supported\n"),
+ key_attr->algo, gcry_pk_algo_name (key_attr->algo));
+ return gpg_error (GPG_ERR_PUBKEY_ALGO);
+ }
+
err = agent_scd_setattr ("KEY-ATTR", args, strlen (args), NULL);
if (err)
- log_error (_("error changing size of key %d to %u bits: %s\n"),
- keyno+1, nbits, gpg_strerror (err));
+ log_error (_("error changing key attribute for key %d: %s\n"),
+ keyno+1, gpg_strerror (err));
return err;
}
static void
+key_attr (void)
+{
+ struct agent_card_info_s info;
+ gpg_error_t err;
+ int keyno;
+
+ err = get_info_for_key_operation (&info);
+ if (err)
+ {
+ log_error (_("error getting card info: %s\n"), gpg_strerror (err));
+ return;
+ }
+
+ if (!(info.is_v2 && info.extcap.aac))
+ {
+ log_error (_("This command is not supported by this card\n"));
+ goto leave;
+ }
+
+ for (keyno = 0; keyno < DIM (info.key_attr); keyno++)
+ {
+ struct key_attr *key_attr;
+
+ if ((key_attr = ask_card_keyattr (keyno, &info.key_attr[keyno])))
+ {
+ err = do_change_keyattr (keyno, key_attr);
+ xfree (key_attr);
+ if (err)
+ {
+ /* Error: Better read the default key attribute again. */
+ agent_release_card_info (&info);
+ if (get_info_for_key_operation (&info))
+ goto leave;
+ /* Ask again for this key. */
+ keyno--;
+ }
+ }
+ }
+
+ leave:
+ agent_release_card_info (&info);
+}
+
+
+static void
generate_card_keys (ctrl_t ctrl)
{
struct agent_card_info_s info;
int forced_chv1;
int want_backup;
- int keyno;
if (get_info_for_key_operation (&info))
return;
@@ -1503,41 +1646,10 @@ generate_card_keys (ctrl_t ctrl)
tty_printf ("\n");
}
+
if (check_pin_for_key_operation (&info, &forced_chv1))
goto leave;
- /* If the cards features changeable key attributes, we ask for the
- key size. */
- if (info.is_v2 && info.extcap.aac)
- {
- unsigned int nbits;
-
- for (keyno = 0; keyno < DIM (info.key_attr); keyno++)
- {
- if (info.key_attr[keyno].algo == PUBKEY_ALGO_RSA
- || info.key_attr[keyno].algo == PUBKEY_ALGO_ECDH
- || info.key_attr[keyno].algo == PUBKEY_ALGO_EDDSA)
- {
- if (info.key_attr[keyno].algo == PUBKEY_ALGO_RSA)
- nbits = ask_card_keyattr (keyno, info.key_attr[keyno].nbits);
- else
- nbits = ask_card_keyattr (keyno, 25519 /* magic */);
-
- if (nbits && do_change_keyattr (keyno, nbits))
- {
- /* Error: Better read the default key size again. */
- agent_release_card_info (&info);
- if (get_info_for_key_operation (&info))
- goto leave;
- /* Ask again for this key size. */
- keyno--;
- }
- }
- }
- /* Note that INFO has not be synced. However we will only use
- the serialnumber and thus it won't harm. */
- }
-
generate_keypair (ctrl, 1, NULL, info.serialno, want_backup);
leave:
@@ -1596,36 +1708,6 @@ card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock)
if (err)
goto leave;
- /* If the cards features changeable key attributes, we ask for the
- key size. */
- if (info.is_v2 && info.extcap.aac)
- {
- if (info.key_attr[keyno-1].algo == PUBKEY_ALGO_RSA
- || info.key_attr[keyno].algo == PUBKEY_ALGO_ECDH
- || info.key_attr[keyno].algo == PUBKEY_ALGO_EDDSA)
- {
- unsigned int nbits;
-
- ask_again:
- if (info.key_attr[keyno].algo == PUBKEY_ALGO_RSA)
- nbits = ask_card_keyattr (keyno-1, info.key_attr[keyno-1].nbits);
- else
- nbits = ask_card_keyattr (keyno-1, 25519);
-
- if (nbits && do_change_keyattr (keyno-1, nbits))
- {
- /* Error: Better read the default key size again. */
- agent_release_card_info (&info);
- err = get_info_for_key_operation (&info);
- if (err)
- goto leave;
- goto ask_again;
- }
- }
- /* Note that INFO has not be synced. However we will only use
- the serialnumber and thus it won't harm. */
- }
-
err = generate_card_subkeypair (ctrl, pub_keyblock, keyno, info.serialno);
leave:
@@ -1904,11 +1986,12 @@ factory_reset (void)
#define USER_PIN_DEFAULT "123456"
#define ADMIN_PIN_DEFAULT "12345678"
-#define KDF_DATA_LENGTH 110
+#define KDF_DATA_LENGTH_MIN 90
+#define KDF_DATA_LENGTH_MAX 110
/* Generate KDF data. */
static gpg_error_t
-gen_kdf_data (unsigned char *data)
+gen_kdf_data (unsigned char *data, int single_salt)
{
const unsigned char h0[] = { 0x81, 0x01, 0x03,
0x82, 0x01, 0x08,
@@ -1941,14 +2024,21 @@ gen_kdf_data (unsigned char *data)
salt_user = (p += sizeof h1);
gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
p += 8;
- memcpy (p, h2, sizeof h2);
- p += sizeof h2;
- gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
- p += 8;
- memcpy (p, h3, sizeof h3);
- salt_admin = (p += sizeof h3);
- gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
- p += 8;
+
+ if (single_salt)
+ salt_admin = salt_user;
+ else
+ {
+ memcpy (p, h2, sizeof h2);
+ p += sizeof h2;
+ gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+ p += 8;
+ memcpy (p, h3, sizeof h3);
+ salt_admin = (p += sizeof h3);
+ gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+ p += 8;
+ }
+
memcpy (p, h4, sizeof h4);
p += sizeof h4;
err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
@@ -1969,11 +2059,12 @@ gen_kdf_data (unsigned char *data)
/* Setup KDF data object which is used for PIN authentication. */
static void
-kdf_setup (void)
+kdf_setup (const char *args)
{
struct agent_card_info_s info;
gpg_error_t err;
- unsigned char kdf_data[KDF_DATA_LENGTH];
+ unsigned char kdf_data[KDF_DATA_LENGTH_MAX];
+ int single = (*args != 0);
memset (&info, 0, sizeof info);
@@ -1990,10 +2081,19 @@ kdf_setup (void)
goto leave;
}
- if (!(err = gen_kdf_data (kdf_data))
- && !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL)))
- err = agent_scd_getattr ("KDF", &info);
+ err = gen_kdf_data (kdf_data, single);
+ if (err)
+ goto leave_error;
+
+ err = agent_scd_setattr ("KDF", kdf_data,
+ single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX,
+ NULL);
+ if (err)
+ goto leave_error;
+
+ err = agent_scd_getattr ("KDF", &info);
+ leave_error:
if (err)
log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
@@ -2010,6 +2110,7 @@ enum cmdids
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
+ cmdKEYATTR,
cmdINVCMD
};
@@ -2044,6 +2145,7 @@ static struct
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
{ "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
+ { "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL },
@@ -2328,7 +2430,11 @@ card_edit (ctrl_t ctrl, strlist_t commands)
break;
case cmdKDFSETUP:
- kdf_setup ();
+ kdf_setup (arg_string);
+ break;
+
+ case cmdKEYATTR:
+ key_attr ();
break;
case cmdQUIT:
diff --git a/g10/cpr.c b/g10/cpr.c
index a7fd1aaba..435442636 100644
--- a/g10/cpr.c
+++ b/g10/cpr.c
@@ -245,9 +245,13 @@ write_status_errcode (const char *where, int errcode)
void
write_status_failure (const char *where, gpg_error_t err)
{
+ static int any_failure_printed;
+
if (!statusfp || !status_currently_allowed (STATUS_FAILURE))
return; /* Not enabled or allowed. */
-
+ if (any_failure_printed)
+ return;
+ any_failure_printed = 1;
es_fprintf (statusfp, "[GNUPG:] %s %s %u\n",
get_status_string (STATUS_FAILURE), where, err);
if (es_fflush (statusfp) && opt.exit_on_status_write_error)
diff --git a/g10/getkey.c b/g10/getkey.c
index a838c3c61..445e8a6a1 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1810,6 +1810,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
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);
diff --git a/g10/gpg.c b/g10/gpg.c
index 277b5dbbb..1f3314eb3 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1203,6 +1203,7 @@ 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);
}
@@ -3169,7 +3170,7 @@ main (int argc, char **argv)
case oCommandFD:
opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
if (! gnupg_fd_valid (opt.command_fd))
- log_fatal ("command-fd is invalid: %s\n", strerror (errno));
+ 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);
@@ -3631,7 +3632,16 @@ main (int argc, char **argv)
case oNoop: break;
default:
- pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
+ 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;
}
}
@@ -3650,7 +3660,10 @@ main (int argc, char **argv)
}
xfree(configname); configname = NULL;
if (log_get_errorcount (0))
- g10_exit(2);
+ {
+ 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. */
@@ -3671,7 +3684,10 @@ main (int argc, char **argv)
"--print-pks-records",
"--export-options export-pka");
if (log_get_errorcount (0))
- g10_exit(2);
+ {
+ write_status_failure ("option-checking", gpg_error(GPG_ERR_GENERAL));
+ g10_exit(2);
+ }
if( nogreeting )
@@ -3772,6 +3788,7 @@ main (int argc, char **argv)
{
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);
}
@@ -3937,7 +3954,11 @@ main (int argc, char **argv)
}
if( log_get_errorcount(0) )
- g10_exit(2);
+ {
+ write_status_failure ("option-postprocessing",
+ gpg_error(GPG_ERR_GENERAL));
+ g10_exit (2);
+ }
if(opt.compress_level==0)
opt.compress_algo=COMPRESS_ALGO_NONE;
@@ -4051,7 +4072,10 @@ main (int argc, char **argv)
/* 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 ) {
@@ -5035,7 +5059,10 @@ main (int argc, char **argv)
hd = keydb_new ();
if (! hd)
- g10_exit (1);
+ {
+ write_status_failure ("tofu-driver", gpg_error(GPG_ERR_GENERAL));
+ g10_exit (1);
+ }
tofu_begin_batch_update (ctrl);
@@ -5049,6 +5076,7 @@ main (int argc, char **argv)
{
log_error (_("error parsing key specification '%s': %s\n"),
argv[i], gpg_strerror (rc));
+ write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
@@ -5062,6 +5090,8 @@ main (int argc, char **argv)
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);
}
@@ -5072,6 +5102,7 @@ main (int argc, char **argv)
the string. */
log_error ("keydb_search_reset failed: %s\n",
gpg_strerror (rc));
+ write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
@@ -5080,6 +5111,7 @@ main (int argc, char **argv)
{
log_error (_("key \"%s\" not found: %s\n"), argv[i],
gpg_strerror (rc));
+ write_status_failure ("tofu-driver", rc);
g10_exit (1);
}
@@ -5088,12 +5120,16 @@ main (int argc, char **argv)
{
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))
- g10_exit (1);
+ {
+ write_status_failure ("tofu-driver", rc);
+ g10_exit (1);
+ }
release_kbnode (kb);
}
@@ -5175,6 +5211,12 @@ emergency_cleanup (void)
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 (log_get_errorcount (0))
+ write_status_failure ("gpg-exit", gpg_error (GPG_ERR_GENERAL));
+
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
if (DBG_CLOCK)
log_clock ("stop");
diff --git a/g10/keydb.h b/g10/keydb.h
index f2ea8a7d2..69365793c 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -26,13 +26,16 @@
#include "../common/util.h"
#include "packet.h"
-/* What qualifies as a certification (rather than a signature?) */
+/* What qualifies as a certification (key-signature in contrast to a
+ * data signature)? Note that a back signature is special and can be
+ * made by key and data signatures capable subkeys.) */
#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
|| IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
#define IS_SIG(s) (!IS_CERT(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
+#define IS_BACK_SIG(s) ((s)->sig_class == 0x19)
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 2cb9bb2ff..3d4418ead 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -4563,10 +4563,10 @@ menu_changeusage (ctrl_t ctrl, kbnode_t keyblock)
return 0;
}
else if (n1)
- tty_printf ("Changing usage of a subkey.\n");
+ tty_printf (_("Changing usage of a subkey.\n"));
else
{
- tty_printf ("Changing usage of the primary key.\n");
+ tty_printf (_("Changing usage of the primary key.\n"));
mainkey = 1;
}
@@ -4606,6 +4606,8 @@ menu_changeusage (ctrl_t ctrl, kbnode_t keyblock)
if ((mainkey && main_pk->version < 4)
|| (!mainkey && sub_pk->version < 4))
{
+ /* Note: This won't happen because we don't support
+ * v3 keys anymore. */
log_info ("You can't change the capabilities of a v3 key\n");
return 0;
}
@@ -4630,7 +4632,7 @@ menu_changeusage (ctrl_t ctrl, kbnode_t keyblock)
if (rc)
{
log_error ("make_keysig_packet failed: %s\n",
- gpg_strerror (rc));
+ gpg_strerror (rc));
return 0;
}
diff --git a/g10/keygen.c b/g10/keygen.c
index cded87c45..9e9cead07 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -147,8 +147,8 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *algostr, const char *usagestr,
const char *expirestr,
int *r_algo, unsigned int *r_usage,
- u32 *r_expire,
- unsigned int *r_nbits, char **r_curve);
+ u32 *r_expire, unsigned int *r_nbits,
+ const char **r_curve);
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
struct output_control_s *outctrl, int card );
static int write_keyblock (iobuf_t out, kbnode_t node);
@@ -2336,10 +2336,10 @@ ask_keysize (int algo, unsigned int primary_keysize)
/* Ask for the curve. ALGO is the selected algorithm which this
- function may adjust. Returns a malloced string with the name of
- the curve. BOTH tells that gpg creates a primary and subkey. */
-static char *
-ask_curve (int *algo, int *subkey_algo)
+ function may adjust. Returns a const string of the name of the
+ curve. */
+const char *
+ask_curve (int *algo, int *subkey_algo, const char *current)
{
/* NB: We always use a complete algo list so that we have stable
numbers in the menu regardless on how Gpg was configured. */
@@ -2370,7 +2370,7 @@ ask_curve (int *algo, int *subkey_algo)
#undef MY_USE_ECDSADH
int idx;
char *answer;
- char *result = NULL;
+ const char *result = NULL;
gcry_sexp_t keyparms;
tty_printf (_("Please select which elliptic curve you want:\n"));
@@ -2430,7 +2430,12 @@ ask_curve (int *algo, int *subkey_algo)
answer = cpr_get ("keygen.curve", _("Your selection? "));
cpr_kill_prompt ();
idx = *answer? atoi (answer) : 1;
- if (*answer && !idx)
+ if (!*answer && current)
+ {
+ xfree(answer);
+ return NULL;
+ }
+ else if (*answer && !idx)
{
/* See whether the user entered the name of the curve. */
for (idx=0; idx < DIM(curves); idx++)
@@ -2461,16 +2466,16 @@ ask_curve (int *algo, int *subkey_algo)
if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
*subkey_algo = PUBKEY_ALGO_EDDSA;
*algo = PUBKEY_ALGO_EDDSA;
- result = xstrdup (curves[idx].eddsa_curve);
+ result = curves[idx].eddsa_curve;
}
else
- result = xstrdup (curves[idx].name);
+ result = curves[idx].name;
break;
}
}
if (!result)
- result = xstrdup (curves[0].name);
+ result = curves[0].name;
return result;
}
@@ -4161,7 +4166,7 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
unsigned int use;
u32 expire;
unsigned int nbits;
- char *curve;
+ const char *curve;
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve);
@@ -4356,7 +4361,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
}
else
{
- char *curve = NULL;
+ const char *curve = NULL;
if (subkey_algo)
{
@@ -4366,7 +4371,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
- curve = ask_curve (&algo, &subkey_algo);
+ curve = ask_curve (&algo, &subkey_algo, NULL);
r = xmalloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo);
@@ -4419,8 +4424,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
{
/* Need to switch to a different curve for the
encryption key. */
- xfree (curve);
- curve = xstrdup ("Curve25519");
+ curve = "Curve25519";
}
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pSUBKEYCURVE;
@@ -4437,7 +4441,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
{
- curve = ask_curve (&algo, NULL);
+ curve = ask_curve (&algo, NULL, NULL);
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = pKEYCURVE;
strcpy (r->u.value, curve);
@@ -4480,8 +4484,6 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
r->next = para;
para = r;
}
-
- xfree (curve);
}
}
else /* Default key generation. */
@@ -5024,7 +5026,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *algostr, const char *usagestr,
const char *expirestr,
int *r_algo, unsigned int *r_usage, u32 *r_expire,
- unsigned int *r_nbits, char **r_curve)
+ unsigned int *r_nbits, const char **r_curve)
{
gpg_error_t err;
int algo;
@@ -5082,11 +5084,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
return gpg_error (GPG_ERR_INV_VALUE);
if (curve)
- {
- *r_curve = xtrystrdup (curve);
- if (!*r_curve)
- return gpg_error_from_syserror ();
- }
+ *r_curve = curve;
*r_algo = algo;
*r_usage = use;
*r_expire = expire;
@@ -5111,7 +5109,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
unsigned int use;
u32 expire;
unsigned int nbits = 0;
- char *curve = NULL;
+ const char *curve = NULL;
u32 cur_time;
char *key_from_hexgrip = NULL;
char *hexgrip = NULL;
@@ -5185,7 +5183,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
else if (algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA
|| algo == PUBKEY_ALGO_ECDH)
- curve = ask_curve (&algo, NULL);
+ curve = ask_curve (&algo, NULL, NULL);
else
nbits = ask_keysize (algo, 0);
@@ -5263,7 +5261,6 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
leave:
xfree (key_from_hexgrip);
- xfree (curve);
xfree (hexgrip);
xfree (serialno);
xfree (cache_nonce);
diff --git a/g10/main.h b/g10/main.h
index de8639e98..453d1226a 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -310,6 +310,7 @@ u32 parse_expire_string(const char *string);
u32 ask_expire_interval(int object,const char *def_expire);
u32 ask_expiredate(void);
unsigned int ask_key_flags (int algo, int subkey, unsigned int current);
+const char *ask_curve (int *algo, int *subkey_algo, const char *current);
void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
const char *usagestr, const char *expirestr);
void generate_keypair (ctrl_t ctrl, int full, const char *fname,
diff --git a/g10/sig-check.c b/g10/sig-check.c
index f8e366b7e..fc6983993 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -115,98 +115,100 @@ check_signature2 (ctrl_t ctrl,
PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate,
int *r_expired, int *r_revoked, PKT_public_key **r_pk)
{
- int rc=0;
- PKT_public_key *pk;
-
- if (r_expiredate)
- *r_expiredate = 0;
- if (r_expired)
- *r_expired = 0;
- if (r_revoked)
- *r_revoked = 0;
- if (r_pk)
- *r_pk = NULL;
-
- pk = xtrycalloc (1, sizeof *pk);
- if (!pk)
- return gpg_error_from_syserror ();
-
- if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
- ; /* We don't have this digest. */
- else if (! gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
- {
- /* Compliance failure. */
- log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
- gcry_md_algo_name (sig->digest_algo),
- gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_DIGEST_ALGO);
- }
- else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
- ; /* We don't have this pubkey algo. */
- else if (!gcry_md_is_enabled (digest,sig->digest_algo))
- {
- /* Sanity check that the md has a context for the hash that the
- sig is expecting. This can happen if a onepass sig header does
- not match the actual sig, and also if the clearsign "Hash:"
- header is missing or does not match the actual sig. */
+ int rc=0;
+ PKT_public_key *pk;
- log_info(_("WARNING: signature digest conflict in message\n"));
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- else if( get_pubkey (ctrl, pk, sig->keyid ) )
- rc = gpg_error (GPG_ERR_NO_PUBKEY);
- else if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
- pk->pubkey_algo, pk->pkey,
- nbits_from_pk (pk),
- NULL))
- {
- /* Compliance failure. */
- log_error (_("key %s may not be used for signing in %s mode\n"),
- keystr_from_pk (pk),
- gnupg_compliance_option_string (opt.compliance));
- rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
- }
- else if(!pk->flags.valid)
- {
- /* You cannot have a good sig from an invalid key. */
- rc = gpg_error (GPG_ERR_BAD_PUBKEY);
- }
- else
- {
- if(r_expiredate)
- *r_expiredate = pk->expiredate;
-
- rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
-
- /* Check the backsig. This is a 0x19 signature from the
- subkey on the primary key. The idea here is that it should
- not be possible for someone to "steal" subkeys and claim
- them as their own. The attacker couldn't actually use the
- subkey, but they could try and claim ownership of any
- signatures issued by it. */
- if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
- {
- if (!pk->flags.backsig)
- {
- log_info(_("WARNING: signing subkey %s is not"
- " cross-certified\n"),keystr_from_pk(pk));
- log_info(_("please see %s for more information\n"),
- "https://gnupg.org/faq/subkey-cross-certify.html");
- /* --require-cross-certification makes this warning an
- error. TODO: change the default to require this
- after more keys have backsigs. */
- if(opt.flags.require_cross_cert)
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- else if(pk->flags.backsig == 1)
- {
- log_info(_("WARNING: signing subkey %s has an invalid"
- " cross-certification\n"),keystr_from_pk(pk));
- rc = gpg_error (GPG_ERR_GENERAL);
- }
- }
+ if (r_expiredate)
+ *r_expiredate = 0;
+ if (r_expired)
+ *r_expired = 0;
+ if (r_revoked)
+ *r_revoked = 0;
+ if (r_pk)
+ *r_pk = NULL;
- }
+ pk = xtrycalloc (1, sizeof *pk);
+ if (!pk)
+ return gpg_error_from_syserror ();
+
+ if ((rc=openpgp_md_test_algo(sig->digest_algo)))
+ {
+ /* We don't have this digest. */
+ }
+ else if (!gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
+ {
+ /* Compliance failure. */
+ log_info (_("digest algorithm '%s' may not be used in %s mode\n"),
+ gcry_md_algo_name (sig->digest_algo),
+ gnupg_compliance_option_string (opt.compliance));
+ rc = gpg_error (GPG_ERR_DIGEST_ALGO);
+ }
+ else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
+ {
+ /* We don't have this pubkey algo. */
+ }
+ else if (!gcry_md_is_enabled (digest,sig->digest_algo))
+ {
+ /* Sanity check that the md has a context for the hash that the
+ * sig is expecting. This can happen if a onepass sig header
+ * does not match the actual sig, and also if the clearsign
+ * "Hash:" header is missing or does not match the actual sig. */
+ log_info(_("WARNING: signature digest conflict in message\n"));
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ else if (get_pubkey (ctrl, pk, sig->keyid))
+ rc = gpg_error (GPG_ERR_NO_PUBKEY);
+ else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+ pk->pubkey_algo, pk->pkey,
+ nbits_from_pk (pk),
+ NULL))
+ {
+ /* Compliance failure. */
+ log_error (_("key %s may not be used for signing in %s mode\n"),
+ keystr_from_pk (pk),
+ gnupg_compliance_option_string (opt.compliance));
+ rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+ }
+ else if (!pk->flags.valid)
+ {
+ /* You cannot have a good sig from an invalid key. */
+ rc = gpg_error (GPG_ERR_BAD_PUBKEY);
+ }
+ else
+ {
+ if (r_expiredate)
+ *r_expiredate = pk->expiredate;
+
+ rc = check_signature_end (pk, sig, digest, r_expired, r_revoked, NULL);
+
+ /* Check the backsig. This is a back signature (0x19) from
+ * the subkey on the primary key. The idea here is that it
+ * should not be possible for someone to "steal" subkeys and
+ * claim them as their own. The attacker couldn't actually
+ * use the subkey, but they could try and claim ownership of
+ * any signatures issued by it. */
+ if (!rc && !pk->flags.primary && pk->flags.backsig < 2)
+ {
+ if (!pk->flags.backsig)
+ {
+ log_info (_("WARNING: signing subkey %s is not"
+ " cross-certified\n"),keystr_from_pk(pk));
+ log_info (_("please see %s for more information\n"),
+ "https://gnupg.org/faq/subkey-cross-certify.html");
+ /* The default option --require-cross-certification
+ * makes this warning an error. */
+ if (opt.flags.require_cross_cert)
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ else if(pk->flags.backsig == 1)
+ {
+ log_info (_("WARNING: signing subkey %s has an invalid"
+ " cross-certification\n"), keystr_from_pk(pk));
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ }
+
+ }
if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
/* This signature id works best with DLP algorithms because
@@ -235,54 +237,54 @@ check_signature2 (ctrl_t ctrl,
int i;
char hashbuf[20]; /* We use SHA-1 here. */
- nbytes = 6;
- for (i=0; i < nsig; i++ )
- {
- if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
- BUG();
- nbytes += n;
- }
+ nbytes = 6;
+ for (i=0; i < nsig; i++ )
+ {
+ if (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, sig->data[i]))
+ BUG();
+ nbytes += n;
+ }
- /* Make buffer large enough to be later used as output buffer. */
- if (nbytes < 100)
- nbytes = 100;
- nbytes += 10; /* Safety margin. */
-
- /* Fill and hash buffer. */
- buffer = p = xmalloc (nbytes);
- *p++ = sig->pubkey_algo;
- *p++ = sig->digest_algo;
- *p++ = (a >> 24) & 0xff;
- *p++ = (a >> 16) & 0xff;
- *p++ = (a >> 8) & 0xff;
- *p++ = a & 0xff;
- nbytes -= 6;
- for (i=0; i < nsig; i++ )
- {
- if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
- BUG();
- p += n;
- nbytes -= n;
- }
- gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);
-
- p = make_radix64_string (hashbuf, 20);
- sprintf (buffer, "%s %s %lu",
- p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
- xfree (p);
- write_status_text (STATUS_SIG_ID, buffer);
- xfree (buffer);
+ /* Make buffer large enough to be later used as output buffer. */
+ if (nbytes < 100)
+ nbytes = 100;
+ nbytes += 10; /* Safety margin. */
+
+ /* Fill and hash buffer. */
+ buffer = p = xmalloc (nbytes);
+ *p++ = sig->pubkey_algo;
+ *p++ = sig->digest_algo;
+ *p++ = (a >> 24) & 0xff;
+ *p++ = (a >> 16) & 0xff;
+ *p++ = (a >> 8) & 0xff;
+ *p++ = a & 0xff;
+ nbytes -= 6;
+ for (i=0; i < nsig; i++ )
+ {
+ if (gcry_mpi_print (GCRYMPI_FMT_PGP, p, nbytes, &n, sig->data[i]))
+ BUG();
+ p += n;
+ nbytes -= n;
+ }
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, buffer, p-buffer);
+
+ p = make_radix64_string (hashbuf, 20);
+ sprintf (buffer, "%s %s %lu",
+ p, strtimestamp (sig->timestamp), (ulong)sig->timestamp);
+ xfree (p);
+ write_status_text (STATUS_SIG_ID, buffer);
+ xfree (buffer);
}
- if (r_pk)
- *r_pk = pk;
- else
- {
- release_public_key_parts (pk);
- xfree (pk);
- }
+ if (r_pk)
+ *r_pk = pk;
+ else
+ {
+ release_public_key_parts (pk);
+ xfree (pk);
+ }
- return rc;
+ return rc;
}
@@ -307,87 +309,86 @@ static int
check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
int *r_expired, int *r_revoked)
{
- u32 cur_time;
+ u32 cur_time;
- if(r_expired)
- *r_expired = 0;
- if(r_revoked)
- *r_revoked = 0;
+ if (r_expired)
+ *r_expired = 0;
+ if (r_revoked)
+ *r_revoked = 0;
- if( pk->timestamp > sig->timestamp )
- {
- ulong d = pk->timestamp - sig->timestamp;
- if ( d < 86400 )
- {
- log_info
- (ngettext
- ("public key %s is %lu second newer than the signature\n",
- "public key %s is %lu seconds newer than the signature\n",
- d), keystr_from_pk (pk), d);
- }
- else
- {
- d /= 86400;
- log_info
- (ngettext
- ("public key %s is %lu day newer than the signature\n",
- "public key %s is %lu days newer than the signature\n",
- d), keystr_from_pk (pk), d);
- }
- if (!opt.ignore_time_conflict)
- return GPG_ERR_TIME_CONFLICT; /* pubkey newer than signature. */
- }
+ if (pk->timestamp > sig->timestamp )
+ {
+ ulong d = pk->timestamp - sig->timestamp;
+ if ( d < 86400 )
+ {
+ log_info (ngettext
+ ("public key %s is %lu second newer than the signature\n",
+ "public key %s is %lu seconds newer than the signature\n",
+ d), keystr_from_pk (pk), d);
+ }
+ else
+ {
+ d /= 86400;
+ log_info (ngettext
+ ("public key %s is %lu day newer than the signature\n",
+ "public key %s is %lu days newer than the signature\n",
+ d), keystr_from_pk (pk), d);
+ }
+ if (!opt.ignore_time_conflict)
+ return GPG_ERR_TIME_CONFLICT; /* pubkey newer than signature. */
+ }
- cur_time = make_timestamp();
- if( pk->timestamp > cur_time )
- {
- ulong d = pk->timestamp - cur_time;
- if (d < 86400)
- {
- log_info (ngettext("key %s was created %lu second"
- " in the future (time warp or clock problem)\n",
- "key %s was created %lu seconds"
- " in the future (time warp or clock problem)\n",
- d), keystr_from_pk (pk), d);
- }
- else
- {
- d /= 86400;
- log_info (ngettext("key %s was created %lu day"
- " in the future (time warp or clock problem)\n",
- "key %s was created %lu days"
- " in the future (time warp or clock problem)\n",
- d), keystr_from_pk (pk), d);
- }
- if (!opt.ignore_time_conflict)
- return GPG_ERR_TIME_CONFLICT;
- }
+ cur_time = make_timestamp ();
+ if (pk->timestamp > cur_time)
+ {
+ ulong d = pk->timestamp - cur_time;
+ if (d < 86400)
+ {
+ log_info (ngettext("key %s was created %lu second"
+ " in the future (time warp or clock problem)\n",
+ "key %s was created %lu seconds"
+ " in the future (time warp or clock problem)\n",
+ d), keystr_from_pk (pk), d);
+ }
+ else
+ {
+ d /= 86400;
+ log_info (ngettext("key %s was created %lu day"
+ " in the future (time warp or clock problem)\n",
+ "key %s was created %lu days"
+ " in the future (time warp or clock problem)\n",
+ d), keystr_from_pk (pk), d);
+ }
+ if (!opt.ignore_time_conflict)
+ return GPG_ERR_TIME_CONFLICT;
+ }
- /* Check whether the key has expired. We check the has_expired
- flag which is set after a full evaluation of the key (getkey.c)
- as well as a simple compare to the current time in case the
- merge has for whatever reasons not been done. */
- if( pk->has_expired || (pk->expiredate && pk->expiredate < cur_time)) {
- char buf[11];
- if (opt.verbose)
- log_info(_("Note: signature key %s expired %s\n"),
- keystr_from_pk(pk), asctimestamp( pk->expiredate ) );
- sprintf(buf,"%lu",(ulong)pk->expiredate);
- write_status_text(STATUS_KEYEXPIRED,buf);
- if(r_expired)
- *r_expired = 1;
+ /* Check whether the key has expired. We check the has_expired
+ * flag which is set after a full evaluation of the key (getkey.c)
+ * as well as a simple compare to the current time in case the
+ * merge has for whatever reasons not been done. */
+ if (pk->has_expired || (pk->expiredate && pk->expiredate < cur_time))
+ {
+ char buf[11];
+ if (opt.verbose)
+ log_info (_("Note: signature key %s expired %s\n"),
+ keystr_from_pk(pk), asctimestamp( pk->expiredate ) );
+ snprintf (buf, sizeof buf, "%lu",(ulong)pk->expiredate);
+ write_status_text (STATUS_KEYEXPIRED, buf);
+ if (r_expired)
+ *r_expired = 1;
}
- if (pk->flags.revoked)
- {
- if (opt.verbose)
- log_info (_("Note: signature key %s has been revoked\n"),
- keystr_from_pk(pk));
- if (r_revoked)
- *r_revoked=1;
- }
+ if (pk->flags.revoked)
+ {
+ if (opt.verbose)
+ log_info (_("Note: signature key %s has been revoked\n"),
+ keystr_from_pk(pk));
+ if (r_revoked)
+ *r_revoked=1;
+ }
- return 0;
+ return 0;
}
@@ -425,70 +426,96 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest,
int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
{
- int rc = 0;
+ int rc = 0;
- if ((rc = check_signature_metadata_validity (pk, sig,
- r_expired, r_revoked)))
- return rc;
+ if ((rc = check_signature_metadata_validity (pk, sig,
+ r_expired, r_revoked)))
+ return rc;
- if ((rc = check_signature_end_simple (pk, sig, digest)))
- return rc;
+ if ((rc = check_signature_end_simple (pk, sig, digest)))
+ return rc;
- if(!rc && ret_pk)
- copy_public_key(ret_pk,pk);
+ if (!rc && ret_pk)
+ copy_public_key(ret_pk,pk);
- return rc;
+ return rc;
}
+
/* This function is similar to check_signature_end, but it only checks
- whether the signature was generated by PK. It does not check
- expiration, revocation, etc. */
+ * whether the signature was generated by PK. It does not check
+ * expiration, revocation, etc. */
static int
check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
gcry_md_hd_t digest)
{
- gcry_mpi_t result = NULL;
- int rc = 0;
- const struct weakhash *weak;
+ gcry_mpi_t result = NULL;
+ int rc = 0;
+ const struct weakhash *weak;
- if (!opt.flags.allow_weak_digest_algos)
+ if (!opt.flags.allow_weak_digest_algos)
+ {
for (weak = opt.weak_digests; weak; weak = weak->next)
if (sig->digest_algo == weak->algo)
{
print_digest_rejected_note(sig->digest_algo);
return GPG_ERR_DIGEST_ALGO;
}
+ }
+
+ /* For key signatures check that the key has a cert usage. We may
+ * do this only for subkeys because the primary may always issue key
+ * signature. The latter may not be reflected in the pubkey_usage
+ * field because we need to check the key signatures to extract the
+ * key usage. */
+ if (!pk->flags.primary
+ && IS_CERT (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_CERT))
+ {
+ rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ if (!opt.quiet)
+ log_info (_("bad key signature from key %s: %s (0x%02x, 0x%x)\n"),
+ keystr_from_pk (pk), gpg_strerror (rc),
+ sig->sig_class, pk->pubkey_usage);
+ return rc;
+ }
+ /* Fixme: Should we also check the signing capability here for data
+ * signature? */
- /* Make sure the digest algo is enabled (in case of a detached
- signature). */
- gcry_md_enable (digest, sig->digest_algo);
+ /* Make sure the digest algo is enabled (in case of a detached
+ * signature). */
+ gcry_md_enable (digest, sig->digest_algo);
- /* Complete the digest. */
- if( sig->version >= 4 )
- gcry_md_putc( digest, sig->version );
- gcry_md_putc( digest, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- gcry_md_putc( digest, (a >> 24) & 0xff );
- gcry_md_putc( digest, (a >> 16) & 0xff );
- gcry_md_putc( digest, (a >> 8) & 0xff );
- gcry_md_putc( digest, a & 0xff );
+ /* Complete the digest. */
+ if (sig->version >= 4)
+ gcry_md_putc (digest, sig->version);
+
+ gcry_md_putc( digest, sig->sig_class );
+ if (sig->version < 4)
+ {
+ u32 a = sig->timestamp;
+ gcry_md_putc (digest, ((a >> 24) & 0xff));
+ gcry_md_putc (digest, ((a >> 16) & 0xff));
+ gcry_md_putc (digest, ((a >> 8) & 0xff));
+ gcry_md_putc (digest, ( a & 0xff));
}
- else {
- byte buf[6];
- size_t n;
- gcry_md_putc( digest, sig->pubkey_algo );
- gcry_md_putc( digest, sig->digest_algo );
- if( sig->hashed ) {
- n = sig->hashed->len;
- gcry_md_putc (digest, (n >> 8) );
- gcry_md_putc (digest, n );
- gcry_md_write (digest, sig->hashed->data, n);
- n += 6;
+ else
+ {
+ byte buf[6];
+ size_t n;
+ gcry_md_putc (digest, sig->pubkey_algo);
+ gcry_md_putc (digest, sig->digest_algo);
+ if (sig->hashed)
+ {
+ n = sig->hashed->len;
+ gcry_md_putc (digest, (n >> 8) );
+ gcry_md_putc (digest, n );
+ gcry_md_write (digest, sig->hashed->data, n);
+ n += 6;
}
- else {
+ else
+ {
/* Two octets for the (empty) length of the hashed
- section. */
+ * section. */
gcry_md_putc (digest, 0);
gcry_md_putc (digest, 0);
n = 6;
@@ -517,62 +544,69 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
log_clock ("leave pk_verify");
gcry_mpi_release (result);
- if( !rc && sig->flags.unknown_critical )
- {
- log_info(_("assuming bad signature from key %s"
- " due to an unknown critical bit\n"),keystr_from_pk(pk));
- rc = GPG_ERR_BAD_SIGNATURE;
- }
+ if (!rc && sig->flags.unknown_critical)
+ {
+ log_info(_("assuming bad signature from key %s"
+ " due to an unknown critical bit\n"),keystr_from_pk(pk));
+ rc = GPG_ERR_BAD_SIGNATURE;
+ }
- return rc;
+ return rc;
}
/* Add a uid node to a hash context. See section 5.2.4, paragraph 4
- of RFC 4880. */
+ * of RFC 4880. */
static void
hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig )
{
- if( uid->attrib_data ) {
- if( sig->version >=4 ) {
- byte buf[5];
- buf[0] = 0xd1; /* packet of type 17 */
- buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
- buf[2] = uid->attrib_len >> 16;
- buf[3] = uid->attrib_len >> 8;
- buf[4] = uid->attrib_len;
- gcry_md_write( md, buf, 5 );
+ if (uid->attrib_data)
+ {
+ if (sig->version >=4)
+ {
+ byte buf[5];
+ buf[0] = 0xd1; /* packet of type 17 */
+ buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->attrib_len >> 16;
+ buf[3] = uid->attrib_len >> 8;
+ buf[4] = uid->attrib_len;
+ gcry_md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->attrib_data, uid->attrib_len );
+ gcry_md_write( md, uid->attrib_data, uid->attrib_len );
}
- else {
- if( sig->version >=4 ) {
- byte buf[5];
- buf[0] = 0xb4; /* indicates a userid packet */
- buf[1] = uid->len >> 24; /* always use 4 length bytes */
- buf[2] = uid->len >> 16;
- buf[3] = uid->len >> 8;
- buf[4] = uid->len;
- gcry_md_write( md, buf, 5 );
+ else
+ {
+ if (sig->version >=4)
+ {
+ byte buf[5];
+ buf[0] = 0xb4; /* indicates a userid packet */
+ buf[1] = uid->len >> 24; /* always use 4 length bytes */
+ buf[2] = uid->len >> 16;
+ buf[3] = uid->len >> 8;
+ buf[4] = uid->len;
+ gcry_md_write( md, buf, 5 );
}
- gcry_md_write( md, uid->name, uid->len );
+ gcry_md_write( md, uid->name, uid->len );
}
}
static void
cache_sig_result ( PKT_signature *sig, int result )
{
- if ( !result ) {
- sig->flags.checked = 1;
- sig->flags.valid = 1;
+ if (!result)
+ {
+ sig->flags.checked = 1;
+ sig->flags.valid = 1;
}
- else if ( gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE ) {
- sig->flags.checked = 1;
- sig->flags.valid = 0;
+ else if (gpg_err_code (result) == GPG_ERR_BAD_SIGNATURE)
+ {
+ sig->flags.checked = 1;
+ sig->flags.valid = 0;
}
- else {
- sig->flags.checked = 0;
- sig->flags.valid = 0;
+ else
+ {
+ sig->flags.checked = 0;
+ sig->flags.valid = 0;
}
}
@@ -690,14 +724,14 @@ check_revocation_keys (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
}
/* Check that the backsig BACKSIG from the subkey SUB_PK to its
- primary key MAIN_PK is valid.
-
- Backsigs (0x19) have the same format as binding sigs (0x18), but
- this function is simpler than check_key_signature in a few ways.
- For example, there is no support for expiring backsigs since it is
- questionable what such a thing actually means. Note also that the
- sig cache check here, unlike other sig caches in GnuPG, is not
- persistent. */
+ * primary key MAIN_PK is valid.
+ *
+ * Backsigs (0x19) have the same format as binding sigs (0x18), but
+ * this function is simpler than check_key_signature in a few ways.
+ * For example, there is no support for expiring backsigs since it is
+ * questionable what such a thing actually means. Note also that the
+ * sig cache check here, unlike other sig caches in GnuPG, is not
+ * persistent. */
int
check_backsig (PKT_public_key *main_pk,PKT_public_key *sub_pk,
PKT_signature *backsig)
@@ -793,32 +827,18 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
/* A signature's class indicates the type of packet that it
signs. */
- if (/* Primary key binding (made by a subkey). */
- sig->sig_class == 0x19
- /* Direct key signature. */
- || sig->sig_class == 0x1f
- /* Primary key revocation. */
- || sig->sig_class == 0x20)
+ if (IS_BACK_SIG (sig) || IS_KEY_SIG (sig) || IS_KEY_REV (sig))
{
/* Key revocations can only be over primary keys. */
if (packet->pkttype != PKT_PUBLIC_KEY)
return gpg_error (GPG_ERR_SIG_CLASS);
}
- else if (/* Subkey binding. */
- sig->sig_class == 0x18
- /* Subkey revocation. */
- || sig->sig_class == 0x28)
+ else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
{
if (packet->pkttype != PKT_PUBLIC_SUBKEY)
return gpg_error (GPG_ERR_SIG_CLASS);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
if (packet->pkttype != PKT_USER_ID)
return gpg_error (GPG_ERR_SIG_CLASS);
@@ -853,7 +873,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
else
{
/* See if one of the subkeys was the signer (although this
- is extremely unlikely). */
+ * is extremely unlikely). */
kbnode_t ctx = NULL;
kbnode_t n;
@@ -894,6 +914,9 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
signer_alloced = 2;
}
+ if (IS_CERT (sig))
+ signer->req_usage = PUBKEY_USAGE_CERT;
+
rc = get_pubkey (ctrl, signer, sig->keyid);
if (rc)
{
@@ -913,40 +936,27 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
/* Hash the relevant data. */
- if (/* Direct key signature. */
- sig->sig_class == 0x1f
- /* Primary key revocation. */
- || sig->sig_class == 0x20)
+ if (IS_KEY_SIG (sig) || IS_KEY_REV (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Primary key binding (made by a subkey). */
- sig->sig_class == 0x19)
+ else if (IS_BACK_SIG (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_KEY);
hash_public_key (md, packet->pkt.public_key);
hash_public_key (md, signer);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Subkey binding. */
- sig->sig_class == 0x18
- /* Subkey revocation. */
- || sig->sig_class == 0x28)
+ else if (IS_SUBKEY_SIG (sig) || IS_SUBKEY_REV (sig))
{
log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
hash_public_key (md, pripk);
hash_public_key (md, packet->pkt.public_key);
rc = check_signature_end_simple (signer, sig, md);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
log_assert (packet->pkttype == PKT_USER_ID);
hash_public_key (md, pripk);
@@ -1077,7 +1087,7 @@ check_key_signature2 (ctrl_t ctrl,
if (rc)
return rc;
- if (sig->sig_class == 0x20) /* key revocation */
+ if (IS_KEY_REV (sig))
{
u32 keyid[2];
keyid_from_pk( pk, keyid );
@@ -1095,8 +1105,7 @@ check_key_signature2 (ctrl_t ctrl,
is_selfsig, ret_pk);
}
}
- else if (sig->sig_class == 0x28 /* subkey revocation */
- || sig->sig_class == 0x18) /* key binding */
+ else if (IS_SUBKEY_REV (sig) || IS_SUBKEY_SIG (sig))
{
kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
@@ -1106,9 +1115,10 @@ check_key_signature2 (ctrl_t ctrl,
r_expired, NULL);
if (! rc)
{
- /* 0x28 must be a self-sig, but 0x18 needn't be. */
+ /* A subkey revocation (0x28) must be a self-sig, but a
+ * subkey signature (0x18) needn't be. */
rc = check_signature_over_key_or_uid (ctrl,
- sig->sig_class == 0x18
+ IS_SUBKEY_SIG (sig)
? NULL : pk,
sig, root, snode->pkt,
is_selfsig, ret_pk);
@@ -1118,7 +1128,7 @@ check_key_signature2 (ctrl_t ctrl,
{
if (opt.verbose)
{
- if (sig->sig_class == 0x28)
+ if (IS_SUBKEY_REV (sig))
log_info (_("key %s: no subkey for subkey"
" revocation signature\n"), keystr_from_pk(pk));
else if (sig->sig_class == 0x18)
@@ -1128,7 +1138,7 @@ check_key_signature2 (ctrl_t ctrl,
rc = GPG_ERR_SIG_CLASS;
}
}
- else if (sig->sig_class == 0x1f) /* direct key signature */
+ else if (IS_KEY_SIG (sig)) /* direct key signature */
{
rc = check_signature_metadata_validity (pk, sig,
r_expired, NULL);
@@ -1136,13 +1146,7 @@ check_key_signature2 (ctrl_t ctrl,
rc = check_signature_over_key_or_uid (ctrl, pk, sig, root, root->pkt,
is_selfsig, ret_pk);
}
- else if (/* Certification. */
- sig->sig_class == 0x10
- || sig->sig_class == 0x11
- || sig->sig_class == 0x12
- || sig->sig_class == 0x13
- /* Certification revocation. */
- || sig->sig_class == 0x30)
+ else if (IS_UID_SIG (sig) || IS_UID_REV (sig))
{
kbnode_t unode = find_prev_kbnode (root, node, PKT_USER_ID);