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>
* srv.c (getsrv): Fix type-punning warning.

View File

@ -36,3 +36,30 @@ get_status_string ( int no )
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_UNEXPECTED,
STATUS_INV_RECP,
STATUS_INV_SGNR,
STATUS_NO_RECP,
STATUS_NO_SGNR,
STATUS_ALREADY_SIGNED,
STATUS_KEYEXPIRED,
@ -127,6 +129,7 @@ enum
const char *get_status_string (int code);
const char *get_inv_recpsgnr_code (gpg_error_t err);
#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>
* gpg.texi (OpenPGP Options): Don't mention

View File

@ -361,7 +361,7 @@ more arguments in future versions.
KEYEXPIRED <expire-timestamp>
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
this subkey is not used. To check whether a key used to sign
a message has expired, the EXPKEYSIG status line is to be
@ -571,7 +571,8 @@ more arguments in future versions.
Issued by pipemode.
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:
0 := "No specific reason given".
1 := "Not Found"
@ -584,13 +585,20 @@ more arguments in future versions.
8 := "Policy mismatch"
9 := "Not a secret key"
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>
Issued when no recipients are usable.
NO_SGNR <reserved>
Issued when no recipients/senders are usable.
ALREADY_SIGNED <long-keyid>
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>
* 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) {
fputs (string, statusfp);
count += strlen (string);
/* Make sure that there is space after the string. */
if (*string && string[strlen (string)-1] != ' ')
{
putc (' ', statusfp);
count++;
}
}
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 ) {
log_info(_("secret key parts are not available\n"));
return G10ERR_GENERAL;
return G10ERR_UNU_SECKEY;
}
if( sk->protect.algo == CIPHER_ALGO_NONE )
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 )) ) {
free_secret_key( sk ); sk = NULL;
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)) )
{
@ -138,6 +140,8 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
log_info(_("key is not flagged as insecure - "
"can't use it with the faked RNG!\n"));
free_secret_key( sk ); sk = NULL;
write_status_text (STATUS_INV_SGNR,
get_inv_recpsgnr_code (GPG_ERR_NOT_TRUSTED));
}
else
{
@ -152,6 +156,7 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
{
free_secret_key( sk ); sk = NULL;
log_error("invalid default secret key: %s\n", g10_errstr(rc) );
write_status_text (STATUS_INV_SGNR, get_inv_recpsgnr_code (rc));
}
}
else {
@ -176,6 +181,9 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
free_secret_key( sk ); sk = NULL;
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);
}
else if ( key_present_in_sk_list(sk_list, sk) == 0) {
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;
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);
}
else if( !(rc=openpgp_pk_test_algo2 (sk->pubkey_algo, use)) ) {
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"
" is not secure for signatures!"));
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 ) ) {
log_info(_("key is not flagged as insecure - "
"can't use it with the faked RNG!\n"));
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 {
r = xmalloc( sizeof *r );
@ -214,6 +233,9 @@ build_sk_list( strlist_t locusr, SK_LIST *ret_sk_list,
else {
free_secret_key( sk ); sk = NULL;
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 ) {
log_error("no valid signators\n");
write_status_text (STATUS_NO_SGNR, "0");
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>
* 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));
gpgsm_status2 (ctrl, STATUS_INV_RECP,
gpg_err_code (rc) == -1? "1":
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);
get_inv_recpsgnr_code (rc), name, NULL);
}
else
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"),
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,
gpg_err_code (rc) == -1? "1":
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);
get_inv_recpsgnr_code (rc), sl->d, NULL);
}
}

View File

@ -384,20 +384,8 @@ cmd_recipient (assuan_context_t ctx, char *line)
&ctrl->server_local->recplist, 0);
if (rc)
{
gpg_err_code_t r = gpg_err_code (rc);
gpgsm_status2 (ctrl, STATUS_INV_RECP,
r == -1? "1":
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);
get_inv_recpsgnr_code (rc), line, NULL);
}
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
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
operation.
Note that this command returns an INV_RECP status which is a bit
strange, but they are very similar. */
operation. */
static int
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);
if (rc)
{
gpg_err_code_t r = gpg_err_code (rc);
gpgsm_status2 (ctrl, STATUS_INV_RECP,
r == -1? "1":
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_NO_SECKEY? "9":
r == GPG_ERR_MISSING_CERT? "11":
"0",
line, NULL);
gpgsm_status2 (ctrl, STATUS_INV_SGNR,
get_inv_recpsgnr_code (rc), line, NULL);
/* For compatibiliy reasons we also issue the old code after the
new one. */
gpgsm_status2 (ctrl, STATUS_INV_RECP,
get_inv_recpsgnr_code (rc), line, NULL);
}
return rc;
}

View File

@ -372,6 +372,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!cert)
{
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);
goto leave;
}
@ -382,7 +384,15 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
if (!rc)
rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
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. */
signerlist = xtrycalloc (1, sizeof *signerlist);