Improved detection of bad/invalid signer keys.

This commit is contained in:
Werner Koch 2009-08-06 20:12:00 +00:00
parent f27bdef888
commit 019601191a
13 changed files with 122 additions and 63 deletions

View File

@ -1,3 +1,8 @@
2009-08-06 Werner Koch <wk@g10code.com>
* status.h (STATUS_INV_SGNR, STATUS_NO_SGNR): New.
* status.c (get_inv_recpsgnr_code): New.
2009-07-23 David Shaw <dshaw@jabberwocky.com> 2009-07-23 David Shaw <dshaw@jabberwocky.com>
* srv.c (getsrv): Fix type-punning warning. * srv.c (getsrv): Fix type-punning warning.

View File

@ -36,3 +36,30 @@ get_status_string ( int no )
return statusstr_msgstr + statusstr_msgidx[idx]; return statusstr_msgstr + statusstr_msgidx[idx];
} }
const char *
get_inv_recpsgnr_code (gpg_error_t err)
{
const char *errstr;
switch (gpg_err_code (err))
{
case GPG_ERR_NO_PUBKEY: errstr = "1"; break;
case GPG_ERR_AMBIGUOUS_NAME: errstr = "2"; break;
case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
case GPG_ERR_NO_CRL_KNOWN: errstr = "6"; break;
case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;
case GPG_ERR_UNUSABLE_SECKEY:
case GPG_ERR_NO_SECKEY: errstr = "9"; break;
case GPG_ERR_NOT_TRUSTED: errstr = "10"; break;
case GPG_ERR_MISSING_CERT: errstr = "11"; break;
default: errstr = "0"; break;
}
return errstr;
}

View File

@ -91,7 +91,9 @@ enum
STATUS_USERID_HINT, STATUS_USERID_HINT,
STATUS_UNEXPECTED, STATUS_UNEXPECTED,
STATUS_INV_RECP, STATUS_INV_RECP,
STATUS_INV_SGNR,
STATUS_NO_RECP, STATUS_NO_RECP,
STATUS_NO_SGNR,
STATUS_ALREADY_SIGNED, STATUS_ALREADY_SIGNED,
STATUS_KEYEXPIRED, STATUS_KEYEXPIRED,
@ -127,6 +129,7 @@ enum
const char *get_status_string (int code); const char *get_status_string (int code);
const char *get_inv_recpsgnr_code (gpg_error_t err);
#endif /*GNUPG_COMMON_STATUS_H*/ #endif /*GNUPG_COMMON_STATUS_H*/

View File

@ -1,3 +1,7 @@
2009-08-06 Werner Koch <wk@g10code.com>
* DETAILS: Describe the new INV_SNDR and NO_SNDR..
2009-07-31 David Shaw <dshaw@jabberwocky.com> 2009-07-31 David Shaw <dshaw@jabberwocky.com>
* gpg.texi (OpenPGP Options): Don't mention * gpg.texi (OpenPGP Options): Don't mention

View File

@ -361,7 +361,7 @@ more arguments in future versions.
KEYEXPIRED <expire-timestamp> KEYEXPIRED <expire-timestamp>
The key has expired. expire-timestamp is the expiration time The key has expired. expire-timestamp is the expiration time
in seconds sice Epoch. This status line is not very useful in seconds since Epoch. This status line is not very useful
because it will also be emitted for expired subkeys even if because it will also be emitted for expired subkeys even if
this subkey is not used. To check whether a key used to sign this subkey is not used. To check whether a key used to sign
a message has expired, the EXPKEYSIG status line is to be a message has expired, the EXPKEYSIG status line is to be
@ -571,7 +571,8 @@ more arguments in future versions.
Issued by pipemode. Issued by pipemode.
INV_RECP <reason> <requested_recipient> INV_RECP <reason> <requested_recipient>
Issued for each unusable recipient. The reasons codes INV_SGNR <reason> <requested_sender>
Issued for each unusable recipient/sender. The reasons codes
currently in use are: currently in use are:
0 := "No specific reason given". 0 := "No specific reason given".
1 := "Not Found" 1 := "Not Found"
@ -584,13 +585,20 @@ more arguments in future versions.
8 := "Policy mismatch" 8 := "Policy mismatch"
9 := "Not a secret key" 9 := "Not a secret key"
10 := "Key not trusted" 10 := "Key not trusted"
11 := "Missing certifciate" (e.g. intermediate or root cert.) 11 := "Missing certificate" (e.g. intermediate or root cert.)
Note that for historical reasons the INV_RECP status is also
used for gpgsm's SIGNER command where it relates to signer's
of course. Newer GnuPG versions are using INV_SGNR;
applications should ignore the INV_RECP during the sender's
command processing once they have seen an INV_SGNR. We use
different code so that we can distinguish them while doing an
encrypt+sign.
Note that this status is also used for gpgsm's SIGNER command
where it relates to signer's of course.
NO_RECP <reserved> NO_RECP <reserved>
Issued when no recipients are usable. NO_SGNR <reserved>
Issued when no recipients/senders are usable.
ALREADY_SIGNED <long-keyid> ALREADY_SIGNED <long-keyid>
Warning: This is experimental and might be removed at any time. Warning: This is experimental and might be removed at any time.

