]> granicus.if.org Git - neomutt/commitdiff
S/MIME fixes from Oliver Ehli:
authorThomas Roessler <roessler@does-not-exist.org>
Tue, 5 Feb 2002 13:07:27 +0000 (13:07 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Tue, 5 Feb 2002 13:07:27 +0000 (13:07 +0000)
- smime_keys.pl:

  support for multiple email adrresses in cert: will add one entry
  to {keys, cetrificates}/.index now (for each mailbox)

  support for certificates without intermediate certs (e.g. for
  people who are their own CA: use root as intermediate, for it
  probably wouldn't be known to anyone...)

  bugfix in handle_pem: the checks if some type of cert is present;
  die() could never be reached, as the variables checked wouldn't
  have been set in that case, so it would break because of undefined
  value or some such thing.... (so it has to check $iter instead)

- smime.c (init.h, ....)

  support for importing certificates issued for multiple addresses.

  introduced smime_fingerprint_cert_command, so finally certs can
  get compared ... (so the above works..)

  cleaned up some error messages, that would mess up the terminal.

  fixed typos (init.h)

contrib/smime.rc
init.h
smime.c
smime.h
smime_keys.pl

index 8a66ae20921756b8f2c7551f848be4836bc0b26d..edbbf3681823923121199c063daa97d8c2f553af 100644 (file)
@@ -45,6 +45,10 @@ set smime_get_signer_cert_command="openssl smime -verify -in %f -noverify -signe
 # above directory
 set smime_hash_cert_command="openssl x509 -in  %f -noout -hash"
 
+# This is used to get a md5-fingerprint of a certificate for purpose
+# of comparism
+set smime_fingerprint_cert_command="openssl x509 -in  %f -noout -fingerprint"
+
 # This is used to get the email address the certificate was issued to.
 set smime_get_cert_email_command="openssl x509 -in  %f -noout -email"
 
diff --git a/init.h b/init.h
index 0c45ec9b91c4af1220f19ef76d74bc058f06c133..0755d5372c8feac09514d850067176f254c1542a 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1485,11 +1485,11 @@ struct option_t MuttVars[] = {
   /*
   ** .pp
   ** Since there is no pubring/secring as with PGP, mutt has to handle
-  ** storage ad retrieval of keys by itself. This is very basic right now,
+  ** storage ad retrieval of keys/certs by itself. This is very basic right now,
   ** and stores keys and certificates in two different directories, both
-  ** named as the hash-value retrieved from OpenSSl. There is an index file
-  ** which contains mailbox-address keyid pai, and which can be manually
-  ** edited.
+  ** named as the hash-value retrieved from OpenSSL. There is an index file
+  ** which contains mailbox-address keyid pair, and which can be manually
+  ** edited. This one points to the location of the private keys.
   */
   { "smime_ca_location",       DT_PATH, R_NONE, UL &SmimeCALocation, 0 },
   /*
@@ -1505,12 +1505,12 @@ struct option_t MuttVars[] = {
   ** and stores keys and certificates in two different directories, both
   ** named as the hash-value retrieved from OpenSSl. There is an index file
   ** which contains mailbox-address keyid pai, and which can be manually
-  ** edited.
+  ** edited. This one points to the location of the certificates.
   */
   { "smime_decrypt_command",   DT_STR, R_NONE, UL &SmimeDecryptCommand, 0},
   /*
   ** .pp
-  ** This format strings specifies a command which is used to decrypt
+  ** This format string specifies a command which is used to decrypt
   ** application/x-pkcs7-mime attachments.
   ** .pp
   ** The OpenSSL command formats have their own set of printf-like sequences
@@ -1528,7 +1528,7 @@ struct option_t MuttVars[] = {
   ** .                 "-CApath $$smime_ca_location" or "-CAfile $$smime_ca_location".
   ** .de
   ** .pp
-  ** For examples on how to configure these formats, see the smime.rc
+  ** For examples on how to configure these formats, see the smime.rc in
   ** the samples/ subdirectory which has been installed on your system
   ** alongside the documentation.
   */
@@ -1565,7 +1565,7 @@ struct option_t MuttVars[] = {
   /*
   ** .pp
   ** This command is used to extract PKCS7 structures of S/MIME signatures,
-  ** in Order to extract the public X509 certificate(s).
+  ** in order to extract the public X509 certificate(s).
   */
   { "smime_get_cert_command",  DT_STR, R_NONE, UL &SmimeGetCertCommand, 0},
   /*
@@ -1575,28 +1575,34 @@ struct option_t MuttVars[] = {
   { "smime_get_signer_cert_command",   DT_STR, R_NONE, UL &SmimeGetSignerCertCommand, 0},
   /*
   ** .pp
-  ** This command is used to extract only the signers X509 certificate from a S/MIME signature,
-  ** so that the certificate's owner may get compared to the email's from field.
+  ** This command is used to extract only the signers X509 certificate from a S/MIME
+  **  signature, so that the certificate's owner may get compared to the email's 
+  ** 'From'-field.
   */
   { "smime_hash_cert_command",         DT_STR, R_NONE, UL &SmimeHashCertCommand, 0},
   /*
   ** .pp
   ** This command is used to calculate a hash value used for storing
-  ** X509 certificates.
+  ** X509 certificates. (The value is derived from the cert's subject field)
+  */
+  { "smime_fingerprint_cert_command",  DT_STR, R_NONE, UL &SmimeFingerprintCertCommand, 0},
+  /*
+  ** .pp
+  ** This command returns a md5-fingerprint of the certificate.
+  ** That way, certificates with an identical subject field can get compared.
   */
   { "smime_get_cert_email_command",    DT_STR, R_NONE, UL &SmimeGetCertEmailCommand, 0},
   /*
   ** .pp
-  ** This command is used to extract the mail address used for storing
-  ** X509 certificates, abd for verification purposes (to see if the
-  ** certifacate was issued for the sender's mailbox.
+  ** This command is used to extract the mail address(es) used for storing
+  ** X509 certificates, and for verification purposes (to check, wether the
+  ** certifacate was issued for the sender's mailbox).
   */
   { "smime_sign_as",           DT_STR,  R_NONE, UL &SmimeSignAs, 0 },
   /*
   ** .pp
   ** This is the default key-pair to use vor signing. This must be set to the
-  ** keyid (the hash-value, OpenSSL generates) to work properly (key handling
-  ** is very limited right now.)
+  ** keyid (the hash-value that OpenSSL generates) to work properly
   */
 #endif /* HAVE_SMIME */
   
diff --git a/smime.c b/smime.c
index e1c163ba1a7812a622e05d97341c094a3a5753eb..b640972cf587f2902c0ccef3b49a96dd4902a1c8 100644 (file)
--- a/smime.c
+++ b/smime.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Oliver Ehli <elmy@acm.org>
+ * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
  * Copyright (C) 2002 Mike Schiraldi <raldi@research.netsol.com>
  *
  *     This program is free software; you can redistribute it and/or modify
@@ -856,12 +856,13 @@ char *smime_findKeys (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc)
 
 
 
-static int smime_check_cert_email (char *certificate, char *mailbox)
+static int smime_handle_cert_email (char *certificate, char *mailbox,
+                                  int copy, char ***buffer, int *num)
 {
   FILE *fpout = NULL, *fperr = NULL;
   char tmpfname[_POSIX_PATH_MAX];
   char email[STRING];
-  int ret = -1;
+  int ret = -1, count = 0;
   pid_t thepid;
 
   mutt_mktemp (tmpfname);
@@ -902,14 +903,14 @@ static int smime_check_cert_email (char *certificate, char *mailbox)
 
   while ((fgets (email, sizeof (email), fpout)))
   {
-    *(email+mutt_strlen(email)-1) = '\0';
-    if(mutt_strncasecmp (email, mailbox, mutt_strlen (mailbox))==0)
-    {
-      ret = 0;
-      break;
-    }
-    ret = 1;
+    *(email + mutt_strlen (email)-1) = '\0';
+    if(mutt_strncasecmp (email, mailbox, mutt_strlen (mailbox)) == 0)
+      ret=1;
+
+    ret = ret < 0 ? 0 : ret;
+    count++;
   }
+
   if (ret == -1)
   {
     mutt_copy_stream (fperr, stdout);
@@ -917,13 +918,30 @@ static int smime_check_cert_email (char *certificate, char *mailbox)
     mutt_error (_("Alert: No mailbox specified in certificate.\n"));
     ret = 1;
   }
-  else if (ret == 1)
+  else if (!ret)
   {
     mutt_endwin(NULL);
-    mutt_error (_("Alert: Certificate belongs to \"%s\".\n"
-                  "       But sender was \"%s\".\n"), email, mailbox);
+    mutt_error (_("Alert: Certificate does *NOT* belong to \"%s\".\n"), mailbox);
     ret = 1;
   }
+  else ret = 0;
+
+  if(copy && buffer && num)
+  {
+    (*num) = count;
+    *buffer =  safe_calloc(sizeof(char*), count);
+    count = 0;
+
+    rewind (fpout);
+    while ((fgets (email, sizeof (email), fpout)))
+    {
+      *(email + mutt_strlen (email) - 1) = '\0';
+      (*buffer)[count] = safe_calloc(1, mutt_strlen (email) + 1);
+      strncpy((*buffer)[count], email, mutt_strlen (email));
+      count++;
+    }
+  }
+  else if(copy) ret = 2;
 
   fclose (fpout);
   fclose (fperr);
@@ -1108,22 +1126,108 @@ static char *smime_extract_signer_certificate (char *infile)
 }
 
 
+
+static int smime_compare_fingerprint (char *certificate, char *hashval, char *dest)
+{
+  FILE *fpout = NULL, *fperr = NULL;
+  char tmpfname[_POSIX_PATH_MAX];
+  char md5New[STRING], md5Old[STRING];
+  pid_t thepid;
+
+  mutt_mktemp (tmpfname);
+  if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
+  {
+    mutt_perror (tmpfname);
+    return -1;
+  }
+  mutt_unlink (tmpfname);
+
+  mutt_mktemp (tmpfname);
+  if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
+  {
+    fclose (fperr);
+    mutt_perror (tmpfname);
+    return -1;
+  }
+  mutt_unlink (tmpfname);
+
+  /* fingerprint the certificate to add */
+  if ((thepid =  smime_invoke (NULL, NULL, NULL,
+                              -1, fileno (fpout), fileno (fperr),
+                              certificate, NULL, NULL, NULL, NULL, NULL,
+                              SmimeFingerprintCertCommand))== -1)
+  {
+    mutt_message (_("Error: unable to create OpenSSL subprocess!"));
+    fclose (fperr);
+    fclose (fpout);
+    return -1;
+  }
+
+  mutt_wait_filter (thepid);
+  
+  fflush (fpout);
+  rewind (fpout);
+  fflush (fperr);
+  rewind (fperr);
+
+  if (!(fgets (md5New, sizeof (md5New), fpout)))
+  {
+    mutt_copy_stream (fperr, stdout);
+    fclose (fpout);
+    fclose (fperr);
+    return -1;
+  }
+
+  /* fingerprint the certificate already installed */
+  if ((thepid =  smime_invoke (NULL, NULL, NULL,
+                              -1, fileno (fpout), fileno (fperr),
+                              dest, NULL, NULL, NULL, NULL, NULL,
+                              SmimeFingerprintCertCommand))== -1)
+  {
+    mutt_message (_("Error: unable to create OpenSSL subprocess!"));
+    fclose (fperr);
+    fclose (fpout);
+    return -1;
+  }
+
+  mutt_wait_filter (thepid);
+  
+  fflush (fpout);
+  rewind (fpout);
+  fflush (fperr);
+  rewind (fperr);
+
+  if (!(fgets (md5Old, sizeof (md5Old), fpout)))
+  {
+    mutt_copy_stream (fperr, stdout);
+    fclose (fpout);
+    fclose (fperr);
+    return -1;
+  }
+
+  fclose (fpout);
+  fclose (fperr);
+
+  return ((mutt_strcasecmp (md5Old, md5New) == 0));
+}
+
+
 /* Add a certificate and update index file. */
 
-static void smime_add_certificate (char *certificate, char *mailbox, short public)
+static int smime_add_certificate (char *certificate, char *mailbox)
 {
   FILE *fpin = NULL, *fpout = NULL, *fperr = NULL;
   char tmpfname[_POSIX_PATH_MAX], dest[_POSIX_PATH_MAX];
   char buf[LONG_STRING], hashval[STRING], *tmpKey;
   struct stat info;
-  int i = 0;
+  int i = 0, certExists=0;
   pid_t thepid;
 
   mutt_mktemp (tmpfname);
   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
   {
     mutt_perror (tmpfname);
-    return;
+    return 1;
   }
   mutt_unlink (tmpfname);
 
@@ -1132,7 +1236,7 @@ static void smime_add_certificate (char *certificate, char *mailbox, short publi
   {
     fclose (fperr);
     mutt_perror (tmpfname);
-    return;
+    return 1;
   }
   mutt_unlink (tmpfname);
 
@@ -1152,22 +1256,22 @@ static void smime_add_certificate (char *certificate, char *mailbox, short publi
     mutt_message (_("Error: unable to create OpenSSL subprocess!"));
     fclose (fperr);
     fclose (fpout);
-    return;
+    return 1;
   }
 
   mutt_wait_filter (thepid);
   
   fflush (fpout);
   rewind (fpout);
-  rewind (fperr);
   fflush (fperr);
+  rewind (fperr);
 
   if (!(fgets (hashval, sizeof (hashval), fpout)))
   {
     mutt_copy_stream (fperr, stdout);
     fclose (fpout);
     fclose (fperr);
-    return;
+    return 1;
   }
   fclose (fpout);
   fclose (fperr);
@@ -1181,56 +1285,63 @@ static void smime_add_certificate (char *certificate, char *mailbox, short publi
 
     if (stat (dest, &info))
       break;
-    else
-      i++;
+    else { /* check wether this certificate already exists. */
+      if((certExists = smime_compare_fingerprint (certificate, hashval, dest)) == 1)
+      {
+       break;
+      }
+      else
+      {
+       if(!certExists)
+         i++;
+       else  /* some error: abort. */
+         return 1;
+      }
+    }
   }
-    
-  if ((fpout = safe_fopen (dest, "w+")) == NULL)
+  
+  if(!certExists)
   {
-    mutt_perror (dest);
-    return;
-  }
+    if ((fpout = safe_fopen (dest, "w+")) == NULL)
+    {
+      mutt_perror (dest);
+      return 1;
+    }
 
-  if ((fpin = safe_fopen (certificate, "r")) == NULL)
-  {
-    mutt_perror (certificate);
+    if ((fpin = safe_fopen (certificate, "r")) == NULL)
+    {
+      mutt_perror (certificate);
+      fclose (fpout);
+      mutt_unlink (dest);
+      return 1;
+    }
+    
+    mutt_copy_stream (fpin, fpout);
     fclose (fpout);
-    mutt_unlink (dest);
-    return;
+    fclose (fpin);
   }
-    
-  mutt_copy_stream (fpin, fpout);
-  fclose (fpout);
-  fclose (fpin);
 
 
   /*
     Now check if the mailbox is already found with the certificate's
-    hash value.
-
-    openssl uses md5 fingerprints to check wether two keys are identical.
-    I have to add that.
-    
+    hash value and/or md5 fingerprint.
   */
   
-  tmpKey = smime_get_field_from_db (mailbox, NULL, public, 0);
+  tmpKey = smime_get_field_from_db (mailbox, NULL, 1, 0); /* _always_ public! */
 
-  /* check if hash values are identical => same certificate ? */
+  /* check if hash is identical => same certificate! */
   /* perhaps we should ask for permission to overwrite ? */
   /* what about revoked certificates anyway ? */
 
-  /* reminder: openssl checks md5 - fingerprint for equality. add this. */
-
   if (tmpKey && !mutt_strncmp (tmpKey, hashval, mutt_strlen (hashval)))
   {
     mutt_message (_("Certificate \"%s\" exists for \"%s\"."), hashval, mailbox);
-    mutt_unlink (dest);
-    return;
+    return 0;
   }
     
-  /* append to index. */
+  /* doesn't exist or is a new one, so append to index. */
   snprintf (tmpfname, sizeof (tmpfname), "%s/.index",
-           (public ? NONULL(SmimeCertificates) : NONULL(SmimeKeys)));
+           NONULL(SmimeCertificates)); /* _always_ public: we don't add keys here */
   
   if (!stat (tmpfname, &info))
   {
@@ -1238,11 +1349,11 @@ static void smime_add_certificate (char *certificate, char *mailbox, short publi
     {
       mutt_perror (tmpfname);
       mutt_unlink (dest);
-      return;
+      return 1;
     }
     /*
        ? = unknown issuer, - = unassigned label,
-       u = undefined trust settings.
+       v = undefined trust settings (else we wouldn't have got that far).
     */
     snprintf (buf, sizeof (buf), "%s %s.%d - ? u\n", mailbox, hashval, i);
     fputs (buf, fpout);
@@ -1251,40 +1362,52 @@ static void smime_add_certificate (char *certificate, char *mailbox, short publi
     mutt_message (_("Successfully added certificate \"%s\" for \"%s\". "), hashval, mailbox);
   }
 
-  return;
+  return 0;
 }
 
 
 
 void smime_invoke_import (char *infile, char *mailbox)
 {
-  char *certfile = NULL;
-  int i;
+  char *certfile = NULL, **addrList=0;
+  int i, addrCount=0, ret = 0;
   certfile = smime_extract_signer_certificate(infile);
   
-  if (certfile == NULL)
+  if (certfile)
   { 
-    mutt_message _("Certificate *NOT* added.");
-    return;
-  }  
-  
-  i = smime_check_cert_email (certfile, mailbox);
+    i = smime_handle_cert_email (certfile, mailbox, 1, &addrList, &addrCount);
   
-  mutt_unlink(certfile);
+    mutt_unlink(certfile);
   
-  if (i)
-  {
-    mutt_message _("Certificate *NOT* added.");
-    return;
-  }
+    if (i)
+    {
+      mutt_message _("Certificate *NOT* added.");
+      return;
+    }
+    if ((certfile = smime_extract_certificate(infile)))
+    {
+      for (i = 0; i < addrCount; i++)
+      {
+       /* perhaps we shouldn't abort completley ? */
+
+       if(!ret)
+         ret = smime_add_certificate (certfile, addrList[i]);
 
-  if ((certfile = smime_extract_certificate(infile)))
+       safe_free((void **)&(addrList[i]));
+      }
+      mutt_unlink (certfile);
+      safe_free((void **)&certfile);
+      safe_free((void **)&addrList);
+    }
+    if(!ret)
+      return;
+  }  
+
+  if(isendwin())
   {
-    smime_add_certificate (certfile, mailbox, 1);
-    mutt_unlink (certfile);
-    safe_free((void **)&certfile);
+    mutt_any_key_to_continue(NULL);
+    mutt_message _("Certificate *NOT* added.");
   }
-  
   return;
 }
 
@@ -1329,7 +1452,7 @@ int smime_verify_sender(HEADER *h)
     if ((certfile = smime_extract_signer_certificate(tempfname)))
     {
       mutt_unlink(tempfname);
-      if (smime_check_cert_email (certfile, mbox))
+      if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL))
        mutt_any_key_to_continue(NULL);
       else
        retval = 0;
diff --git a/smime.h b/smime.h
index 11fa6cff808b7e39a979b6d4af47614e7b307b46..2f56e6d518b513b8432cf60ccfccce44c52a54c9 100644 (file)
--- a/smime.h
+++ b/smime.h
@@ -43,6 +43,7 @@ WHERE char *SmimeGetSignerCertCommand;
 WHERE char *SmimePk7outCommand;
 WHERE char *SmimeGetCertCommand;
 WHERE char *SmimeHashCertCommand;
+WHERE char *SmimeFingerprintCertCommand;
 WHERE char *SmimeGetCertEmailCommand;
 
 
index d2d7087e6b8e37dec0c95824c45d3fee640af2a3..aa7a707f595077f4228b1decef519e45d61e8c30 100755 (executable)
@@ -1,6 +1,6 @@
 #! /usr/bin/perl -w
 
-# Copyright (C) 2001 Oliver Ehli <elmy@acm.org>
+# Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
 # Copyright (C) 2001 Mike Schiraldi <raldi@research.netsol.com>
 #
 #     This program is free software; you can redistribute it and/or modify
@@ -107,8 +107,10 @@ elsif( @ARGV == 2 and $ARGV[0] eq "add_p12") {
     handle_pem(@pem);
 }
 elsif(@ARGV == 4 and $ARGV[0] eq "add_chain") {
+    my $mailbox;
     my $cmd = "openssl x509 -noout -hash -in $ARGV[2]";
     my $cert_hash = `$cmd`;
+
     $? and die "'$cmd' returned $?";
     
     $cmd = "openssl x509 -noout -hash -in $ARGV[3]";
@@ -121,9 +123,12 @@ elsif(@ARGV == 4 and $ARGV[0] eq "add_chain") {
     my $label = query_label;
     
     add_certificate($ARGV[3], \$issuer_hash, 0, $label); 
-    my $mailbox = &add_certificate($ARGV[2], \$cert_hash, 1, $label, $issuer_hash);
+    my @mailbox = &add_certificate($ARGV[2], \$cert_hash, 1, $label, $issuer_hash);
     
-    add_key($ARGV[1], $cert_hash, $mailbox, $label);
+    foreach $mailbox (@mailbox) {
+      chomp($mailbox);
+      add_key($ARGV[1], $cert_hash, $mailbox, $label);
+    }
 }
 elsif((@ARGV == 2 or @ARGV == 3) and $ARGV[0] eq "verify") {
     verify_cert($ARGV[1], $ARGV[2]);
@@ -264,8 +269,8 @@ sub list_certs () {
       print "$fields[1]: Issued for: $fields[0] \"$fields[2]\" $keyflags{$fields[4]}\n";
     }
 
-    (my $subject_in, my $email_in, my $issuer_in, my $date1_in, my $date2_in) =
-      `openssl x509 -subject -email -issuer -dates -noout -in $certificates_path/$fields[1]`;
+    (my $subject_in, my $issuer_in, my $date1_in, my $date2_in) =
+      `openssl x509 -subject -issuer -dates -noout -in $certificates_path/$fields[1]`;
 
     my @subject = split(/\//, $subject_in);
     while(@subject) {
@@ -379,6 +384,7 @@ sub add_certificate ($$$$;$) {
     my $issuer_hash = shift;
 
     my $iter = 0;
+    my @mailbox;
     my $mailbox;
 
     while(-e "$certificates_path/$$hashvalue.$iter") {
@@ -404,20 +410,22 @@ sub add_certificate ($$$$;$) {
 
         if ($add_to_index) {
            my $cmd = "openssl x509 -in $filename -email -noout";
-           $mailbox = `$cmd`;
+           @mailbox = `$cmd`;
            $? and die "'$cmd' returned $?";
 
-           chomp($mailbox);
-           add_entry($mailbox, $$hashvalue, 1, $label, $issuer_hash);
+           foreach $mailbox (@mailbox) {
+             chomp($mailbox);
+             add_entry($mailbox, $$hashvalue, 1, $label, $issuer_hash);
 
-            print "added certificate: $certificates_path/$$hashvalue for $mailbox.\n";
+             print "added certificate: $certificates_path/$$hashvalue for $mailbox.\n";
+           }
         }
         else {
             print "added certificate: $certificates_path/$$hashvalue.\n";
         }
     }
 
-    return $mailbox;
+    return @mailbox;
 }
 
 
@@ -430,10 +438,11 @@ sub add_key ($$$$) {
     unless (-e "$private_keys_path/$hashvalue") {
         my $cmd = "cp $file $private_keys_path/$hashvalue";
        system $cmd and die "$cmd returned $!";
-       print "added private key: " .
-             "$private_keys_path/$hashvalue for $mailbox\n";
-       add_entry($mailbox, $hashvalue, 0, $label, "");
     }    
+
+    add_entry($mailbox, $hashvalue, 0, $label, "");
+    print "added private key: " .
+      "$private_keys_path/$hashvalue for $mailbox\n";
 } 
 
 
@@ -514,6 +523,8 @@ sub handle_pem (@) {
     my $root_cert;
     my $key;
     my $certificate;
+    my $intermediate;
+    my @mailbox;
     my $mailbox;
 
     @pem_contents = &parse_pem(@_);
@@ -526,7 +537,7 @@ sub handle_pem (@) {
         }
         $iter++;
     }
-    ($key > $#pem_contents>>2) and die("Couldn't find private key!");
+    ($iter > $#pem_contents>>2) and die("Couldn't find private key!");
 
     $pem_contents[($key<<2)+1] or die("Attribute 'localKeyID' wasn't set.");
 
@@ -539,7 +550,7 @@ sub handle_pem (@) {
         }
         $iter++;
     }
-    ($certificate > $#pem_contents>>2) and die("Couldn't find matching certificate!");
+    ($iter > $#pem_contents>>2) and die("Couldn't find matching certificate!");
 
     my $cmd = "cp cert_tmp.$key tmp_key";
     system $cmd and die "'$cmd' returned $?";
@@ -562,13 +573,15 @@ sub handle_pem (@) {
         }
         $iter++;
     }
-    ($root_cert > $#pem_contents>>2) and die("Couldn't identify root certificate!");
+    ($iter > $#pem_contents>>2) and die("Couldn't identify root certificate!");
 
     # what's left are intermediate certificates.
     $iter = 0;
 
     unlink "tmp_issuer_cert";
 
+    # needs to be set, so we can check it later
+    $intermediate = $root_cert;
     while($iter <= $#pem_contents>>2) {
         if ($iter == $key or $iter == $certificate or $iter == $root_cert) {
             $iter++; 
@@ -578,9 +591,17 @@ sub handle_pem (@) {
         my $cmd = "cat cert_tmp.$iter >> tmp_issuer_cert";
         system $cmd and die "'$cmd' returned $?";
 
+       # although there may be many, just need to know if there was any
+       $intermediate = $iter;
+
         $iter++;
     }
 
+    # no intermediate certificates ? use root-cert instead
+    if($intermediate == $root_cert) {
+      $cmd = "cp cert_tmp.$root_cert tmp_issuer_cert";
+    }
+
     my $label = query_label;
 
     $cmd = "openssl x509 -noout -hash -in tmp_certificate";
@@ -596,8 +617,11 @@ sub handle_pem (@) {
     # Note: $cert_hash will be changed to reflect the correct filename
     #       within add_cert() ONLY, so these _have_ to get called first..
     add_certificate("tmp_issuer_cert", \$issuer_hash, 0, $label);
-    $mailbox = &add_certificate("tmp_certificate", \$cert_hash, 1, $label, $issuer_hash); 
-    add_key("tmp_key", $cert_hash, $mailbox, $label);
+    @mailbox = &add_certificate("tmp_certificate", \$cert_hash, 1, $label, $issuer_hash); 
+    foreach $mailbox (@mailbox) {
+      chomp($mailbox);
+      add_key("tmp_key", $cert_hash, $mailbox, $label);
+    }
     
     unlink <cert_tmp.*>;
     unlink <tmp_*>;