diff --git a/ChangeLog b/ChangeLog index 48f36a3b7..9613806bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-12-12 Werner Koch + + * configure.ac (USE_CAMELLIA): Define by new option --enable-camellia. + 2007-12-03 Werner Koch * configure.ac: Add test gt_LC_MESSAGES.. diff --git a/NEWS b/NEWS index 87ea82f77..e6fe5a914 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,14 @@ Noteworthy changes in version 2.0.8 * The envvars XAUTHORITY and PINENTRY_USER_DATA are now passed to the pinentry. + * Allow encryption using Elgamal keys with the algorithm id 20. + + * Fixed the auto creation of the key stub for smartcards. + + * Fixed a rare bug in decryption using the OpenPGP card. + + * Creating DSA2 keys is now possible. + Noteworthy changes in version 2.0.7 (2007-09-10) ------------------------------------------------ diff --git a/TODO b/TODO index 7eebe4487..630e832b8 100644 --- a/TODO +++ b/TODO @@ -91,7 +91,7 @@ ** issue a NO_SECKEY xxxx if a -u key was not found. -* When switching to libgcrypt 1.3 +* When switching to libgcrypt 1.4 ** scd#encode_md_for_card, g10#encode_md_value, sm@do_encode_md Remove the extra test for a valid algorithm as libgcrypt will do it then in gcry_md_algo_info. diff --git a/common/ChangeLog b/common/ChangeLog index a9e393201..b6b12f95b 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,9 @@ +2007-12-11 Werner Koch + + * asshelp.c (send_pinentry_environment): Allow using of old + gpg-agents not capabale of the xauthority and pinentry_user_data + options. + 2007-12-04 Werner Koch * Makefile.am (t_helpfile_LDADD, module_maint_tests): New. diff --git a/common/asshelp.c b/common/asshelp.c index 5aa61c773..8274d88a7 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -172,6 +172,8 @@ send_pinentry_environment (assuan_context_t ctx, { err = send_one_option (ctx, errsource, "xauthority", opt_xauthority ? opt_xauthority : dft_xauthority); + if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) + err = 0; if (err) return err; } @@ -183,6 +185,8 @@ send_pinentry_environment (assuan_context_t ctx, err = send_one_option (ctx, errsource, "pinentry-user-data", opt_pinentry_user_data ? opt_pinentry_user_data : dft_pinentry_user_data); + if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) + err = 0; if (err) return err; } diff --git a/common/audit.c b/common/audit.c index 40cbb8274..59f881cd5 100644 --- a/common/audit.c +++ b/common/audit.c @@ -449,9 +449,9 @@ writeout_li (audit_ctx_t ctx, const char *oktext, const char *format, ...) if (ctx->use_html && format && oktext) { - if (!strcmp (oktext, "OK") || !strcmp (oktext, "Yes")) + if (!strcmp (oktext, "Yes")) color = "green"; - else if (!strcmp (oktext, "FAIL") || !strcmp (oktext, "No")) + else if (!strcmp (oktext, "No")) color = "red"; } @@ -648,42 +648,20 @@ get_cert_subject (ksba_cert_t cert, int idx) } -/* List the chain of certificates from STARTITEM up to STOPEVENT. The - certifcates are written out as comments. */ +/* List the given certificiate. If CERT is NULL, this is a NOP. */ static void -list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent) +list_cert (audit_ctx_t ctx, ksba_cert_t cert, int with_subj) { - log_item_t item; char *name; int idx; - startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent); - if (!startitem) + name = get_cert_name (cert); + writeout_rem (ctx, "%s", name); + xfree (name); + if (with_subj) { - 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++) + for (idx=0; (name = get_cert_subject (cert, idx)); idx++) { writeout_rem (ctx, "%s", name); xfree (name); @@ -693,8 +671,142 @@ list_certchain (audit_ctx_t ctx, log_item_t startitem, audit_event_t stopevent) } +/* 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; + + startitem = find_next_log_item (ctx, startitem, AUDIT_CHAIN_BEGIN,stopevent); + writeout_li (ctx, startitem? "Yes":"No", _("Certificate chain available")); + if (!startitem) + return; + + item = find_next_log_item (ctx, startitem, + AUDIT_CHAIN_ROOTCERT, AUDIT_CHAIN_END); + if (!item) + writeout_rem (ctx, "%s", _("root certificate missing")); + else + { + list_cert (ctx, item->cert, 0); + } + item = startitem; + while ( ((item = find_next_log_item (ctx, item, + AUDIT_CHAIN_CERT, AUDIT_CHAIN_END)))) + { + list_cert (ctx, item->cert, 1); + } +} + + -/* Process a verification operation. */ +/* Process an encrypt operation's log. */ +static void +proc_type_encrypt (audit_ctx_t ctx) +{ + log_item_t loopitem, item; + int recp_no, idx; + char numbuf[35]; + int algo; + char *name; + + item = find_log_item (ctx, AUDIT_ENCRYPTION_DONE, 0); + writeout_li (ctx, item?"Yes":"No", "%s", _("Data encryption 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_SESSION_KEY, 0); + writeout_li (ctx, item? "Yes":"No", "%s", _("Session key created")); + if (item) + { + 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")); + } + + item = find_log_item (ctx, AUDIT_GOT_RECIPIENTS, 0); + snprintf (numbuf, sizeof numbuf, "%d", + item && item->have_intvalue? item->intvalue : 0); + writeout_li (ctx, numbuf, "%s", _("Number of recipients")); + + /* Loop over all recipients. */ + loopitem = NULL; + recp_no = 0; + while ((loopitem=find_next_log_item (ctx, loopitem, AUDIT_ENCRYPTED_TO, 0))) + { + recp_no++; + writeout_li (ctx, NULL, _("Recipient %d"), recp_no); + if (loopitem->cert) + { + name = get_cert_name (loopitem->cert); + writeout_rem (ctx, "%s", name); + xfree (name); + enter_li (ctx); + for (idx=0; (name = get_cert_subject (loopitem->cert, idx)); idx++) + { + writeout_rem (ctx, "%s", name); + xfree (name); + } + leave_li (ctx); + } + } + + leave_li (ctx); +} + + + +/* Process a sign operation's log. */ +static void +proc_type_sign (audit_ctx_t ctx) +{ + log_item_t item; + + item = NULL; + 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")); + + + leave_li (ctx); +} + + + +/* Process a decrypt operation's log. */ +static void +proc_type_decrypt (audit_ctx_t ctx) +{ + log_item_t item; + + item = NULL; + writeout_li (ctx, item?"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")); + + + leave_li (ctx); +} + + + +/* Process a verification operation's log. */ static void proc_type_verify (audit_ctx_t ctx) { @@ -702,13 +814,12 @@ proc_type_verify (audit_ctx_t ctx) int signo, count, idx; char numbuf[35]; + /* If there is at least one signature status we claim that the + verifciation 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")); 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")); @@ -721,19 +832,14 @@ proc_type_verify (audit_ctx_t ctx) goto leave; item = find_log_item (ctx, AUDIT_DATA_HASH_ALGO, AUDIT_NEW_SIG); - if (item) - writeout_li (ctx, "OK", "%s", _("Parsing signature")); - else + writeout_li (ctx, item?"Yes":"No", "%s", _("Parsing signature succeeded")); + if (!item) { 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") ); + writeout_rem (ctx, _("Bad hash algorithm: %s"), + item->string? item->string:"?"); + goto leave; } @@ -761,19 +867,30 @@ proc_type_verify (audit_ctx_t ctx) AUDIT_CHAIN_STATUS, AUDIT_NEW_SIG); if (item && item->have_err) { - writeout_li (ctx, item->err? "FAIL":"OK", - _("Validation of certificate chain")); + writeout_li (ctx, item->err? "No":"Yes", + _("Certificate chain valid")); 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")); - add_helptag (ctx, "gpgsm.root-cert-not-trusted"); + item = find_next_log_item (ctx, loopitem, + AUDIT_ROOT_TRUSTED, AUDIT_CHAIN_STATUS); + if (item) + { + writeout_li (ctx, item->err?"No":"Yes", "%s", + _("Root certificate trustworthy")); + if (item->err) + { + add_helptag (ctx, "gpgsm.root-cert-not-trusted"); + writeout_rem (ctx, "%s", gpg_strerror (item->err)); + list_cert (ctx, item->cert, 0); + } + } /* Show result of the CRL/OCSP check. */ writeout_li (ctx, "-", "%s", _("CRL/OCSP check of certificates")); - add_helptag (ctx, "gpgsm.ocsp-problem"); + /* add_helptag (ctx, "gpgsm.ocsp-problem"); */ leave_li (ctx); @@ -805,8 +922,6 @@ proc_type_verify (audit_ctx_t ctx) } leave_li (ctx); } - - leave_li (ctx); leave_li (ctx); } @@ -818,16 +933,24 @@ void audit_print_result (audit_ctx_t ctx, estream_t out, int use_html) { int idx; - int maxlen; size_t n; + log_item_t item; helptag_t helptag; - - if (getenv ("use_html")) - use_html = 1; - + const char *s; + int show_raw = 0; + if (!ctx) return; + /* 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; + } + assert (!ctx->outstream); ctx->outstream = out; ctx->use_html = use_html; @@ -843,51 +966,87 @@ audit_print_result (audit_ctx_t ctx, estream_t out, int use_html) goto leave; } - for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++) + if (show_raw) { - n = strlen (eventstr_msgstr + eventstr_msgidx[idx]); - if (n > maxlen) - maxlen = n; + int maxlen; + + for (idx=0,maxlen=0; idx < DIM (eventstr_msgidx); idx++) + { + n = strlen (eventstr_msgstr + eventstr_msgidx[idx]); + if (n > maxlen) + maxlen = n; + } + + if (use_html) + es_fputs ("
\n", out);
+      for (idx=0; idx < ctx->logused; idx++)
+        {
+          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_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_fputs (" err=`", out);
+              writeout (ctx, gpg_strerror (ctx->log[idx].err)); 
+              es_fputs ("'", out);
+            }
+          es_fputs ("\n", out);
+        }
+      if (use_html)
+        es_fputs ("
\n", out); + else + es_fputs ("\n", out); } - if (use_html) - es_fputs ("
\n", out);
-  for (idx=0; idx < ctx->logused; idx++)
-    {
-      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_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_fputs (" err=`", out);
-          writeout (ctx, gpg_strerror (ctx->log[idx].err)); 
-          es_fputs ("'", out);
-        }
-      es_fputs ("\n", out);
-    }
-  if (use_html)
-    es_fputs ("
\n", out); - else - es_fputs ("\n", out); - + enter_li (ctx); switch (ctx->type) { case AUDIT_TYPE_NONE: - writeout_para (ctx, _("Audit of this operation is not supported.")); + writeout_li (ctx, NULL, _("Unknown operation")); + break; + case AUDIT_TYPE_ENCRYPT: + proc_type_encrypt (ctx); + break; + case AUDIT_TYPE_SIGN: + proc_type_sign (ctx); + break; + case AUDIT_TYPE_DECRYPT: + proc_type_decrypt (ctx); break; case AUDIT_TYPE_VERIFY: proc_type_verify (ctx); break; } + item = find_log_item (ctx, AUDIT_AGENT_READY, 0); + if (item && item->have_err) + { + writeout_li (ctx, item->err? "No":"Yes", "%s", _("Gpg-Agent usable")); + if (item->err) + { + writeout_rem (ctx, "%s", gpg_strerror (item->err)); + add_helptag (ctx, "gnupg.agent-problem"); + } + } + item = find_log_item (ctx, AUDIT_DIRMNGR_READY, 0); + if (item && item->have_err) + { + writeout_li (ctx, item->err? "No":"Yes", "%s", _("Dirmngr usable")); + if (item->err) + { + writeout_rem (ctx, "%s", gpg_strerror (item->err)); + add_helptag (ctx, "gnupg.dirmngr-problem"); + } + } + leave_li (ctx); /* Show the help from the collected help tags. */ diff --git a/common/audit.h b/common/audit.h index 514ef120e..85c2ffc25 100644 --- a/common/audit.h +++ b/common/audit.h @@ -31,6 +31,9 @@ typedef struct audit_ctx_s *audit_ctx_t; typedef enum { AUDIT_TYPE_NONE = 0, /* No type set. */ + AUDIT_TYPE_ENCRYPT, /* Data encryption. */ + AUDIT_TYPE_SIGN, /* Signature creation. */ + AUDIT_TYPE_DECRYPT, /* Data decryption. */ AUDIT_TYPE_VERIFY /* Signature verification. */ } audit_type_t; @@ -49,6 +52,16 @@ typedef enum now. This indicates that all parameters are okay and we can start to process the actual data. */ + AUDIT_AGENT_READY, /* err */ + /* Indicates whether the gpg-agent is available. For some + operations the agent is not required and thus no such event + will be logged. */ + + AUDIT_DIRMNGR_READY, /* err */ + /* Indicates whether the Dirmngr is available. For some + operations the Dirmngr is not required and thus no such event + will be logged. */ + AUDIT_GOT_DATA, /* Data to be processed has been seen. */ @@ -122,6 +135,28 @@ typedef enum AUDIT_CHAIN_STATUS, /* err */ /* Tells the final status of the chain validation. */ + AUDIT_ROOT_TRUSTED, /* cert, err */ + /* Tells whether the root certificate is trusted. This event is + emmited durcing chain validation. */ + + AUDIT_GOT_RECIPIENTS, /* int */ + /* Records the number of recipients to be used for encryption. + This includes the recipients set by --encrypt-to but records 0 + if no real recipient has been given. */ + + AUDIT_SESSION_KEY, /* string */ + /* Mark the creation or availibility of the session key. The + parameter is the algorithm ID. */ + + AUDIT_ENCRYPTED_TO, /* cert, err */ + /* Records the certificate used for encryption and whether the + session key could be encrypted to it (err==0). */ + + AUDIT_ENCRYPTION_DONE, + /* Encryption succeeded. */ + + + AUDIT_LAST_EVENT /* Marker for parsing this list. */ } diff --git a/configure.ac b/configure.ac index 13714dace..95905449b 100644 --- a/configure.ac +++ b/configure.ac @@ -73,6 +73,7 @@ have_libusb=no use_bzip2=yes use_exec=yes disable_keyserver_path=no +use_camellia=no GNUPG_BUILD_PROGRAM(gpg, yes) @@ -172,6 +173,21 @@ AC_ARG_ENABLE(bzip2, use_bzip2=$enableval) AC_MSG_RESULT($use_bzip2) +# Check whether testing support for Camellia has been requested +AC_MSG_CHECKING([whether to enable the CAMELLIA cipher for gpg]) +AC_ARG_ENABLE(camellia, + AC_HELP_STRING([--enable-camellia],[enable the CAMELLIA cipher for gpg]), + use_camellia=$enableval) +AC_MSG_RESULT($use_camellia) +if test x"$use_camellia" = xyes ; then + AC_DEFINE(USE_CAMELLIA,1,[Define to include the CAMELLIA cipher into gpg]) + AC_MSG_WARN([[ +*** +*** The Camellia cipher for gpg is for testing only and +*** is NOT for production use! +***]]) +fi + # Configure option to allow or disallow execution of external # programs, like a photo viewer. @@ -1417,4 +1433,10 @@ echo " gpg-check-pattern will not be build. " fi +if test x"$use_camellia" = xyes ; then + echo + echo "WARNING: The Camellia cipher for gpg is for testing only" + echo " and is NOT for production use!" + echo +fi diff --git a/doc/help.de.txt b/doc/help.de.txt index 0518c3885..4d8236ead 100644 --- a/doc/help.de.txt +++ b/doc/help.de.txt @@ -272,6 +272,6 @@ Eine Leerzeile beendet die Eingabe. # Local variables: -# mode: fundamental +# mode: default-generic # coding: utf-8 # End: diff --git a/doc/help.txt b/doc/help.txt index afaaa29dc..4b8ec6277 100644 --- a/doc/help.txt +++ b/doc/help.txt @@ -52,6 +52,44 @@ configured passphrase constraints. . +.gnupg.agent-problem +# There was a problem accessing or starting the agent. +It was either not possible to connect to a running Gpg-Agent or a +communication problem with a running agent occurred. + +The system uses a background process, called Gpg-Agent, for processing +private keys and to ask for passphrases. The agent is usually started +when the user logs in and runs as long the user is logged in. In case +that no agent is available, the system tries to start one on the fly +but that version of the agent is somewhat limited in functionality and +thus may lead to little problems. + +You probably need to ask your administrator on how to solve the +problem. As a workaround you might try to log out and in to your +session and see whether this helps. If this helps please tell the +administrator anyway because this indicates a bug in the software. +. + + +.gnupg.dirmngr-problem +# There was a problen accessing the dirmngr. +It was either not possible to connect to a running Dirmngr or a +communication problem with a running Dirmngr occurred. + +To lookup certificate revocation lists (CRLs), performing OCSP +validation and to lookup keys through LDAP servers, the system uses an +external service program named Dirmngr. The Dirmngr is usually running +as a system service (daemon) and does not need any attention by the +user. In case of problems the system might start its own copy of the +Dirmngr on a per request base; this is a workaround and yields limited +performance. + +If you encounter this problem, you should ask your system +administrator how to proceed. As an interim solution you may try to +disable CRL checking in gpgsm's configuration. +. + + .gpg.edit_ownertrust.value # The help identies prefixed with "gpg." used to be hard coded in gpg # but may now be overridden by help texts from this file. @@ -312,6 +350,6 @@ your system administrator whether you should trust this certificate. # Local variables: -# mode: fundamental +# mode: default-generic # coding: utf-8 # End: diff --git a/g10/ChangeLog b/g10/ChangeLog index f6019a435..9e6602c6e 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,6 +1,30 @@ +2007-12-12 Werner Koch + + * misc.c (map_cipher_openpgp_to_gcry): New. Used to map Camellia + algorithms to Gcrypt. + (openpgp_cipher_test_algo): Call new map function. Replace + all remaining calls to gcry_cipher_test_algo by a call to this. + (openpgp_cipher_algo_name): New. Replace all remaining calls to + gcry_cipher_algo_name by a call to this. + (map_cipher_gcry_to_openpgp): New. + (string_to_cipher_algo): Use it. + * gpg.c (main): Print a warning if Camellia support is build in. + + * gpg.c (print_algo_names): New. From the 1.4 branch by David. + (list_config): Use it here for the "ciphername" and "digestname" + config items so we can get a script-parseable list of the names. + + * parse-packet.c (parse_onepass_sig): Sigclass is hex, so include + the 0x. + + * sign.c (match_dsa_hash): Remove conditional builds dending on + USE_SHAxxx. We don't need this becuase it can be expected that + libgcrypt provides it. However we need to runtime test for SHA244 + becuase that is only available with libgcrypt 2.4. + 2007-12-11 Werner Koch - * mainproc.c (proc_pubkey_enc): Allo type 20 Elgamal key for + * mainproc.c (proc_pubkey_enc): Allow type 20 Elgamal key for decryption. 2007-12-10 Werner Koch diff --git a/g10/encode.c b/g10/encode.c index ee2ce9703..92aa9b27d 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -244,7 +244,7 @@ encode_simple( const char *filename, int mode, int use_seskey ) if(opt.verbose) log_info(_("using cipher %s\n"), - gcry_cipher_algo_name (cfx.dek->algo)); + openpgp_cipher_algo_name (cfx.dek->algo)); cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); } @@ -558,7 +558,7 @@ encode_crypt( const char *filename, strlist_t remusr, int use_symkey ) opt.def_cipher_algo,NULL)!=opt.def_cipher_algo) log_info(_("WARNING: forcing symmetric cipher %s (%d)" " violates recipient preferences\n"), - gcry_cipher_algo_name (opt.def_cipher_algo), + openpgp_cipher_algo_name (opt.def_cipher_algo), opt.def_cipher_algo); cfx.dek->algo = opt.def_cipher_algo; @@ -750,7 +750,7 @@ encrypt_filter( void *opaque, int control, NULL)!=opt.def_cipher_algo) log_info(_("forcing symmetric cipher %s (%d) " "violates recipient preferences\n"), - gcry_cipher_algo_name (opt.def_cipher_algo), + openpgp_cipher_algo_name (opt.def_cipher_algo), opt.def_cipher_algo); efx->cfx.dek->algo = opt.def_cipher_algo; @@ -847,7 +847,7 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out ) char *ustr = get_user_id_string_native (enc->keyid); log_info(_("%s/%s encrypted for: \"%s\"\n"), gcry_pk_algo_name (enc->pubkey_algo), - gcry_cipher_algo_name (dek->algo), + openpgp_cipher_algo_name (dek->algo), ustr ); xfree(ustr); } diff --git a/g10/encr-data.c b/g10/encr-data.c index a05ff468a..56d787c7e 100644 --- a/g10/encr-data.c +++ b/g10/encr-data.c @@ -88,8 +88,9 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) if ( opt.verbose && !dek->algo_info_printed ) { - if (!gcry_cipher_test_algo (dek->algo)) - log_info (_("%s encrypted data\n"), gcry_cipher_algo_name (dek->algo)); + if (!openpgp_cipher_test_algo (dek->algo)) + log_info (_("%s encrypted data\n"), + openpgp_cipher_algo_name (dek->algo)); else log_info (_("encrypted with unknown algorithm %d\n"), dek->algo ); dek->algo_info_printed = 1; diff --git a/g10/gpg.c b/g10/gpg.c index 38b5fadb5..75d44f6ca 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -791,7 +791,7 @@ my_strusage( int level ) case 35: if( !ciphers ) ciphers = build_list(_("Cipher: "), 'S', - gcry_cipher_algo_name, + openpgp_cipher_algo_name, openpgp_cipher_test_algo ); p = ciphers; break; @@ -1384,6 +1384,24 @@ print_algo_numbers(int (*checker)(int)) } +static void +print_algo_names(int (*checker)(int),const char *(*mapper)(int)) +{ + int i,first=1; + + for(i=0;i<=110;i++) + { + if(!checker(i)) + { + if(first) + first=0; + else + printf(";"); + printf("%s",mapper(i)); + } + } +} + /* In the future, we can do all sorts of interesting configuration output here. For now, just give "group" as the Enigmail folks need it, and pubkey, cipher, hash, and compress as they may be useful @@ -1450,6 +1468,14 @@ list_config(char *items) any=1; } + if (show_all || !ascii_strcasecmp (name,"ciphername")) + { + printf ("cfg:ciphername:"); + print_algo_names (openpgp_cipher_test_algo,openpgp_cipher_algo_name); + printf ("\n"); + any = 1; + } + if(show_all || ascii_strcasecmp(name,"digest")==0 || ascii_strcasecmp(name,"hash")==0) @@ -1460,6 +1486,16 @@ list_config(char *items) any=1; } + if (show_all + || !ascii_strcasecmp(name,"digestname") + || !ascii_strcasecmp(name,"hashname")) + { + printf ("cfg:digestname:"); + print_algo_names (openpgp_md_test_algo, gcry_md_algo_name); + printf("\n"); + any=1; + } + if(show_all || ascii_strcasecmp(name,"compress")==0) { printf("cfg:compress:"); @@ -2864,6 +2900,15 @@ main (int argc, char **argv ) log_set_prefix (NULL, 1|2|4); } +#ifdef USE_CAMELLIA + /* We better also print a runtime warning if people build it with + support for Camellia (which is not yet defined by OpenPGP). */ + log_info ("WARNING: This version has been built with support for the " + "Camellia cipher.\n"); + log_info (" It is for testing only and is NOT for production " + "use!\n"); +#endif + if (opt.verbose > 2) log_info ("using character set `%s'\n", get_native_charset ()); @@ -3129,7 +3174,7 @@ main (int argc, char **argv ) if(opt.def_cipher_algo && !algo_available(PREFTYPE_SYM,opt.def_cipher_algo,NULL)) { - badalg = gcry_cipher_algo_name (opt.def_cipher_algo); + badalg = openpgp_cipher_algo_name (opt.def_cipher_algo); badtype = PREFTYPE_SYM; } else if(opt.def_digest_algo diff --git a/g10/import.c b/g10/import.c index 66aa875c4..41198b687 100644 --- a/g10/import.c +++ b/g10/import.c @@ -602,9 +602,9 @@ check_prefs(KBNODE keyblock) if (openpgp_cipher_test_algo (prefs->value)) { const char *algo = - (gcry_cipher_test_algo (prefs->value) + (openpgp_cipher_test_algo (prefs->value) ? num - : gcry_cipher_algo_name (prefs->value)); + : openpgp_cipher_algo_name (prefs->value)); if(!problem) check_prefs_warning(pk); log_info(_(" \"%s\": preference for cipher" diff --git a/g10/keyedit.c b/g10/keyedit.c index 8efe824ce..c81594be2 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -2325,9 +2325,10 @@ show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ - if (!gcry_cipher_test_algo (prefs[i].value) + if (!openpgp_cipher_test_algo (prefs[i].value) && prefs[i].value < 100 ) - tty_printf ("%s", gcry_cipher_algo_name (prefs[i].value)); + tty_printf ("%s", + openpgp_cipher_algo_name (prefs[i].value)); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == CIPHER_ALGO_3DES ) @@ -2337,7 +2338,7 @@ show_prefs (PKT_user_id *uid, PKT_signature *selfsig, int verbose) if (!des_seen) { if (any) tty_printf (", "); - tty_printf ("%s", gcry_cipher_algo_name (CIPHER_ALGO_3DES)); + tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); } tty_printf ("\n "); tty_printf (_("Digest: ")); diff --git a/g10/main.h b/g10/main.h index 963387007..bf3df6417 100644 --- a/g10/main.h +++ b/g10/main.h @@ -83,6 +83,7 @@ u16 checksum_mpi( gcry_mpi_t a ); u32 buffer_to_u32( const byte *buffer ); const byte *get_session_marker( size_t *rlen ); int openpgp_cipher_test_algo( int algo ); +const char *openpgp_cipher_algo_name (int algo); int openpgp_pk_test_algo( int algo ); int openpgp_pk_test_algo2 ( int algo, unsigned int use ); int openpgp_pk_algo_usage ( int algo ); diff --git a/g10/mainproc.c b/g10/mainproc.c index 10d665b80..3756e2f96 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -274,9 +274,9 @@ proc_symkey_enc( CTX c, PACKET *pkt ) else if(!c->dek) { int algo = enc->cipher_algo; - const char *s = gcry_cipher_algo_name (algo); + const char *s = openpgp_cipher_algo_name (algo); - if (!gcry_cipher_test_algo (algo)) + if (!openpgp_cipher_test_algo (algo)) { if(!opt.quiet) { @@ -524,8 +524,8 @@ proc_encrypted( CTX c, PACKET *pkt ) algo = opt.def_cipher_algo; if ( algo ) log_info (_("assuming %s encrypted data\n"), - gcry_cipher_algo_name (algo)); - else if ( gcry_cipher_test_algo (CIPHER_ALGO_IDEA) ) + openpgp_cipher_algo_name (algo)); + else if ( openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) ) { algo = opt.def_cipher_algo; if (!algo) @@ -533,7 +533,7 @@ proc_encrypted( CTX c, PACKET *pkt ) idea_cipher_warn(1); log_info (_("IDEA cipher unavailable, " "optimistically attempting to use %s instead\n"), - gcry_cipher_algo_name (algo)); + openpgp_cipher_algo_name (algo)); } else { diff --git a/g10/misc.c b/g10/misc.c index 5f9af54c3..fa85e61c7 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -301,7 +301,7 @@ print_cipher_algo_note( int algo ) { warn=1; log_info (_("WARNING: using experimental cipher algorithm %s\n"), - gcry_cipher_algo_name (algo)); + openpgp_cipher_algo_name (algo)); } } } @@ -324,6 +324,33 @@ print_digest_algo_note( int algo ) gcry_md_algo_name (algo)); } + +/* Map OpenPGP algo numbers to those used by Libgcrypt. We need to do + this for algorithms we implemented in Libgcrypt after they become + part of OpenPGP. */ +static int +map_cipher_openpgp_to_gcry (int algo) +{ + switch (algo) + { + case CIPHER_ALGO_CAMELLIA128: return 310; + case CIPHER_ALGO_CAMELLIA256: return 312; + default: return algo; + } +} + +/* The inverse fucntion of above. */ +static int +map_cipher_gcry_to_openpgp (int algo) +{ + switch (algo) + { + case 310: return CIPHER_ALGO_CAMELLIA128; + case 312: return CIPHER_ALGO_CAMELLIA256; + default: return algo; + } +} + /**************** * Wrapper around the libgcrypt function with additonal checks on * the OpenPGP contraints for the algo ID. @@ -331,12 +358,32 @@ print_digest_algo_note( int algo ) int openpgp_cipher_test_algo( int algo ) { - /* 5 and 6 are marked reserved by rfc2440bis. */ + /* (5 and 6 are marked reserved by rfc4880.) */ if ( algo < 0 || algo > 110 || algo == 5 || algo == 6 ) return gpg_error (GPG_ERR_CIPHER_ALGO); - return gcry_cipher_test_algo (algo); + + /* Camellia is not yet defined for OpenPGP thus only allow it if + requested. */ +#ifndef USE_CAMELLIA + if (algo == CIPHER_ALGO_CAMELLIA128 + || algo == CIPHER_ALGO_CAMELLIA256) + return gpg_error (GPG_ERR_CIPHER_ALGO); +#endif + + return gcry_cipher_test_algo (map_cipher_openpgp_to_gcry (algo)); } +/* Map the OpenPGP cipher algorithm whose ID is contained in ALGORITHM to a + string representation of the algorithm name. For unknown algorithm + IDs this function returns "?". */ +const char * +openpgp_cipher_algo_name (int algo) +{ + return gcry_cipher_algo_name (map_cipher_openpgp_to_gcry (algo)); +} + + + int openpgp_pk_test_algo( int algo ) { @@ -690,7 +737,7 @@ string_to_cipher_algo (const char *string) { int val; - val = gcry_cipher_map_name (string); + val = map_cipher_gcry_to_openpgp (gcry_cipher_map_name (string)); if (!val && string && (string[0]=='S' || string[0]=='s')) { char *endptr; diff --git a/g10/parse-packet.c b/g10/parse-packet.c index b1b01e515..6b8e79ec1 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1588,8 +1588,10 @@ parse_onepass_sig( IOBUF inp, int pkttype, unsigned long pktlen, ops->keyid[1] = read_32(inp); pktlen -= 4; ops->last = iobuf_get_noeof(inp); pktlen--; if( list_mode ) - fprintf (listfp, ":onepass_sig packet: keyid %08lX%08lX\n" - "\tversion %d, sigclass %02x, digest %d, pubkey %d, last=%d\n", + fprintf (listfp, + ":onepass_sig packet: keyid %08lX%08lX\n" + "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, " + "last=%d\n", (ulong)ops->keyid[0], (ulong)ops->keyid[1], version, ops->sig_class, ops->digest_algo, ops->pubkey_algo, ops->last ); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index e0ae55fd7..b7e76a874 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -282,7 +282,7 @@ get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) && !opt.quiet && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo )) log_info (_("WARNING: cipher algorithm %s not found in recipient" - " preferences\n"), gcry_cipher_algo_name (dek->algo)); + " preferences\n"), openpgp_cipher_algo_name (dek->algo)); if (!rc) { KBNODE k; diff --git a/g10/sign.c b/g10/sign.c index 6bb30f04b..022622b20 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -345,22 +345,24 @@ match_dsa_hash (unsigned int qbytes) { if (qbytes <= 20) return DIGEST_ALGO_SHA1; -#ifdef USE_SHA256 - if (qbytes <= 28) + + /* SHA244 is only available with libgcrypt 1.4 - thus do a runtime + test. */ + if (qbytes <= 28 && !gcry_md_test_algo (DIGEST_ALGO_SHA224)) return DIGEST_ALGO_SHA224; + if (qbytes <= 32) return DIGEST_ALGO_SHA256; -#endif -#ifdef USE_SHA512 if (qbytes <= 48) return DIGEST_ALGO_SHA384; + if (qbytes <= 64) return DIGEST_ALGO_SHA512; -#endif + return DEFAULT_DIGEST_ALGO; /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong - answer we have if the larger SHAs aren't there. */ + answer we have if a digest larger than 512 bits is requested. */ } @@ -1258,7 +1260,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) algo = default_cipher_algo(); if (!opt.quiet || !opt.batch) log_info (_("%s encryption will be used\n"), - gcry_cipher_algo_name (algo) ); + openpgp_cipher_algo_name (algo) ); cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { diff --git a/include/ChangeLog b/include/ChangeLog index 344ae6555..b4362bedd 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2007-12-12 Werner Koch + + * cipher.h (CIPHER_ALGO_CAMELLIA128, CIPHER_ALGO_CAMELLIA256): New. + 2006-09-20 Werner Koch * errors.h, http.h, memory.h, mpi.h, util.h, i18n.h: Removed. diff --git a/include/cipher.h b/include/cipher.h index 9d2471a68..52c4f27b1 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -1,5 +1,6 @@ /* cipher.h - Definitions for OpenPGP - * Copyright (C) 1998, 1999, 2000, 2001, 2006 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2006, + * 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -44,6 +45,9 @@ #define CIPHER_ALGO_RIJNDAEL192 CIPHER_ALGO_AES192 #define CIPHER_ALGO_RIJNDAEL256 CIPHER_ALGO_AES256 #define CIPHER_ALGO_TWOFISH /* 10 */ GCRY_CIPHER_TWOFISH /* 256 bit */ +/* Note: Camellia ids don't match those used by libgcrypt. */ +#define CIPHER_ALGO_CAMELLIA128 11 +#define CIPHER_ALGO_CAMELLIA256 12 #define CIPHER_ALGO_DUMMY 110 /* No encryption at all. */ #define PUBKEY_ALGO_RSA /* 1 */ GCRY_PK_RSA @@ -66,8 +70,8 @@ #define DIGEST_ALGO_SHA256 /* 8 */ GCRY_MD_SHA256 #define DIGEST_ALGO_SHA384 /* 9 */ GCRY_MD_SHA384 #define DIGEST_ALGO_SHA512 /* 10 */ GCRY_MD_SHA512 -/* SHA224 is as of now only defined in the libgcrypt SVN; thus we - can't use that macro. */ +/* SHA224 is only available in libgcrypt 1.4.0; thus we + can't use the GCRY macro here. */ #define DIGEST_ALGO_SHA224 /* 11 */ 11 /* GCRY_MD_SHA224 */ #define COMPRESS_ALGO_NONE 0 diff --git a/scd/ChangeLog b/scd/ChangeLog index 166f30891..51db189fa 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,6 +1,6 @@ 2007-12-10 Werner Koch - * app-openpgp.c (do_decipher): Take care of cryptograms shiorther + * app-openpgp.c (do_decipher): Take care of cryptograms shorter that 128 bytes. Fixes bug#851. 2007-11-14 Werner Koch diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 5cfec0407..e26a31e8d 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -2461,7 +2461,7 @@ do_decipher (app_t app, const char *keyidstr, /* We might encounter a couple of leading zeroes in the cryptogram. Due to internal use of MPIs thease leading - zeroes are stripped. However the OpenPGp card expects + zeroes are stripped. However the OpenPGP card expects exactly 128 bytes for the cryptogram (for a 1k key). Thus we need to fix it up. We do this for up to 16 leading zero bytes; a cryptogram with more than this is with a very high diff --git a/sm/ChangeLog b/sm/ChangeLog index 5f03b86c5..49ed50669 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,20 @@ +2007-12-11 Werner Koch + + * certchain.c (do_validate_chain): Log AUDIT_ROOT_TRUSTED. + + * server.c (cmd_sign, cmd_decrypt, cmd_encrypt): Start audit log. + (cmd_recipient): Start audit session. + + * gpgsm.c (main): Revamp creation of the audit log. + + * gpgsm.h (struct server_control_s): Add AGENT_SEEN and DIRMNGR_SEEN. + * call-agent.c (start_agent): Record an audit event. + * call-dirmngr.c (start_dirmngr): Ditto. Add new arg CTRL and pass + it from all callers. + (prepare_dirmngr): New helper for start_dirmngr. + + * encrypt.c (gpgsm_encrypt): Add calls to audit_log. + 2007-12-03 Werner Koch * gpgsm.c (main): All gnupg_reopen_std. diff --git a/sm/call-agent.c b/sm/call-agent.c index 3f4e11ec2..af35ac53a 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -1,5 +1,6 @@ /* call-agent.c - divert operations to the agent - * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2005, + * 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -69,13 +70,14 @@ struct learn_parm_s static int start_agent (ctrl_t ctrl) { + int rc; + if (agent_ctx) - return 0; /* fixme: We need a context for each thread or serialize - the access to the agent (which is suitable given that - the agent is not MT. */ - - - return start_new_gpg_agent (&agent_ctx, + rc = 0; /* fixme: We need a context for each thread or + serialize the access to the agent (which is + suitable given that the agent is not MT. */ + else + rc = start_new_gpg_agent (&agent_ctx, GPG_ERR_SOURCE_DEFAULT, opt.homedir, opt.agent_program, @@ -84,7 +86,13 @@ start_agent (ctrl_t ctrl) opt.xauthority, opt.pinentry_user_data, opt.verbose, DBG_ASSUAN, gpgsm_status2, ctrl); + if (!ctrl->agent_seen) + { + ctrl->agent_seen = 1; + audit_log_ok (ctrl->audit, AUDIT_AGENT_READY, rc); + } + return rc; } diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index a35e93cde..a4b6fbca7 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -1,5 +1,5 @@ /* call-dirmngr.c - communication with the dromngr - * Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2005, 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -134,13 +134,32 @@ get_membuf (struct membuf *mb, size_t *len) } +/* This fucntion prepares the dirmngr for a new session. The + audit-events option is used so that other dirmngr clients won't get + disturbed by such events. */ +static void +prepare_dirmngr (ctrl_t ctrl, assuan_context_t ctx, gpg_error_t err) +{ + if (!ctrl->dirmngr_seen) + { + ctrl->dirmngr_seen = 1; + if (!err) + { + err = assuan_transact (ctx, "OPTION audit-events=1", + NULL, NULL, NULL, NULL, NULL, NULL); + if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) + err = 0; /* Allow the use of old dirmngr versions. */ + } + audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err); + } +} /* Try to connect to the agent via socket or fork it off and work by pipes. Handle the server's initial greeting */ static int -start_dirmngr (void) +start_dirmngr (ctrl_t ctrl) { int rc; char *infostr, *p; @@ -148,8 +167,11 @@ start_dirmngr (void) int try_default = 0; if (dirmngr_ctx) - return 0; /* fixme: We need a context for each thread or serialize - the access to the dirmngr */ + { + prepare_dirmngr (ctrl, dirmngr_ctx, 0); + return 0; /* fixme: We need a context for each thread or serialize + the access to the dirmngr */ + } /* Note: if you change this to multiple connections, you also need to take care of the implicit option sending caching. */ @@ -220,7 +242,7 @@ start_dirmngr (void) log_error (_("malformed DIRMNGR_INFO environment variable\n")); xfree (infostr); force_pipe_server = 1; - return start_dirmngr (); + return start_dirmngr (ctrl); } *p++ = 0; pid = atoi (p); @@ -233,7 +255,7 @@ start_dirmngr (void) prot); xfree (infostr); force_pipe_server = 1; - return start_dirmngr (); + return start_dirmngr (ctrl); } } else @@ -251,11 +273,13 @@ start_dirmngr (void) { log_error (_("can't connect to the dirmngr - trying fall back\n")); force_pipe_server = 1; - return start_dirmngr (); + return start_dirmngr (ctrl); } #endif /*!HAVE_W32_SYSTEM*/ } + prepare_dirmngr (ctrl, ctx, rc); + if (rc) { log_error ("can't connect to the dirmngr: %s\n", gpg_strerror (rc)); @@ -424,7 +448,7 @@ gpgsm_dirmngr_isvalid (ctrl_t ctrl, struct isvalid_status_parm_s stparm; - rc = start_dirmngr (); + rc = start_dirmngr (ctrl); if (rc) return rc; @@ -691,7 +715,7 @@ gpgsm_dirmngr_lookup (ctrl_t ctrl, strlist_t names, struct lookup_parm_s parm; size_t len; - rc = start_dirmngr (); + rc = start_dirmngr (ctrl); if (rc) return rc; @@ -821,7 +845,7 @@ gpgsm_dirmngr_run_command (ctrl_t ctrl, const char *command, size_t len; struct run_command_parm_s parm; - rc = start_dirmngr (); + rc = start_dirmngr (ctrl); if (rc) return rc; diff --git a/sm/certchain.c b/sm/certchain.c index f30c0c0ae..a21a38a07 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -1127,6 +1127,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, associated with that specific root certificate. */ istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, rootca_flags); + audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED, + subject_cert, istrusted_rc); /* If the chain model extended attribute is used, make sure that our chain model flag is set. */ if (has_validation_model_chain (subject_cert, listmode, listfp)) diff --git a/sm/encrypt.c b/sm/encrypt.c index 1e36e960c..5f79be1bf 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -1,5 +1,5 @@ /* encrypt.c - Encrypt a message - * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2003, 2004, 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -318,9 +318,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) int recpno; FILE *data_fp = NULL; certlist_t cl; + int count; memset (&encparm, 0, sizeof encparm); + audit_set_type (ctrl->audit, AUDIT_TYPE_ENCRYPT); + /* Check that the certificate list is not empty and that at least one certificate is not flagged as encrypt_to; i.e. is a real recipient. */ @@ -331,10 +334,15 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) { log_error(_("no valid recipients given\n")); gpgsm_status (ctrl, STATUS_NO_RECP, "0"); + audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, 0); rc = gpg_error (GPG_ERR_NO_PUBKEY); goto leave; } + for (count = 0, cl = recplist; cl; cl = cl->next) + count++; + audit_log_i (ctrl->audit, AUDIT_GOT_RECIPIENTS, count); + kh = keydb_new (0); if (!kh) { @@ -385,6 +393,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) goto leave; } + audit_log (ctrl->audit, AUDIT_GOT_DATA); + /* We are going to create enveloped data with uninterpreted data as inner content */ err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA); @@ -432,6 +442,8 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) rc = out_of_core (); goto leave; } + + audit_log_s (ctrl->audit, AUDIT_SESSION_KEY, dek->algoid); /* Gather certificates of recipients, encrypt the session key for each and store them in the CMS object */ @@ -442,6 +454,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) rc = encrypt_dek (dek, cl->cert, &encval); if (rc) { + audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, rc); log_error ("encryption failed for recipient no. %d: %s\n", recpno, gpg_strerror (rc)); goto leave; @@ -450,6 +463,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) err = ksba_cms_add_recipient (cms, cl->cert); if (err) { + audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err); log_error ("ksba_cms_add_recipient failed: %s\n", gpg_strerror (err)); rc = err; @@ -459,6 +473,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) err = ksba_cms_set_enc_val (cms, recpno, encval); xfree (encval); + audit_log_cert (ctrl->audit, AUDIT_ENCRYPTED_TO, cl->cert, err); if (err) { log_error ("ksba_cms_set_enc_val failed: %s\n", @@ -466,7 +481,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) rc = err; goto leave; } - } + } /* Main control loop for encryption. */ recpno = 0; @@ -496,6 +511,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp) log_error ("write failed: %s\n", gpg_strerror (rc)); goto leave; } + audit_log (ctrl->audit, AUDIT_ENCRYPTION_DONE); log_info ("encrypted data created\n"); leave: diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 10e39159d..93474b37a 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -848,6 +848,7 @@ main ( int argc, char **argv) certlist_t signerlist = NULL; int do_not_setup_keys = 0; int recp_required = 0; + estream_t auditfp = NULL; /*mtrace();*/ @@ -1482,6 +1483,26 @@ main ( int argc, char **argv) keydb_add_resource (sl->d, 0, 0, NULL); FREE_STRLIST(nrings); + + /* Prepare the audit log feature for certain commands. */ + if (auditlog) + { + switch (cmd) + { + case aEncr: + case aSign: + case aDecrypt: + case aVerify: + audit_release (ctrl.audit); + ctrl.audit = audit_new (); + auditfp = open_es_fwrite (auditlog); + break; + default: + break; + } + } + + if (!do_not_setup_keys) { for (sl = locusr; sl ; sl = sl->next) @@ -1528,6 +1549,7 @@ main ( int argc, char **argv) fname = argc? *argv : NULL; + /* Dispatch command. */ switch (cmd) { case aGPGConfList: @@ -1650,7 +1672,6 @@ main ( int argc, char **argv) case aVerify: { FILE *fp = NULL; - estream_t auditfp = NULL; set_binary (stdin); if (argc == 2 && opt.outfile) @@ -1658,13 +1679,6 @@ main ( int argc, char **argv) else if (opt.outfile) fp = open_fwrite (opt.outfile); - if (auditlog) - { - audit_release (ctrl.audit); - ctrl.audit = audit_new (); - auditfp = open_es_fwrite (auditlog); - } - if (!argc) gpgsm_verify (&ctrl, 0, -1, fp); /* normal signature from stdin */ else if (argc == 1) @@ -1674,16 +1688,8 @@ main ( int argc, char **argv) else wrong_args ("--verify [signature [detached_data]]"); - if (auditlog) - { - audit_print_result (ctrl.audit, auditfp, 0); - audit_release (ctrl.audit); - ctrl.audit = NULL; - } - if (fp && fp != stdout) fclose (fp); - es_fclose (auditfp); } break; @@ -1846,6 +1852,15 @@ main ( int argc, char **argv) log_error ("invalid command (there is no implicit command)\n"); break; } + + /* Print the audit result if needed. */ + if (auditlog && auditfp) + { + audit_print_result (ctrl.audit, auditfp, 0); + audit_release (ctrl.audit); + ctrl.audit = NULL; + es_fclose (auditfp); + } /* cleanup */ gpgsm_release_certlist (recplist); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 8f9692a73..5232ce427 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -152,6 +152,10 @@ struct server_control_s struct server_local_s *server_local; audit_ctx_t audit; /* NULL or a context for the audit subsystem. */ + int agent_seen; /* Flag indicating that the gpg-agent has been + accessed. */ + int dirmngr_seen; /* Flag indicating that the dirmngr has been + accessed. */ int with_colons; /* Use column delimited output format */ int with_chain; /* Include the certifying certs in a listing */ diff --git a/sm/server.c b/sm/server.c index e61f9d600..b9fe2a25e 100644 --- a/sm/server.c +++ b/sm/server.c @@ -366,7 +366,14 @@ cmd_recipient (assuan_context_t ctx, char *line) ctrl_t ctrl = assuan_get_pointer (ctx); int rc; - rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist, 0); + if (!ctrl->audit) + rc = start_audit_session (ctrl); + else + rc = 0; + + if (!rc) + rc = gpgsm_add_to_certlist (ctrl, line, 0, + &ctrl->server_local->recplist, 0); if (rc) { gpg_err_code_t r = gpg_err_code (rc); @@ -477,6 +484,8 @@ cmd_encrypt (assuan_context_t ctx, char *line) rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert, &ctrl->server_local->recplist, 1); } + if (!rc) + rc = ctrl->audit? 0 : start_audit_session (ctrl); if (!rc) rc = gpgsm_encrypt (assuan_get_pointer (ctx), ctrl->server_local->recplist, @@ -492,6 +501,7 @@ cmd_encrypt (assuan_context_t ctx, char *line) return rc; } + /* DECRYPT This performs the decrypt operation after doing some check on the @@ -517,7 +527,10 @@ cmd_decrypt (assuan_context_t ctx, char *line) out_fp = fdopen (dup(out_fd), "w"); if (!out_fp) return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed"); - rc = gpgsm_decrypt (ctrl, inp_fd, out_fp); + + rc = start_audit_session (ctrl); + if (!rc) + rc = gpgsm_decrypt (ctrl, inp_fd, out_fp); fclose (out_fp); /* close and reset the fd */ @@ -600,8 +613,10 @@ cmd_sign (assuan_context_t ctx, char *line) if (!out_fp) return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed"); - rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist, - inp_fd, detached, out_fp); + rc = start_audit_session (ctrl); + if (!rc) + rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist, + inp_fd, detached, out_fp); fclose (out_fp); /* close and reset the fd */