[svn] GnuPG - r4642 - in trunk: . common sm
svn author wk
cvs at cvs.gnupg.org
Thu Dec 6 16:55:04 CET 2007
Author: wk
Date: 2007-12-06 16:55:03 +0100 (Thu, 06 Dec 2007)
New Revision: 4642
Modified:
trunk/NEWS
trunk/common/audit.c
trunk/common/audit.h
trunk/sm/gpgsm.c
trunk/sm/server.c
trunk/sm/verify.c
Log:
More code for the audit log.
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/NEWS 2007-12-06 15:55:03 UTC (rev 4642)
@@ -2,8 +2,8 @@
------------------------------------------------
* Make sure that under Windows the file permissions of the socket are
- taken into account. This required a change of our the socket
- emulation code; thus old GnuPG modules can't be used anymore.
+ taken into account. This required a change of our socket emulation
+ code; thus old GnuPG modules can't be used anymore.
* Fixed a crash in gpgconf.
Modified: trunk/common/audit.c
===================================================================
--- trunk/common/audit.c 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/common/audit.c 2007-12-06 15:55:03 UTC (rev 4642)
@@ -19,9 +19,12 @@
#include <config.h>
#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
-
#include "util.h"
+#include "i18n.h"
#include "audit.h"
#include "audit-events.h"
@@ -50,11 +53,21 @@
size_t logsize; /* The allocated size for LOG. */
size_t logused; /* The used size of LOG. */
+ estream_t outstream; /* The current output stream. */
+ int use_html; /* The output shall be HTML formatted. */
+ int indentlevel; /* Current level of indentation. */
};
+
+static void writeout_li (audit_ctx_t ctx, const char *oktext,
+ const char *format, ...) JNLIB_GCC_A_PRINTF(3,4);
+static void writeout_rem (audit_ctx_t ctx,
+ const char *format, ...) JNLIB_GCC_A_PRINTF(2,3);
+
+
static const char *
event2str (audit_event_t event)
{
@@ -294,22 +307,486 @@
}
+/* Write TEXT to the outstream. */
+static void
+writeout (audit_ctx_t ctx, const char *text)
+{
+ if (ctx->use_html)
+ {
+ for (; *text; text++)
+ {
+ if (*text == '<')
+ es_fputs ("<", ctx->outstream);
+ else if (*text == '&')
+ es_fputs ("&", ctx->outstream);
+ else
+ es_putc (*text, ctx->outstream);
+ }
+ }
+ else
+ es_fputs (text, ctx->outstream);
+}
+
+/* Write TEXT to the outstream using a variable argument list. */
+static void
+writeout_v (audit_ctx_t ctx, const char *format, va_list arg_ptr)
+{
+ char *buf;
+
+ estream_vasprintf (&buf, format, arg_ptr);
+ if (buf)
+ {
+ writeout (ctx, buf);
+ xfree (buf);
+ }
+ else
+ writeout (ctx, "[!!Out of core!!]");
+}
+
+
+/* Write TEXT as a paragraph. */
+static void
+writeout_para (audit_ctx_t ctx, const char *text)
+{
+ if (ctx->use_html)
+ es_fputs ("<p>", ctx->outstream);
+ writeout (ctx, text);
+ if (ctx->use_html)
+ es_fputs ("</p>\n", ctx->outstream);
+ else
+ es_fputc ('\n', ctx->outstream);
+}
+
+
+static void
+enter_li (audit_ctx_t ctx)
+{
+ if (ctx->use_html)
+ {
+ if (!ctx->indentlevel)
+ {
+ es_fputs ("<table border=\"0\">\n"
+ " <colgroup>\n"
+ " <col width=\"80%\" />\n"
+ " <col width=\"20%\" />\n"
+ " </colgroup>\n",
+ ctx->outstream);
+ }
+ }
+ ctx->indentlevel++;
+}
+
+
+static void
+leave_li (audit_ctx_t ctx)
+{
+ ctx->indentlevel--;
+ if (ctx->use_html)
+ {
+ if (!ctx->indentlevel)
+ es_fputs ("</table>\n", ctx->outstream);
+ }
+}
+
+
+/* Write TEXT as a list element. If OKTEXT is not NULL, append it to
+ the last line. */
+static void
+writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...)
+{
+ va_list arg_ptr;
+ const char *color = NULL;
+
+ if (ctx->use_html && format && oktext)
+ {
+ if (!strcmp (oktext, "OK") || !strcmp (oktext, "Yes"))
+ color = "green";
+ else if (!strcmp (oktext, "FAIL") || !strcmp (oktext, "No"))
+ color = "red";
+ }
+
+ if (ctx->use_html)
+ {
+ int i;
+
+ es_fputs (" <tr><td><table><tr><td>", ctx->outstream);
+ if (color)
+ es_fprintf (ctx->outstream, "<font color=\"%s\">*</font>", color);
+ else
+ es_fputs ("*", ctx->outstream);
+ for (i=1; i < ctx->indentlevel; i++)
+ es_fputs (" ", ctx->outstream);
+ es_fputs ("</td><td>", ctx->outstream);
+ }
+ else
+ es_fprintf (ctx->outstream, "* %*s", (ctx->indentlevel-1)*2, "");
+ if (format)
+ {
+ va_start (arg_ptr, format) ;
+ writeout_v (ctx, format, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (ctx->use_html)
+ es_fputs ("</td></tr></table>", ctx->outstream);
+ if (format && oktext)
+ {
+ if (ctx->use_html)
+ {
+ es_fputs ("</td><td>", ctx->outstream);
+ if (color)
+ es_fprintf (ctx->outstream, "<font color=\"%s\">", color);
+ }
+ else
+ writeout (ctx, ": ");
+ writeout (ctx, oktext);
+ if (color)
+ es_fputs ("</font>", ctx->outstream);
+ }
+
+ if (ctx->use_html)
+ es_fputs ("</td></tr>\n", ctx->outstream);
+ else
+ es_fputc ('\n', ctx->outstream);
+}
+
+
+/* Write a remark line. */
+static void
+writeout_rem (audit_ctx_t ctx, const char *format, ...)
+{
+ va_list arg_ptr;
+
+ if (ctx->use_html)
+ {
+ int i;
+
+ es_fputs (" <tr><td><table><tr><td>*", ctx->outstream);
+ for (i=1; i < ctx->indentlevel; i++)
+ es_fputs (" ", ctx->outstream);
+ es_fputs (" </td><td> (", ctx->outstream);
+
+ }
+ else
+ es_fprintf (ctx->outstream, "* %*s (", (ctx->indentlevel-1)*2, "");
+ if (format)
+ {
+ va_start (arg_ptr, format) ;
+ writeout_v (ctx, format, arg_ptr);
+ va_end (arg_ptr);
+ }
+ if (ctx->use_html)
+ es_fputs (")</td></tr></table></td></tr>\n", ctx->outstream);
+ else
+ es_fputs (")\n", ctx->outstream);
+}
+
+
+/* Return the first log item for EVENT. If STOPEVENT is not 0 never
+ look behind that event in the log. If STARTITEM is not NULL start
+ search _after_that item. */
+static log_item_t
+find_next_log_item (audit_ctx_t ctx, log_item_t startitem,
+ audit_event_t event, audit_event_t stopevent)
+{
+ int idx;
+
+ for (idx=0; idx < ctx->logused; idx++)
+ {
+ if (startitem)
+ {
+ if (ctx->log + idx == startitem)
+ startitem = NULL;
+ }
+ else if (stopevent && ctx->log[idx].event == stopevent)
+ break;
+ else if (ctx->log[idx].event == event)
+ return ctx->log + idx;
+ }
+ return NULL;
+}
+
+
+static log_item_t
+find_log_item (audit_ctx_t ctx, audit_event_t event, audit_event_t stopevent)
+{
+ return find_next_log_item (ctx, NULL, event, stopevent);
+}
+
+
+/* Helper to a format a serial number. */
+static char *
+format_serial (ksba_const_sexp_t sn)
+{
+ const char *p = (const char *)sn;
+ unsigned long n;
+ char *endp;
+
+ if (!p)
+ return NULL;
+ if (*p != '(')
+ BUG (); /* Not a valid S-expression. */
+ n = strtoul (p+1, &endp, 10);
+ p = endp;
+ if (*p != ':')
+ BUG (); /* Not a valid S-expression. */
+ return bin2hex (p+1, n, NULL);
+}
+
+
+/* Return a malloced string with the serial number and the issuer DN
+ of the certificate. */
+static char *
+get_cert_name (ksba_cert_t cert)
+{
+ char *result;
+ ksba_sexp_t sn;
+ char *issuer, *p;
+
+ if (!cert)
+ return xtrystrdup ("[no certificate]");
+
+ issuer = ksba_cert_get_issuer (cert, 0);
+ sn = ksba_cert_get_serial (cert);
+ if (issuer && sn)
+ {
+ p = format_serial (sn);
+ if (!p)
+ result = xtrystrdup ("[invalid S/N]");
+ else
+ {
+ result = xtrymalloc (strlen (p) + strlen (issuer) + 2 + 1);
+ if (result)
+ {
+ *result = '#';
+ strcpy (stpcpy (stpcpy (result+1, p),"/"), issuer);
+ }
+ xfree (p);
+ }
+ }
+ else
+ result = xtrystrdup ("[missing S/N or issuer]");
+ ksba_free (sn);
+ xfree (issuer);
+ return result;
+}
+
+/* Return a malloced string with the serial number and the issuer DN
+ of the certificate. */
+static char *
+get_cert_subject (ksba_cert_t cert, int idx)
+{
+ char *result;
+ char *subject;
+
+ if (!cert)
+ return xtrystrdup ("[no certificate]");
+
+ subject = ksba_cert_get_subject (cert, idx);
+ if (subject)
+ {
+ result = xtrymalloc (strlen (subject) + 1 + 1);
+ if (result)
+ {
+ *result = '/';
+ strcpy (result+1, subject);
+ }
+ }
+ else
+ result = NULL;
+ xfree (subject);
+ return result;
+}
+
+
+/* List the chain of certificates from STARTITEM up to STOPEVENT. The
+ certifcates are written out as comments. */
+static void
+list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent)
+{
+ log_item_t item;
+ char *name;
+ int idx;
+
+ startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent);
+ if (!startitem)
+ {
+ writeout_li (ctx, gpg_strerror (GPG_ERR_MISSING_CERT)
+ , _("Certificate chain"));
+ return;
+ }
+ writeout_li (ctx, "OK", _("Certificate chain"));
+ item = find_next_log_item (ctx, startitem,
+ AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END);
+ if (!item)
+ writeout_rem (ctx, "%s", _("root certificate missing"));
+ else
+ {
+ name = get_cert_name (item->cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ item = startitem;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_CHAIN_CERT, AUDIT_CHAIN_END))))
+ {
+ name = get_cert_name (item->cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+}
+
+
+
+/* Process a verification operation. */
+static void
+proc_type_verify (audit_ctx_t ctx)
+{
+ log_item_t loopitem, item;
+ int signo, count, idx;
+ char numbuf[35];
+
+ enter_li (ctx);
+
+ writeout_li (ctx, "fixme", "%s", _("Signature verification"));
+ enter_li (ctx);
+
+ writeout_li (ctx, "fixme", "%s", _("Gpg-Agent ready"));
+ writeout_li (ctx, "fixme", "%s", _("Dirmngr ready"));
+
+ item = find_log_item (ctx, AUDIT_GOT_DATA, AUDIT_NEW_SIG);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Data available"));
+ if (!item)
+ goto leave;
+
+ item = find_log_item (ctx, AUDIT_NEW_SIG, 0);
+ writeout_li (ctx, item? "Yes":"No", "%s", _("Signature available"));
+ if (!item)
+ goto leave;
+
+ item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG);
+ if (item)
+ writeout_li (ctx, "OK", "%s", _("Parsing signature"));
+ else
+ {
+ item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG);
+ if (item)
+ {
+ writeout_li (ctx,"FAIL", "%s", _("Parsing signature"));
+ writeout_rem (ctx, _("Bad hash algorithm: %s"),
+ item->string? item->string:"?");
+ }
+ else
+ writeout_li (ctx, "FAIL", "%s", _("Parsing signature") );
+ goto leave;
+ }
+
+ /* Loop over all signatures. */
+ loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0);
+ assert (loopitem);
+ do
+ {
+ signo = loopitem->have_intvalue? loopitem->intvalue : -1;
+
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_SIG_STATUS, AUDIT_NEW_SIG);
+ writeout_li (ctx, item? item->string:"?", _("Signature %d"), signo);
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_SIG_NAME, AUDIT_NEW_SIG);
+ if (item)
+ writeout_rem (ctx, "%s", item->string);
+ enter_li (ctx);
+
+ /* List the certificate chain. */
+ list_certchain (ctx, loopitem, AUDIT_NEW_SIG);
+
+ /* Show the result of the chain validation. */
+ item = find_next_log_item (ctx, loopitem,
+ AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG);
+ if (item && item->have_err)
+ {
+ writeout_li (ctx, item->err? "FAIL":"OK",
+ _("Validation of certificate chain"));
+ if (item->err)
+ writeout_rem (ctx, "%s", gpg_strerror (item->err));
+ }
+
+ /* Show whether the root certificate is fine. */
+ writeout_li (ctx, "No", "%s", _("Root certificate trustworthy"));
+
+ /* Show result of the CRL/OCSP check. */
+ writeout_li (ctx, "-", "%s", _("CRL/OCSP check of certificates"));
+
+
+ leave_li (ctx);
+ }
+ while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0)));
+
+
+ leave:
+ /* Always list the certificates stored in the signature. */
+ item = NULL;
+ count = 0;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
+ count++;
+ snprintf (numbuf, sizeof numbuf, "%d", count);
+ writeout_li (ctx, numbuf, _("Included certificates"));
+ item = NULL;
+ while ( ((item = find_next_log_item (ctx, item,
+ AUDIT_SAVE_CERT, AUDIT_NEW_SIG))))
+ {
+ char *name = get_cert_name (item->cert);
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ enter_li (ctx);
+ for (idx=0; (name = get_cert_subject (item->cert, idx)); idx++)
+ {
+ writeout_rem (ctx, "%s", name);
+ xfree (name);
+ }
+ leave_li (ctx);
+ }
+
+ leave_li (ctx);
+ leave_li (ctx);
+}
+
+
+
+
/* Print the formatted audit result. THIS IS WORK IN PROGRESS. */
void
-audit_print_result (audit_ctx_t ctx, estream_t out)
+audit_print_result (audit_ctx_t ctx, estream_t out, int use_html)
{
int idx;
int maxlen;
size_t n;
- es_fputs ("<div class=\"GnuPGAuditLog\">\n", out);
+ if (getenv ("use_html"))
+ use_html = 1;
if (!ctx)
- goto leave;
+ return;
+
+ assert (!ctx->outstream);
+ ctx->outstream = out;
+ ctx->use_html = use_html;
+ ctx->indentlevel = 0;
+
+ if (use_html)
+ es_fputs ("<div class=\"GnuPGAuditLog\">\n", ctx->outstream);
+
if (!ctx->log || !ctx->logused)
{
- es_fprintf (out, "<p>AUDIT-LOG: No entries</p>\n");
+ writeout_para (ctx, _("No audit log entries."));
goto leave;
}
@@ -320,24 +797,49 @@
maxlen = n;
}
- es_fputs ("<ul>\n", out);
+ if (use_html)
+ es_fputs ("<pre>\n", out);
for (idx=0; idx < ctx->logused; idx++)
{
- es_fprintf (out, " <li>%-*s",
+ es_fprintf (out, "log: %-*s",
maxlen, event2str (ctx->log[idx].event));
if (ctx->log[idx].have_intvalue)
es_fprintf (out, " i=%d", ctx->log[idx].intvalue);
if (ctx->log[idx].string)
- es_fprintf (out, " s=`%s'", ctx->log[idx].string);
+ {
+ es_fputs (" s=`", out);
+ writeout (ctx, ctx->log[idx].string);
+ es_fputs ("'", out);
+ }
if (ctx->log[idx].cert)
es_fprintf (out, " has_cert");
if (ctx->log[idx].have_err)
- es_fprintf (out, " err=\"%s\"", gpg_strerror (ctx->log[idx].err));
- es_fputs ("</li>\n", out);
+ {
+ es_fputs (" err=`", out);
+ writeout (ctx, gpg_strerror (ctx->log[idx].err));
+ es_fputs ("'", out);
+ }
+ es_fputs ("\n", out);
}
- es_fputs ("</ul>\n", out);
+ if (use_html)
+ es_fputs ("</pre>\n", out);
+ else
+ es_fputs ("\n", out);
+ switch (ctx->type)
+ {
+ case AUDIT_TYPE_NONE:
+ writeout_para (ctx, _("Audit of this operation is not supported."));
+ break;
+ case AUDIT_TYPE_VERIFY:
+ proc_type_verify (ctx);
+ break;
+ }
+
leave:
- es_fputs ("</div>\n", out);
+ if (use_html)
+ es_fputs ("</div>\n", ctx->outstream);
+ ctx->outstream = NULL;
+ ctx->use_html = 0;
}
Modified: trunk/common/audit.h
===================================================================
--- trunk/common/audit.h 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/common/audit.h 2007-12-06 15:55:03 UTC (rev 4642)
@@ -49,6 +49,9 @@
now. This indicates that all parameters are okay and we can
start to process the actual data. */
+ AUDIT_GOT_DATA,
+ /* Data to be processed has been seen. */
+
AUDIT_DETACHED_SIGNATURE,
/* The signature is a detached one. */
@@ -91,7 +94,7 @@
/* The name of a signer. This is the name or other identification
data as known from the signature and not the name from the
certificate used for verification. An example for STRING when
- using CMS is:b "#1234/CN=Prostetnic Vogon Jeltz". */
+ using CMS is: "#1234/CN=Prostetnic Vogon Jeltz". */
AUDIT_SIG_STATUS, /* string */
/* The signature status of the current signer. This is the last
@@ -116,6 +119,8 @@
certificate chain. ROOTCERT is used for the trustanchor and
CERT for all other certificates. */
+ AUDIT_CHAIN_STATUS, /* err */
+ /* Tells the final status of the chain validation. */
AUDIT_LAST_EVENT /* Marker for parsing this list. */
@@ -133,7 +138,7 @@
void audit_log_cert (audit_ctx_t ctx, audit_event_t event,
ksba_cert_t cert, gpg_error_t err);
-void audit_print_result (audit_ctx_t ctx, estream_t stream);
+void audit_print_result (audit_ctx_t ctx, estream_t stream, int use_html);
Modified: trunk/sm/gpgsm.c
===================================================================
--- trunk/sm/gpgsm.c 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/sm/gpgsm.c 2007-12-06 15:55:03 UTC (rev 4642)
@@ -1676,7 +1676,7 @@
if (auditlog)
{
- audit_print_result (ctrl.audit, auditfp);
+ audit_print_result (ctrl.audit, auditfp, 0);
audit_release (ctrl.audit);
ctrl.audit = NULL;
}
Modified: trunk/sm/server.c
===================================================================
--- trunk/sm/server.c 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/sm/server.c 2007-12-06 15:55:03 UTC (rev 4642)
@@ -934,12 +934,15 @@
-/* GETAUDITLOG [--data]
+/* GETAUDITLOG [--data] [--html]
!!!WORK in PROGRESS!!!
If --data is used, the output is send using D-lines and not to the
source given by an OUTPUT command.
+
+ If --html is used the output is formated as an XHTML block. This is
+ designed to be incorporated into a HTML document.
*/
static int
cmd_getauditlog (assuan_context_t ctx, char *line)
@@ -947,10 +950,11 @@
ctrl_t ctrl = assuan_get_pointer (ctx);
int out_fd;
estream_t out_stream;
- int opt_data;
+ int opt_data, opt_html;
int rc;
opt_data = has_option (line, "--data");
+ opt_html = has_option (line, "--html");
line = skip_options (line);
if (!ctrl->audit)
@@ -976,7 +980,7 @@
}
}
- audit_print_result (ctrl->audit, out_stream);
+ audit_print_result (ctrl->audit, out_stream, opt_html);
rc = 0;
es_fclose (out_stream);
Modified: trunk/sm/verify.c
===================================================================
--- trunk/sm/verify.c 2007-12-04 15:00:14 UTC (rev 4641)
+++ trunk/sm/verify.c 2007-12-06 15:55:03 UTC (rev 4642)
@@ -184,7 +184,10 @@
if (stopreason == KSBA_SR_NEED_HASH
|| stopreason == KSBA_SR_BEGIN_DATA)
- { /* We are now able to enable the hash algorithms */
+ {
+ audit_log (ctrl->audit, AUDIT_GOT_DATA);
+
+ /* We are now able to enable the hash algorithms */
for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
{
algo = gcry_md_map_name (algoid);
@@ -535,6 +538,7 @@
xfree (buf);
}
+ audit_log_ok (ctrl->audit, AUDIT_CHAIN_STATUS, rc);
if (rc) /* of validate_chain */
{
log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
More information about the Gnupg-commits
mailing list