From ae7b03d427062e7cdcbbf4c91c869a59e113df56 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 3 Dec 2009 19:39:39 +0000 Subject: [PATCH] Backported some stuff from trunk --- NEWS | 4 +- common/ChangeLog | 9 ++ common/audit.c | 214 ++++++++++++++++++++++++++++++++++++++++++----- common/audit.h | 51 +++++++++-- g10/ChangeLog | 2 + g10/gpg.c | 5 ++ g10/keygen.c | 2 + sm/ChangeLog | 15 ++++ sm/certreqgen.c | 6 +- sm/decrypt.c | 53 +++++++++++- sm/gpgsm.c | 29 +++++-- sm/sign.c | 52 ++++++++---- sm/verify.c | 6 +- 13 files changed, 390 insertions(+), 58 deletions(-) diff --git a/NEWS b/NEWS index 9974c89dc..42531c9dd 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1,14 @@ Noteworthy changes in version 2.0.14 ------------------------------------------------- - * The default for --inlucde-cert is now to include all certificates + * The default for --include-cert is now to include all certificates in the chain except for the root certificate. * Numerical values may now be used as an alternative to the debug-level keywords. + * The GPGSM --audit-log feature is now more complete. + Noteworthy changes in version 2.0.13 (2009-09-04) ------------------------------------------------- diff --git a/common/ChangeLog b/common/ChangeLog index 08f30d606..8b6b67d89 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,12 @@ +2009-12-03 Werner Koch + + From trunk: + * audit.c (proc_type_decrypt, proc_type_sign): Implemented. + (proc_type_verify): Print hash algo infos. + * audit.h (AUDIT_DATA_CIPHER_ALGO, AUDIT_BAD_DATA_CIPHER_ALSO) + (AUDIT_NEW_RECP, AUDIT_DECRYPTION_RESULT, AUDIT_RECP_RESULT) + (AUDIT_ATTR_HASH_ALGO, AUDIT_SIGNED_BY, AUDIT_SIGNING_DONE): + 2009-09-03 Werner Koch Update from libestream: diff --git a/common/audit.c b/common/audit.c index 436f0d25d..02a0a2b22 100644 --- a/common/audit.c +++ b/common/audit.c @@ -1,5 +1,5 @@ /* audit.c - GnuPG's audit subsystem - * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2007, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,7 +42,7 @@ struct log_item_s { audit_event_t event; /* The event. */ gpg_error_t err; /* The logged error code. */ - int intvalue; /* A logged interger value. */ + int intvalue; /* A logged integer value. */ char *string; /* A malloced string or NULL. */ ksba_cert_t cert; /* A certifciate or NULL. */ int have_err:1; @@ -483,6 +483,14 @@ writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...) oktext = _("|audit-log-result|Not enabled"); else if (!strcmp (oktext, "error")) oktext = _("|audit-log-result|Error"); + else if (!strcmp (oktext, "not-used")) + oktext = _("|audit-log-result|Not used"); + else if (!strcmp (oktext, "okay")) + oktext = _("|audit-log-result|Okay"); + else if (!strcmp (oktext, "skipped")) + oktext = _("|audit-log-result|Skipped"); + else if (!strcmp (oktext, "some")) + oktext = _("|audit-log-result|Some"); else s = ""; @@ -806,16 +814,72 @@ proc_type_encrypt (audit_ctx_t ctx) static void proc_type_sign (audit_ctx_t ctx) { - log_item_t item; + log_item_t item, loopitem; + int signer, idx; + const char *result; + ksba_cert_t cert; + char *name; + int lastalgo; - item = NULL; + item = find_log_item (ctx, AUDIT_SIGNING_DONE, 0); writeout_li (ctx, item?"Yes":"No", "%s", _("Data signing succeeded")); enter_li (ctx); item = find_log_item (ctx, AUDIT_GOT_DATA, 0); writeout_li (ctx, item? "Yes":"No", "%s", _("Data available")); + /* Write remarks with the data hash algorithms. We use a very + simple scheme to avoid some duplicates. */ + loopitem = NULL; + lastalgo = 0; + while ((loopitem = find_next_log_item + (ctx, loopitem, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG))) + { + if (loopitem->intvalue && loopitem->intvalue != lastalgo) + writeout_rem (ctx, _("data hash algorithm: %s"), + gcry_md_algo_name (loopitem->intvalue)); + lastalgo = loopitem->intvalue; + } + /* Loop over all signer. */ + loopitem = NULL; + signer = 0; + while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_NEW_SIG, 0))) + { + signer++; + + item = find_next_log_item (ctx, loopitem, AUDIT_SIGNED_BY, AUDIT_NEW_SIG); + if (!item) + result = "error"; + else if (!item->err) + result = "okay"; + else if (gpg_err_code (item->err) == GPG_ERR_CANCELED) + result = "skipped"; + else + result = gpg_strerror (item->err); + cert = item? item->cert : NULL; + + writeout_li (ctx, result, _("Signer %d"), signer); + item = find_next_log_item (ctx, loopitem, + AUDIT_ATTR_HASH_ALGO, AUDIT_NEW_SIG); + if (item) + writeout_rem (ctx, _("attr hash algorithm: %s"), + gcry_md_algo_name (item->intvalue)); + + if (cert) + { + name = get_cert_name (cert); + writeout_rem (ctx, "%s", name); + xfree (name); + enter_li (ctx); + for (idx=0; (name = get_cert_subject (cert, idx)); idx++) + { + writeout_rem (ctx, "%s", name); + xfree (name); + } + leave_li (ctx); + } + } leave_li (ctx); } @@ -826,16 +890,87 @@ proc_type_sign (audit_ctx_t ctx) static void proc_type_decrypt (audit_ctx_t ctx) { - log_item_t item; + log_item_t loopitem, item; + int algo, recpno; + char *name; + char numbuf[35]; + int idx; - item = NULL; - writeout_li (ctx, item?"Yes":"No", "%s", _("Data decryption succeeded")); + item = find_log_item (ctx, AUDIT_DECRYPTION_RESULT, 0); + writeout_li (ctx, item && !item->err?"Yes":"No", + "%s", _("Data decryption succeeded")); enter_li (ctx); item = find_log_item (ctx, AUDIT_GOT_DATA, 0); writeout_li (ctx, item? "Yes":"No", "%s", _("Data available")); + item = find_log_item (ctx, AUDIT_DATA_CIPHER_ALGO, 0); + algo = item? item->intvalue : 0; + writeout_li (ctx, algo?"Yes":"No", "%s", _("Encryption algorithm supported")); + if (algo) + writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo)); + + item = find_log_item (ctx, AUDIT_BAD_DATA_CIPHER_ALGO, 0); + if (item && item->string) + { + algo = gcry_cipher_map_name (item->string); + if (algo) + writeout_rem (ctx, _("algorithm: %s"), gcry_cipher_algo_name (algo)); + else if (item->string && !strcmp (item->string, "1.2.840.113549.3.2")) + writeout_rem (ctx, _("unsupported algorithm: %s"), "RC2"); + else if (item->string) + writeout_rem (ctx, _("unsupported algorithm: %s"), item->string); + else + writeout_rem (ctx, _("seems to be not encrypted")); + } + + + for (recpno = 0, item = NULL; + (item = find_next_log_item (ctx, item, AUDIT_NEW_RECP, 0)); recpno++) + ; + snprintf (numbuf, sizeof numbuf, "%d", recpno); + writeout_li (ctx, numbuf, "%s", _("Number of recipients")); + + /* Loop over all recipients. */ + loopitem = NULL; + while ((loopitem = find_next_log_item (ctx, loopitem, AUDIT_NEW_RECP, 0))) + { + const char *result; + + recpno = loopitem->have_intvalue? loopitem->intvalue : -1; + + item = find_next_log_item (ctx, loopitem, + AUDIT_RECP_RESULT, AUDIT_NEW_RECP); + if (!item) + result = "not-used"; + else if (!item->err) + result = "okay"; + else if (gpg_err_code (item->err) == GPG_ERR_CANCELED) + result = "skipped"; + else + result = gpg_strerror (item->err); + + item = find_next_log_item (ctx, loopitem, + AUDIT_RECP_NAME, AUDIT_NEW_RECP); + writeout_li (ctx, result, _("Recipient %d"), recpno); + if (item && item->string) + writeout_rem (ctx, "%s", item->string); + + /* If we have a certificate write out more infos. */ + item = find_next_log_item (ctx, loopitem, + AUDIT_SAVE_CERT, AUDIT_NEW_RECP); + if (item && item->cert) + { + 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); } @@ -847,11 +982,12 @@ static void proc_type_verify (audit_ctx_t ctx) { log_item_t loopitem, item; - int signo, count, idx; + int signo, count, idx, n_good, n_bad; char numbuf[35]; + const char *result; /* If there is at least one signature status we claim that the - verifciation succeeded. This does not mean that the data has + verification succeeded. This does not mean that the data has verified okay. */ item = find_log_item (ctx, AUDIT_SIG_STATUS, 0); writeout_li (ctx, item?"Yes":"No", "%s", _("Data verification succeeded")); @@ -867,17 +1003,41 @@ proc_type_verify (audit_ctx_t ctx) if (!item) goto leave; - item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG); - writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded")); - if (!item) + /* Print info about the used data hashing algorithms. */ + for (idx=0, n_good=n_bad=0; idx < ctx->logused; idx++) { - item = find_log_item (ctx, AUDIT_BAD_DATA_HASH_ALGO, AUDIT_NEW_SIG); - if (item) - writeout_rem (ctx, _("Bad hash algorithm: %s"), - item->string? item->string:"?"); - - goto leave; + item = ctx->log + idx; + if (item->event == AUDIT_NEW_SIG) + break; + else if (item->event == AUDIT_DATA_HASH_ALGO) + n_good++; + else if (item->event == AUDIT_BAD_DATA_HASH_ALGO) + n_bad++; } + item = find_log_item (ctx, AUDIT_DATA_HASHING, AUDIT_NEW_SIG); + if (!item || item->err || !n_good) + result = "No"; + else if (n_good && !n_bad) + result = "Yes"; + else + result = "Some"; + writeout_li (ctx, result, "%s", _("Parsing data succeeded")); + if (n_good || n_bad) + { + for (idx=0; idx < ctx->logused; idx++) + { + item = ctx->log + idx; + if (item->event == AUDIT_NEW_SIG) + break; + else if (item->event == AUDIT_DATA_HASH_ALGO) + writeout_rem (ctx, _("data hash algorithm: %s"), + gcry_md_algo_name (item->intvalue)); + else if (item->event == AUDIT_BAD_DATA_HASH_ALGO) + writeout_rem (ctx, _("bad data hash algorithm: %s"), + item->string? item->string:"?"); + } + } + /* Loop over all signatures. */ loopitem = find_log_item (ctx, AUDIT_NEW_SIG, 0); @@ -893,6 +1053,18 @@ proc_type_verify (audit_ctx_t ctx) AUDIT_SIG_NAME, AUDIT_NEW_SIG); if (item) writeout_rem (ctx, "%s", item->string); + + item = find_next_log_item (ctx, loopitem, + AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG); + if (item) + writeout_rem (ctx, _("data hash algorithm: %s"), + gcry_md_algo_name (item->intvalue)); + item = find_next_log_item (ctx, loopitem, + AUDIT_ATTR_HASH_ALGO, AUDIT_NEW_SIG); + if (item) + writeout_rem (ctx, _("attr hash algorithm: %s"), + gcry_md_algo_name (item->intvalue)); + enter_li (ctx); /* List the certificate chain. */ @@ -1006,11 +1178,7 @@ audit_print_result (audit_ctx_t ctx, estream_t out, int use_html) /* We use an environment variable to include some debug info in the log. */ if ((s = getenv ("gnupg_debug_audit"))) - { - show_raw = 1; - if (!strcmp (s, "html")) - use_html = 1; - } + show_raw = 1; assert (!ctx->outstream); ctx->outstream = out; diff --git a/common/audit.h b/common/audit.h index 491710706..bc67a2ee8 100644 --- a/common/audit.h +++ b/common/audit.h @@ -62,6 +62,12 @@ typedef enum operations the Dirmngr is not required and thus no such event will be logged. */ + AUDIT_GPG_READY, /* err */ + /* Indicates whether the Gpg engine is available. */ + + AUDIT_GPGSM_READY, /* err */ + /* Indicates whether the Gpgsm engine is available. */ + AUDIT_GOT_DATA, /* Data to be processed has been seen. */ @@ -72,15 +78,27 @@ typedef enum /* A certifciate only signature has been detected. */ AUDIT_DATA_HASH_ALGO, /* int */ - /* The hash algo given as argument is used for this signature. - This event will be repeated for all hash algorithms used with - the data. */ + /* The hash algo given as argument is used for the data. This + event will be repeated for all hash algorithms used with the + data. */ + + AUDIT_ATTR_HASH_ALGO, /* int */ + /* The hash algo given as argument is used to hash the message + digest and other signed attributes of this signature. */ + + AUDIT_DATA_CIPHER_ALGO, /* int */ + /* The cipher algo given as argument is used for this data. */ AUDIT_BAD_DATA_HASH_ALGO, /* string */ /* The hash algo as specified by the signature can't be used. STRING is the description of this algorithm which usually is an OID string. STRING may be NULL. */ + AUDIT_BAD_DATA_CIPHER_ALGO, /* string */ + /* The symmetric cipher algorithm is not supported. STRING is the + description of this algorithm which usually is an OID string. + STRING may be NULL. */ + AUDIT_DATA_HASHING, /* ok_err */ /* Logs the result of the data hashing. */ @@ -109,7 +127,7 @@ typedef enum certificate used for verification. An example for STRING when using CMS is: "#1234/CN=Prostetnic Vogon Jeltz". */ - AUDIT_SIG_STATUS, /* string */ + AUDIT_SIG_STATUS, /* string */ /* The signature status of the current signer. This is the last audit information for one signature. STRING gives the status: @@ -121,6 +139,24 @@ typedef enum "good" - good signature */ + AUDIT_NEW_RECP, /* int */ + /* A new recipient has been seen during decryption. The argument + is the recipient number as used internally by the program. */ + + AUDIT_RECP_NAME, /* string */ + /* The name of a recipient. This is the name or other identification + data as known from the decryption and not the name from the + certificate used for decryption. An example for STRING when + using CMS is: "#1234/CN=Prostetnic Vogon Jeltz". */ + + AUDIT_RECP_RESULT, /* ok_err */ + /* The status of the session key decryption. This is only written + for recipients tried. */ + + AUDIT_DECRYPTION_RESULT, /* ok_err */ + /* The status of the entire decryption. The decryption was + successful if the error code is 0. */ + AUDIT_VALIDATE_CHAIN, /* Start the validation of a certificate chain. */ @@ -158,7 +194,12 @@ typedef enum AUDIT_ENCRYPTION_DONE, /* Encryption succeeded. */ - + AUDIT_SIGNED_BY, /* cert, err */ + /* Records the certificate used for signed and whether the signure + could be created (if err==0). */ + + AUDIT_SIGNING_DONE, + /* Signing succeeded. */ AUDIT_LAST_EVENT /* Marker for parsing this list. */ diff --git a/g10/ChangeLog b/g10/ChangeLog index ed9482e3a..c075d2160 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -3,6 +3,8 @@ * gpg.c (set_debug): Allow for numerical debug levels. Print active debug flags. + * gpg.c (gpgconf_list): Add key "default_pubkey_algo". + 2009-09-28 Werner Koch * trustdb.c (get_validity_info): Take care of a NULL PK. Fixes diff --git a/g10/gpg.c b/g10/gpg.c index 9555be38c..cdbc7b990 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1613,6 +1613,11 @@ gpgconf_list (const char *configfile) printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); printf ("group:%lu:\n", GC_OPT_FLAG_NONE); + /* The next one is an info only item and should match what + keygen:ask_keysize actually implements. */ + printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, + "RSA-2048"); + xfree (configfile_esc); } diff --git a/g10/keygen.c b/g10/keygen.c index 3abc19bd0..3e0f36e8f 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1765,6 +1765,8 @@ ask_algo (int addmode, int *r_subkey_algo, unsigned int *r_usage) static unsigned ask_keysize (int algo, unsigned int primary_keysize) { + /* NOTE: If you change the default key size/algo, remember to change + it also in gpg.c:gpgconf_list. */ unsigned int nbits, min, def=2048, max=4096; int for_subkey = !!primary_keysize; int autocomp = 0; diff --git a/sm/ChangeLog b/sm/ChangeLog index 67931eafe..267befa05 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,18 @@ +2009-12-03 Werner Koch + + From trunk: + + * verify.c (gpgsm_verify): Add audit info on hash algorithms. + * sign.c (gpgsm_sign): Add audit log calls. + (hash_data): Return an error indicator. + * decrypt.c (gpgsm_decrypt): Add audit log calls. + + * gpgsm.c: New option --html-audit-log. + + * certreqgen.c (proc_parameters): Change fallback key length to + 2048. + * gpgsm.c (main) : Add key "default_pubkey_algo". + 2009-12-03 Werner Koch * gpgsm.c (set_debug): Allow for numerical debug levels. Print diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 59e667981..49b2b9208 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -61,7 +61,7 @@ The format of the native parameter file is follows: This is a required parameter. For now the only supported algorithm is "rsa". Key-Length: - Length of the key in bits. Default is 1024. + Length of the key in bits. Default is 2048. Key-Grip: hexstring This is optional and used to generate a request for an already existing key. Key-Length will be ignored when given, @@ -83,7 +83,7 @@ Here is an example: $ cat >foo < 4096) && !cardkeyid) diff --git a/sm/decrypt.c b/sm/decrypt.c index 8fb9f2dfd..de025516f 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -253,6 +253,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) memset (&dfparm, 0, sizeof dfparm); + audit_set_type (ctrl->audit, AUDIT_TYPE_DECRYPT); + kh = keydb_new (0); if (!kh) { @@ -296,6 +298,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) goto leave; } + audit_log (ctrl->audit, AUDIT_SETUP_READY); + /* Parser loop. */ do { @@ -313,6 +317,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) const char *algoid; int any_key = 0; + audit_log (ctrl->audit, AUDIT_GOT_DATA); + algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/); algo = gcry_cipher_map_name (algoid); mode = gcry_cipher_mode_from_oid (algoid); @@ -330,6 +336,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) sprintf (numbuf, "%d", rc); gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm", numbuf, algoid?algoid:"?", NULL); + audit_log_s (ctrl->audit, AUDIT_BAD_DATA_CIPHER_ALGO, algoid); } /* If it seems that this is not an encrypted message we @@ -339,6 +346,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) goto leave; } + + audit_log_i (ctrl->audit, AUDIT_DATA_CIPHER_ALGO, algo); dfparm.algo = algo; dfparm.mode = mode; dfparm.blklen = gcry_cipher_get_algo_blklen (algo); @@ -369,6 +378,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial); if (rc == -1 && recp) break; /* no more recipients */ + audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); if (rc) log_error ("recp %d - error getting info: %s\n", recp, gpg_strerror (rc)); @@ -382,6 +392,13 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) gpgsm_dump_serial (serial); log_printf ("\n"); + if (ctrl->audit) + { + char *tmpstr = gpgsm_format_sn_issuer (serial, issuer); + audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr); + xfree (tmpstr); + } + keydb_search_reset (kh); rc = keydb_search_issuer_sn (kh, issuer, serial); if (rc) @@ -415,6 +432,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) kidbuf, "0", "0", NULL); } + /* Put the certificate into the audit log. */ + audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert, 0); /* Just in case there is a problem with the own certificate we print this message - should never @@ -462,10 +481,41 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) decrypt_filter, &dfparm); } + audit_log_ok (ctrl->audit, AUDIT_RECP_RESULT, rc); } xfree (hexkeygrip); xfree (desc); } + + /* If we write an audit log add the unused recipients to the + log as well. */ + if (ctrl->audit && any_key) + { + for (;; recp++) + { + char *issuer; + ksba_sexp_t serial; + int tmp_rc; + + tmp_rc = ksba_cms_get_issuer_serial (cms, recp, + &issuer, &serial); + if (tmp_rc == -1) + break; /* no more recipients */ + audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); + if (tmp_rc) + log_error ("recp %d - error getting info: %s\n", + recp, gpg_strerror (rc)); + else + { + char *tmpstr = gpgsm_format_sn_issuer (serial, issuer); + audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr); + xfree (tmpstr); + xfree (issuer); + xfree (serial); + } + } + } + if (!any_key) { rc = gpg_error (GPG_ERR_NO_SECKEY); @@ -488,7 +538,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) dfparm.lastblock, dfparm.blklen - npadding); if (rc) - goto leave; + goto leave; for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++) { @@ -515,6 +565,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp) leave: + audit_log_ok (ctrl->audit, AUDIT_DECRYPTION_RESULT, rc); if (rc) { gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 65de94ed3..982328192 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -99,6 +99,7 @@ enum cmd_and_opt_values { oLogFile, oNoLogFile, oAuditLog, + oHtmlAuditLog, oEnableSpecialFilenames, @@ -286,6 +287,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oAuditLog, "audit-log", N_("|FILE|write an audit log to FILE")), + ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", ""), ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), ARGPARSE_s_n (oBatch, "batch", N_("batch mode: never ask")), ARGPARSE_s_n (oAnswerYes, "yes", N_("assume yes on most questions")), @@ -863,6 +865,7 @@ main ( int argc, char **argv) int default_keyring = 1; char *logfile = NULL; char *auditlog = NULL; + char *htmlauditlog = NULL; int greeting = 0; int nogreeting = 0; int debug_wait = 0; @@ -878,6 +881,7 @@ main ( int argc, char **argv) int do_not_setup_keys = 0; int recp_required = 0; estream_t auditfp = NULL; + estream_t htmlauditfp = NULL; /*mtrace();*/ @@ -1194,6 +1198,7 @@ main ( int argc, char **argv) case oNoLogFile: logfile = NULL; break; case oAuditLog: auditlog = pargs.r.ret_str; break; + case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break; case oBatch: opt.batch = 1; @@ -1422,11 +1427,6 @@ main ( int argc, char **argv) } # endif - if (auditlog) - log_info ("NOTE: The audit log feature (--audit-log) is " - "WORK IN PRORESS and not ready for use!\n"); - - if (may_coredump && !opt.quiet) log_info (_("WARNING: program may create a core file!\n")); @@ -1558,7 +1558,7 @@ main ( int argc, char **argv) /* Prepare the audit log feature for certain commands. */ - if (auditlog) + if (auditlog || htmlauditlog) { switch (cmd) { @@ -1568,7 +1568,10 @@ main ( int argc, char **argv) case aVerify: audit_release (ctrl.audit); ctrl.audit = audit_new (); - auditfp = open_es_fwrite (auditlog); + if (auditlog) + auditfp = open_es_fwrite (auditlog); + if (htmlauditlog) + htmlauditfp = open_es_fwrite (htmlauditlog); break; default: break; @@ -1645,6 +1648,10 @@ main ( int argc, char **argv) printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_DEFAULT); printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE); + /* The next one is an info only item and should match what + proc_parameters actually implements. */ + printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, + "RSA-2048"); } break; case aGPGConfTest: @@ -1920,12 +1927,16 @@ main ( int argc, char **argv) } /* Print the audit result if needed. */ - if (auditlog && auditfp) + if ((auditlog && auditfp) || (htmlauditlog && htmlauditfp)) { - audit_print_result (ctrl.audit, auditfp, 0); + if (auditlog && auditfp) + audit_print_result (ctrl.audit, auditfp, 0); + if (htmlauditlog && htmlauditfp) + audit_print_result (ctrl.audit, htmlauditfp, 1); audit_release (ctrl.audit); ctrl.audit = NULL; es_fclose (auditfp); + es_fclose (htmlauditfp); } /* cleanup */ diff --git a/sm/sign.c b/sm/sign.c index 776a5a571..fd7c4ff2f 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -34,18 +34,20 @@ #include "i18n.h" -static void +/* Hash the data and return if something was hashed. Return -1 on error. */ +static int hash_data (int fd, gcry_md_hd_t md) { FILE *fp; char buffer[4096]; int nread; + int rc = 0; fp = fdopen ( dup (fd), "rb"); if (!fp) { log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno)); - return; + return -1; } do @@ -55,8 +57,12 @@ hash_data (int fd, gcry_md_hd_t md) } while (nread); if (ferror (fp)) + { log_error ("read error on fd %d: %s\n", fd, strerror (errno)); + rc = -1; + } fclose (fp); + return rc; } static int @@ -321,6 +327,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, certlist_t cl; int release_signerlist = 0; + audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN); + kh = keydb_new (0); if (!kh) { @@ -539,8 +547,11 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } gcry_md_enable (data_md, algo); + audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo); } + audit_log (ctrl->audit, AUDIT_SETUP_READY); + if (detached) { /* We hash the data right now so that we can store the message digest. ksba_cms_build() takes this as an flag that detached @@ -548,7 +559,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, unsigned char *digest; size_t digest_len; - hash_data (data_fd, data_md); + if (!hash_data (data_fd, data_md)) + audit_log (ctrl->audit, AUDIT_GOT_DATA); for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { digest = gcry_md_read (data_md, cl->hash_algo); @@ -623,6 +635,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, rc = hash_and_copy_data (data_fd, data_md, writer); if (rc) goto leave; + audit_log (ctrl->audit, AUDIT_GOT_DATA); for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { digest = gcry_md_read (data_md, cl->hash_algo); @@ -663,13 +676,18 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, unsigned char *sigval = NULL; char *buf, *fpr; + audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer); if (signer) gcry_md_reset (md); { certlist_t cl_tmp; for (cl_tmp=signerlist; cl_tmp; cl_tmp = cl_tmp->next) - gcry_md_enable (md, cl_tmp->hash_algo); + { + gcry_md_enable (md, cl_tmp->hash_algo); + audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, + cl_tmp->hash_algo); + } } rc = ksba_cms_hash_signed_attrs (cms, signer); @@ -685,6 +703,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, md, cl->hash_algo, &sigval); if (rc) { + audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, rc); gcry_md_close (md); goto leave; } @@ -693,6 +712,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, xfree (sigval); if (err) { + audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err); log_error ("failed to store the signature: %s\n", gpg_strerror (err)); rc = err; @@ -708,28 +728,29 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, gcry_md_close (md); goto leave; } + rc = 0; { int pkalgo = gpgsm_get_key_algo_info (cl->cert, NULL); - rc = asprintf (&buf, "%c %d %d 00 %s %s", - detached? 'D':'S', - pkalgo, - cl->hash_algo, - signed_at, - fpr); + buf = xtryasprintf ("%c %d %d 00 %s %s", + detached? 'D':'S', + pkalgo, + cl->hash_algo, + signed_at, + fpr); + if (!buf) + rc = gpg_error_from_syserror (); } xfree (fpr); - if (rc < 0) + if (rc) { - rc = gpg_error (GPG_ERR_ENOMEM); gcry_md_close (md); goto leave; } - rc = 0; gpgsm_status (ctrl, STATUS_SIG_CREATED, buf); - free (buf); /* yes, we must use the regular free() here */ + xfree (buf); + audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, 0); } gcry_md_close (md); - } } while (stopreason != KSBA_SR_READY); @@ -741,6 +762,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } + audit_log (ctrl->audit, AUDIT_SIGNING_DONE); log_info ("signature created\n"); diff --git a/sm/verify.c b/sm/verify.c index 77517c61f..c8663e3e6 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -216,6 +216,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp) log_debug ("enabling extra hash algorithm %d\n", opt.extra_digest_algo); gcry_md_enable (data_md, opt.extra_digest_algo); + audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, + opt.extra_digest_algo); } if (is_detached) { @@ -236,7 +238,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp) } else if (stopreason == KSBA_SR_END_DATA) { /* The data bas been hashed */ - + audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING, 0); } } while (stopreason != KSBA_SR_READY); @@ -452,6 +454,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp) log_printf (_(" using certificate ID 0x%08lX\n"), gpgsm_get_short_fingerprint (cert, NULL)); + audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo); if (msgdigest) { /* Signed attributes are available. */ @@ -484,6 +487,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp) goto next_signer; } + audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, sigval_hash_algo); rc = gcry_md_open (&md, sigval_hash_algo, 0); if (rc) {