Add -resign and -md options to smime command to support resigning an
authorDr. Stephen Henson <steve@openssl.org>
Thu, 18 May 2006 23:44:44 +0000 (23:44 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 18 May 2006 23:44:44 +0000 (23:44 +0000)
existing structure and using alternative digest for signing.

CHANGES
apps/smime.c
crypto/pkcs7/pk7_doit.c
crypto/pkcs7/pk7_mime.c
crypto/pkcs7/pk7_smime.c
crypto/pkcs7/pkcs7.h
crypto/pkcs7/pkcs7err.c

diff --git a/CHANGES b/CHANGES
index 13a42b5..cb5f161 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 0.9.8b and 0.9.9  [xx XXX xxxx]
 
+  *) New -resign option to smime utility. This adds one or more signers
+     to an existing PKCS#7 signedData structure. Also -md option to use an
+     alternative message digest algorithm for signing.
+     [Steve Henson]
+
   *) Tidy up PKCS#7 routines and add new functions to make it easier to
      create PKCS7 structures containing multiple signers. Update smime
      application to support multiple signers.
index dc28ced..7b788cb 100644 (file)
@@ -73,11 +73,14 @@ static int save_certs(char *signerfile, STACK_OF(X509) *signers);
 static int smime_cb(int ok, X509_STORE_CTX *ctx);
 
 #define SMIME_OP       0x10
+#define SMIME_IP       0x20
+#define SMIME_SIGNERS  0x40
 #define SMIME_ENCRYPT  (1 | SMIME_OP)
-#define SMIME_DECRYPT  2
-#define SMIME_SIGN     (3 | SMIME_OP)
-#define SMIME_VERIFY   4
-#define SMIME_PK7OUT   5
+#define SMIME_DECRYPT  (2 | SMIME_IP)
+#define SMIME_SIGN     (3 | SMIME_OP | SMIME_SIGNERS)
+#define SMIME_VERIFY   (4 | SMIME_IP)
+#define SMIME_PK7OUT   (5 | SMIME_OP)
+#define SMIME_RESIGN   (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
 
 int MAIN(int, char **);
 
@@ -106,6 +109,7 @@ int MAIN(int argc, char **argv)
        char *passargin = NULL, *passin = NULL;
        char *inrand = NULL;
        int need_rand = 0;
+       const EVP_MD *sign_md = NULL;
        int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
         int keyform = FORMAT_PEM;
 #ifndef OPENSSL_NO_ENGINE
@@ -136,6 +140,8 @@ int MAIN(int argc, char **argv)
                        operation = SMIME_DECRYPT;
                else if (!strcmp (*args, "-sign"))
                        operation = SMIME_SIGN;
+               else if (!strcmp (*args, "-resign"))
+                       operation = SMIME_RESIGN;
                else if (!strcmp (*args, "-verify"))
                        operation = SMIME_VERIFY;
                else if (!strcmp (*args, "-pk7out"))
@@ -252,6 +258,18 @@ int MAIN(int argc, char **argv)
                                goto argerr;
                        recipfile = *++args;
                        }
+               else if (!strcmp (*args, "-md"))
+                       {
+                       if (!args[1])
+                               goto argerr;
+                       sign_md = EVP_get_digestbyname(*++args);
+                       if (sign_md == NULL)
+                               {
+                               BIO_printf(bio_err, "Unknown digest %s\n",
+                                                       *args);
+                               goto argerr;
+                               }
+                       }
                else if (!strcmp (*args, "-inkey"))
                        {
                        if (!args[1])   
@@ -335,13 +353,13 @@ int MAIN(int argc, char **argv)
                args++;
                }
 
-       if ((operation != SMIME_SIGN) && (skkeys || sksigners))
+       if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners))
                {
                BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
                goto argerr;
                }
 
