diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/call-agent.h | 15 | ||||
-rw-r--r-- | g10/card-util.c | 370 | ||||
-rw-r--r-- | g10/cpr.c | 6 | ||||
-rw-r--r-- | g10/getkey.c | 2 | ||||
-rw-r--r-- | g10/gpg.c | 56 | ||||
-rw-r--r-- | g10/keydb.h | 5 | ||||
-rw-r--r-- | g10/keyedit.c | 8 | ||||
-rw-r--r-- | g10/keygen.c | 53 | ||||
-rw-r--r-- | g10/main.h | 1 | ||||
-rw-r--r-- | g10/sig-check.c | 690 |
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: @@ -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); @@ -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); |