Implement signing with automatic protocol selection.
authorWerner Koch <wk@gnupg.org>
Thu, 6 Mar 2008 15:05:48 +0000 (15:05 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 6 Mar 2008 15:05:48 +0000 (15:05 +0000)
ChangeLog
doc/gpgol.texi
src/ChangeLog
src/engine-assuan.c
src/engine-assuan.h
src/engine.c
src/engine.h
src/main.c
src/mimemaker.c
src/olflange.cpp

index fdff682..a992a9f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2008-03-06  Werner Koch  <wk@g10code.com>
+
+       * doc/gpgol.texi (SIGN): Extend the SIGNER command to allow
+       suggestion of a protocol.
+
 2008-02-18  Werner Koch  <wk@g10code.com>
 
        Release 0.10.5 development version.
index 28ae75c..1cc3258 100644 (file)
@@ -232,7 +232,7 @@ Use the CMS (PKCS#7) protocol (RFC-3852).
 @end deffn
 
 To support automagically selection of the protocol depending on the
-selected keys, the server may implement the follwoing extra command:
+selected keys, the server MAY implement the command:
 
 @deffn Command PREP_ENCRYPT [-@w{}-protocol=@var{name}]
 
@@ -320,6 +320,9 @@ RFC-2822) enclosed in angle brackets.  The address set with this command
 is valid until a successful @code{SIGN} command or until a @code{RESET}
 command.  A second command overrides the effect of the first one; if
 @var{email} is not given the server shall use the default signing key.
+The server shall also suggest a protocol to use for signing.  The client
+may use this suggested protocol on its own discretion.  The same status
+line as with PREP_ENCRYPT is used for this.
 @end deffn
 
 @noindent
index b812d83..bc62192 100644 (file)
@@ -1,3 +1,14 @@
+2008-03-06  Werner Koch  <wk@g10code.com>
+
+       * mimemaker.c (do_mime_sign): Figure out the protocol to use.
+       * engine.c (engine_sign_start): Add new args SENDER and R_PROTOCOL.
+       * engine-assuan.c (op_assuan_sign): Ditto.  Send SENDER command.
+
+2008-03-05  Werner Koch  <wk@g10code.com>
+
+       * main.c (read_options): Insert the debug registry key.
+       (write_options): More debug output.
+
 2008-02-28  Werner Koch  <wk@g10code.com>
 
        * olflange-dlgs.cpp (GPGOptionsDlgProc): Fix initial setting of
index 50526c8..8630d2b 100644 (file)
@@ -1333,8 +1333,8 @@ get_protocol_name (protocol_t protocol)
 }
 
 