-       if (operation == SMIME_SIGN)
+       if (operation & SMIME_SIGNERS)
                {
                /* Check to see if any final signer needs to be appended */
                if (keyfile && !signerfile)
@@ -468,13 +486,11 @@ int MAIN(int argc, char **argv)
 
        ret = 2;
 
-       if (operation != SMIME_SIGN)
+       if (!(operation & SMIME_SIGNERS))
                flags &= ~PKCS7_DETACHED;
 
        if (operation & SMIME_OP)
                {
-               if (flags & PKCS7_BINARY)
-                       inmode = "rb";
                if (outformat == FORMAT_ASN1)
                        outmode = "wb";
                }
@@ -482,9 +498,18 @@ int MAIN(int argc, char **argv)
                {
                if (flags & PKCS7_BINARY)
                        outmode = "wb";
+               }
+
+       if (operation & SMIME_IP)
+               {
                if (informat == FORMAT_ASN1)
                        inmode = "rb";
                }
+       else
+               {
+               if (flags & PKCS7_BINARY)
+                       inmode = "rb";
+               }
 
        if (operation == SMIME_ENCRYPT)
                {
@@ -514,26 +539,11 @@ int MAIN(int argc, char **argv)
                        }
                }
 
-       if (signerfile && (operation == SMIME_SIGN))
-               {
-               if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM, NULL,
-                       e, "signer certificate")))
-                       {
-#if 0                  /* An appropri message has already been printed */
-                       BIO_printf(bio_err, "Can't read signer certificate file %s\n", signerfile);
-#endif
-                       goto end;
-                       }
-               }
-
        if (certfile)
                {
                if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL,
                        e, "certificate file")))
                        {
-#if 0                  /* An appropriate message has already been printed */
-                       BIO_printf(bio_err, "Can't read certificate file %s\n", certfile);
-#endif
                        ERR_print_errors(bio_err);
                        goto end;
                        }
@@ -544,9 +554,6 @@ int MAIN(int argc, char **argv)
                if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL,
                        e, "recipient certificate file")))
                        {
-#if 0                  /* An appropriate message has alrady been printed */
-                       BIO_printf(bio_err, "Can't read recipient certificate file %s\n", recipfile);
-#endif
                        ERR_print_errors(bio_err);
                        goto end;
                        }
@@ -584,6 +591,36 @@ int MAIN(int argc, char **argv)
        else
                in = BIO_new_fp(stdin, BIO_NOCLOSE);
 
+       if (operation & SMIME_IP)
+               {
+               if (informat == FORMAT_SMIME) 
+                       p7 = SMIME_read_PKCS7(in, &indata);
+               else if (informat == FORMAT_PEM) 
+                       p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
+               else if (informat == FORMAT_ASN1) 
+                       p7 = d2i_PKCS7_bio(in, NULL);
+               else
+                       {
+                       BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
+                       goto end;
+                       }
+
+               if (!p7)
+                       {
+                       BIO_printf(bio_err, "Error reading S/MIME message\n");
+                       goto end;
+                       }
+               if (contfile)
+                       {
+                       BIO_free(indata);
+                       if (!(indata = BIO_new_file(contfile, "rb")))
+                               {
+                               BIO_printf(bio_err, "Can't read content file %s\n", contfile);
+                               goto end;
+                               }
+                       }
+               }
+
        if (outfile)
                {
                if (!(out = BIO_new_file(outfile, outmode)))
@@ -618,16 +655,22 @@ int MAIN(int argc, char **argv)
 
        if (operation == SMIME_ENCRYPT)
                p7 = PKCS7_encrypt(encerts, in, cipher, flags);
-       else if (operation == SMIME_SIGN)
+       else if (operation & SMIME_SIGNERS)
                {
                int i;
                /* If detached data and SMIME output enable partial
                 * signing.
                 */
-               if ((flags & PKCS7_DETACHED) && (outformat == FORMAT_SMIME))
-                       flags |= PKCS7_STREAM;
-               flags |= PKCS7_PARTIAL;
-               p7 = PKCS7_sign(NULL, NULL, other, in, flags);
+               if (operation == SMIME_SIGN)
+                       {
+                       if ((flags & PKCS7_DETACHED)
+                               && (outformat == FORMAT_SMIME))
+                               flags |= PKCS7_STREAM;
+                       flags |= PKCS7_PARTIAL;
+                       p7 = PKCS7_sign(NULL, NULL, other, in, flags);
+                       }
+               else
+                       flags |= PKCS7_REUSE_DIGEST;
                for (i = 0; i < sk_num(sksigners); i++)
                        {
                        signerfile = sk_value(sksigners, i);
@@ -641,15 +684,15 @@ int MAIN(int argc, char **argv)
                        if (!key)
                                goto end;
                        if (!PKCS7_sign_add_signer(p7, signer, key,
-                                               NULL, flags))
+                                               sign_md, flags))
                                goto end;
                        X509_free(signer);
                        signer = NULL;
                        EVP_PKEY_free(key);
                        key = NULL;
                        }