View File

@ -1,3 +1,9 @@
2009-08-06 Werner Koch <wk@g10code.com>
* skclist.c (build_sk_list): Print INV_SGNR status line.
* seckey-cert.c (do_check): Return G10ERR_UNU_SECKEY instead of
general error.
2009-08-05 Werner Koch <wk@g10code.com> 2009-08-05 Werner Koch <wk@g10code.com>
* card-util.c: Enable readline support also in GnuPG-2. * card-util.c: Enable readline support also in GnuPG-2.

View File

@ -202,6 +202,12 @@ write_status_text_and_buffer ( int no, const char *string,
if (first && string) { if (first && string) {
fputs (string, statusfp); fputs (string, statusfp);
count += strlen (string); count += strlen (string);
/* Make sure that there is space after the string. */
if (*string && string[strlen (string)-1] != ' ')
{
putc (' ', statusfp);
count++;
}
} }
first = 0; first = 0;
} }

View File

@ -53,7 +53,7 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
if( sk->protect.s2k.mode == 1001 ) { if( sk->protect.s2k.mode == 1001 ) {
log_info(_("secret key parts are not available\n")); log_info(_("secret key parts are not available\n"));
return G10ERR_GENERAL; return G10ERR_UNU_SECKEY;
} }
if( sk->protect.algo == CIPHER_ALGO_NONE ) if( sk->protect.algo == CIPHER_ALGO_NONE )
BUG(); BUG();

View File

@ -128,6 +128,8 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
if( (rc = get_seckey_byname( sk, NULL, unlock )) ) { if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
log_error("no default secret key: %s\n", g10_errstr(rc) ); log_error("no default secret key: %s\n", g10_errstr(rc) );
write_status_text (STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY));
} }
else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) )
{ {
@ -138,6 +140,8 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
log_info(_("key is not flagged as insecure - " log_info(_("key is not flagged as insecure - "
"can't use it with the faked RNG!\n")); "can't use it with the faked RNG!\n"));
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
write_status_text (STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
} }
else else
{ {
@ -152,6 +156,7 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
{ {
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
log_error("invalid default secret key: %s\n", g10_errstr(rc) ); log_error("invalid default secret key: %s\n", g10_errstr(rc) );
write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc));
} }
} }
else { else {
@ -176,6 +181,9 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
log_error(_("skipped \"%s\": %s\n"), log_error(_("skipped \"%s\": %s\n"),
locusr->d, g10_errstr(rc) ); locusr->d, g10_errstr(rc) );
write_status_text_and_buffer
(STATUS_INV_SGNR, get_inv_recpsgnr_code (rc),
locusr->d, strlen (locusr->d), -1);
} }
else if ( key_present_in_sk_list(sk_list, sk) == 0) { else if ( key_present_in_sk_list(sk_list, sk) == 0) {
free_secret_key(sk); sk = NULL; free_secret_key(sk); sk = NULL;
@ -186,6 +194,9 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
log_error(_("skipped \"%s\": %s\n"), log_error(_("skipped \"%s\": %s\n"),
locusr->d, g10_errstr(rc) ); locusr->d, g10_errstr(rc) );
write_status_text_and_buffer
(STATUS_INV_SGNR, get_inv_recpsgnr_code (rc),
locusr->d, strlen (locusr->d), -1);
} }
else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) { else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) {
SK_LIST r; SK_LIST r;
@ -197,11 +208,19 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
_("this is a PGP generated Elgamal key which" _("this is a PGP generated Elgamal key which"
" is not secure for signatures!")); " is not secure for signatures!"));
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
write_status_text_and_buffer
(STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_WRONG_KEY_USAGE),
locusr->d, strlen (locusr->d), -1);
} }
else if( random_is_faked() && !is_insecure( sk ) ) { else if( random_is_faked() && !is_insecure( sk ) ) {
log_info(_("key is not flagged as insecure - " log_info(_("key is not flagged as insecure - "
"can't use it with the faked RNG!\n")); "can't use it with the faked RNG!\n"));
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
write_status_text_and_buffer
(STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED),
locusr->d, strlen (locusr->d), -1);
} }
else { else {
r = xmalloc( sizeof *r ); r = xmalloc( sizeof *r );
@ -214,6 +233,9 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
else { else {
free_secret_key( sk ); sk = NULL; free_secret_key( sk ); sk = NULL;
log_error("skipped \"%s\": %s\n", locusr->d, g10_errstr(rc) ); log_error("skipped \"%s\": %s\n", locusr->d, g10_errstr(rc) );
write_status_text_and_buffer
(STATUS_INV_SGNR, get_inv_recpsgnr_code (rc),
locusr->d, strlen (locusr->d), -1);
} }
} }
} }
@ -221,6 +243,7 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
if( !rc && !sk_list ) { if( !rc && !sk_list ) {
log_error("no valid signators\n"); log_error("no valid signators\n");
write_status_text (STATUS_NO_SGNR, "0");
rc = G10ERR_NO_USER_ID; rc = G10ERR_NO_USER_ID;
} }