-/* Callback used to get the protocool status line form a PREP_*
-   command.  */
+/* Callback used to get the protocool status line form a PREP_ENCRYPT
+   or SENDER command.  */
 static assuan_error_t
 prep_foo_status_cb (void *opaque, const char *line)
 {
@@ -1496,11 +1496,14 @@ sign_closure (closure_data_t cld)
 
 /* Created a detached signature for INDATA and write it to OUTDATA.
    On termination of the signing command engine_private_finished() is
-   called with FILTER as the first argument.  */
+   called with FILTER as the first argument.  SENDER is the sender's
+   mail address (a mailbox).  The used protocol wioll be stored at
+   R_PROTOCOL. */
 int 
 op_assuan_sign (protocol_t protocol, 
                 gpgme_data_t indata, gpgme_data_t outdata,
-                engine_filter_t filter, void *hwnd)
+                engine_filter_t filter, void *hwnd,
+                const char *sender, protocol_t *r_used_protocol)
 {
   gpg_error_t err;
   closure_data_t cld;
@@ -1509,11 +1512,11 @@ op_assuan_sign (protocol_t protocol,
   HANDLE inpipe[2], outpipe[2];
   ULONG cmdid;
   pid_t pid;
+  int detect_protocol;
   const char *protocol_name;
+  protocol_t suggested_protocol;
 
-
-  if (!(protocol_name = get_protocol_name (protocol)))
-    return gpg_error(GPG_ERR_INV_VALUE);
+  detect_protocol = !(protocol_name = get_protocol_name (protocol));
 
   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
   if (err)
@@ -1535,6 +1538,36 @@ op_assuan_sign (protocol_t protocol,
   if (err)
     goto leave;
 
+  /* We always send the SENDER command becuase it allows us to figure
+     out the protocol to use.  In case the UI server faisl to send the
+     protocol we fall back to OpenPGP.  */
+  suggested_protocol = PROTOCOL_UNKNOWN;
+  if (!sender)
+    sender = "<kleopatra-does-not-allow-an-empty-arg@example.net>";
+  snprintf (line, sizeof line, "SENDER%s%s", sender? " ":"", sender?sender:"");
+  err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL,
+                         prep_foo_status_cb, &suggested_protocol);
+  if (err)
+    {
+      if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
+        err = gpg_error (GPG_ERR_INV_VALUE);
+      goto leave;
+    }
+  if (detect_protocol)
+    {
+      log_debug ("%s:%s: suggested protocol is %d", 
+                 SRCNAME, __func__, suggested_protocol);
+      protocol = (suggested_protocol == PROTOCOL_UNKNOWN?
+                  PROTOCOL_OPENPGP : suggested_protocol);
+      if ( !(protocol_name = get_protocol_name (protocol)) )
+        {
+          err = gpg_error (GPG_ERR_INV_VALUE);
+          goto leave;
+        }
+    }
+  *r_used_protocol = protocol;
+  log_debug ("%s:%s: using protocol %s", SRCNAME, __func__, protocol_name);
+
   snprintf (line, sizeof line, "INPUT FD=%ld", (unsigned long int)inpipe[0]);
   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (err)
@@ -1544,8 +1577,6 @@ op_assuan_sign (protocol_t protocol,
   if (err)
     goto leave;
 
-  /* FIXME: Implement the optinonal SENDER command. */
-
   enqueue_callback (" input", ctx, indata, inpipe[1], 1, finalize_handler,
                     cmdid, NULL, 0); 
   enqueue_callback ("output", ctx, outdata, outpipe[0], 0, finalize_handler, 
index 1663e55..4493396 100644 (file)
@@ -41,7 +41,8 @@ int op_assuan_encrypt (protocol_t protocol,
                        char **recipients, protocol_t *r_used_protocol);
 int op_assuan_sign (protocol_t protocol, 
                     gpgme_data_t indata, gpgme_data_t outdata,
-                    engine_filter_t filter, void *hwnd);
+                    engine_filter_t filter, void *hwnd,
+                    const char *sender, protocol_t *r_used_protocol);
 int op_assuan_decrypt (protocol_t protocol,
                        gpgme_data_t indata, gpgme_data_t outdata, 
                        engine_filter_t filter, void *hwnd,
index 57ca5fc..f0a1963 100644 (file)
@@ -691,18 +691,30 @@ engine_encrypt_start (engine_filter_t filter, HWND hwnd,
    finish the operation.  A filter object may not be reused after
    having been used through this function.  However, the lifetime of
    the filter object lasts until the final engine_wait or
-   engine_cancel.  */
+   engine_cancel.  SENDER is the sender's mailbox or NULL.  On return
+   the protocol to be used is stored at R_PROTOCOL. */
 int
-engine_sign_start (engine_filter_t filter, HWND hwnd, protocol_t protocol)
+engine_sign_start (engine_filter_t filter, HWND hwnd, protocol_t protocol,
+                   const char *sender, protocol_t *r_protocol)
 {
   gpg_error_t err;
+  protocol_t used_protocol;
 
   if (filter->use_assuan)
-    err = op_assuan_sign (protocol, filter->indata, filter->outdata,
-                         filter, hwnd);
+    {
+      err = op_assuan_sign (protocol, filter->indata, filter->outdata,
+                            filter, hwnd, sender, &used_protocol);
+      if (!err)
+        *r_protocol = used_protocol;
+    }
   else
-    err = op_gpgme_sign (protocol, filter->indata, filter->outdata,
-                         filter, hwnd);
+    {
+      err = op_gpgme_sign (protocol, filter->indata, filter->outdata,
+                           filter, hwnd);
+      if (!err)
+        *r_protocol = (protocol == GPGME_PROTOCOL_UNKNOWN?
+                       GPGME_PROTOCOL_OpenPGP : protocol);
+    }
   return err;
 }
 
index f10932f..cef58c4 100644 (file)
@@ -65,7 +65,9 @@ void engine_cancel (engine_filter_t filter);
 int engine_encrypt_start (engine_filter_t filter, HWND hwnd,
                           protocol_t req_protocol, char **recipients,
                           protocol_t *r_protocol);
-int engine_sign_start (engine_filter_t filter, HWND hwnd, protocol_t protocol);
+int engine_sign_start (engine_filter_t filter, HWND hwnd, protocol_t protocol,
+                       const char *sender, protocol_t *r_protocol);
+
 int engine_decrypt_start (engine_filter_t filter, HWND hwnd,
                           protocol_t protocol, int with_verify);
 int engine_verify_start (engine_filter_t filter, HWND hwnd,
index 9683ba4..4a642cb 100644 (file)
@@ -510,6 +510,13 @@ read_options (void)
  
   load_extension_value ("enableDebug", &val);
   opt.enable_debug = val? strtoul (val, NULL, 0) : 0;
+  if (!val)
+    {
+      /* To help the user enable debugging make sure that the registry
+         key exists.  Note that the other registry keys are stored
+         after using the configuration dialog.  */
+      store_extension_value ("enableDebug", "0");
+    }
   xfree (val); val = NULL;
 
   load_extension_value ("enableSmime", &val);
@@ -640,22 +647,29 @@ write_options (void)
   };
   char buf[32];
   int rc, i;
+  const char *string;
 
   for (i=0; table[i].name; i++) 
     {
-      log_debug ("storing option `%s'\n", table[i].name);
       switch (table[i].mode)
         {
         case 0:
-          rc = store_extension_value (table[i].name, table[i].value? "1": "0");
+          string = table[i].value? "1": "0";
+          log_debug ("storing option `%s' value=`%s'\n",
+                     table[i].name, string);
+          rc = store_extension_value (table[i].name, string);
           break;
         case 1:
           sprintf (buf, "%d", table[i].value);
+          log_debug ("storing option `%s' value=`%s'\n",
+                     table[i].name, buf);
           rc = store_extension_value (table[i].name, buf);
           break;
         case 2:
-          rc = store_extension_value (table[i].name,
-                                      table[i].s_val? table[i].s_val : "");
+          string = table[i].s_val? table[i].s_val : "";
+          log_debug ("storing option `%s' value=`%s'\n",
+                     table[i].name, string);
+          rc = store_extension_value (table[i].name, string);
           break;
         case 3:
           buf[0] = '0';
@@ -666,6 +680,8 @@ write_options (void)
             case PROTOCOL_OPENPGP: buf[0] = '1'; break;
             case PROTOCOL_SMIME:   buf[0] = '2'; break;
             }
+          log_debug ("storing option `%s' value=`%s'\n",
+                     table[i].name, buf);
           rc = store_extension_value (table[i].name, buf);
           break;  
 
index 76b658d..c5e0c49 100644 (file)
@@ -1169,10 +1169,6 @@ do_mime_sign (LPMESSAGE message, HWND hwnd, protocol_t protocol,
   memset (hashsink, 0, sizeof *hashsink);
   memset (&sigbuffer, 0, sizeof sigbuffer);
 
-  protocol = check_protocol (protocol);
-  if (protocol == PROTOCOL_UNKNOWN)
-    return -1;
-
   if (tmpsink)
     {
       attach = NULL;
@@ -1185,12 +1181,20 @@ do_mime_sign (LPMESSAGE message, HWND hwnd, protocol_t protocol,
         return -1;
     }
 
-  /* Prepare the signing.  */
+  /* Prepare the signing.  FIXME: figure out the signer of the mail.  */
   if (engine_create_filter (&filter, collect_signature, &sigbuffer))
     goto failure;
-  if (engine_sign_start (filter, hwnd, protocol))
+  if (engine_sign_start (filter, hwnd, protocol, NULL, &protocol))
     goto failure;
 
+  protocol = check_protocol (protocol);
+  if (protocol == PROTOCOL_UNKNOWN)
+    {
+      log_error ("%s:%s: no protocol selected", SRCNAME, __func__);
+      goto failure;
+    }
+
+
   /* Get the attachment info and the body.  */
   body = mapi_get_body (message, NULL);
   if (body && !*body)
@@ -1726,7 +1730,8 @@ mime_sign_encrypt (LPMESSAGE message, HWND hwnd,
 
   /* Prepare the encryption.  We do this early as it is quite common
      that some recipients are not be available and thus the encryption
-     will fail early. */
+     will fail early.  This is also required to allow the UIserver to
+     figure out the protocol to use if we have not forced one.  */
   if (engine_create_filter (&filter, write_buffer_for_cb, sink))
     goto failure;
   if ((rc=engine_encrypt_start (filter, hwnd, 
@@ -1741,7 +1746,8 @@ mime_sign_encrypt (LPMESSAGE message, HWND hwnd,
      complete MIME object of the signed message.  We can't do the
      encryption in streaming mode while running the encryption because
      we need to fix up that ugly micalg parameter after having created
-     the signature.  */
+     the signature.  Note that the protocol to use is taken from the
+     encryption operation. */
   if (do_mime_sign (message, hwnd, protocol, &att_table, tmpsink))
     goto failure;
 
index f6c68fd..ade09fe 100644 (file)
@@ -179,6 +179,19 @@ DllRegisterServer (void)
   RegDeleteValue (hkey, "GPG Exchange");
 
   /* Set outlook update flag. */
+  /* Fixme: We have not yet implemented this hint from Microsoft:
+
+       In order for .ecf-based ECEs to be detected by Outlook on Vista,
+       one needs to delete if present:
+
+       [HKEY_CURRENT_USER\Software\Microsoft\Office\[Office Version]\Outlook]
+       "Exchange Client Extension"=
+             "4.0;Outxxx.dll;7;000000000000000;0000000000;OutXXX"
+
+       [Office Version] is 11.0 ( for OL 03 ), 12.0 ( OL 07 )...
+
+     Obviously due to HKCU, that also requires to run this code at
+     startup.  However, we don't use an ECF right now.  */
   strcpy (szEntry, "4.0;Outxxx.dll;7;000000000000000;0000000000;OutXXX");
   dwTemp = lstrlen (szEntry) + 1;
   RegSetValueEx (hkey, "Outlook Setup Extension",
@@ -259,6 +272,8 @@ DllUnregisterServer (void)
   RegSetValueEx (hkey, "Outlook Setup Extension", 0, 
                 REG_SZ, (BYTE*) buf, ntemp);
   RegCloseKey (hkey);
+
+  /* Fixme: delet CLSIDs. */
   
   return S_OK;
 }