Implemented opaque signed+encrypted. gpgol-0.10.9
authorWerner Koch <wk@gnupg.org>
Wed, 19 Mar 2008 18:30:14 +0000 (18:30 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 19 Mar 2008 18:30:14 +0000 (18:30 +0000)
Implemented old-style PGP with attachments.

15 files changed:
ChangeLog
NEWS
autogen.sh
configure.ac
doc/gpgol.texi
po/de.po
po/sv.po
src/ChangeLog
src/common.h
src/mapihelp.cpp
src/mapihelp.h
src/message.cpp
src/mimemaker.c
src/mimeparser.c
src/mimeparser.h

index 4970b30..6d43a57 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2008-03-19  Werner Koch  <wk@g10code.com>
+
+       * Release 0.10.9.
+
 2008-03-18  Werner Koch  <wk@g10code.com>
 
        * Release 0.10.8.
diff --git a/NEWS b/NEWS
index 03e7756..3910563 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+Noteworthy changes for version 0.10.9 (2008-03-19)
+=================================================
+
+ * Decrypt opaque signed and encrypted S/MIME mails.
+
+ * Handle old-style PGP message with attachments.  Note that the
+   signature verification currently may indicate a bad signature.
+
+
 Noteworthy changes for version 0.10.8 (2008-03-18)
 =================================================
 
index eac2688..d51febd 100755 (executable)
@@ -160,4 +160,4 @@ $AUTOMAKE --gnu;
 echo "Running autoconf${FORCE} ..."
 $AUTOCONF${FORCE}
 
-echo "You may now run \"./configure --enable-maintainer-mode && make\"."
+echo "You may now run \"./autogen.sh --build-w32 && make\"."
index b06d4e3..5929693 100644 (file)
@@ -16,7 +16,7 @@ min_automake_version="1.9.4"
 # Remember to change the version number immediately *after* a release.
 # Set my_issvn to "yes" for non-released code.  Remember to run an
 # "svn up" and "autogen.sh" right before creating a distribution.
-m4_define([my_version], [0.10.8])
+m4_define([my_version], [0.10.9])
 m4_define([my_issvn], [no])
 
 m4_define([svn_revision], m4_esyscmd([echo -n $( (svn info 2>/dev/null \
index 810eaaa..0107358 100644 (file)
@@ -673,6 +673,10 @@ Tell how the filter I/O locks the resources.
 Tell about resource allocation.
 @item 64 (0x0040)
 Tell about command events.
+@item 128 (0x0080)
+Tell what the MIME parser is doing
+@item 256 (0x0100)
+Print data lines while parsing MIME.
 @end table
 You may use the regular C-syntax for entering the value.
 
index f27e9d5..7e4997d 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GpgOL 0.10.0\n"
 "Report-Msgid-Bugs-To: bug-gpgol@g10code.com\n"
-"POT-Creation-Date: 2008-03-11 11:36+0100\n"
+"POT-Creation-Date: 2008-03-18 11:59+0100\n"
 "PO-Revision-Date: 2008-03-07 13:31+0100\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: de\n"
@@ -444,11 +444,11 @@ msgstr "Verschl├╝sselungsfehler (%s)"
 msgid "Signing failed (%s)"
 msgstr "Unterschrifterstellungsfehler (%s)"
 
-#: src/mimeparser.c:1108
+#: src/mimeparser.c:1112
 msgid "Error writing to stream"
 msgstr "Dateischreibfehler"
 
-#: src/mimeparser.c:1109
+#: src/mimeparser.c:1113
 msgid "I/O-Error"
 msgstr "Ein-/Ausgabefehler"
 
index 2699b30..e534ec2 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GPGol\n"
 "Report-Msgid-Bugs-To: bug-gpgol@g10code.com\n"
-"POT-Creation-Date: 2008-03-11 11:36+0100\n"
+"POT-Creation-Date: 2008-03-18 11:59+0100\n"
 "PO-Revision-Date: 2006-12-12 23:52+0100\n"
 "Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
@@ -424,12 +424,12 @@ msgstr "Kryptering misslyckades"
 msgid "Signing failed (%s)"
 msgstr "Signering misslyckades"
 
-#: src/mimeparser.c:1108
+#: src/mimeparser.c:1112
 #, fuzzy
 msgid "Error writing to stream"
 msgstr "Fel vid skrivning av fil"
 
-#: src/mimeparser.c:1109
+#: src/mimeparser.c:1113
 msgid "I/O-Error"
 msgstr "In-/Ut-fel"
 
index 18200ef..afaae63 100644 (file)
@@ -1,3 +1,19 @@
+2008-03-19  Werner Koch  <wk@g10code.com>
+
+       * mapihelp.cpp (mapi_change_message_class): Look into
+       multipart/mixed for PGP messages.
+
+       * mapihelp.cpp (mapi_get_attach): Add arg UNPROTECT and changed
+       all callers.
+       * common.h (DBG_MIME_PARSER, DBG_MIME_DATA): New.
+       * mimeparser.c (debug_mime_parser, debug_mime_data): New to
+       replace DEBUG_PARSER.
+       (struct mime_context): Add field is_opaque_signed. 
+       (t2body): Set it.
+       (mime_decrypt): Handle an embedded opaque signed S/MIME part.
+       (mime_verify_opaque): Add arg INBUFER, INBUFFERLEN and
+       START_PART_COUNTER.
+
 2008-03-18  Werner Koch  <wk@g10code.com>
 
        * mimeparser.c (message_cb): Clear all mimestruct fields.  Fixes
index 698f586..41cb84d 100644 (file)
@@ -148,14 +148,16 @@ typedef struct b64_state_s b64_state_t;
 
 /* Bit values used for extra log file verbosity.  Value 1 is reserved
    to enable debug menu options.  */
-#define DBG_IOWORKER        2
-#define DBG_IOWORKER_EXTRA  4
-#define DBG_FILTER          8
-#define DBG_FILTER_EXTRA   16 
-#define DBG_MEMORY         32
-#define DBG_COMMANDS       64
-
-/* Macros to used in conditionals to enabel debug output.  */
+#define DBG_IOWORKER       (1<<1)
+#define DBG_IOWORKER_EXTRA (1<<2) 
+#define DBG_FILTER         (1<<3)
+#define DBG_FILTER_EXTRA   (1<<4) 
+#define DBG_MEMORY         (1<<5)
+#define DBG_COMMANDS       (1<<6)
+#define DBG_MIME_PARSER    (1<<7)
+#define DBG_MIME_DATA      (1<<8)
+
+/* Macros to used in conditionals to enable debug output.  */
 #define debug_commands    (opt.enable_debug & DBG_COMMANDS)
 
 
index c7714a7..cbba3f5 100644 (file)
@@ -384,8 +384,8 @@ mapi_get_body (LPMESSAGE message, size_t *r_nbytes)
 
 
 /* Look at the body of the MESSAGE and try to figure out whether this
-   is a supported PGP message.  Returns the new message class on
-   return or NULL if not.  */
+   is a supported PGP message.  Returns the new message class or NULL
+   if it does not look like a PGP message.  */
 static char *
 get_msgcls_from_pgp_lines (LPMESSAGE message)
 {
@@ -720,6 +720,13 @@ mapi_change_message_class (LPMESSAGE message, int sync_override)
                 {
                   newvalue = get_msgcls_from_pgp_lines (message);
                 }
+              else if (!strcmp (ct, "multipart/mixed"))
+                {
+                  /* It is quite common to have a multipart/mixed mail
+                     with separate encrypted PGP parts.  Look at the
+                     body to decide.  */
+                  newvalue = get_msgcls_from_pgp_lines (message);
+                }
               
               xfree (ct);
             }
@@ -1600,9 +1607,11 @@ attach_to_buffer (LPATTACH att, size_t *r_nbytes, int unprotect,
 
 
 /* Return an attachment as a malloced buffer.  The size of the buffer
-   will be stored at R_NBYTES.  Returns NULL on failure. */
+   will be stored at R_NBYTES.  If unprotect is true, the atatchment
+   will be unprotected.  Returns NULL on failure. */
 char *
-mapi_get_attach (LPMESSAGE message, mapi_attach_item_t *item, size_t *r_nbytes)
+mapi_get_attach (LPMESSAGE message, int unprotect, 
+                 mapi_attach_item_t *item, size_t *r_nbytes)
 {
   HRESULT hr;
   LPATTACH att;
@@ -1625,7 +1634,7 @@ mapi_get_attach (LPMESSAGE message, mapi_attach_item_t *item, size_t *r_nbytes)
       return NULL;
     }
 
-  buffer = attach_to_buffer (att, r_nbytes, 0, NULL);
+  buffer = attach_to_buffer (att, r_nbytes, unprotect, NULL);
   att->Release ();
 
   return buffer;
index ba256c4..419bf10 100644 (file)
@@ -117,7 +117,7 @@ void mapi_release_attach_table (mapi_attach_item_t *table);
 LPSTREAM mapi_get_attach_as_stream (LPMESSAGE message, 
                                     mapi_attach_item_t *item, 
                                     LPATTACH *r_attach);
-char *mapi_get_attach (LPMESSAGE message, 
+char *mapi_get_attach (LPMESSAGE message, int unprotect,
                        mapi_attach_item_t *item, size_t *r_nbytes);
 int mapi_mark_moss_attach (LPMESSAGE message, mapi_attach_item_t *item);
 int mapi_has_sig_status (LPMESSAGE msg);
index 8441b27..d9aa04c 100644 (file)
@@ -330,7 +330,7 @@ show_message (HWND hwnd, const char *text)
 \f
 /* Convert the clear signed message from INPUT into a PGP/MIME signed
    message and return it in a new allocated buffer.  OUTPUTLEN
-   received the valid length of that buffer; the buffer is guarnateed
+   received the valid length of that buffer; the buffer is guaranteed
    to be Nul terminated.  */
 static char *
 pgp_mime_from_clearsigned (LPSTREAM input, size_t *outputlen)
@@ -649,7 +649,7 @@ message_verify (LPMESSAGE message, msgtype_t msgtype, int force, HWND hwnd)
           return -1; /* No original attachment - this should not happen.  */
         }
 
-      inbuf = mapi_get_attach (message, table+0, &inbuflen);
+      inbuf = mapi_get_attach (message, 0, table+0, &inbuflen);
       if (!inbuf)
         {
           mapi_release_attach_table (table);
@@ -658,7 +658,8 @@ message_verify (LPMESSAGE message, msgtype_t msgtype, int force, HWND hwnd)
     }
 
   if (opaquestream)
-    err = mime_verify_opaque (protocol, opaquestream, message, hwnd, 0);
+    err = mime_verify_opaque (protocol, opaquestream,
+                              NULL, 0, message, hwnd, 0, 0);
   else
     err = mime_verify (protocol, inbuf, inbuflen, message, hwnd, 0);
   log_debug ("mime_verify%s returned %d", opaquestream? "_opaque":"", err);
@@ -877,7 +878,7 @@ message_decrypt (LPMESSAGE message, msgtype_t msgtype, int force, HWND hwnd)
          However, due to problems with Outlook overwriting the body of
          the message after decryption, we need to save the body away
          before decrypting it.  We then always look for that original
-         body atatchment and create one if it does not exist.  */
+         body attachment or create one if it does not exist.  */
       part1_idx = -1;
       table = mapi_create_attach_table (message, 0);
       if (!table)
index 7100fe6..dbe6610 100644 (file)
@@ -903,7 +903,7 @@ write_attachments (sink_t sink,
       if (table[idx].attach_type == ATTACHTYPE_UNKNOWN
           && table[idx].method == ATTACH_BY_VALUE)
         {
-          buffer = mapi_get_attach (message, table+idx, &buflen);
+          buffer = mapi_get_attach (message, 0, table+idx, &buflen);
           if (!buffer)
             log_debug ("Attachment at index %d not found\n", idx);
           else
index 5578dbc..6cda93d 100644 (file)
 #include "serpent.h"
 #include "mimeparser.h"
 
-/* Define the next to get extra debug message for the MIME parser.  */
-#define DEBUG_PARSER 1
 
 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
                                      SRCNAME, __func__, __LINE__); \
                         } while (0)
 
+#define debug_mime_parser (opt.enable_debug & (DBG_MIME_PARSER|DBG_MIME_DATA))
+#define debug_mime_data (opt.enable_debug & DBG_MIME_DATA)
+
+
 static const char oid_mimetag[] =
     {0x2A, 0x86, 0x48, 0x86, 0xf7, 0x14, 0x03, 0x0a, 0x04};
 
@@ -112,6 +114,7 @@ struct mime_context
   int is_qp_encoded;      /* Current part is QP encoded. */
   int is_base64_encoded;  /* Current part is base 64 encoded. */
   int is_body;            /* The current part belongs to the body.  */
+  int is_opaque_signed;   /* Flag indicating opaque signed S/MIME. */
   protocol_t protocol;    /* The detected crypto protocol.  */
 
   int part_counter;       /* Counts the number of processed parts. */
@@ -213,9 +216,8 @@ debug_message_event (mime_context_t ctx, rfc822parse_event_t event)
     case RFC822PARSE_EPILOGUE: s= "Epilogue"; break;
     default: s= "[unknown event]"; break;
     }
-#ifdef DEBUG_PARSER
-  log_debug ("%s: ctx=%p, rfc822 event %s\n", SRCNAME, ctx, s);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s: ctx=%p, rfc822 event %s\n", SRCNAME, ctx, s);
 }
 
 
@@ -233,9 +235,8 @@ start_attachment (mime_context_t ctx, int is_body)
   LPSTREAM to = NULL;
   LPUNKNOWN punk;
 
-#ifdef DEBUG_PARSER
-  log_debug ("%s:%s: for ctx=%p is_body=%d", SRCNAME, __func__, ctx, is_body);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: for ctx=%p is_body=%d", SRCNAME, __func__, ctx,is_body);
 
   /* Just in case something has not been finished, do it here. */
   if (ctx->outstream)
@@ -480,9 +481,8 @@ finish_attachment (mime_context_t ctx, int cancel)
   HRESULT hr;
   int retval = -1;
 
-#ifdef DEBUG_PARSER
-  log_debug ("%s:%s: for ctx=%p cancel=%d", SRCNAME, __func__, ctx, cancel);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: for ctx=%p cancel=%d", SRCNAME, __func__, ctx, cancel);
 
   if (ctx->outstream && ctx->is_body && !ctx->body_saved.outstream)
     {
@@ -755,10 +755,9 @@ t2body (mime_context_t ctx, rfc822parse_t msg)
       ctsub  = "plain";
     }
 
-#ifdef DEBUG_PARSER  
-  log_debug ("%s:%s: ctx=%p, ct=`%s/%s'\n",
-             SRCNAME, __func__, ctx, ctmain, ctsub);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: ctx=%p, ct=`%s/%s'\n",
+               SRCNAME, __func__, ctx, ctmain, ctsub);
 
   s = rfc822parse_query_parameter (field, "charset", 0);
   if (s)
@@ -830,17 +829,30 @@ t2body (mime_context_t ctx, rfc822parse_t msg)
     }
   else /* Other type. */
     {
+      /* Check whether this attachment is an opaque signed S/MIME
+         part.  We use a counter to later check that tehre is only one
+         such part. */
+      if (!strcmp (ctmain, "application") && !strcmp (ctsub, "pkcs7-mime"))
+        {
+          const char *smtype = rfc822parse_query_parameter (field,
+                                                            "smime-type", 0);
+          if (smtype && !strcmp (smtype, "signed-data"))
+            ctx->is_opaque_signed++;
+        }
+
       if (!ctx->preview)
         ctx->collect_attachment = 1;
     }
   rfc822parse_release_field (field); /* (Content-type) */
   ctx->in_data = 1;
 
-#ifdef DEBUG_PARSER
-  log_debug ("%s: this body: nesting=%d partno=%d is_text=%d charset=\"%s\"\n",
-             SRCNAME, ctx->nesting_level, ctx->part_counter, is_text, 
-             ctx->mimestruct_cur->charset?ctx->mimestruct_cur->charset:"");
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: this body: nesting=%d partno=%d is_text=%d, is_opq=%d"
+               " charset=\"%s\"\n",
+               SRCNAME, __func__, 
+               ctx->nesting_level, ctx->part_counter, is_text, 
+               ctx->is_opaque_signed,
+               ctx->mimestruct_cur->charset?ctx->mimestruct_cur->charset:"");
 
   /* If this is a text part, decide whether we treat it as our body. */
   if (is_text)
@@ -884,9 +896,8 @@ t2body (mime_context_t ctx, rfc822parse_t msg)
         {
           /* We already got one body and thus we can continue that
              last attachment.  */
-#ifdef DEBUG_PARSER
-          log_debug ("%s:%s: continuing body part\n", SRCNAME, __func__);
-#endif
+          if (debug_mime_parser)
+            log_debug ("%s:%s: continuing body part\n", SRCNAME, __func__);
           ctx->is_body = 1;
           ctx->outstream = ctx->body_saved.outstream;
           ctx->mapi_attach = ctx->body_saved.mapi_attach;
@@ -927,10 +938,9 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
         return 0; /*  We need to skip the OPEN event.  */
       if (!ctx->body_seen)
         {
-#ifdef DEBUG_PARSER
-          log_debug ("%s:%s: assuming this is plain text without headers\n",
-                     SRCNAME, __func__);
-#endif
+          if (debug_mime_parser)
+            log_debug ("%s:%s: assuming this is plain text without headers\n",
+                       SRCNAME, __func__);
           ctx->in_data = 1;
           ctx->collect_attachment = 2; /* 2 so we don't skip the first line. */
           ctx->body_seen = 1;
@@ -1050,8 +1060,9 @@ plaintext_handler (void *handle, const void *buffer, size_t size)
           if (pos && ctx->linebuf[pos-1] == '\r')
             pos--;
 
-/*           log_debug ("%s:%s: ctx=%p, line=`%.*s'\n", */
-/*                      SRCNAME, __func__, ctx, (int)pos, ctx->linebuf); */
+          if (debug_mime_data)
+            log_debug ("%s:%s: ctx=%p, line=`%.*s'\n",
+                       SRCNAME, __func__, ctx, (int)pos, ctx->linebuf);
           if (rfc822parse_insert (ctx->msg, ctx->linebuf, pos))
             {
               log_error ("%s: ctx=%p, rfc822 parser failed: %s\n",
@@ -1191,7 +1202,9 @@ mime_verify (protocol_t protocol, const char *message, size_t messagelen,
   while ( (s = memchr (message, '\n', messagelen)) )
     {
       len = s - message + 1;
-/*       log_debug ("passing '%.*s'\n", (int)len, message); */
+      if (debug_mime_data)
+        log_debug ("%s:%s: passing '%.*s'\n", 
+                   SRCNAME, __func__, (int)len, message);
       plaintext_handler (ctx, message, len);
       if (ctx->parser_error || ctx->line_too_long)
         {
@@ -1284,13 +1297,17 @@ mime_verify (protocol_t protocol, const char *message, size_t messagelen,
 
 
 /* A special version of mime_verify which works only for S/MIME opaque
-   signed messages.  The message is expected to be a binary data
-   stream with a CMS signature.  This function passes the entire
-   message to the crypto engine and then parses the (cleartext) output
-   for rendering the data.  */
+   signed messages.  The message is expected to be a binary CMS
+   signature eityher as an ISTREAM (if instream is not NULL) or
+   provided in a buffer (INBUFFER and INBUFERLEN).  This function
+   passes the entire message to the crypto engine and then parses the
+   (cleartext) output for rendering the data.  START_PART_COUNTER
+   should normally be set to 0. */
 int
 mime_verify_opaque (protocol_t protocol, LPSTREAM instream, 
-                    LPMESSAGE mapi_message, HWND hwnd, int preview_mode)
+                    const char *inbuffer, size_t inbufferlen,
+                    LPMESSAGE mapi_message, HWND hwnd, int preview_mode,
+                    int start_part_counter)
 {
   gpg_error_t err = 0;
   mime_context_t ctx;
@@ -1298,6 +1315,10 @@ mime_verify_opaque (protocol_t protocol, LPSTREAM instream,
 
   log_debug ("%s:%s: enter (protocol=%d)", SRCNAME, __func__, protocol);
 
+  if ((instream && (inbuffer || inbufferlen))
+      || (!instream && !inbuffer))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
   if (protocol != PROTOCOL_SMIME)
     return gpg_error (GPG_ERR_INV_VALUE);
 
@@ -1308,6 +1329,7 @@ mime_verify_opaque (protocol_t protocol, LPSTREAM instream,
   ctx->verify_mode = 0;
   ctx->mapi_message = mapi_message;
   ctx->mimestruct_tail = &ctx->mimestruct;
+  ctx->part_counter = start_part_counter;
 
   ctx->msg = rfc822parse_open (message_cb, ctx);
   if (!ctx->msg)
@@ -1323,28 +1345,36 @@ mime_verify_opaque (protocol_t protocol, LPSTREAM instream,
   if ((err=engine_verify_start (filter, hwnd, NULL, 0, protocol)))
     goto leave;
 
-  /* Filter the stream.  */
-  do
+  if (instream)
     {
-      HRESULT hr;
-      ULONG nread;
-      char buffer[4096];
-      
-      hr = IStream_Read (instream, buffer, sizeof buffer, &nread);
-      if (hr)
-        {
-          log_error ("%s:%s: IStream::Read failed: hr=%#lx", 
-                     SRCNAME, __func__, hr);
-          err = gpg_error (GPG_ERR_EIO);
-        }
-      else if (nread)
+      /* Filter the stream.  */
+      do
         {
-          err = engine_filter (filter, buffer, nread);
+          HRESULT hr;
+          ULONG nread;
+          char buffer[4096];
+      
+          hr = IStream_Read (instream, buffer, sizeof buffer, &nread);
+          if (hr)
+            {
+              log_error ("%s:%s: IStream::Read failed: hr=%#lx", 
+                         SRCNAME, __func__, hr);
+              err = gpg_error (GPG_ERR_EIO);
+            }
+          else if (nread)
+            {
+              err = engine_filter (filter, buffer, nread);
+            }
+          else
+            break; /* EOF */
         }
-      else
-        break; /* EOF */
+      while (!err);
+    }
+  else
+    {
+      /* Filter the buffer.  */
+      err = engine_filter (filter, inbuffer, inbufferlen);
     }
-  while (!err);
   if (err)
     goto leave;
 
@@ -1437,18 +1467,17 @@ ciphermessage_t2body (mime_context_t ctx, rfc822parse_t msg)
       ctsub  = "plain";
     }
 
-#ifdef DEBUG_PARSER  
-  log_debug ("%s:%s: ctx=%p, ct=`%s/%s'\n",
-             SRCNAME, __func__, ctx, ctmain, ctsub);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: ctx=%p, ct=`%s/%s'\n",
+               SRCNAME, __func__, ctx, ctmain, ctsub);
+
   rfc822parse_release_field (field); /* (Content-type) */
   ctx->in_data = 1;
 
-#ifdef DEBUG_PARSER
-  log_debug ("%s:%s: this body: nesting=%d part_counter=%d is_text=%d\n",
-             SRCNAME, __func__, 
-             ctx->nesting_level, ctx->part_counter, is_text);
-#endif
+  if (debug_mime_parser)
+    log_debug ("%s:%s: this body: nesting=%d part_counter=%d is_text=%d\n",
+               SRCNAME, __func__, 
+               ctx->nesting_level, ctx->part_counter, is_text);
 
 
   return 0;
@@ -1533,8 +1562,9 @@ ciphertext_handler (void *handle, const void *buffer, size_t size)
           if (pos && ctx->linebuf[pos-1] == '\r')
             pos--;
 
-/*           log_debug ("%s:%s: ctx=%p, line=`%.*s'\n", */
-/*                      SRCNAME, __func__, ctx, (int)pos, ctx->linebuf); */
+          if (debug_mime_data)
+            log_debug ("%s:%s: ctx=%p, line=`%.*s'\n",
+                       SRCNAME, __func__, ctx, (int)pos, ctx->linebuf);
           if (rfc822parse_insert (ctx->msg, ctx->linebuf, pos))
             {
               log_error ("%s:%s: ctx=%p, rfc822 parser failed: %s\n",
@@ -1598,6 +1628,8 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
   gpg_error_t err;
   mime_context_t decctx, ctx;
   engine_filter_t filter = NULL;
+  int opaque_signed = 0;
+  int last_part_counter = 0;
 
   log_debug ("%s:%s: enter (protocol=%d, is_rfc822=%d)",
              SRCNAME, __func__, protocol, is_rfc822);
@@ -1736,6 +1768,8 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
         }
       symenc_close (ctx->symenc);
       symenc_close (ctx->body_saved.symenc);
+      last_part_counter = ctx->part_counter;
+      opaque_signed = (ctx->is_opaque_signed == 1);
       xfree (ctx);
     }
   if (decctx)
@@ -1743,6 +1777,55 @@ mime_decrypt (protocol_t protocol, LPSTREAM instream, LPMESSAGE mapi_message,
       rfc822parse_close (decctx->msg);
       xfree (decctx);
     }
+
+  if (!err && opaque_signed)
+    {
+      /* Handle an S/MIME opaque signed part.  The decryption has
+         written an attachment we are now going to verify and render
+         to the body attachment.  */
+      mapi_attach_item_t *table;
+      char *plainbuffer = NULL;
+      size_t plainbufferlen;
+      int i;
+
+      table = mapi_create_attach_table (mapi_message, 0);
+      if (!table)
+        {
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave_verify;
+        }
+
+      for (i=0; !table[i].end_of_table; i++)
+        if (table[i].attach_type == ATTACHTYPE_FROMMOSS
+            && table[i].content_type               
+            && !strcmp (table[i].content_type, "application/pkcs7-mime"))
+          break;
+      if (table[i].end_of_table)
+        {
+          log_debug ("%s:%s: attachment for opaque signed S/MIME not found",
+                     SRCNAME, __func__);
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave_verify;
+        }
+      plainbuffer = mapi_get_attach (mapi_message, 1, table+i,
+                                     &plainbufferlen);
+      if (!plainbuffer)
+        {
+          err = gpg_error (GPG_ERR_GENERAL);
+          goto leave_verify;
+        }
+
+      err = mime_verify_opaque (PROTOCOL_SMIME, NULL, 
+                                plainbuffer, plainbufferlen,
+                                mapi_message, hwnd, 0, last_part_counter+1);
+      
+      log_debug ("%s:%s: mime_verify_opaque returned %d", 
+                 SRCNAME, __func__, err);
+
+    leave_verify:
+      xfree (plainbuffer);
+      mapi_release_attach_table (table);
+    }
   return err;
 }
 
index 0343174..7737d6a 100644 (file)
@@ -32,7 +32,9 @@ int mime_verify (protocol_t protocol, const char *message, size_t messagelen,
                  LPMESSAGE mapi_message, 
                  HWND hwnd, int preview_mode);
 int mime_verify_opaque (protocol_t protocol, LPSTREAM instream, 
-                        LPMESSAGE mapi_message, HWND hwnd, int preview_mode);
+                        const char *inbuffer, size_t inbufferlen,
+                        LPMESSAGE mapi_message, HWND hwnd, int preview_mode,
+                        int start_part_counter);
 int mime_decrypt (protocol_t protocol, 
                   LPSTREAM instream, LPMESSAGE mapi_message, int is_rfc822,
                   int simple_pgp, HWND hwnd, int preview_mode);