Add -resign and -md options to smime command to support resigning an
existing structure and using alternative digest for signing.
This commit is contained in:
parent
a620626a33
commit
5531192151
5
CHANGES
5
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.
|
||||
|
149
apps/smime.c
149
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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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"},
|
||||
|
Loading…
x
Reference in New Issue
Block a user