changeset: 6447:babc30377614
user:      Kevin McCarthy <[email protected]>
date:      Fri May 15 10:47:38 2015 -0700
link:      http://dev.mutt.org/hg/mutt/rev/babc30377614

Start cleaning up and fixing smime_keys.pl (closes #3324) (see #2456)

* Convert to using File::Temp (#3324).  This was also suggested at
  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=775199

* Use File::Temp for add_p12 temp file. (#2456)

* Make the query_label() method a bit more robust with empty strings,
  ctrl-d, and leading spaces.

* Clean up openssl_do_verify() logic.  Mark cert as invalid
  rather that die'ing if an openssl verify command fails.

* General cleanup:
  - Clearly separate op handler, certificate management, and helper
    functions by section and using prefixes.
  - Create openssl helper functions to reduce copy/paste invocations
    and make the code clearer.
  - Make indentation consistent at 2 spaces.
  - Change handle_add_pem() to re-use handle_add_chain() once the
    correct files are identified.
  - Change openssl_parse_pem() to return a single array of data
    structures representing the parsed certs/keys.

diffs (truncated from 1545 to 950 lines):

diff -r c46dfbdb5eff -r babc30377614 smime_keys.pl
--- a/smime_keys.pl     Sun May 03 16:25:45 2015 -0700
+++ b/smime_keys.pl     Fri May 15 10:47:38 2015 -0700
@@ -8,12 +8,12 @@
 #     it under the terms of the GNU General Public License as published by
 #     the Free Software Foundation; either version 2 of the License, or
 #     (at your option) any later version.
-# 
+#
 #     This program is distributed in the hope that it will be useful,
 #     but WITHOUT ANY WARRANTY; without even the implied warranty of
 #     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 #     GNU General Public License for more details.
-# 
+#
 #     You should have received a copy of the GNU General Public License
 #     along with this program; if not, write to the Free Software
 #     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
02110-1301, USA.
@@ -21,158 +21,129 @@
 use strict;
 use File::Copy;
 use File::Glob ':glob';
+use File::Temp qw(tempfile tempdir);
 
 umask 077;
 
 use Time::Local;
 
+# helper routines
 sub usage ();
-sub newfile ($;$$);
-sub mutt_Q ($ );
+sub mutt_Q ($);
 sub mycopy ($$);
+sub query_label ();
+sub mkdir_recursive ($);
+sub verify_files_exist (@);
+sub create_tempfile (;$);
+sub new_cert_structure ();
 
-#  directory setup routines
-sub mkdir_recursive ($ );
-sub init_paths ();
+# openssl helpers
+sub openssl_format ($);
+sub openssl_hash ($);
+sub openssl_fingerprint ($);
+sub openssl_emails ($);
+sub openssl_do_verify($$$);
+sub openssl_parse_pem ($$);
 
 # key/certificate management methods
-sub list_certs ();
-sub query_label ();
-sub add_entry ($$$$$ );
-sub add_certificate ($$$$;$ );
-sub add_key ($$$$);
-sub add_root_cert ($ );
-sub parse_pem (@ );
-sub handle_pem (@ );
-sub modify_entry ($$$;$ );
-sub remove_pair ($ );
-sub change_label ($ );
-sub verify_cert($$);
-sub do_verify($$$ );
-              
-# Get the directories mutt uses for certificate/key storage.
+sub cm_list_certs ();
+sub cm_add_entry ($$$$$);
+sub cm_add_certificate ($$$$;$);
+sub cm_add_key ($$$$);
+sub cm_modify_entry ($$$;$);
+
+# op handlers
+sub handle_init_paths ();
+sub handle_change_label ($);
+sub handle_add_cert ($);
+sub handle_add_pem ($);
+sub handle_add_p12 ($);
+sub handle_add_chain ($$$);
+sub handle_verify_cert($$);
+sub handle_remove_pair ($);
+sub handle_add_root_cert ($);
+
 
 my $mutt = $ENV{MUTT_CMDLINE} || 'mutt';
 my $opensslbin = "/usr/bin/openssl";
-my @tempfiles = ();
-my @cert_tmp_file = ();
+my $tmpdir;
 
-my $tmpdir;
+# Get the directories mutt uses for certificate/key storage.
+
 my $private_keys_path = mutt_Q 'smime_keys';
 die "smime_keys is not set in mutt's configuration file"
-       if length $private_keys_path == 0;
+   if length $private_keys_path == 0;
 
 my $certificates_path = mutt_Q 'smime_certificates';
 die "smime_certificates is not set in mutt's configuration file"
-       if length $certificates_path == 0;
+   if length $certificates_path == 0;
+
 my $root_certs_path   = mutt_Q 'smime_ca_location';
 die "smime_ca_location is not set in mutt's configuration file"
-       if length $root_certs_path == 0;
+   if length $root_certs_path == 0;
 
 my $root_certs_switch;
 if ( -d $root_certs_path) {
-       $root_certs_switch = -CApath;
+  $root_certs_switch = -CApath;
 } else {
-       $root_certs_switch = -CAfile;
+  $root_certs_switch = -CAfile;
 }
 
 
-#
+######
 # OPS
-#
+######
 
 if(@ARGV == 1 and $ARGV[0] eq "init") {
-    init_paths;
+  handle_init_paths();
 }
 elsif(@ARGV == 1 and $ARGV[0] eq "list") {
-    list_certs;
+  cm_list_certs();
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "label") {
-    change_label($ARGV[1]);
+  handle_change_label($ARGV[1]);
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "add_cert") {
-    my $format = -B $ARGV[1] ? 'DER' : 'PEM'; 
-    my $cmd = "$opensslbin x509 -noout -hash -in $ARGV[1] -inform $format";
-    my $cert_hash = `$cmd`;
-    $? and die "'$cmd' returned $?";
-    chomp($cert_hash); 
-    my $label = query_label;
-    &add_certificate($ARGV[1], \$cert_hash, 1, $label, '?');
+  verify_files_exist($ARGV[1]);
+  handle_add_cert($ARGV[1]);
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "add_pem") {
-    -e $ARGV[1] and -s $ARGV[1] or die("$ARGV[1] is nonexistent or empty.");
-    open(PEM_FILE, "<$ARGV[1]") or die("Can't open $ARGV[1]: $!");
-    my @pem = <PEM_FILE>;
-    close(PEM_FILE);
-    handle_pem(@pem);
+  verify_files_exist($ARGV[1]);
+  handle_add_pem($ARGV[1]);
 }
 elsif( @ARGV == 2 and $ARGV[0] eq "add_p12") {
-    -e $ARGV[1] and -s $ARGV[1] or die("$ARGV[1] is nonexistent or empty.");
-
-    print "\nNOTE: This will ask you for two passphrases:\n";
-    print "       1. The passphrase you used for exporting\n";
-    print "       2. The passphrase you wish to secure your private key 
with.\n\n";
-
-    my $pem_file = "$ARGV[1].pem";
-    
-    my $cmd = "$opensslbin pkcs12 -in $ARGV[1] -out $pem_file";
-    system $cmd and die "'$cmd' returned $?";
-    
-    -e $pem_file and -s $pem_file or die("Conversion of $ARGV[1] failed.");
-    open(PEM_FILE, $pem_file) or die("Can't open $pem_file: $!");
-    my @pem = <PEM_FILE>;
-    close(PEM_FILE);
-    unlink $pem_file;
-    handle_pem(@pem);
+  verify_files_exist($ARGV[1]);
+  handle_add_p12($ARGV[1]);
 }
 elsif(@ARGV == 4 and $ARGV[0] eq "add_chain") {
-    my $mailbox;
-    my $format = -B $ARGV[2] ? 'DER' : 'PEM'; 
-    my $cmd = "$opensslbin x509 -noout -hash -in $ARGV[2] -inform $format";
-    my $cert_hash = `$cmd`;
-
-    $? and die "'$cmd' returned $?";
-
-    $format = -B $ARGV[3] ? 'DER' : 'PEM'; 
-
-    $cmd = "$opensslbin x509 -noout -hash -in $ARGV[3] -inform $format";
-    my $issuer_hash = `$cmd`;
-    $? and die "'$cmd' returned $?";
-    
-    chomp($cert_hash); 
-    chomp($issuer_hash);
-
-    my $label = query_label;
-    
-    add_certificate($ARGV[3], \$issuer_hash, 0, $label); 
-    my @mailbox = &add_certificate($ARGV[2], \$cert_hash, 1, $label, 
$issuer_hash);
-    
-    foreach $mailbox (@mailbox) {
-      chomp($mailbox);
-      add_key($ARGV[1], $cert_hash, $mailbox, $label);
-    }
+  verify_files_exist($ARGV[1], $ARGV[2], $ARGV[3]);
+  handle_add_chain($ARGV[1], $ARGV[2], $ARGV[3]);
 }
 elsif((@ARGV == 2 or @ARGV == 3) and $ARGV[0] eq "verify") {
-    verify_cert($ARGV[1], $ARGV[2]);
+  verify_files_exist($ARGV[2]) if (@ARGV == 3);
+  handle_verify_cert($ARGV[1], $ARGV[2]);
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "remove") {
-    remove_pair($ARGV[1]);
+  handle_remove_pair($ARGV[1]);
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "add_root") {
-    add_root_cert($ARGV[1]);
+  verify_files_exist($ARGV[1]);
+  handle_add_root_cert($ARGV[1]);
 }
-else {    
-    usage;
-    exit(1);
+else {
+  usage();
+  exit(1);
 }
 
 exit(0);
 
 
+##############  sub-routines  ########################
 
 
-
-##############  sub-routines  ########################
+###################
+#  helper routines
+###################
 
 sub usage () {
     print <<EOF;
@@ -207,87 +178,336 @@
 }
 
 sub mutt_Q ($) {
-    my $var = shift or die;
+  my ($var) = @_;
 
-    my $cmd = "$mutt -v >/dev/null 2>/dev/null";
-    system ($cmd) == 0 
-        or die<<EOF;
+  my $cmd = "$mutt -v >/dev/null 2>/dev/null";
+  system ($cmd) == 0 or die<<EOF;
 Couldn't launch mutt. I attempted to do so by running the command "$mutt".
-If that's not the right command, you can override it by setting the 
+If that's not the right command, you can override it by setting the
 environment variable \$MUTT_CMDLINE
 EOF
 
-    $cmd = "$mutt -Q $var 2>/dev/null";
-    my $answer = `$cmd`;
+  $cmd = "$mutt -Q $var 2>/dev/null";
+  my $answer = `$cmd`;
 
-    $? and die<<EOF;
-Couldn't look up the value of the mutt variable "$var". 
+  $? and die<<EOF;
+Couldn't look up the value of the mutt variable "$var".
 You must set this in your mutt config file. See contrib/smime.rc for an 
example.
 EOF
-#'
 
-    $answer =~ /\"(.*?)\"/ and return bsd_glob($1, GLOB_TILDE | GLOB_NOCHECK);
-    
-    $answer =~ /^Mutt (.*?) / and die<<EOF;
+  $answer =~ /\"(.*?)\"/ and return bsd_glob($1, GLOB_TILDE | GLOB_NOCHECK);
+
+  $answer =~ /^Mutt (.*?) / and die<<EOF;
 This script requires mutt 1.5.0 or later. You are using mutt $1.
 EOF
-    
-    die "Value of $var is weird\n";
+
+  die "Value of $var is weird\n";
 }
 
 sub mycopy ($$) {
-    my $source = shift or die;
-    my $dest = shift or die;
+  my ($source, $dest) = @_;
 
-    copy $source, $dest or die "Problem copying $source to $dest: $!\n";
+  copy $source, $dest or die "Problem copying $source to $dest: $!\n";
 }
 
-#
-#  directory setup routines
-#
+sub query_label () {
+  my $input;
+  my $label;
+  my $junk;
 
+  print "\nYou may assign a label to this key, so you don't have to 
remember\n";
+  print "the key ID. This has to be _one_ word (no whitespaces).\n\n";
+
+  print "Enter label: ";
+  $input = <STDIN>;
+
+  if (defined($input) && ($input !~ /^\s*$/)) {
+    chomp($input);
+    $input =~ s/^\s+//;
+    ($label, $junk) = split(/\s/, $input, 2);
+
+    if (defined($junk)) {
+      print "\nUsing '$label' as label; ignoring '$junk'\n";
+    }
+  }
+
+  if ((! defined($label)) || ($label =~ /^\s*$/)) {
+    $label =  "-";
+  }
+
+  return $label;
+}
 
 sub mkdir_recursive ($) {
-    my $path = shift or die;
-    my $tmp_path;
-    
-    for my $dir (split /\//, $path) {
-        $tmp_path .= "$dir/";
+  my ($path) = @_;
+  my $tmp_path;
 
-        -d $tmp_path 
-            or mkdir $tmp_path, 0700
-                or die "Can't mkdir $tmp_path: $!";
-    }
+  for my $dir (split /\//, $path) {
+    $tmp_path .= "$dir/";
+
+    -d $tmp_path
+      or mkdir $tmp_path, 0700
+        or die "Can't mkdir $tmp_path: $!";
+  }
 }
 
-sub init_paths () {
-    mkdir_recursive($certificates_path);
-    mkdir_recursive($private_keys_path);
+sub verify_files_exist (@) {
+  my (@files) = @_;
 
-    my $file;
-
-    $file = $certificates_path . "/.index";
-    -f $file or open(TMP_FILE, ">$file") and close(TMP_FILE)
-        or die "Can't touch $file: $!";
-
-    $file = $private_keys_path . "/.index";
-    -f $file or open(TMP_FILE, ">$file") and close(TMP_FILE)
-        or die "Can't touch $file: $!";
+  foreach my $file (@files) {
+    if ((! -e $file) || (! -s $file)) {
+      die("$file is nonexistent or empty.");
+    }
+  }
 }
 
+# Returns a list ($fh, $filename)
+sub create_tempfile (;$) {
+  my ($directory) = @_;
 
+  if (! defined($directory)) {
+    if (! defined($tmpdir)) {
+      $tmpdir = tempdir(CLEANUP => 1);
+    }
+    $directory = $tmpdir;
+  }
 
-#
+  return tempfile(DIR => $directory);
+}
+
+# Creates a cert data structure used by openssl_parse_pem
+sub new_cert_structure () {
+  my $cert_data = {};
+
+  $cert_data->{datafile} = "";
+  $cert_data->{type} = "";
+  $cert_data->{localKeyID} = "";
+  $cert_data->{subject} = "";
+  $cert_data->{issuer} = "";
+
+  return $cert_data;
+}
+
+
+##################
+# openssl helpers
+##################
+
+sub openssl_format ($) {
+  my ($filename) = @_;
+
+  return -B $filename ? 'DER' : 'PEM';
+}
+
+sub openssl_hash ($) {
+  my ($filename) = @_;
+
+  my $format = openssl_format($filename);
+  my $cmd = "$opensslbin x509 -noout -hash -in $filename -inform $format";
+  my $cert_hash = `$cmd`;
+  $? and die "'$cmd' returned $?";
+
+  chomp($cert_hash);
+  return $cert_hash;
+}
+
+sub openssl_fingerprint ($) {
+  my ($filename) = @_;
+
+  my $format = openssl_format($filename);
+  my $cmd = "$opensslbin x509 -in $filename -inform $format -fingerprint 
-noout";
+  my $fingerprint = `$cmd`;
+  $? and die "'$cmd' returned $?";
+
+  chomp($fingerprint);
+  return $fingerprint;
+}
+
+sub openssl_emails ($) {
+  my ($filename) = @_;
+
+  my $format = openssl_format($filename);
+  my $cmd = "$opensslbin x509 -in $filename -inform $format -email -noout";
+  my @mailboxes = `$cmd`;
+  $? and die "'$cmd' returned $?";
+
+  chomp(@mailboxes);
+  return @mailboxes;
+}
+
+sub openssl_do_verify ($$$) {
+  my ($cert, $issuerid, $crl) = @_;
+
+  my $result = 't';
+  my $issuer_path;
+  my $cert_path = "$certificates_path/$cert";
+
+  if($issuerid eq '?') {
+    $issuer_path = "$certificates_path/$cert";
+  } else {
+    $issuer_path = "$certificates_path/$issuerid";
+  }
+
+  my $cmd = "$opensslbin verify $root_certs_switch $root_certs_path -purpose 
smimesign -purpose smimeencrypt -untrusted $issuer_path $cert_path";
+  my $output = `$cmd`;
+  chomp $output;
+  if ($?) {
+    print "'$cmd' returned exit code " . ($? >> 8) . " with output:\n";
+    print "$output\n\n";
+    print "Marking as invalid\n";
+    return 'i';
+  }
+  print "\n$output\n";
+
+  if ($output !~ /OK/) {
+    return 'i';
+  }
+
+  my $format = openssl_format($cert_path);
+  $cmd = "$opensslbin x509 -dates -serial -noout -in $cert_path -inform 
$format";
+  (my $not_before, my $not_after, my $serial_in) = `$cmd`;
+  $? and die "'$cmd' returned $?";
+
+  if ( defined $not_before and defined $not_after ) {
+    my %months = ('Jan', '00', 'Feb', '01', 'Mar', '02', 'Apr', '03',
+                  'May', '04', 'Jun', '05', 'Jul', '06', 'Aug', '07',
+                  'Sep', '08', 'Oct', '09', 'Nov', '10', 'Dec', '11');
+
+    my @tmp = split (/\=/, $not_before);
+    my $not_before_date = $tmp[1];
+    my @fields =
+      $not_before_date =~ /(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)\s*GMT/;
+    if ($#fields == 5) {
+      if (timegm($fields[4], $fields[3], $fields[2], $fields[1],
+                 $months{$fields[0]}, $fields[5]) > time) {
+        print "Certificate is not yet valid.\n";
+        return 'e';
+      }
+    } else {
+      print "Expiration Date: Parse Error :  $not_before_date\n\n";
+    }
+
+    @tmp = split (/\=/, $not_after);
+    my $not_after_date = $tmp[1];
+    @fields =
+      $not_after_date =~ /(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)\s*GMT/;
+    if ($#fields == 5) {
+      if (timegm($fields[4], $fields[3], $fields[2], $fields[1],
+                 $months{$fields[0]}, $fields[5]) < time) {
+        print "Certificate has expired.\n";
+        return 'e';
+      }
+    } else {
+      print "Expiration Date: Parse Error :  $not_after_date\n\n";
+    }
+  }
+
+  if ( defined $crl ) {
+    my @serial = split (/\=/, $serial_in);
+    my $cmd = "$opensslbin crl -text -noout -in $crl | grep -A1 $serial[1]";
+    (my $l1, my $l2) = `$cmd`;
+    $? and die "'$cmd' returned $?";
+
+    if ( defined $l2 ) {
+      my @revoke_date = split (/:\s/, $l2);
+      print "FAILURE: Certificate $cert has been revoked on $revoke_date[1]\n";
+      $result = 'r';
+    }
+  }
+  print "\n";
+
+  return $result;
+}
+
+sub openssl_parse_pem ($$) {
+  my ($filename, $attrs_required) = @_;
+
+  my $state = 0;
+  my $cert_data;
+  my @certs;
+  my $cert_count = 0;
+  my $bag_count = 0;
+  my $cert_tmp_fh;
+  my $cert_tmp_filename;
+
+  $cert_data = new_cert_structure();
+  ($cert_tmp_fh, $cert_data->{datafile}) = create_tempfile();
+
+  open(PEM_FILE, "<$filename") or die("Can't open $filename: $!");
+  while(<PEM_FILE>) {
+    if(/^Bag Attributes/) {
+      $bag_count++;
+      $state == 0 or  die("PEM-parse error at: $.");
+      $state = 1;
+    }
+
+    if ($state == 1) {
+      if (/localKeyID:\s*(.*)/) {
+        $cert_data->{localKeyID} = $1;
+      }
+
+      if (/subject=\s*(.*)/) {
+        $cert_data->{subject} = $1;
+      }
+
+      if (/issuer=\s*(.*)/) {
+        $cert_data->{issuer} = $1;
+      }
+    }
+
+
+    if(/^-----/) {
+      if(/BEGIN/) {
+        print $cert_tmp_fh $_;
+        $state = 2;
+
+        if(/PRIVATE/) {
+            $cert_data->{type} = "K";
+            next;
+        }
+        if(/CERTIFICATE/) {
+            $cert_data->{type} = "C";
+            next;
+        }
+        die("What's this: $_");
+      }
+      if(/END/) {
+        $state = 0;
+        print $cert_tmp_fh $_;
+        close($cert_tmp_fh);
+
+        $cert_count++;
+        push (@certs, $cert_data);
+
+        $cert_data = new_cert_structure();
+        ($cert_tmp_fh, $cert_data->{datafile}) = create_tempfile();
+        next;
+      }
+    }
+    print $cert_tmp_fh $_;
+  }
+  close($cert_tmp_fh);
+  close(PEM_FILE);
+
+  if ($attrs_required && ($bag_count != $cert_count)) {
+    die("Not all contents were bagged. can't continue.");
+  }
+
+  return @certs;
+}
+
+
+#################################
 # certificate management methods
-#
+#################################
 
-sub list_certs () {
+sub cm_list_certs () {
   my %keyflags = ( 'i', '(Invalid)',  'r', '(Revoked)', 'e', '(Expired)',
-                  'u', '(Unverified)', 'v', '(Valid)', 't', '(Trusted)');
+                   'u', '(Unverified)', 'v', '(Valid)', 't', '(Trusted)');
 
-  open(INDEX, "<$certificates_path/.index") or 
+  open(INDEX, "<$certificates_path/.index") or
     die "Couldn't open $certificates_path/.index: $!";
-  
+
   print "\n";
   while(<INDEX>) {
     my $tmp;
@@ -308,7 +528,7 @@
             die "Couldn't open $certfile: $!";
         local $/;
         $cert = <F>;
-       close F;
+        close F;
     }
 
     my $subject_in;
@@ -316,7 +536,7 @@
     my $date1_in;
     my $date2_in;
 
-    my $format = -B $certfile ? 'DER' : 'PEM'; 
+    my $format = openssl_format($certfile);
     my $cmd = "$opensslbin x509 -subject -issuer -dates -noout -in $certfile 
-inform $format";
     ($subject_in, $issuer_in, $date1_in, $date2_in) = `$cmd`;
     $? and print "ERROR: '$cmd' returned $?\n\n" and next;
@@ -345,13 +565,13 @@
       $tmp = $tmp[1];
       @tmp = split (/\=/, $date2_in);
       print $tab."Certificate is not valid before $tmp".
-       $tab."                      or after  ".$tmp[1];
+        $tab."                      or after  ".$tmp[1];
     }
 
     -e "$private_keys_path/$fields[1]" and
       print "$tab - Matching private key installed -\n";
 
-    $format = -B "$certificates_path/$fields[1]" ? 'DER' : 'PEM'; 
+    $format = openssl_format("$certificates_path/$fields[1]");
     $cmd = "$opensslbin x509 -purpose -noout -in $certfile -inform $format";
     my $purpose_in = `$cmd`;
     $? and die "'$cmd' returned $?";
@@ -367,406 +587,335 @@
 
     print "\n";
   }
-  
+
   close(INDEX);
 }
 
+sub cm_add_entry ($$$$$) {
+  my ($mailbox, $hashvalue, $use_cert, $label, $issuer_hash) = @_;
 
+  my @fields;
 
-sub query_label () {
-    my @words;
-    my $input;
+  if ($use_cert) {
+    open(INDEX, "+<$certificates_path/.index") or
+        die "Couldn't open $certificates_path/.index: $!";
+  }
+  else {
+    open(INDEX, "+<$private_keys_path/.index") or
+        die "Couldn't open $private_keys_path/.index: $!";
+  }
 
-    print "\nYou may assign a label to this key, so you don't have to 
remember\n";
-    print "the key ID. This has to be _one_ word (no whitespaces).\n\n";
+  while(<INDEX>) {
+    @fields = split;
+    return if ($fields[0] eq $mailbox && $fields[1] eq $hashvalue);
+  }
 
-    print "Enter label: ";
-    chomp($input = <STDIN>);
+  if ($use_cert) {
+    print INDEX "$mailbox $hashvalue $label $issuer_hash u\n";
+  }
+  else {
+    print INDEX "$mailbox $hashvalue $label \n";
+  }
 
-    my ($label, $junk) = split(/\s/, $input, 2);     
-    
-    defined $junk 
-        and print "\nUsing '$label' as label; ignoring '$junk'\n";
-
-    defined $label || ($label =  "-");
-
-    return $label;
+  close(INDEX);
 }
 
+sub cm_add_certificate ($$$$;$) {
+  my ($filename, $hashvalue, $add_to_index, $label, $issuer_hash) = @_;
 
+  my $iter = 0;
+  my @mailboxes;
 
-sub add_entry ($$$$$) {
-    my $mailbox = shift or die;
-    my $hashvalue = shift or die;
-    my $use_cert = shift;
-    my $label = shift or die;
-    my $issuer_hash = shift;
+  my $fp1 = openssl_fingerprint($filename);
 
-    my @fields;
+  while (-e "$certificates_path/$$hashvalue.$iter") {
+    my $fp2 = openssl_fingerprint("$certificates_path/$$hashvalue.$iter");
 
-    if ($use_cert) {
-        open(INDEX, "+<$certificates_path/.index") or 
-            die "Couldn't open $certificates_path/.index: $!";
+    last if $fp1 eq $fp2;
+    $iter++;
+  }
+  $$hashvalue .= ".$iter";
+
+  if (-e "$certificates_path/$$hashvalue") {
+    print "\nCertificate: $certificates_path/$$hashvalue already installed.\n";
+  }
+  else {
+    mycopy $filename, "$certificates_path/$$hashvalue";
+
+    if ($add_to_index) {
+      @mailboxes = openssl_emails($filename);
+      foreach my $mailbox (@mailboxes) {
+        cm_add_entry($mailbox, $$hashvalue, 1, $label, $issuer_hash);
+        print "\ncertificate $$hashvalue ($label) for $mailbox added.\n";
+      }
+      cm_modify_entry('V', $$hashvalue, 1);
     }
     else {
-        open(INDEX, "+<$private_keys_path/.index") or 
-            die "Couldn't open $private_keys_path/.index: $!";
+      print "added certificate: $certificates_path/$$hashvalue.\n";
     }
+  }
 
-    while(<INDEX>) {
-        @fields = split;
-        return if ($fields[0] eq $mailbox && $fields[1] eq $hashvalue);
-    }
-
-    if ($use_cert) {
-        print INDEX "$mailbox $hashvalue $label $issuer_hash u\n";
-    }
-    else {
-        print INDEX "$mailbox $hashvalue $label \n";
-    }
-
-    close(INDEX);
+  return @mailboxes;
 }
 
-
-sub add_certificate ($$$$;$) {
-    my $filename = shift or die;
-    my $hashvalue = shift or die;
-    my $add_to_index = shift;
-    my $label = shift or die;
-    my $issuer_hash = shift;
-
-    my $iter = 0;
-    my @mailbox;
-    my $mailbox;
-
-    while(-e "$certificates_path/$$hashvalue.$iter") {
-        my ($t1, $t2);
-        my $format = -B $filename ? 'DER' : 'PEM'; 
-        my $cmd = "$opensslbin x509 -in $filename -inform $format -fingerprint 
-noout";
-        $t1 = `$cmd`;
-        $? and die "'$cmd' returned $?";
-
-        $format = -B "$certificates_path/$$hashvalue.$iter" ? 'DER' : 'PEM'; 
-        $cmd = "$opensslbin x509 -in $certificates_path/$$hashvalue.$iter 
-inform $format -fingerprint -noout";
-        $t2 = `$cmd`;
-        $? and die "'$cmd' returned $?";
-        
-        $t1 eq $t2 and last;
-
-        $iter++;
-    }
-    $$hashvalue .= ".$iter";
-    
-    if (-e "$certificates_path/$$hashvalue") {
-            print "\nCertificate: $certificates_path/$$hashvalue already 
installed.\n";
-    }
-    else {
-        mycopy $filename, "$certificates_path/$$hashvalue";
-
-        if ($add_to_index) {
-            my $format = -B $filename ? 'DER' : 'PEM'; 
-           my $cmd = "$opensslbin x509 -in $filename -inform $format -email 
-noout";
-           @mailbox = `$cmd`;
-           $? and die "'$cmd' returned $?";
-
-           foreach $mailbox (@mailbox) {
-             chomp($mailbox);
-             add_entry($mailbox, $$hashvalue, 1, $label, $issuer_hash);
-
-             print "\ncertificate $$hashvalue ($label) for $mailbox added.\n";
-           }
-           verify_cert($$hashvalue, undef);
-        }
-        else {
-            print "added certificate: $certificates_path/$$hashvalue.\n";
-        }
-    }
-
-    return @mailbox;
-}
-
-
-sub add_key ($$$$) {
-    my $file = shift or die;
-    my $hashvalue = shift or die;
-    my $mailbox = shift or die;
-    my $label = shift or die;
+sub cm_add_key ($$$$) {
+    my ($file, $hashvalue, $mailbox, $label) = @_;
 
     unless (-e "$private_keys_path/$hashvalue") {
         mycopy $file, "$private_keys_path/$hashvalue";
-    }    
+    }
 
-    add_entry($mailbox, $hashvalue, 0, $label, "");
+    cm_add_entry($mailbox, $hashvalue, 0, $label, "");
     print "added private key: " .
       "$private_keys_path/$hashvalue for $mailbox\n";
-} 
-
-
-
-
-
-
-sub parse_pem (@) {
-    my $state = 0;
-    my $cert_iter = 0;
-    my @bag_attribs;
-    my $numBags = 0;
-
-    $cert_tmp_file[$cert_iter] = newfile("cert_tmp.$cert_iter","temp");
-    my $cert_tmp_iter = $cert_tmp_file[$cert_iter];
-    open(CERT_FILE, ">$cert_tmp_iter") 
-        or die "Couldn't open $cert_tmp_iter: $!";
-
-    while($_ = shift(@_)) {
-        if(/^Bag Attributes/) {
-            $numBags++;
-            $state == 0 or  die("PEM-parse error at: $.");
-           $state = 1;
-            $bag_attribs[$cert_iter*4+1] = "";
-            $bag_attribs[$cert_iter*4+2] = "";
-            $bag_attribs[$cert_iter*4+3] = "";
-        }
-
-        ($state == 1) and /localKeyID:\s*(.*)/ 
-            and ($bag_attribs[$cert_iter*4+1] = $1);
-
-        ($state == 1) and /subject=\s*(.*)/    
-            and ($bag_attribs[$cert_iter*4+2] = $1);
-
-        ($state == 1) and /issuer=\s*(.*)/     
-            and ($bag_attribs[$cert_iter*4+3] = $1);
-        
-        if(/^-----/) {
-            if(/BEGIN/) {
-                print CERT_FILE;
-                $state = 2;
-
-                if(/PRIVATE/) {
-                    $bag_attribs[$cert_iter*4] = "K";
-                    next;
-                }
-                if(/CERTIFICATE/) {
-                    $bag_attribs[$cert_iter*4] = "C";
-                    next;
-                }
-                die("What's this: $_");
-            }
-            if(/END/) {
-                $state = 0;
-                print CERT_FILE;
-                close(CERT_FILE);
-                $cert_iter++;
-               $cert_tmp_file[$cert_iter] = 
newfile("cert_tmp.$cert_iter","temp");
-               $cert_tmp_iter = $cert_tmp_file[$cert_iter];
-                open(CERT_FILE, ">$cert_tmp_iter")
-                    or die "Couldn't open $cert_tmp_iter: $!";
-                next;
-            }
-        }
-        print CERT_FILE;
-    }
-    close(CERT_FILE);
-
-    # I'll add support for unbagged cetificates, in case this is needed.
-    $numBags == $cert_iter or 
-        die("Not all contents were bagged. can't continue.");
-
-    return @bag_attribs;
 }
 
+sub cm_modify_entry ($$$;$) {
+  my ($op, $hashvalue, $use_cert, $opt_param) = @_;
 
-# This requires the Bag Attributes to be set
-sub handle_pem (@) {
+  my $crl;
+  my $label;
+  my $path;
+  my @fields;
 
-    my @pem_contents;
-    my $iter=0;
-    my $root_cert;
-    my $key;
-    my $certificate;
-    my $intermediate;
-    my @mailbox;
-    my $mailbox;
+  $op eq 'L' and ($label = $opt_param);
+  $op eq 'V' and ($crl = $opt_param);
 

Reply via email to