-               /* If not streaming finalize structure */
-               if (!(flags & PKCS7_STREAM))
+               /* If not streaming or resigning finalize structure */
+               if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM))
                        {
                        if (!PKCS7_final(p7, in, flags))
                                goto end;
@@ -660,35 +703,6 @@ int MAIN(int argc, char **argv)
                                }
                        }
                }
-       else
-               {
-               if (informat == FORMAT_SMIME) 
-                       p7 = SMIME_read_PKCS7(in, &indata);
-               else if (informat == FORMAT_PEM) 
-                       p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
-               else if (informat == FORMAT_ASN1) 
-                       p7 = d2i_PKCS7_bio(in, NULL);
-               else
-                       {
-                       BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
-                       goto end;
-                       }
-
-               if (!p7)
-                       {
-                       BIO_printf(bio_err, "Error reading S/MIME message\n");
-                       goto end;
-                       }
-               if (contfile)
-                       {
-                       BIO_free(indata);
-                       if (!(indata = BIO_new_file(contfile, "rb")))
-                               {
-                               BIO_printf(bio_err, "Can't read content file %s\n", contfile);
-                               goto end;
-                               }
-                       }
-               }
 
        if (!p7)
                {
@@ -736,7 +750,12 @@ int MAIN(int argc, char **argv)
                if (subject)
                        BIO_printf(out, "Subject: %s\n", subject);
                if (outformat == FORMAT_SMIME) 
-                       SMIME_write_PKCS7(out, p7, in, flags);
+                       {
+                       if (operation == SMIME_RESIGN)
+                               SMIME_write_PKCS7(out, p7, indata, flags);
+                       else
+                               SMIME_write_PKCS7(out, p7, in, flags);
+                       }
                else if (outformat == FORMAT_PEM) 
                        PEM_write_bio_PKCS7(out,p7);
                else if (outformat == FORMAT_ASN1) 
index 0b441fe..157cf19 100644 (file)
@@ -854,7 +854,6 @@ int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
        EVP_MD_CTX_cleanup(&mctx);
 
        ASN1_STRING_set0(si->enc_digest, abuf, siglen);
-       abuf = NULL;
 
        return 1;
 
index 134746c..c0edb07 100644 (file)
@@ -204,7 +204,7 @@ int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags)
                msg_type = "enveloped-data";
        else if (PKCS7_type_is_signed(p7))
                {
-               /* If we have any signers it is signed-data othewise 
+               /* If we have any signers it is signed-data otherwise 
                 * certs-only.
                 */
                STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
index e09fb38..28ec531 100644 (file)
@@ -63,6 +63,8 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
+static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
+
 PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
                  BIO *data, int flags)
 {
@@ -198,6 +200,14 @@ PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
                                || !PKCS7_add_attrib_smimecap (si, smcap))
                                goto err;
                        sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
+                       smcap = NULL;
+                       }
+               if (flags & PKCS7_REUSE_DIGEST)
+                       {
+                       if (!pkcs7_copy_existing_digest(p7, si))
+                               goto err;
+                       if (!PKCS7_SIGNER_INFO_sign(si))
+                               goto err;
                        }
                }
        return si;
@@ -209,6 +219,41 @@ PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
        return NULL;
        }
 