View File

@ -1,3 +1,13 @@
2009-08-06 Werner Koch <wk@g10code.com>
* sign.c (gpgsm_sign): Print INV_SNDR for a bad default key.
* server.c (cmd_signer): Remove unneeded case for -1. Send
INV_SGNR. Use new map function.
(cmd_recipient): Use new map function.
* gpgsm.c (do_add_recipient): Use new map function for INV_RECP.
(main): Ditto. Also send INV_SGNR.
2009-07-30 Werner Koch <wk@g10code.com> 2009-07-30 Werner Koch <wk@g10code.com>
* call-agent.c (learn_cb): Do not store as ephemeral. * call-agent.c (learn_cb): Do not store as ephemeral.

View File

@ -704,17 +704,7 @@ do_add_recipient (ctrl_t ctrl, const char *name,
{ {
log_error ("can't encrypt to `%s': %s\n", name, gpg_strerror (rc)); log_error ("can't encrypt to `%s': %s\n", name, gpg_strerror (rc));
gpgsm_status2 (ctrl, STATUS_INV_RECP, gpgsm_status2 (ctrl, STATUS_INV_RECP,
gpg_err_code (rc) == -1? "1": get_inv_recpsgnr_code (rc), name, NULL);
gpg_err_code (rc) == GPG_ERR_NO_PUBKEY? "1":
gpg_err_code (rc) == GPG_ERR_AMBIGUOUS_NAME? "2":
gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE? "3":
gpg_err_code (rc) == GPG_ERR_CERT_REVOKED? "4":
gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED? "5":
gpg_err_code (rc) == GPG_ERR_NO_CRL_KNOWN? "6":
gpg_err_code (rc) == GPG_ERR_CRL_TOO_OLD? "7":
gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH? "8":
"0",
name, NULL);
} }
else else
log_info (_("NOTE: won't be able to encrypt to `%s': %s\n"), log_info (_("NOTE: won't be able to encrypt to `%s': %s\n"),
@ -1570,19 +1560,10 @@ main ( int argc, char **argv)
{ {
log_error (_("can't sign using `%s': %s\n"), log_error (_("can't sign using `%s': %s\n"),
sl->d, gpg_strerror (rc)); sl->d, gpg_strerror (rc));
gpgsm_status2 (&ctrl, STATUS_INV_SGNR,
get_inv_recpsgnr_code (rc), sl->d, NULL);
gpgsm_status2 (&ctrl, STATUS_INV_RECP, gpgsm_status2 (&ctrl, STATUS_INV_RECP,
gpg_err_code (rc) == -1? "1": get_inv_recpsgnr_code (rc), sl->d, NULL);
gpg_err_code (rc) == GPG_ERR_NO_PUBKEY? "1":
gpg_err_code (rc) == GPG_ERR_AMBIGUOUS_NAME? "2":
gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE? "3":
gpg_err_code (rc) == GPG_ERR_CERT_REVOKED? "4":
gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED? "5":
gpg_err_code (rc) == GPG_ERR_NO_CRL_KNOWN? "6":
gpg_err_code (rc) == GPG_ERR_CRL_TOO_OLD? "7":
gpg_err_code (rc) == GPG_ERR_NO_POLICY_MATCH? "8":
gpg_err_code (rc) == GPG_ERR_NO_SECKEY? "9":
"0",
sl->d, NULL);
} }
} }

View File

@ -384,20 +384,8 @@ cmd_recipient (assuan_context_t ctx, char *line)
&ctrl->server_local->recplist, 0); &ctrl->server_local->recplist, 0);
if (rc) if (rc)
{ {
gpg_err_code_t r = gpg_err_code (rc);
gpgsm_status2 (ctrl, STATUS_INV_RECP, gpgsm_status2 (ctrl, STATUS_INV_RECP,
r == -1? "1": get_inv_recpsgnr_code (rc), line, NULL);
r == GPG_ERR_NO_PUBKEY? "1":
r == GPG_ERR_AMBIGUOUS_NAME? "2":
r == GPG_ERR_WRONG_KEY_USAGE? "3":
r == GPG_ERR_CERT_REVOKED? "4":
r == GPG_ERR_CERT_EXPIRED? "5":
r == GPG_ERR_NO_CRL_KNOWN? "6":
r == GPG_ERR_CRL_TOO_OLD? "7":
r == GPG_ERR_NO_POLICY_MATCH? "8":
r == GPG_ERR_MISSING_CERT? "11":
"0",
line, NULL);
} }
return rc; return rc;
@ -415,10 +403,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
has to take care of this. All SIGNER commands are cumulative until has to take care of this. All SIGNER commands are cumulative until
a RESET but they are *not* reset by an SIGN command becuase it can a RESET but they are *not* reset by an SIGN command becuase it can
be expected that set of signers are used for more than one sign be expected that set of signers are used for more than one sign
operation. operation. */
Note that this command returns an INV_RECP status which is a bit
strange, but they are very similar. */
static int static int
cmd_signer (assuan_context_t ctx, char *line) cmd_signer (assuan_context_t ctx, char *line)
{ {
@ -429,21 +414,12 @@ cmd_signer (assuan_context_t ctx, char *line)
&ctrl->server_local->signerlist, 0); &ctrl->server_local->signerlist, 0);
if (rc) if (rc)
{ {
gpg_err_code_t r = gpg_err_code (rc); gpgsm_status2 (ctrl, STATUS_INV_SGNR,
gpgsm_status2 (ctrl, STATUS_INV_RECP, get_inv_recpsgnr_code (rc), line, NULL);
r == -1? "1": /* For compatibiliy reasons we also issue the old code after the
r == GPG_ERR_NO_PUBKEY? "1": new one. */
r == GPG_ERR_AMBIGUOUS_NAME? "2": gpgsm_status2 (ctrl, STATUS_INV_RECP,
r == GPG_ERR_WRONG_KEY_USAGE? "3": get_inv_recpsgnr_code (rc), line, NULL);
r == GPG_ERR_CERT_REVOKED? "4":
r == GPG_ERR_CERT_EXPIRED? "5":
r == GPG_ERR_NO_CRL_KNOWN? "6":
r == GPG_ERR_CRL_TOO_OLD? "7":
r == GPG_ERR_NO_POLICY_MATCH? "8":
r == GPG_ERR_NO_SECKEY? "9":
r == GPG_ERR_MISSING_CERT? "11":
"0",
line, NULL);
} }
return rc; return rc;
} }

View File

@ -372,6 +372,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!cert) if (!cert)
{ {
log_error ("no default signer found\n"); log_error ("no default signer found\n");
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
rc = gpg_error (GPG_ERR_GENERAL); rc = gpg_error (GPG_ERR_GENERAL);
goto leave; goto leave;
} }
@ -382,7 +384,15 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!rc) if (!rc)
rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL); rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
if (rc) if (rc)
goto leave; {
char *tmpfpr;
tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
get_inv_recpsgnr_code (rc), tmpfpr, NULL);
xfree (tmpfpr);
goto leave;
}
/* That one is fine - create signerlist. */ /* That one is fine - create signerlist. */
signerlist = xtrycalloc (1, sizeof *signerlist); signerlist = xtrycalloc (1, sizeof *signerlist);