From c36089daf76d53a1d1912f58f284b78bafe14508 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Feb 2013 19:28:54 +0100 Subject: [PATCH 01/19] Update .gitignore for non-VPATH builds. -- --- .gitignore | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index a6b178146..b75b40416 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,8 @@ po/en@boldquot.po po/en@quot.insert-header po/en@quot.po po/stamp-po +po/remove-potcdate.sed +po/gnupg.pot agent/gpg-agent agent/gpg-preset-passphrase agent/gpg-protect-tool @@ -47,6 +49,8 @@ common/t-sysutils common/t-stringhelp common/t-timestuff common/t-ssh-utils +common/t-dns-cert +common/t-openpgp-oid doc/addgnupghome.8 doc/applygnupgdefaults.8 doc/faq.html @@ -89,14 +93,20 @@ keyserver/gpg2keys_ldap scd/gnupg-pcsc-wrapper scd/scdaemon sm/gpgsm +g13/g13 dirmngr/dirmngr dirmngr/dirmngr-client dirmngr/dirmngr_ldap dirmngr/no-libgcrypt.c tests/asschk tests/gpg-agent.conf +tests/gpg.conf tests/gpgsm.conf tests/inittests.stamp +tests/private-keys-v1.d/ +tests/pubring.kbx +tests/testdir.stamp +tests/trustlist.txt tests/openpgp/data-32000 tests/openpgp/data-500 tests/openpgp/data-80000 @@ -112,6 +122,12 @@ tests/openpgp/pubring.gpg tests/openpgp/pubring.pkr tests/openpgp/secring.gpg tests/openpgp/secring.skr +tests/openpgp/private-keys-v1.d/ +tests/openpgp/*.log +tests/openpgp/trustdb.gpg +tests/openpgp/gpg.conf +tests/openpgp/random_seed +tests/openpgp/z tests/pkits/ReadMe.txt tests/pkits/certpairs/ tests/pkits/certs/ @@ -126,13 +142,6 @@ tests/pkits/policies.txt tests/pkits/smime/ tests/pkits/testdir.stamp tests/pkits/trustlist.txt -tests/private-keys-v1.d/ -tests/pubring.kbx -tests/testdir.stamp -tests/trustlist.txt -tests/openpgp/*.log -tests/openpgp/trustdb.gpg -tests/openpgp/z tools/clean-sat tools/gpg-check-pattern tools/gpg-connect-agent @@ -145,5 +154,6 @@ tools/mk-tdata tools/symcryptrun tools/watchgnupg tools/gpgtar -g13/g13 -/po/gnupg.pot + + +x.parm From 7d376ffa321d4af6e62a2bc64ef2b8574b122b1a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 22 Feb 2013 11:00:27 +0900 Subject: [PATCH 02/19] gpg: fix keytocard and support ECC card for key attribute. * g10/call-agent.c (agent_keytocard): Supply PARM arg. * g10/card-util.c (card_status): Support ECC. (card_store_subkey): Don't assume RSA. --- g10/call-agent.c | 8 ++++++-- g10/card-util.c | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index 85a3f2842..e3250fe46 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -606,6 +606,10 @@ agent_keytocard (const char *hexgrip, int keyno, int force, { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s parm; + + memset (&parm, 0, sizeof parm); + parm.ctx = agent_ctx; snprintf (line, DIM(line)-1, "KEYTOCARD %s%s %s OPENPGP.%d %s", force?"--force ": "", hexgrip, serialno, keyno, timestamp); @@ -615,8 +619,8 @@ agent_keytocard (const char *hexgrip, int keyno, int force, if (rc) return rc; - rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, - NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm, + NULL, NULL); if (rc) return rc; diff --git a/g10/card-util.c b/g10/card-util.c index 75208cc86..add8eed09 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -550,7 +550,9 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen) tty_fprintf (fp, " %u%c", info.key_attr[i].nbits, info.key_attr[i].algo == 1? 'R': - info.key_attr[i].algo == 17? 'D': '?'); + info.key_attr[i].algo == 17? 'D': + info.key_attr[i].algo == 18? 'e': + info.key_attr[i].algo == 19? 'E': '?'); tty_fprintf (fp, "\n"); } tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n", @@ -1560,7 +1562,7 @@ card_store_subkey (KBNODE node, int use) nbits = nbits_from_pk (pk); - if (!is_RSA (pk->pubkey_algo) || (!info.is_v2 && nbits != 1024) ) + if (!info.is_v2 && nbits != 1024) { tty_printf ("You may only store a 1024 bit RSA key on the card\n"); tty_printf ("\n"); From 3c3648e720b8014828573bd708c88ba4775014e3 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 22 Feb 2013 12:55:11 +0900 Subject: [PATCH 03/19] agent: fix two bugs. * agent/command.c (cmd_keytocard): Decrement KEYDATALEN. * agent/findkey.c (agent_public_key_from_file): Increment for ELEMS. -- For ECDSA and ECDH, there are 6 elements. --- agent/command.c | 1 + agent/findkey.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/agent/command.c b/agent/command.c index 2844398f6..823b233bf 100644 --- a/agent/command.c +++ b/agent/command.c @@ -2197,6 +2197,7 @@ cmd_keytocard (assuan_context_t ctx, char *line) gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen); gcry_sexp_release (s_skey); + keydatalen--; /* Decrement for last '\0'. */ /* Add timestamp "created-at" in the private key */ timestamp = isotime2epoch (timestamp_str); snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp); diff --git a/agent/findkey.c b/agent/findkey.c index b17870ef7..ebdcc038e 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -828,7 +828,7 @@ agent_public_key_from_file (ctrl_t ctrl, int i, idx; gcry_sexp_t s_skey; char algoname[6]; - char elems[6]; + char elems[7]; gcry_sexp_t uri_sexp, comment_sexp; const char *uri, *comment; size_t uri_length, comment_length; From 21f5a9ec27c0794141a835a5bb3c69495ee554a6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 20 Feb 2013 20:31:52 +0100 Subject: [PATCH 04/19] Remove build hacks for FreeBSD. * configure.ac [freebsd]: Do not add /usr/local to CPPFLAGS and LDFLAGS. -- Back in ~2000 we introduced a quick hack to make building of Libgcrypt on FreeBSD easier by always adding -I/usr/local/include and -L/usr/local/lib . It turned out that this is a bad idea if one wants to build with library version which is not installed in /usr/local. The hack made was eventually (in 2003) copied from Libgcrypt to GnuPG-2. --- configure.ac | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure.ac b/configure.ac index 5881df1a1..cf5ab3fa6 100644 --- a/configure.ac +++ b/configure.ac @@ -627,12 +627,6 @@ case "${host}" in try_gettext="no" ;; - *-*-freebsd*) - # FreeBSD - CPPFLAGS="$CPPFLAGS -I/usr/local/include" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - ;; - *-*-hpux*) if test -z "$GCC" ; then CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE" From 2838385e76c8c7108bc949d5a1d1c947051bd5be Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 21 Feb 2013 20:25:12 +0100 Subject: [PATCH 05/19] common: Add func has_leading_keyword. * common/stringhelp.c (has_leading_keyword): New. --- common/stringhelp.c | 23 +++++++++++++++++++++++ common/stringhelp.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/common/stringhelp.c b/common/stringhelp.c index 842f6a14b..d51d3e0ce 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -73,6 +73,29 @@ change_slashes (char *name) } +/* + * Check whether STRINGS starts with KEYWORD. The keyword is + * delimited by end of string, a space or a tab. Returns NULL if not + * found or a pointer into STRING to the next non-space character + * after the KEYWORD (which may be end of string). + */ +char * +has_leading_keyword (const char *string, const char *keyword) +{ + size_t n = strlen (keyword); + + if (!strncmp (string, keyword, n) + && (!string[n] || string[n] == ' ' || string[n] == '\t')) + { + string += n; + while (*string == ' ' || *string == '\t') + string++; + return (char*)string; + } + return NULL; +} + + /* * Look for the substring SUB in buffer and return a pointer to that * substring in BUFFER or NULL if not found. diff --git a/common/stringhelp.h b/common/stringhelp.h index 60ba12b8c..c1f7ea12d 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -34,6 +34,8 @@ #include "types.h" +char *has_leading_keyword (const char *string, const char *keyword); + const char *memistr (const void *buf, size_t buflen, const char *sub); char *mem2str( char *, const void *, size_t); char *trim_spaces( char *string ); From baee681d2406530c45fd6d4bde77193ba23ac263 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 21 Feb 2013 20:27:20 +0100 Subject: [PATCH 06/19] gpg: Handle the agent's NEW_PASSPHRASE inquiry. * g10/call-agent.c (default_inq_cb): Take care of NEW_PASSPHRASE. --- g10/call-agent.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/g10/call-agent.c b/g10/call-agent.c index e3250fe46..908d2761c 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -336,7 +336,7 @@ default_inq_cb (void *opaque, const char *line) gpg_error_t err = 0; struct default_inq_parm_s *parm = opaque; - if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) + if (has_leading_keyword (line, "PINENTRY_LAUNCHED")) { err = gpg_proxy_pinentry_notify (parm->ctrl, line); if (err) @@ -344,7 +344,8 @@ default_inq_cb (void *opaque, const char *line) "PINENTRY_LAUNCHED"); /* We do not pass errors to avoid breaking other code. */ } - else if (!strncmp (line, "PASSPHRASE", 10) && (line[10]==' '||!line[10]) + else if ((has_leading_keyword (line, "PASSPHRASE") + || has_leading_keyword (line, "NEW_PASSPHRASE")) && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK) { if (have_static_passphrase ()) From 161674118d568025896026ede5e03d26bdfdfa68 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 21 Feb 2013 20:35:10 +0100 Subject: [PATCH 07/19] gpg: Fix a memory leak in batch key generation * g10/keygen.c (append_to_parameter): New. (proc_parameter_file): Use new func to extend the parameter list. * g10/passphrase.c (passphrase_to_dek_ext): Print a diagnostic of gcry_kdf_derive failed. * g10/keygen.c (proc_parameter_file): Print a diagnostic if passphrase_to_dek failed. -- Due to an improper way of using the linked list head, all memory for items allocated in proc_parameter_file was never released. If batched key generation with a passphrase and more than ~200 keys was used this exhausted the secure memory. --- g10/keygen.c | 48 +++++++++++++++++++++++++++++------------------- g10/passphrase.c | 18 +++++++++++------- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/g10/keygen.c b/g10/keygen.c index b5ccf0287..fc985eef3 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -2591,6 +2591,17 @@ generate_user_id (KBNODE keyblock) } +/* Append R to the linked list PARA. */ +static void +append_to_parameter (struct para_data_s *para, struct para_data_s *r) +{ + assert (para); + while (para->next) + para = para->next; + para->next = r; +} + +/* Release the parameter list R. */ static void release_parameter_list (struct para_data_s *r) { @@ -2817,8 +2828,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, r->u.usage = (is_default ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG) : openpgp_pk_algo_usage(algo)); - r->next = para; - para = r; + append_to_parameter (para, r); } else if (err == -1) return -1; @@ -2854,8 +2864,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, r->u.usage = (is_default ? PUBKEY_USAGE_ENC : openpgp_pk_algo_usage (algo)); - r->next = para; - para = r; + append_to_parameter (para, r); } else if (err == -1) return -1; @@ -2892,8 +2901,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); if( s3 ) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); - r->next = para; - para = r; + append_to_parameter (para, r); have_user_id=1; } } @@ -2946,13 +2954,11 @@ proc_parameter_file( struct para_data_s *para, const char *fname, r = xmalloc_clear( sizeof *r ); r->key = pPASSPHRASE_DEK; r->u.dek = dek; - r->next = para; - para = r; + append_to_parameter (para, r); r = xmalloc_clear( sizeof *r ); r->key = pPASSPHRASE_S2K; r->u.s2k = s2k; - r->next = para; - para = r; + append_to_parameter (para, r); } if (canceled) @@ -2971,27 +2977,32 @@ proc_parameter_file( struct para_data_s *para, const char *fname, * but because we do this always, why not here. */ STRING2KEY *s2k; DEK *dek; + static int count; - s2k = xmalloc_secure ( sizeof *s2k ); + s2k = xmalloc ( sizeof *s2k ); s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; set_next_passphrase ( r->u.value ); dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL, NULL); - set_next_passphrase (NULL ); - assert (dek); + if (!dek) + { + log_error ("%s:%d: error post processing the passphrase\n", + fname, r->lnr ); + xfree (s2k); + return -1; + } + set_next_passphrase (NULL); memset (r->u.value, 0, strlen(r->u.value)); r = xmalloc_clear (sizeof *r); r->key = pPASSPHRASE_S2K; r->u.s2k = s2k; - r->next = para; - para = r; + append_to_parameter (para, r); r = xmalloc_clear (sizeof *r); r->key = pPASSPHRASE_DEK; r->u.dek = dek; - r->next = para; - para = r; + append_to_parameter (para, r); } } @@ -3029,8 +3040,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname, r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYEXPIRE; r->u.expire = seconds; - r->next = para; - para = r; + append_to_parameter (para, r); } do_generate_keypair( para, outctrl, card ); diff --git a/g10/passphrase.c b/g10/passphrase.c index d872e36ae..f83e66825 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -569,17 +569,21 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, dek->keylen = 0; else { + gpg_error_t err; + dek->keylen = openpgp_cipher_get_algo_keylen (dek->algo); if (!(dek->keylen > 0 && dek->keylen <= DIM(dek->key))) BUG (); - if (gcry_kdf_derive (pw, strlen (pw), - s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K : - s2k->mode == 1? GCRY_KDF_SALTED_S2K : - /* */ GCRY_KDF_SIMPLE_S2K, - s2k->hash_algo, s2k->salt, 8, - S2K_DECODE_COUNT(s2k->count), - dek->keylen, dek->key)) + err = gcry_kdf_derive (pw, strlen (pw), + s2k->mode == 3? GCRY_KDF_ITERSALTED_S2K : + s2k->mode == 1? GCRY_KDF_SALTED_S2K : + /* */ GCRY_KDF_SIMPLE_S2K, + s2k->hash_algo, s2k->salt, 8, + S2K_DECODE_COUNT(s2k->count), + dek->keylen, dek->key); + if (err) { + log_error ("gcry_kdf_derive failed: %s", gpg_strerror (err)); xfree (pw); xfree (dek); write_status( STATUS_MISSING_PASSPHRASE ); From c6b8f05517228c6aeab28d2bf5da7724c059bb1a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Feb 2013 19:28:54 +0100 Subject: [PATCH 08/19] Remove some unused variables. * tools/gpgconf-comp.c (gc_process_gpgconf_conf): Remove unused used_components. * agent/command-ssh.c (ssh_signature_encoder_ecdsa): Mark unused arg. * g13/g13.c (main): Comment variable of yet unimplemented options. --- agent/command-ssh.c | 2 ++ g13/g13.c | 18 +++++++++--------- tools/gpgconf-comp.c | 6 ------ 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index c0b608a4a..94538b3d8 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1247,6 +1247,8 @@ ssh_signature_encoder_ecdsa (ssh_key_type_spec_t *spec, gpg_error_t err; int i; + (void)spec; + innerlen = 0; for (i = 0; i < DIM(data); i++) { diff --git a/g13/g13.c b/g13/g13.c index 82ed9d895..fca9e7a19 100644 --- a/g13/g13.c +++ b/g13/g13.c @@ -323,7 +323,7 @@ main ( int argc, char **argv) int orig_argc; char **orig_argv; gpg_error_t err = 0; - const char *fname; + /* const char *fname; */ int may_coredump; FILE *configfp = NULL; char *configname = NULL; @@ -334,10 +334,10 @@ main ( int argc, char **argv) char *logfile = NULL; int greeting = 0; int nogreeting = 0; - int debug_wait = 0; + /* int debug_wait = 0; */ int use_random_seed = 1; - int nodetach = 0; - int nokeysetup = 0; + /* int nodetach = 0; */ + /* int nokeysetup = 0; */ enum cmd_and_opt_values cmd = 0; struct server_control_s ctrl; strlist_t recipients = NULL; @@ -473,13 +473,13 @@ main ( int argc, char **argv) case aGPGConfTest: set_cmd (&cmd, pargs.r_opt); nogreeting = 1; - nokeysetup = 1; + /* nokeysetup = 1; */ break; case aServer: case aMount: case aUmount: - nokeysetup = 1; + /* nokeysetup = 1; */ case aCreate: set_cmd (&cmd, pargs.r_opt); break; @@ -504,13 +504,13 @@ main ( int argc, char **argv) case oLogFile: logfile = pargs.r.ret_str; break; case oNoLogFile: logfile = NULL; break; - case oNoDetach: nodetach = 1; break; + case oNoDetach: /*nodetach = 1; */break; case oDebug: debug_value |= pargs.r.ret_ulong; break; case oDebugAll: debug_value = ~0; break; case oDebugNone: debug_value = 0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; - case oDebugWait: debug_wait = pargs.r.ret_int; break; + case oDebugWait: /*debug_wait = pargs.r.ret_int; */break; case oDebugAllowCoreDump: may_coredump = enable_core_dumps (); break; @@ -653,7 +653,7 @@ main ( int argc, char **argv) } /* Store given filename into FNAME. */ - fname = argc? *argv : NULL; + /* fname = argc? *argv : NULL; */ /* Parse all given encryption keys. This does a lookup of the keys and stops if any of the given keys was not found. */ diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 9dbddeee9..0b3c9c0e7 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -3382,7 +3382,6 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, int in_rule = 0; int got_match = 0; int runtime[GC_BACKEND_NR]; - int used_components[GC_COMPONENT_NR]; int backend_id, component_id; char *fname; @@ -3393,8 +3392,6 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++) runtime[backend_id] = 0; - for (component_id = 0; component_id < GC_COMPONENT_NR; component_id++) - used_components[component_id] = 0; config = fopen (fname, "r"); if (!config) @@ -3621,9 +3618,6 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, if (defaults) { - assert (component_id >= 0 && component_id < GC_COMPONENT_NR); - used_components[component_id] = 1; - /* Here we explicitly allow to update the value again. */ if (newflags) { From 585d5c62eece23911a768d97d11f159be138b13d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Feb 2013 10:56:13 +0100 Subject: [PATCH 09/19] Use has_leading_keyword in the assuan callbacks. * agent/call-pinentry.c (inq_quality): Use has_leading_keyword. * agent/call-scd.c (inq_needpin, inq_writekey_parms): Ditto. * g10/call-agent.c (inq_writecert_parms, keyinfo_status_cb): Ditto. (inq_genkey_parms, inq_ciphertext_cb, inq_import_key_parms): Ditto. * g10/call-dirmngr.c (ks_put_inq_cb): Ditto. * sm/call-agent.c (default_inq_cb, inq_ciphertext_cb): Ditto. (inq_genkey_parms, istrusted_status_cb, learn_status_cb): Ditto. (keyinfo_status_cb, inq_import_key_parms): Ditto. * sm/call-dirmngr.c (inq_certificate, isvalid_status_cb): Ditto. (lookup_status_cb, run_command_inq_cb, run_command_status_cb): Ditto. --- agent/call-pinentry.c | 9 ++---- agent/call-scd.c | 22 +++++---------- g10/call-agent.c | 14 +++++----- g10/call-dirmngr.c | 4 +-- sm/call-agent.c | 28 +++++++++---------- sm/call-dirmngr.c | 64 +++++++++++++++++++------------------------ 6 files changed, 61 insertions(+), 80 deletions(-) diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index c6b6b5282..78e1c1106 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -596,18 +596,15 @@ static gpg_error_t inq_quality (void *opaque, const char *line) { assuan_context_t ctx = opaque; + const char *s; char *pin; int rc; int percent; char numbuf[20]; - if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7])) + if ((s = has_leading_keyword (line, "QUALITY"))) { - line += 7; - while (*line == ' ') - line++; - - pin = unescape_passphrase_string (line); + pin = unescape_passphrase_string (s); if (!pin) rc = gpg_error_from_syserror (); else diff --git a/agent/call-scd.c b/agent/call-scd.c index cbe4d1c34..f4ea20bd3 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -701,17 +701,15 @@ static gpg_error_t inq_needpin (void *opaque, const char *line) { struct inq_needpin_s *parm = opaque; + const char *s; char *pin; size_t pinlen; int rc; parm->any_inq_seen = 1; - if (!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])) + if ((s = has_leading_keyword (line, "NEEDPIN"))) { - line += 7; - while (*line == ' ') - line++; - + line = s; pinlen = 90; pin = gcry_malloc_secure (pinlen); if (!pin) @@ -722,17 +720,11 @@ inq_needpin (void *opaque, const char *line) rc = assuan_send_data (parm->ctx, pin, pinlen); xfree (pin); } - else if (!strncmp (line, "POPUPPINPADPROMPT", 17) - && (line[17] == ' ' || !line[17])) + else if ((s = has_leading_keyword (line, "POPUPPINPADPROMPT"))) { - line += 17; - while (*line == ' ') - line++; - - rc = parm->getpin_cb (parm->getpin_cb_arg, line, NULL, 1); + rc = parm->getpin_cb (parm->getpin_cb_arg, s, NULL, 1); } - else if (!strncmp (line, "DISMISSPINPADPROMPT", 19) - && (line[19] == ' ' || !line[19])) + else if ((s = has_leading_keyword (line, "DISMISSPINPADPROMPT"))) { rc = parm->getpin_cb (parm->getpin_cb_arg, "", NULL, 0); } @@ -1069,7 +1061,7 @@ inq_writekey_parms (void *opaque, const char *line) { struct writekey_parm_s *parm = opaque; - if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) + if (has_leading_keyword (line, "KEYDATA")) return assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen); else return inq_needpin (opaque, line); diff --git a/g10/call-agent.c b/g10/call-agent.c index 908d2761c..cb965e9ad 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -725,7 +725,7 @@ inq_writecert_parms (void *opaque, const char *line) int rc; struct writecert_parm_s *parm = opaque; - if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8])) + if (has_leading_keyword (line, "CERTDATA")) { rc = assuan_send_data (parm->dflt->ctx, parm->certdata, parm->certdatalen); @@ -778,7 +778,7 @@ inq_writekey_parms (void *opaque, const char *line) int rc; struct writekey_parm_s *parm = opaque; - if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) + if (has_leading_keyword (line, "KEYDATA")) { rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen); } @@ -1471,9 +1471,9 @@ keyinfo_status_cb (void *opaque, const char *line) char **serialno = opaque; const char *s, *s2; - if (!strncmp (line, "KEYINFO ", 8) && !*serialno) + if ((s = has_leading_keyword (line, "KEYINFO ")) && !*serialno) { - s = strchr (line+8, ' '); + s = strchr (s, ' '); if (s && s[1] == 'T' && s[2] == ' ' && s[3]) { s += 3; @@ -1575,7 +1575,7 @@ inq_genkey_parms (void *opaque, const char *line) struct genkey_parm_s *parm = opaque; gpg_error_t err; - if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8])) + if (has_leading_keyword (line, "KEYPARAM")) { err = assuan_send_data (parm->dflt->ctx, parm->keyparms, strlen (parm->keyparms)); @@ -1802,7 +1802,7 @@ inq_ciphertext_cb (void *opaque, const char *line) struct cipher_parm_s *parm = opaque; int rc; - if (!strncmp (line, "CIPHERTEXT", 10) && (line[10]==' '||!line[10])) + if (has_leading_keyword (line, "CIPHERTEXT")) { assuan_begin_confidential (parm->ctx); rc = assuan_send_data (parm->dflt->ctx, @@ -1984,7 +1984,7 @@ inq_import_key_parms (void *opaque, const char *line) struct import_key_parm_s *parm = opaque; gpg_error_t err; - if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) + if (has_leading_keyword (line, "KEYDATA")) { err = assuan_send_data (parm->dflt->ctx, parm->key, parm->keylen); } diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index 09ade4eb9..75f25f8a4 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -515,12 +515,12 @@ ks_put_inq_cb (void *opaque, const char *line) struct ks_put_parm_s *parm = opaque; gpg_error_t err = 0; - if (!strncmp (line, "KEYBLOCK", 8) && (line[8] == ' ' || !line[8])) + if (has_leading_keyword (line, "KEYBLOCK")) { if (parm->data) err = assuan_send_data (parm->ctx, parm->data, parm->datalen); } - else if (!strncmp (line, "KEYBLOCK_INFO", 13) && (line[13]==' ' || !line[13])) + else if (has_leading_keyword (line, "KEYBLOCK_INFO")) { kbnode_t node; estream_t fp; diff --git a/sm/call-agent.c b/sm/call-agent.c index acf6c04ad..f99caade4 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -138,7 +138,7 @@ default_inq_cb (void *opaque, const char *line) gpg_error_t err; ctrl_t ctrl = opaque; - if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) + if (has_leading_keyword (line, "PINENTRY_LAUNCHED")) { err = gpgsm_proxy_pinentry_notify (ctrl, line); if (err) @@ -315,7 +315,7 @@ inq_ciphertext_cb (void *opaque, const char *line) struct cipher_parm_s *parm = opaque; int rc; - if (!strncmp (line, "CIPHERTEXT", 10) && (line[10]==' '||!line[10])) + if (has_leading_keyword (line, "CIPHERTEXT")) { assuan_begin_confidential (parm->ctx); rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen); @@ -437,7 +437,7 @@ inq_genkey_parms (void *opaque, const char *line) struct genkey_parm_s *parm = opaque; int rc; - if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8])) + if (has_leading_keyword (line, "KEYPARAM")) { rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen); } @@ -693,14 +693,14 @@ static gpg_error_t istrusted_status_cb (void *opaque, const char *line) { struct rootca_flags_s *flags = opaque; + const char *s; - if (!strncmp (line, "TRUSTLISTFLAG", 13) && (line[13]==' ' || !line[13])) + if ((s = has_leading_keyword (line, "TRUSTLISTFLAG"))) { - for (line += 13; *line == ' '; line++) - ; - if (!strncmp (line, "relax", 5) && (line[5] == ' ' || !line[5])) + line = s; + if (has_leading_keyword (line, "relax")) flags->relax = 1; - else if (!strncmp (line, "cm", 2) && (line[2] == ' ' || !line[2])) + else if (has_leading_keyword (line, "cm")) flags->chain_model = 1; } return 0; @@ -824,14 +824,14 @@ static gpg_error_t learn_status_cb (void *opaque, const char *line) { struct learn_parm_s *parm = opaque; + const char *s; /* Pass progress data to the caller. */ - if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8])) + if ((s = has_leading_keyword (line, "PROGRESS"))) { + line = s; if (parm->ctrl) { - for (line += 8; *line == ' '; line++) - ; if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line)) return gpg_error (GPG_ERR_ASS_CANCELED); } @@ -1017,9 +1017,9 @@ keyinfo_status_cb (void *opaque, const char *line) char **serialno = opaque; const char *s, *s2; - if (!strncmp (line, "KEYINFO ", 8) && !*serialno) + if ((s = has_leading_keyword (line, "KEYINFO")) && !*serialno) { - s = strchr (line+8, ' '); + s = strchr (s, ' '); if (s && s[1] == 'T' && s[2] == ' ' && s[3]) { s += 3; @@ -1172,7 +1172,7 @@ inq_import_key_parms (void *opaque, const char *line) struct import_key_parm_s *parm = opaque; gpg_error_t err; - if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) + if (has_leading_keyword (line, "KEYDATA")) { assuan_begin_confidential (parm->ctx); err = assuan_send_data (parm->ctx, parm->key, parm->keylen); diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index b7417a368..99a14c0e7 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -282,47 +282,40 @@ static gpg_error_t inq_certificate (void *opaque, const char *line) { struct inq_certificate_parm_s *parm = opaque; + const char *s; int rc; + size_t n; const unsigned char *der; size_t derlen; int issuer_mode = 0; ksba_sexp_t ski = NULL; - if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8])) + if ((s = has_leading_keyword (line, "SENDCERT"))) { - line += 8; + line = s; } - else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12])) + else if ((s = has_leading_keyword (line, "SENDCERT_SKI"))) { - size_t n; - /* Send a certificate where a sourceKeyIdentifier is included. */ - line += 12; - while (*line == ' ') - line++; + line = s; ski = make_simple_sexp_from_hexstr (line, &n); line += n; while (*line == ' ') line++; } - else if (!strncmp (line, "SENDISSUERCERT", 14) - && (line[14] == ' ' || !line[14])) + else if ((s = has_leading_keyword (line, "SENDISSUERCERT"))) { - line += 14; + line = s; issuer_mode = 1; } - else if (!strncmp (line, "ISTRUSTED", 9) && (line[9]==' ' || !line[9])) + else if ((s = has_leading_keyword (line, "ISTRUSTED"))) { /* The server is asking us whether the certificate is a trusted root certificate. */ - const char *s; - size_t n; char fpr[41]; struct rootca_flags_s rootca_flags; - line += 9; - while (*line == ' ') - line++; + line = s; for (s=line,n=0; hexdigitp (s); s++, n++) ; @@ -410,22 +403,21 @@ static gpg_error_t isvalid_status_cb (void *opaque, const char *line) { struct isvalid_status_parm_s *parm = opaque; + const char *s; - if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8])) + if ((s = has_leading_keyword (line, "PROGRESS"))) { if (parm->ctrl) { - for (line += 8; *line == ' '; line++) - ; + line = s; if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line)) return gpg_error (GPG_ERR_ASS_CANCELED); } } - else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24) - && (line[24]==' ' || !line[24])) + else if ((s = has_leading_keyword (line, "ONLY_VALID_IF_CERT_VALID"))) { parm->seen++; - if (!line[24] || !unhexify_fpr (line+25, parm->fpr)) + if (!*s || !unhexify_fpr (s, parm->fpr)) parm->seen++; /* Bumb it to indicate an error. */ } return 0; @@ -693,23 +685,22 @@ static gpg_error_t lookup_status_cb (void *opaque, const char *line) { struct lookup_parm_s *parm = opaque; + const char *s; - if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8])) + if ((s = has_leading_keyword (line, "PROGRESS"))) { if (parm->ctrl) { - for (line += 8; *line == ' '; line++) - ; + line = s; if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line)) return gpg_error (GPG_ERR_ASS_CANCELED); } } - else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9])) + else if ((s = has_leading_keyword (line, "TRUNCATED"))) { if (parm->ctrl) { - for (line +=9; *line == ' '; line++) - ; + line = s; gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line); } } @@ -878,16 +869,17 @@ static gpg_error_t run_command_inq_cb (void *opaque, const char *line) { struct run_command_parm_s *parm = opaque; + const char *s; int rc = 0; - if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) ) + if ((s = has_leading_keyword (line, "SENDCERT"))) { /* send the given certificate */ int err; ksba_cert_t cert; const unsigned char *der; size_t derlen; - line += 8; + line = s; if (!*line) return gpg_error (GPG_ERR_ASS_PARAMETER); @@ -907,9 +899,9 @@ run_command_inq_cb (void *opaque, const char *line) ksba_cert_release (cert); } } - else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) ) + else if ((s = has_leading_keyword (line, "PRINTINFO"))) { /* Simply show the message given in the argument. */ - line += 9; + line = s; log_info ("dirmngr: %s\n", line); } else @@ -925,17 +917,17 @@ static gpg_error_t run_command_status_cb (void *opaque, const char *line) { ctrl_t ctrl = opaque; + const char *s; if (opt.verbose) { log_info ("dirmngr status: %s\n", line); } - if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8])) + if ((s = has_leading_keyword (line, "PROGRESS"))) { if (ctrl) { - for (line += 8; *line == ' '; line++) - ; + line = s; if (gpgsm_status (ctrl, STATUS_PROGRESS, line)) return gpg_error (GPG_ERR_ASS_CANCELED); } From ef1983d58b913306e9bf02a7189e530123839c59 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 28 Feb 2013 11:17:47 +0900 Subject: [PATCH 10/19] agent: pksign result conversion to sexp to upper layer. * agent/agent.h (divert_pksign): Add R_SIGLEN argument. * agent/divert-scd.c (divert_pksign): Return length at R_SIGLEN. * agent/call-scd.c (agent_card_pksign): Move composition of S-expression to... * agent/pksign.c (agent_pksign_do): ... here. -- Composing S-expression would be better to be done by SCDaemon. --- agent/agent.h | 3 +- agent/call-scd.c | 29 ++------------- agent/divert-scd.c | 8 +++- agent/pksign.c | 92 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 97 insertions(+), 35 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 030b29520..2fd0b8b8a 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -405,7 +405,8 @@ void agent_reload_trustlist (void); /*-- divert-scd.c --*/ int divert_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, int algo, - const unsigned char *shadow_info, unsigned char **r_sig); + const unsigned char *shadow_info, unsigned char **r_sig, + size_t *r_siglen); int divert_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, diff --git a/agent/call-scd.c b/agent/call-scd.c index f4ea20bd3..a334b15a1 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -825,10 +825,6 @@ agent_card_pksign (ctrl_t ctrl, char *p, line[ASSUAN_LINELENGTH]; membuf_t data; struct inq_needpin_s inqparm; - size_t len; - unsigned char *sigbuf; - size_t sigbuflen; - int prepend_nul; *r_buf = NULL; rc = start_scd (ctrl); @@ -868,32 +864,13 @@ agent_card_pksign (ctrl_t ctrl, if (rc) { + size_t len; + xfree (get_membuf (&data, &len)); return unlock_scd (ctrl, rc); } - sigbuf = get_membuf (&data, &sigbuflen); - /* Create an S-expression from it which is formatted like this: - "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))". We better make sure - that this won't be interpreted as a negative number. */ - prepend_nul = (sigbuflen && (*sigbuf & 0x80)); - - *r_buflen = 21 + 11 + prepend_nul + sigbuflen + 4; - p = xtrymalloc (*r_buflen); - *r_buf = (unsigned char*)p; - if (!p) - return unlock_scd (ctrl, out_of_core ()); - p = stpcpy (p, "(7:sig-val(3:rsa(1:s" ); - sprintf (p, "%u:", (unsigned int)sigbuflen + prepend_nul); - p += strlen (p); - if (prepend_nul) - *p++ = 0; - memcpy (p, sigbuf, sigbuflen); - p += sigbuflen; - strcpy (p, ")))"); - xfree (sigbuf); - - assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL)); + *r_buf = get_membuf (&data, r_buflen); return unlock_scd (ctrl, 0); } diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 5fb037ee5..f0d847389 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -335,7 +335,8 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) int divert_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, int algo, - const unsigned char *shadow_info, unsigned char **r_sig) + const unsigned char *shadow_info, unsigned char **r_sig, + size_t *r_siglen) { int rc; char *kid; @@ -369,7 +370,10 @@ divert_pksign (ctrl_t ctrl, } if (!rc) - *r_sig = sigval; + { + *r_sig = sigval; + *r_siglen = siglen; + } xfree (kid); diff --git a/agent/pksign.c b/agent/pksign.c index dc44b881d..85187305c 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -278,24 +278,104 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, if (!s_skey) { /* Divert operation to the smartcard */ - + gcry_sexp_t s_pkey, l; + const char *name; + size_t len; unsigned char *buf = NULL; - size_t len = 0; + int is_RSA = 0; + int is_ECDSA = 0; + + /* Check keytype by public key */ + rc = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey); + if (rc) + { + log_error ("failed to read the public key\n"); + goto leave; + } + l = gcry_sexp_cadr (s_pkey); + name = gcry_sexp_nth_data (l, 0, &len); + if (len == 3 && !memcmp (name, "rsa", 3)) + is_RSA = 1; + else if (len == 5 && !memcmp (name, "ecdsa", 5)) + is_ECDSA = 1; + gcry_sexp_release (l); + gcry_sexp_release (s_pkey); rc = divert_pksign (ctrl, ctrl->digest.value, ctrl->digest.valuelen, ctrl->digest.algo, - shadow_info, &buf); + shadow_info, &buf, &len); if (rc) { log_error ("smartcard signing failed: %s\n", gpg_strerror (rc)); goto leave; } - len = gcry_sexp_canon_len (buf, 0, NULL, NULL); - assert (len); - rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len); + if (is_RSA) + { + if (*buf & 0x80) + { + len++; + buf = xtryrealloc (buf, len); + if (!buf) + goto leave; + + memmove (buf + 1, buf, len - 1); + *buf = 0; + } + + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf); + } + else if (is_ECDSA) + { + unsigned char *r_buf_allocated = NULL; + unsigned char *s_buf_allocated = NULL; + unsigned char *r_buf, *s_buf; + int r_buflen, s_buflen; + + r_buflen = s_buflen = len/2; + + if (*buf & 0x80) + { + r_buflen++; + r_buf_allocated = xtrymalloc (r_buflen); + if (!r_buf_allocated) + goto leave; + + r_buf = r_buf_allocated; + memcpy (r_buf + 1, buf, len/2); + *r_buf = 0; + } + else + r_buf = buf; + + if (*(buf + len/2) & 0x80) + { + s_buflen++; + s_buf_allocated = xtrymalloc (s_buflen); + if (!s_buf_allocated) + { + xfree (r_buf_allocated); + goto leave; + } + + s_buf = s_buf_allocated; + memcpy (s_buf + 1, buf + len/2, len/2); + *s_buf = 0; + } + else + s_buf = buf + len/2; + + rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", + r_buflen, r_buf, + s_buflen, s_buf); + xfree (r_buf_allocated); + xfree (s_buf_allocated); + } + else + rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + xfree (buf); if (rc) { From 5bac5040dc93343e1e89916b263390b0e52040bf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 25 Feb 2013 13:40:10 +0100 Subject: [PATCH 11/19] Require libgpg-error 1.11. * configure.ac: Require libgpg-error 1.11. * common/util.h (GPG_ERR_NO_KEYSERVER, GPG_ERR_INV_CURVE) (GPG_ERR_UNKNOWN_CURVE): Remove fallback definitions. --- common/util.h | 10 ---------- configure.ac | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/common/util.h b/common/util.h index c8a008fd7..73ba84e41 100644 --- a/common/util.h +++ b/common/util.h @@ -34,16 +34,6 @@ #include /* We need this for the memory function protos. */ #include /* We need errno. */ #include /* We need gpg_error_t. */ -/* Add error codes available only in newer versions of libgpg-error. */ -#ifndef GPG_ERR_NO_KEYSERVER -#define GPG_ERR_NO_KEYSERVER 186 -#endif -#ifndef GPG_ERR_INV_CURVE -#define GPG_ERR_INV_CURVE 187 -#endif -#ifndef GPG_ERR_UNKNOWN_CURVE -#define GPG_ERR_UNKNOWN_CURVE 188 -#endif /* Hash function used with libksba. */ diff --git a/configure.ac b/configure.ac index cf5ab3fa6..353546a09 100644 --- a/configure.ac +++ b/configure.ac @@ -43,7 +43,7 @@ m4_define([mym4_full_version],[mym4_version[]mym4_betastring]) AC_INIT([gnupg],[mym4_full_version], [http://bugs.gnupg.org]) -NEED_GPG_ERROR_VERSION=1.10 +NEED_GPG_ERROR_VERSION=1.11 NEED_LIBGCRYPT_API=1 NEED_LIBGCRYPT_VERSION=1.5.0 From 5132ea8a0d8517dd43cb5b4a4b0921c3b1ca291c Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 5 Mar 2013 04:24:54 -0500 Subject: [PATCH 12/19] Update RFC references to RFC 4880 -- --- doc/gpg.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index cf647e19b..0462c9e45 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2418,7 +2418,7 @@ check. @code{value} may be any printable string; it will be encoded in UTF8, so you should check that your @option{--display-charset} is set correctly. If you prefix @code{name} with an exclamation mark (!), the notation data will be flagged as critical -(rfc2440:5.2.3.15). @option{--sig-notation} sets a notation for data +(rfc4880:5.2.3.16). @option{--sig-notation} sets a notation for data signatures. @option{--cert-notation} sets a notation for key signatures (certifications). @option{--set-notation} sets both. @@ -2440,7 +2440,7 @@ meaningful when using the OpenPGP smartcard. @opindex sig-policy-url @opindex cert-policy-url @opindex set-policy-url -Use @code{string} as a Policy URL for signatures (rfc2440:5.2.3.19). If +Use @code{string} as a Policy URL for signatures (rfc4880:5.2.3.20). If you prefix it with an exclamation mark (!), the policy URL packet will be flagged as critical. @option{--sig-policy-url} sets a policy url for data signatures. @option{--cert-policy-url} sets a policy url for key From 010bc7f4f06d8affb98950e1adc76c68bfcc9abb Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 8 Mar 2013 11:40:37 +0900 Subject: [PATCH 13/19] scd: support ECDSA public key. * scd/app-openpgp.c (key_type_t): New. (CURVE_NIST_P256, CURVE_NIST_P384, CURVE_NIST_P521): New. (struct app_local_s): Change keyattr to have key_type and union. (get_ecc_key_parameters, get_curve_name): New. (send_key_attr, get_public_key): Support ECDSA. (build_privkey_template, do_writekey, do_genkey): Follow the change of the member KEY_ATTR. (parse_historical): New. (parse_algorithm_attribute): Support ECDSA. -- Add ECDSA support to OpenPGP card. --- scd/app-openpgp.c | 354 +++++++++++++++++++++++++++++++++------------- 1 file changed, 257 insertions(+), 97 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 23b28c3f5..8d507c4ed 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -116,6 +116,16 @@ static struct { }; +/* Type of keys. */ +typedef enum + { + KEY_TYPE_ECDH, + KEY_TYPE_ECDSA, + KEY_TYPE_RSA, + } +key_type_t; + + /* The format of RSA private keys. */ typedef enum { @@ -128,6 +138,15 @@ typedef enum rsa_key_format_t; +/* Elliptic Curves. */ +enum + { + CURVE_NIST_P256, + CURVE_NIST_P384, + CURVE_NIST_P521 + }; + + /* One cache item for DOs. */ struct cache_s { struct cache_s *next; @@ -199,15 +218,27 @@ struct app_local_s { int fixedlen_admin; } pinpad; - struct - { - unsigned int n_bits; /* Size of the modulus in bits. The rest - of this strucuire is only valid if - this is not 0. */ - unsigned int e_bits; /* Size of the public exponent in bits. */ - rsa_key_format_t format; - } keyattr[3]; - + struct + { + key_type_t key_type; + union { + struct { + unsigned int n_bits; /* Size of the modulus in bits. The rest + of this strucuire is only valid if + this is not 0. */ + unsigned int e_bits; /* Size of the public exponent in bits. */ + rsa_key_format_t format; + } rsa; + struct { + int curve; + } ecdsa; + struct { + int curve; + int hashalgo; + int cipheralgo; + } ecdh; + }; + } keyattr[3]; }; @@ -844,19 +875,60 @@ send_key_data (ctrl_t ctrl, const char *name, } +static void +get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid) +{ + if (curve == CURVE_NIST_P256) + { + *r_n_bits = 256; + *r_curve_oid = "1.2.840.10045.3.1.7"; + } + else if (curve == CURVE_NIST_P384) + { + *r_n_bits = 384; + *r_curve_oid = "1.3.132.0.34"; + } + else + { + *r_n_bits = 521; + *r_curve_oid = "1.3.132.0.35"; + } +} + static void send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int number) { char buffer[200]; + int n_bits; + const char *curve_oid; assert (number >=0 && number < DIM(app->app_local->keyattr)); - /* We only support RSA thus the algo identifier is fixed to 1. */ - snprintf (buffer, sizeof buffer, "%d 1 %u %u %d", - number+1, - app->app_local->keyattr[number].n_bits, - app->app_local->keyattr[number].e_bits, - app->app_local->keyattr[number].format); + if (app->app_local->keyattr[number].key_type == KEY_TYPE_RSA) + snprintf (buffer, sizeof buffer, "%d 1 %u %u %d", + number+1, + app->app_local->keyattr[number].rsa.n_bits, + app->app_local->keyattr[number].rsa.e_bits, + app->app_local->keyattr[number].rsa.format); + else if (app->app_local->keyattr[number].key_type == KEY_TYPE_ECDSA) + { + get_ecc_key_parameters (app->app_local->keyattr[number].ecdsa.curve, + &n_bits, &curve_oid); + snprintf (buffer, sizeof buffer, "%d 19 %u %s", + number+1, n_bits, curve_oid); + } + else if (app->app_local->keyattr[number].key_type == KEY_TYPE_ECDH) + { + get_ecc_key_parameters (app->app_local->keyattr[number].ecdh.curve, + &n_bits, &curve_oid); + snprintf (buffer, sizeof buffer, "%d 18 %u %s %d %d", + number+1, n_bits, curve_oid, + app->app_local->keyattr[number].ecdh.hashalgo, + app->app_local->keyattr[number].ecdh.cipheralgo); + } + else + snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); + send_status_direct (ctrl, keyword, buffer); } @@ -1154,6 +1226,18 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, #endif /*GNUPG_MAJOR_VERSION > 1*/ +static const char * +get_curve_name (int curve) +{ + if (curve == CURVE_NIST_P256) + return "NIST P-256"; + else if (curve == CURVE_NIST_P384) + return "NIST P-384"; + else + return "NIST P-521"; +} + + /* Get the public key for KEYNO and store it as an S-expresion with the APP handle. On error that field gets cleared. If we already know about the public key we will just return. Note that this does @@ -1171,11 +1255,14 @@ get_public_key (app_t app, int keyno) gpg_error_t err = 0; unsigned char *buffer; const unsigned char *keydata, *m, *e; - size_t buflen, keydatalen, mlen, elen; + size_t buflen, keydatalen; + size_t mlen = 0; + size_t elen = 0; unsigned char *mbuf = NULL; unsigned char *ebuf = NULL; char *keybuf = NULL; - char *keybuf_p; + gcry_sexp_t s_pkey; + size_t len; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -1227,51 +1314,34 @@ get_public_key (app_t app, int keyno) goto leave; } - m = find_tlv (keydata, keydatalen, 0x0081, &mlen); - if (!m) + if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) { - err = gpg_error (GPG_ERR_CARD); - log_error (_("response does not contain the RSA modulus\n")); - goto leave; - } - - - e = find_tlv (keydata, keydatalen, 0x0082, &elen); - if (!e) - { - err = gpg_error (GPG_ERR_CARD); - log_error (_("response does not contain the RSA public exponent\n")); - goto leave; - } - - /* Prepend numbers with a 0 if needed. */ - if (mlen && (*m & 0x80)) - { - mbuf = xtrymalloc ( mlen + 1); - if (!mbuf) + m = find_tlv (keydata, keydatalen, 0x0081, &mlen); + if (!m) { - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the RSA modulus\n")); goto leave; } - *mbuf = 0; - memcpy (mbuf+1, m, mlen); - mlen++; - m = mbuf; - } - if (elen && (*e & 0x80)) - { - ebuf = xtrymalloc ( elen + 1); - if (!ebuf) + + e = find_tlv (keydata, keydatalen, 0x0082, &elen); + if (!e) { - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the RSA public exponent\n")); + goto leave; + } + } + else + { + m = find_tlv (keydata, keydatalen, 0x0086, &mlen); + if (!m) + { + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the EC public point\n")); goto leave; } - *ebuf = 0; - memcpy (ebuf+1, e, elen); - elen++; - e = ebuf; } - } else { @@ -1328,29 +1398,88 @@ get_public_key (app_t app, int keyno) } } - /* Allocate a buffer to construct the S-expression. */ - /* FIXME: We should provide a generalized S-expression creation - mechanism. */ - keybuf = xtrymalloc (50 + 2*35 + mlen + elen + 1); - if (!keybuf) + + mbuf = xtrymalloc ( mlen + 1); + if (!mbuf) { err = gpg_error_from_syserror (); goto leave; } + /* Prepend numbers with a 0 if needed. */ + if (mlen && (*m & 0x80)) + { + *mbuf = 0; + memcpy (mbuf+1, m, mlen); + mlen++; + } + else + memcpy (mbuf, m, mlen); - sprintf (keybuf, "(10:public-key(3:rsa(1:n%u:", (unsigned int) mlen); - keybuf_p = keybuf + strlen (keybuf); - memcpy (keybuf_p, m, mlen); - keybuf_p += mlen; - sprintf (keybuf_p, ")(1:e%u:", (unsigned int)elen); - keybuf_p += strlen (keybuf_p); - memcpy (keybuf_p, e, elen); - keybuf_p += elen; - strcpy (keybuf_p, ")))"); - keybuf_p += strlen (keybuf_p); + ebuf = xtrymalloc ( elen + 1); + if (!ebuf) + { + err = gpg_error_from_syserror (); + goto leave; + } + /* Prepend numbers with a 0 if needed. */ + if (elen && (*e & 0x80)) + { + *ebuf = 0; + memcpy (ebuf+1, e, elen); + elen++; + } + else + memcpy (ebuf, e, elen); + + if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) + { + err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))", + mlen, mbuf, elen, ebuf); + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + keybuf = xtrymalloc (len); + if (!keybuf) + { + gcry_sexp_release (s_pkey); + err = gpg_error_from_syserror (); + goto leave; + } + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); + gcry_sexp_release (s_pkey); + } + else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECDSA) + { + const char *curve_name + = get_curve_name (app->app_local->keyattr[keyno].ecdsa.curve); + + err = gcry_sexp_build (&s_pkey, NULL, + "(public-key(ecdsa(curve%s)(q%b)))", + curve_name, mlen, mbuf); + if (err) + goto leave; + + len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); + + keybuf = xtrymalloc (len); + if (!keybuf) + { + gcry_sexp_release (s_pkey); + err = gpg_error_from_syserror (); + goto leave; + } + gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len); + gcry_sexp_release (s_pkey); + } + else + { + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + goto leave; + } app->app_local->pk[keyno].key = (unsigned char*)keybuf; - app->app_local->pk[keyno].keylen = (keybuf_p - keybuf); + app->app_local->pk[keyno].keylen = len - 1; /* Decrement for trailing '\0' */ leave: /* Set a flag to indicate that we tried to read the key. */ @@ -2395,7 +2524,7 @@ build_privkey_template (app_t app, int keyno, *result = NULL; *resultlen = 0; - switch (app->app_local->keyattr[keyno].format) + switch (app->app_local->keyattr[keyno].rsa.format) { case RSA_STD: case RSA_STD_N: @@ -2409,7 +2538,7 @@ build_privkey_template (app_t app, int keyno, } /* Get the required length for E. */ - rsa_e_reqlen = app->app_local->keyattr[keyno].e_bits/8; + rsa_e_reqlen = app->app_local->keyattr[keyno].rsa.e_bits/8; assert (rsa_e_len <= rsa_e_reqlen); /* Build the 7f48 cardholder private key template. */ @@ -2425,8 +2554,8 @@ build_privkey_template (app_t app, int keyno, tp += add_tlv (tp, 0x93, rsa_q_len); datalen += rsa_q_len; - if (app->app_local->keyattr[keyno].format == RSA_STD_N - || app->app_local->keyattr[keyno].format == RSA_CRT_N) + if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N + || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N) { tp += add_tlv (tp, 0x97, rsa_n_len); datalen += rsa_n_len; @@ -2478,8 +2607,8 @@ build_privkey_template (app_t app, int keyno, memcpy (tp, rsa_q, rsa_q_len); tp += rsa_q_len; - if (app->app_local->keyattr[keyno].format == RSA_STD_N - || app->app_local->keyattr[keyno].format == RSA_CRT_N) + if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N + || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N) { memcpy (tp, rsa_n, rsa_n_len); tp += rsa_n_len; @@ -2764,7 +2893,7 @@ do_writekey (app_t app, ctrl_t ctrl, goto leave; } - maxbits = app->app_local->keyattr[keyno].n_bits; + maxbits = app->app_local->keyattr[keyno].rsa.n_bits; nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0; if (opt.verbose) log_info ("RSA modulus size is %u bits (%u bytes)\n", @@ -2775,7 +2904,7 @@ do_writekey (app_t app, ctrl_t ctrl, /* Try to switch the key to a new length. */ err = change_keyattr (app, keyno, nbits, pincb, pincb_arg); if (!err) - maxbits = app->app_local->keyattr[keyno].n_bits; + maxbits = app->app_local->keyattr[keyno].rsa.n_bits; } if (nbits != maxbits) { @@ -2785,7 +2914,7 @@ do_writekey (app_t app, ctrl_t ctrl, goto leave; } - maxbits = app->app_local->keyattr[keyno].e_bits; + maxbits = app->app_local->keyattr[keyno].rsa.e_bits; if (maxbits > 32 && !app->app_local->extcap.is_v2) maxbits = 32; /* Our code for v1 does only support 32 bits. */ nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0; @@ -2797,7 +2926,7 @@ do_writekey (app_t app, ctrl_t ctrl, goto leave; } - maxbits = app->app_local->keyattr[keyno].n_bits/2; + maxbits = app->app_local->keyattr[keyno].rsa.n_bits/2; nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0; if (nbits != maxbits) { @@ -2966,7 +3095,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, to put a limit on the max. allowed keysize. 2048 bit will already lead to a 527 byte long status line and thus a 4096 bit key would exceed the Assuan line length limit. */ - keybits = app->app_local->keyattr[keyno].n_bits; + keybits = app->app_local->keyattr[keyno].rsa.n_bits; if (keybits > 4096) return gpg_error (GPG_ERR_TOO_LARGE); @@ -3753,6 +3882,22 @@ parse_historical (struct app_local_s *apploc, } +static int +parse_ecc_curve (const unsigned char *buffer, size_t buflen) +{ + int curve; + + if (buflen == 6 && buffer[5] == 0x22) + curve = CURVE_NIST_P384; + else if (buflen == 6 && buffer[5] == 0x23) + curve = CURVE_NIST_P521; + else + curve = CURVE_NIST_P256; + + return curve; +} + + /* Parse and optionally show the algorithm attributes for KEYNO. KEYNO must be in the range 0..2. */ static void @@ -3765,7 +3910,8 @@ parse_algorithm_attribute (app_t app, int keyno) assert (keyno >=0 && keyno <= 2); - app->app_local->keyattr[keyno].n_bits = 0; + app->app_local->keyattr[keyno].key_type = KEY_TYPE_RSA; + app->app_local->keyattr[keyno].rsa.n_bits = 0; relptr = get_one_do (app, 0xC1+keyno, &buffer, &buflen, NULL); if (!relptr) @@ -3784,27 +3930,41 @@ parse_algorithm_attribute (app_t app, int keyno) log_info ("Key-Attr-%s ..: ", desc[keyno]); if (*buffer == 1 && (buflen == 5 || buflen == 6)) { - app->app_local->keyattr[keyno].n_bits = (buffer[1]<<8 | buffer[2]); - app->app_local->keyattr[keyno].e_bits = (buffer[3]<<8 | buffer[4]); - app->app_local->keyattr[keyno].format = 0; + app->app_local->keyattr[keyno].rsa.n_bits = (buffer[1]<<8 | buffer[2]); + app->app_local->keyattr[keyno].rsa.e_bits = (buffer[3]<<8 | buffer[4]); + app->app_local->keyattr[keyno].rsa.format = 0; if (buflen < 6) - app->app_local->keyattr[keyno].format = RSA_STD; + app->app_local->keyattr[keyno].rsa.format = RSA_STD; else - app->app_local->keyattr[keyno].format = (buffer[5] == 0? RSA_STD : - buffer[5] == 1? RSA_STD_N : - buffer[5] == 2? RSA_CRT : - buffer[5] == 3? RSA_CRT_N : - RSA_UNKNOWN_FMT); + app->app_local->keyattr[keyno].rsa.format = (buffer[5] == 0? RSA_STD : + buffer[5] == 1? RSA_STD_N : + buffer[5] == 2? RSA_CRT : + buffer[5] == 3? RSA_CRT_N : + RSA_UNKNOWN_FMT); if (opt.verbose) log_printf ("RSA, n=%u, e=%u, fmt=%s\n", - app->app_local->keyattr[keyno].n_bits, - app->app_local->keyattr[keyno].e_bits, - app->app_local->keyattr[keyno].format == RSA_STD? "std" : - app->app_local->keyattr[keyno].format == RSA_STD_N?"std+n": - app->app_local->keyattr[keyno].format == RSA_CRT? "crt" : - app->app_local->keyattr[keyno].format == RSA_CRT_N?"crt+n":"?"); + app->app_local->keyattr[keyno].rsa.n_bits, + app->app_local->keyattr[keyno].rsa.e_bits, + app->app_local->keyattr[keyno].rsa.format == RSA_STD? "std" : + app->app_local->keyattr[keyno].rsa.format == RSA_STD_N?"std+n": + app->app_local->keyattr[keyno].rsa.format == RSA_CRT? "crt" : + app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N?"crt+n":"?"); + } + else if (*buffer == 19) /* ECDSA */ + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDSA; + app->app_local->keyattr[keyno].ecdsa.curve + = parse_ecc_curve (buffer + 1, buflen - 1); + } + else if (*buffer == 18 && buflen == 11) /* ECDH */ + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDH; + app->app_local->keyattr[keyno].ecdh.curve + = parse_ecc_curve (buffer + 1, buflen - 1); + app->app_local->keyattr[keyno].ecdh.hashalgo = buffer[1]; + app->app_local->keyattr[keyno].ecdh.cipheralgo = buffer[2]; } else if (opt.verbose) log_printhex ("", buffer, buflen); From 73ad742deacfe2bf7d6efc7cc30f9ced2d83521a Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Sat, 9 Mar 2013 09:36:21 +0900 Subject: [PATCH 14/19] scd: support ECDSA signing. * scd/app-openpgp.c (do_sign): Only prepend message digest block for RSA or do_auth. (do_auth): Remove message digest block for ECDSA. -- If we don't need to check the message digest block by SCDaemon, we don't requite the message digest block for ECDSA by gpg-agent. --- scd/app-openpgp.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 8d507c4ed..1df35b275 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -3416,14 +3416,23 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, memcpy (data + sizeof b ## _prefix, indata, indatalen); \ } - X(SHA1, sha1, 1) - else X(RMD160, rmd160, 1) - else X(SHA224, sha224, app->app_local->extcap.is_v2) - else X(SHA256, sha256, app->app_local->extcap.is_v2) - else X(SHA384, sha384, app->app_local->extcap.is_v2) - else X(SHA512, sha512, app->app_local->extcap.is_v2) + if (use_auth + || app->app_local->keyattr[use_auth? 2: 0].key_type == KEY_TYPE_RSA) + { + X(SHA1, sha1, 1) + else X(RMD160, rmd160, 1) + else X(SHA224, sha224, app->app_local->extcap.is_v2) + else X(SHA256, sha256, app->app_local->extcap.is_v2) + else X(SHA384, sha384, app->app_local->extcap.is_v2) + else X(SHA512, sha512, app->app_local->extcap.is_v2) + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + } else - return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + { + datalen = indatalen; + memcpy (data, indata, indatalen); + } #undef X /* Redirect to the AUTH command if asked to. */ @@ -3515,6 +3524,14 @@ do_auth (app_t app, const char *keyidstr, if (indatalen > 101) /* For a 2048 bit key. */ return gpg_error (GPG_ERR_INV_VALUE); + if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA + && (indatalen == 51 || indatalen == 67 || indatalen == 83) + { + const char *p = (const char *)indata + 19; + indata = p; + indatalen -= 19; + } + /* Check whether an OpenPGP card of any version has been requested. */ if (!strcmp (keyidstr, "OPENPGP.3")) ; From 006782068e4d2a9413770400494421a2e9726ee7 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 15 Mar 2013 08:33:13 +0900 Subject: [PATCH 15/19] scd: fix missing close paren. * scd/app-openpgp.c (du_auth): Fix. -- --- scd/app-openpgp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1df35b275..673570d3f 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -3525,7 +3525,7 @@ do_auth (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_INV_VALUE); if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA - && (indatalen == 51 || indatalen == 67 || indatalen == 83) + && (indatalen == 51 || indatalen == 67 || indatalen == 83)) { const char *p = (const char *)indata + 19; indata = p; From 76dc5c08dc2686eef32e1bd221c60fe91201246f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 15 Mar 2013 08:34:32 +0900 Subject: [PATCH 16/19] scd: ccid-driver supporting larger APDU. * scd/ccid-driver.c (ccid_transceive_apdu_level): Support larger APDU. -- This is still ad hoc change, but it's OK. Supporting full extended APDU exchange level is not worth yet. --- scd/ccid-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 2d1ef8d46..da5fac954 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -2839,7 +2839,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle, /* The maximum length for a short APDU T=1 block is 261. For an extended APDU T=1 block the maximum length 65544; however extended APDU exchange level is not fully supported yet. */ - if (apdulen > 289) + if (apdulen > sizeof (send_buffer) - 10) return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */ msg[0] = PC_to_RDR_XfrBlock; From 4bde12206c5bf199dc6e12a74af8da4558ba41bf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 15 Mar 2013 15:46:03 +0100 Subject: [PATCH 17/19] gpg: Distinguish between missing and cleared key flags. * include/cipher.h (PUBKEY_USAGE_NONE): New. * g10/getkey.c (parse_key_usage): Set new flag. -- We do not want to use the default capabilities (derived from the algorithm) if any key flags are given in a signature. Thus if key flags are used in any way, the default key capabilities are never used. This allows to create a key with key flags set to all zero so it can't be used. This better reflects common sense. --- g10/getkey.c | 8 +++++++- include/cipher.h | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/g10/getkey.c b/g10/getkey.c index 929427302..8cc560100 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1276,13 +1276,19 @@ parse_key_usage (PKT_signature * sig) if (flags) key_usage |= PUBKEY_USAGE_UNKNOWN; + + if (!key_usage) + key_usage |= PUBKEY_USAGE_NONE; } + else if (p) /* Key flags of length zero. */ + key_usage |= PUBKEY_USAGE_NONE; /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a capability that we do not handle. This serves to distinguish between a zero key usage which we handle as the default capabilities for that algorithm, and a usage that we do not - handle. */ + handle. Likewise we use PUBKEY_USAGE_NONE to indicate that + key_flags have been given but they do not specify any usage. */ return key_usage; } diff --git a/include/cipher.h b/include/cipher.h index 191e197bc..557ab70e1 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -54,9 +54,14 @@ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ #define PUBKEY_USAGE_ENC GCRY_PK_USAGE_ENCR /* Good for encryption. */ -#define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys. */ +#define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys.*/ #define PUBKEY_USAGE_AUTH GCRY_PK_USAGE_AUTH /* Good for authentication. */ #define PUBKEY_USAGE_UNKNOWN GCRY_PK_USAGE_UNKN /* Unknown usage flag. */ +#define PUBKEY_USAGE_NONE 256 /* No usage given. */ +#if (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR | GCRY_PK_USAGE_CERT \ + | GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256 +# error Please choose another value for PUBKEY_USAGE_NONE +#endif #define DIGEST_ALGO_MD5 /* 1 */ GCRY_MD_MD5 #define DIGEST_ALGO_SHA1 /* 2 */ GCRY_MD_SHA1 From b693ec02c467696bf9d7324dd081e279f9965151 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 19 Mar 2013 11:25:25 -0400 Subject: [PATCH 18/19] gpg: Allow setting of all zero key flags * g10/keygen.c (do_add_key_flags): Do not check for empty key flags. --- g10/keygen.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/g10/keygen.c b/g10/keygen.c index fc985eef3..2017662e7 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -216,9 +216,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use) if (use & PUBKEY_USAGE_AUTH) buf[0] |= 0x20; - if (!buf[0]) - return; - build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); } From c4dbd1b2de8ae3847a040444e86500848868bcf4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 19 Mar 2013 17:23:56 +0100 Subject: [PATCH 19/19] gpg: Print indicator for unknown key capability. * g10/keylist.c (print_capabilities): Print '?' for unknown usage. --- doc/DETAILS | 1 + g10/keylist.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/doc/DETAILS b/doc/DETAILS index a52979f65..d5c5cea75 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -161,6 +161,7 @@ described here. - s :: Sign - c :: Certify - a :: Authentication + - ? :: Unknown capability A key may have any combination of them in any order. In addition to these letters, the primary key has uppercase versions of the diff --git a/g10/keylist.c b/g10/keylist.c index 87f3a4bb0..d45aed672 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -627,6 +627,9 @@ print_capabilities (PKT_public_key *pk, KBNODE keyblock) if ((use & PUBKEY_USAGE_AUTH)) es_putc ('a', es_stdout); + if ((use & PUBKEY_USAGE_UNKNOWN)) + es_putc ('?', es_stdout); + if (keyblock) { /* Figure out the usable capabilities. */