Переглянути джерело

Add -resign and -md options to smime command to support resigning an
existing structure and using alternative digest for signing.

Dr. Stephen Henson 18 роки тому
батько
коміт
5531192151
7 змінених файлів з 140 додано та 67 видалено
  1. 5 0
      CHANGES
  2. 84 65
      apps/smime.c
  3. 0 1
      crypto/pkcs7/pk7_doit.c
  4. 1 1
      crypto/pkcs7/pk7_mime.c
  5. 45 0
      crypto/pkcs7/pk7_smime.c
  6. 3 0
      crypto/pkcs7/pkcs7.h
  7. 2 0
      crypto/pkcs7/pkcs7err.c

+ 5 - 0
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.

+ 84 - 65
apps/smime.c

@@ -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) 

+ 0 - 1
crypto/pkcs7/pk7_doit.c

@@ -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;
 

+ 1 - 1
crypto/pkcs7/pk7_mime.c

@@ -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;

+ 45 - 0
crypto/pkcs7/pk7_smime.c

@@ -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)
 {

+ 3 - 0
crypto/pkcs7/pkcs7.h

@@ -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

+ 2 - 0
crypto/pkcs7/pkcs7err.c

@@ -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"},