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 **);
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
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"))
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])
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)
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";
}
{
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)
{
}
}
- 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;
}
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;
}
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)))
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);
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;
}
}
}
- 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)
{
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)
#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)
{
|| !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;
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)
{