diff --git a/doc/DETAILS b/doc/DETAILS index ce666da3b..dea9d4263 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -180,6 +180,9 @@ described here. revocation key is also given here, 'x' and 'l' is used the same way. This field if not used for X.509. + "rev" and "rvs" may be followed by a comma and a 2 digit hexnumber + with the revocation reason. + *** Field 12 - Key capabilities The defined capabilities are: @@ -260,6 +263,12 @@ described here. optionally followed by a space and an URL. This goes along with the previous field. The URL is quoted in C style. +*** Field 21 - Comment + + This is currently only used in "rev" and "rvs" records to carry + the the comment field of the recocation reason. The value is + quoted in C style. + ** Special fields *** PKD - Public key data diff --git a/g10/import.c b/g10/import.c index 0f2ccfddf..49381d4cb 100644 --- a/g10/import.c +++ b/g10/import.c @@ -2614,6 +2614,69 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock, +/* Return the recocation reason from signature SIG. If no revocation + * reason is availabale 0 is returned, in other cases the reason + * (0..255). If R_REASON is not NULL a malloced textual + * representation of the code is stored there. If R_COMMENT is not + * NULL the comment from the reason is stored there and its length at + * R_COMMENTLEN. Note that the value at R_COMMENT is not filtered but + * user supplied data in UTF8; thus it needs to be escaped for display + * purposes. Both return values are either NULL or a malloced + * string/buffer. */ +int +get_revocation_reason (PKT_signature *sig, char **r_reason, + char **r_comment, size_t *r_commentlen) +{ + int reason_seq = 0; + size_t reason_n; + const byte *reason_p; + char reason_code_buf[20]; + const char *reason_text = NULL; + int reason_code = 0; + + if (r_reason) + *r_reason = NULL; + if (r_comment) + *r_comment = NULL; + + /* Skip over empty reason packets. */ + while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON, + &reason_n, &reason_seq, NULL)) + && !reason_n) + ; + if (reason_p) + { + reason_code = *reason_p; + reason_n--; reason_p++; + switch (reason_code) + { + case 0x00: reason_text = _("No reason specified"); break; + case 0x01: reason_text = _("Key is superseded"); break; + case 0x02: reason_text = _("Key has been compromised"); break; + case 0x03: reason_text = _("Key is no longer used"); break; + case 0x20: reason_text = _("User ID is no longer valid"); break; + default: + snprintf (reason_code_buf, sizeof reason_code_buf, + "code=%02x", reason_code); + reason_text = reason_code_buf; + break; + } + + if (r_reason) + *r_reason = xstrdup (reason_text); + + if (r_comment && reason_n) + { + *r_comment = xmalloc (reason_n); + memcpy (*r_comment, reason_p, reason_n); + *r_commentlen = reason_n; + } + } + + return reason_code; +} + + /* List the recocation signature as a "rvs" record. SIGRC shows the * character from the signature verification or 0 if no public key was * found. */ @@ -2623,6 +2686,10 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) char *siguid = NULL; size_t siguidlen = 0; char *issuer_fpr = NULL; + int reason_code = 0; + char *reason_text = NULL; + char *reason_comment = NULL; + size_t reason_commentlen; if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode) { @@ -2632,6 +2699,9 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) sigrc = '?'; } + reason_code = get_revocation_reason (sig, &reason_text, + &reason_comment, &reason_commentlen); + if (opt.with_colons) { es_fputs ("rvs:", es_stdout); @@ -2646,13 +2716,25 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) if (siguid) es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL); - es_fprintf (es_stdout, ":%02x%c::", sig->sig_class, + es_fprintf (es_stdout, ":%02x%c", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); + if (reason_text) + es_fprintf (es_stdout, ",%02x", reason_code); + es_fputs ("::", es_stdout); if ((issuer_fpr = issuer_fpr_string (sig))) es_fputs (issuer_fpr, es_stdout); - es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); + es_fprintf (es_stdout, ":::%d:", sig->digest_algo); + + if (reason_comment) + { + es_fputs ("::::", es_stdout); + es_write_sanitized (es_stdout, reason_comment, reason_commentlen, + ":", NULL); + es_putc (':', es_stdout); + } + es_putc ('\n', es_stdout); if (opt.show_subpackets) print_subpackets_colon (sig); @@ -2693,10 +2775,43 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 3, 0); + + if (reason_text) + { + es_fprintf (es_stdout, " %s%s\n", + _("reason for revocation: "), reason_text); + if (reason_comment) + { + const byte *s, *s_lf; + size_t n, n_lf; + + s = reason_comment; + n = reason_commentlen; + s_lf = NULL; + do + { + /* We don't want any empty lines, so we skip them. */ + for (;n && *s == '\n'; s++, n--) + ; + if (n) + { + s_lf = memchr (s, '\n', n); + n_lf = s_lf? s_lf - s : n; + es_fprintf (es_stdout, " %s", + _("revocation comment: ")); + es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); + es_putc ('\n', es_stdout); + s += n_lf; n -= n_lf; + } + } while (s_lf); + } + } } es_fflush (es_stdout); + xfree (reason_text); + xfree (reason_comment); xfree (siguid); xfree (issuer_fpr); } diff --git a/g10/pkclist.c b/g10/pkclist.c index dc19204de..03ad4c850 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -113,7 +113,7 @@ void show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode) { /* Hmmm, this is not so easy because we have to duplicate the code - * used in the trustbd to calculate the keyflags. We need to find + * used in the trustdb to calculate the keyflags. We need to find * a clean way to check revocation certificates on keys and * signatures. And there should be no duplicate code. Because we * enter this function only when the trustdb told us that we have