+/* Search for a digest matching SignerInfo digest type and if found
+ * copy across.
+ */
+
+static int pkcs7_copy_existing_digest(PKCS7 *p7, PKCS7_SIGNER_INFO *si)
+       {
+       int i;
+       STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
+       PKCS7_SIGNER_INFO *sitmp;
+       ASN1_OCTET_STRING *osdig = NULL;
+       sinfos = PKCS7_get_signer_info(p7);
+       for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++)
+               {
+               sitmp = sk_PKCS7_SIGNER_INFO_value(sinfos, i);
+               if (si == sitmp)
+                       break;
+               if (sk_X509_ATTRIBUTE_num(sitmp->auth_attr) <= 0)
+                       continue;
+               if (!OBJ_cmp(si->digest_alg->algorithm,
+                               sitmp->digest_alg->algorithm))
+                       {
+                       osdig = PKCS7_digest_from_attributes(sitmp->auth_attr);
+                       break;
+                       }
+
+               }
+
+       if (osdig)
+               return PKCS7_add1_attrib_digest(si, osdig->data, osdig->length);
+
+       PKCS7err(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST,
+                       PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND);
+       return 0;
+       }
+
 int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
                                        BIO *indata, BIO *out, int flags)
 {
index 7d31b68..581dfb1 100644 (file)
@@ -270,6 +270,7 @@ DECLARE_PKCS12_STACK_OF(PKCS7)
 #define PKCS7_STREAM           0x1000
 #define PKCS7_NOCRL            0x2000
 #define PKCS7_PARTIAL          0x4000
+#define PKCS7_REUSE_DIGEST     0x8000
 
 /* Flags: for compatibility with older code */
 
@@ -412,6 +413,7 @@ void ERR_load_PKCS7_strings(void);
 #define PKCS7_F_PKCS7_ADD_SIGNATURE                     131
 #define PKCS7_F_PKCS7_ADD_SIGNER                        103
 #define PKCS7_F_PKCS7_BIO_ADD_DIGEST                    125
+#define PKCS7_F_PKCS7_COPY_EXISTING_DIGEST              138
 #define PKCS7_F_PKCS7_CTRL                              104
 #define PKCS7_F_PKCS7_DATADECODE                        112
 #define PKCS7_F_PKCS7_DATAFINAL                                 128
@@ -462,6 +464,7 @@ void ERR_load_PKCS7_strings(void);
 #define PKCS7_R_NO_CONTENT                              122
 #define PKCS7_R_NO_CONTENT_TYPE                                 135
 #define PKCS7_R_NO_DEFAULT_DIGEST                       151
+#define PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND           154
 #define PKCS7_R_NO_MULTIPART_BODY_FAILURE               136
 #define PKCS7_R_NO_MULTIPART_BOUNDARY                   137
 #define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE        115
index 9b2bec9..e1e9add 100644 (file)
@@ -81,6 +81,7 @@ static ERR_STRING_DATA PKCS7_str_functs[]=
 {ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNATURE),        "PKCS7_add_signature"},
 {ERR_FUNC(PKCS7_F_PKCS7_ADD_SIGNER),   "PKCS7_add_signer"},
 {ERR_FUNC(PKCS7_F_PKCS7_BIO_ADD_DIGEST),       "PKCS7_BIO_ADD_DIGEST"},
+{ERR_FUNC(PKCS7_F_PKCS7_COPY_EXISTING_DIGEST), "PKCS7_COPY_EXISTING_DIGEST"},
 {ERR_FUNC(PKCS7_F_PKCS7_CTRL), "PKCS7_CTRL"},
 {ERR_FUNC(PKCS7_F_PKCS7_DATADECODE),   "PKCS7_dataDecode"},
 {ERR_FUNC(PKCS7_F_PKCS7_DATAFINAL),    "PKCS7_dataFinal"},
@@ -134,6 +135,7 @@ static ERR_STRING_DATA PKCS7_str_reasons[]=
 {ERR_REASON(PKCS7_R_NO_CONTENT)          ,"no content"},
 {ERR_REASON(PKCS7_R_NO_CONTENT_TYPE)     ,"no content type"},
 {ERR_REASON(PKCS7_R_NO_DEFAULT_DIGEST)   ,"no default digest"},
+{ERR_REASON(PKCS7_R_NO_MATCHING_DIGEST_TYPE_FOUND),"no matching digest type found"},
 {ERR_REASON(PKCS7_R_NO_MULTIPART_BODY_FAILURE),"no multipart body failure"},
 {ERR_REASON(PKCS7_R_NO_MULTIPART_BOUNDARY),"no multipart boundary"},
 {ERR_REASON(PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE),"no recipient matches certificate"},