[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Configuring mhonarc to process application/x-pkcs7-mime signed data



I recently had the need to deal with application/x-pkcs7-mime signed
data for one my personal archives since I've been receiving mails
for a project that use it.

MHonArc does not have direct support for the type, so the content
gets saved to an external file, which is of little use.

After I figured out how to utilize the openssl program to
extract the content successfully from the command-line, I leveraged
the simple callback API mhonarc provides to extract the signed
data out automatically.  Note, I do not care to validate the
signatures.  I just need to get at the message data.

Attached are two files depending on how you may need this
capability.  The mha-p7m script is a custom front-end replacement
for the standard 'mhonarc' command that registers the callbacks
for processing application/x-pkcs7-mime data.

The other attachment is a sample mhasiteinit.pl file defining
the callbacks so the regular 'mhonarc' command can still be used
(see reference manual on how to install mhasiteinit.pl).  Using
mhasiteinit.pl is beneficial if using something like mharc to manage
your archives so the application/x-pkcs7-mime extraction can be made
available for mharc-based archives.

I encourage anyone to extend what I have done to support
other application/x-pkcs7-mime content (e.g. encrypted data).
I did not bother with it since I do not need it and such
support requires dealing with key management, and I did not
want to mess with it at this time.

There may be a general use to make such support intrinsic to
mhonarc  and I have no problem if the openssl command is a required
dependency. However, I've been busy with other things for awhile to
do any real work on mhonarc so do not hold your breath waiting for
me to get something done.

Enjoy,

--ewh

#!/usr/bin/perl

use lib qw( /usr/lib/MHonArc );
use Symbol;
use File::Temp;

my @argv = @ARGV;
require 'mhamain.pl' || die qq/ERROR: Unable to require "mhamain.pl"\n/;

my $openssl = 'openssl';

# Variable that holds the raw header text of the current message
my $current_header_txt = '';

#$mhonarc::Debug = 1;
&mhonarc::initialize();

# Message head callback function to capture raw header text.
# This is needed so we can print it out to temp file when openssl
# is used to extract signed message
#
$mhonarc::CBMessageHeadRead = sub {
  my $fields = shift;
  $current_header_txt = shift;
  $current_header_txt .= "\n";
};

# Raw message body read callback: If application/x-pkcs7-mime signed
# data, openssl used to extract contents and then we replace
# body variable to extracted contents for mhonarc to parse and archive.
#
$mhonarc::CBRawMessageBodyRead = sub {
  my $fields = shift;
  my $data_ref = shift;
  my $ctype = $fields->{'content-type'}[0];

  # If not signed-data, we return immediately
  if (!$ctype || $ctype !~ m{application/x-pkcs7-mime} ||
      $ctype !~ m{signed-data}) {
    return 1;
  }

  # Get here, use openssl to extract main data.

  # Write input data to temp file for use by openssl.
  my $tmp = new File::Temp();
  syswrite($tmp, $current_header_txt);  # openssl requires mail headers
  syswrite($tmp, $$data_ref);

  # Open pipe to openssl to extract the data: The command-line
  # options to make this work is non-intuitive.  Luckily, I found
  # a page on the web that listed the right options for extracting
  # the content w/o the need to validate the signature.
  my $handle = gensym;
  mhonarc::cmd_pipe_open($handle,
                $openssl, 'smime',
                '-verify',
                '-in', $tmp->filename,
                '-noverify');
  my $new_data = join('', <$handle>);
  close($handle);
  close($tmp);

  # Parse the sub-header from extracted data and update
  # main fields to use them over original fields.
  my($sub_header, $txt) = readmail::MAILread_header(\$new_data);
  foreach my $key (keys %$sub_header) {
    $fields->{$key} = $sub_header->{$key};
  }
  if ($sub_header->{'content-type'}) {
    # Make sure update mhonarc's meta field for content-type
    my $ctype = $sub_header->{'content-type'}[0];
    if ($ctype =~ m%^\s*([\w\-\./]+)%) {
      $fields->{'x-mha-content-type'} = $1;
    }
  }
  # IMPORTANT: Make sure CTE is adjusted to reflect extracted data
  if (!$sub_header->{'content-transfer-encoding'}) {
    $fields->{'content-transfer-encoding'} = [ '7bit' ];
  }

  # Replace message data to what was extracted and let mhonarc parse it.
  $$data_ref = $new_data;

  return 1;
};

&mhonarc::process_input(@argv);
#!/usr/local/bin/perl
##---------------------------------------------------------------------------##
##  File:
##      $Id: mhasiteinit.pl,v 1.4 2005/06/02 02:12:30 ehood Exp $
##  Description:
##      Site-specific initialization code for MHonArc.  If used, it
##	should be place in the MHonArc library directory as specified
##	during initialization, or in a directory that perl checks
##	when requiring libraries.
##
##	>>> THE EXPRESSIONS IN THIS FILE ARE EXECUTED EVERYTIME AN
##	>>> ARCHIVE IS OPENED FOR PROCESSING.
##
##	Note, it is recommended to use a default resource file when
##	possible.
##---------------------------------------------------------------------------##

##  Set package to something other than "mhonarc" to protect ourselves
##  from unintentionally screwing with MHonArc's internals

package mhonarc_site_init;

use Symbol;
use File::Temp;

my $openssl = '/usr/bin/openssl';

# Variable that holds the raw header text of the current message
my $current_header_txt = '';

# Message head callback function to capture raw header text.
# This is needed so we can print it out to temp file when openssl
# is used to extract signed message
#
$mhonarc::CBMessageHeadRead = sub {
  my $fields = shift;
  $current_header_txt = shift;
  $current_header_txt .= "\n";
};

# Raw message body read callback: If application/x-pkcs7-mime signed
# data, openssl used to extract contents and then we replace
# body variable to extracted contents for mhonarc to parse and archive.
#
$mhonarc::CBRawMessageBodyRead = sub {
  my $fields = shift;
  my $data_ref = shift;
  my $ctype = $fields->{'content-type'}[0];

  # If not signed-data, we return immediately
  if (!$ctype || $ctype !~ m{application/x-pkcs7-mime} ||
      $ctype !~ m{signed-data}) {
    return 1;
  }

  # Get here, use openssl to extract main data.

  # Write input data to temp file for use by openssl.
  my $tmp = new File::Temp();
  syswrite($tmp, $current_header_txt);  # openssl requires mail headers
  syswrite($tmp, $$data_ref);

  # Open pipe to openssl to extract the data: The command-line
  # options to make this work is non-intuitive.  Luckily, I found
  # a page on the web that listed the right options for extracting
  # the content w/o the need to validate the signature.
  my $handle = gensym;
  mhonarc::cmd_pipe_open($handle,
                $openssl, 'smime',
                '-verify',
                '-in', $tmp->filename,
                '-noverify');
  my $new_data = join('', <$handle>);
  close($handle);
  close($tmp);

  # Parse the sub-header from extracted data and update
  # main fields to use them over original fields.
  my($sub_header, $txt) = readmail::MAILread_header(\$new_data);
  foreach my $key (keys %$sub_header) {
    $fields->{$key} = $sub_header->{$key};
  }
  if ($sub_header->{'content-type'}) {
    # Make sure update mhonarc's meta field for content-type
    my $ctype = $sub_header->{'content-type'}[0];
    if ($ctype =~ m%^\s*([\w\-\./]+)%) {
      $fields->{'x-mha-content-type'} = $1;
    }
  }
  # IMPORTANT: Make sure CTE is adjusted to reflect extracted data
  if (!$sub_header->{'content-transfer-encoding'}) {
    $fields->{'content-transfer-encoding'} = [ '7bit' ];
  }

  # Replace message data to what was extracted and let mhonarc parse it.
  $$data_ref = $new_data;

  return 1;
};

##---------------------------------------------------------------------------##
## Make sure to return a true value for require().
##---------------------------------------------------------------------------##
1;

[Index of Archives]     [Bugtraq]     [Yosemite News]     [Mhonarc Home]