/*
- * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2008-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
OPT_DECRYPT, OPT_SIGN, OPT_CADES, OPT_SIGN_RECEIPT, OPT_RESIGN,
OPT_VERIFY, OPT_VERIFY_RETCODE, OPT_VERIFY_RECEIPT,
OPT_CMSOUT, OPT_DATA_OUT, OPT_DATA_CREATE, OPT_DIGEST_VERIFY,
- OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS,
+ OPT_DIGEST, OPT_DIGEST_CREATE, OPT_COMPRESS, OPT_UNCOMPRESS,
OPT_ED_DECRYPT, OPT_ED_ENCRYPT, OPT_DEBUG_DECRYPT, OPT_TEXT,
OPT_ASCIICRLF, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCERTS,
OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP, OPT_BINARY, OPT_KEYID,
"Generate a signed receipt for a message"},
{"verify_receipt", OPT_VERIFY_RECEIPT, '<',
"Verify receipts; exit if receipt signatures do not verify"},
+ {"digest", OPT_DIGEST, 's', "Sign a pre-computed digest in hex notation"},
{"digest_create", OPT_DIGEST_CREATE, '-',
"Create a CMS \"DigestedData\" object"},
{"digest_verify", OPT_DIGEST_VERIFY, '-',
return NULL;
}
-static void warn_binary(const char *file)
-{
- BIO *bio;
- unsigned char linebuf[1024], *cur, *end;
- int len;
-
- if ((bio = bio_open_default(file, 'r', FORMAT_BINARY)) == NULL)
- return; /* cannot give a proper warning since there is an error */
- while ((len = BIO_read(bio, linebuf, sizeof(linebuf))) > 0) {
- end = linebuf + len;
- for (cur = linebuf; cur < end; cur++) {
- if (*cur == '\0' || *cur >= 0x80) {
- BIO_printf(bio_err, "Warning: input file '%s' contains %s"
- " character; better use -binary option\n",
- file, *cur == '\0' ? "NUL" : "8-bit");
- goto end;
- }
- }
- }
- end:
- BIO_free(bio);
-}
-
int cms_main(int argc, char **argv)
{
CONF *conf = NULL;
const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL;
char *certsoutfile = NULL, *digestname = NULL, *wrapname = NULL;
int noCAfile = 0, noCApath = 0, noCAstore = 0;
+ char *digesthex = NULL;
+ unsigned char *digestbin = NULL;
+ long digestlen = 0;
char *infile = NULL, *outfile = NULL, *rctfile = NULL;
char *passinarg = NULL, *passin = NULL, *signerfile = NULL;
char *originatorfile = NULL, *recipfile = NULL, *ciphername = NULL;
if (encerts == NULL || vpm == NULL)
goto end;
+ opt_set_unknown_name("cipher");
prog = opt_init(argc, argv, cms_options);
while ((o = opt_next()) != OPT_EOF) {
switch (o) {
case OPT_DIGEST_CREATE:
operation = SMIME_DIGEST_CREATE;
break;
+ case OPT_DIGEST:
+ digesthex = opt_arg();
+ break;
case OPT_DIGEST_VERIFY:
operation = SMIME_DIGEST_VERIFY;
break;
rr_allorfirst = 1;
break;
case OPT_RCTFORM:
- if (rctformat == FORMAT_ASN1) {
- if (!opt_format(opt_arg(),
- OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat))
- goto opthelp;
- } else {
- rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient");
- }
+ if (!opt_format(opt_arg(),
+ OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat))
+ goto opthelp;
break;
case OPT_CERTFILE:
certfile = opt_arg();
goto end;
break;
case OPT_WRAP:
- wrapname = opt_unknown();
+ wrapname = opt_arg();
break;
case OPT_AES128_WRAP:
case OPT_AES192_WRAP:
if (!opt_md(digestname, &sign_md))
goto end;
}
- if (ciphername != NULL) {
- if (!opt_cipher_any(ciphername, &cipher))
- goto end;
- }
+ if (!opt_cipher_any(ciphername, &cipher))
+ goto end;
if (wrapname != NULL) {
if (!opt_cipher_any(wrapname, &wrap_cipher))
goto end;
goto end;
}
- if ((flags & CMS_BINARY) == 0)
- warn_binary(infile);
- in = bio_open_default(infile, 'r',
- binary_files ? FORMAT_BINARY : informat);
- if (in == NULL)
- goto end;
+ if (digesthex != NULL) {
+ if (operation != SMIME_SIGN) {
+ BIO_printf(bio_err,
+ "Cannot use -digest for non-signing operation\n");
+ goto end;
+ }
+ if (infile != NULL
+ || (flags & CMS_DETACHED) == 0
+ || (flags & CMS_STREAM) != 0) {
+ BIO_printf(bio_err,
+ "Cannot use -digest when -in, -nodetach or streaming is used\n");
+ goto end;
+ }
+ digestbin = OPENSSL_hexstr2buf(digesthex, &digestlen);
+ if (digestbin == NULL) {
+ BIO_printf(bio_err,
+ "Invalid hex value after -digest\n");
+ goto end;
+ }
+ } else {
+ in = bio_open_default(infile, 'r',
+ binary_files ? FORMAT_BINARY : informat);
+ if (in == NULL)
+ goto end;
+ }
if (operation & SMIME_IP) {
cms = load_content_info(informat, in, flags, &indata, "SMIME");
goto end;
if (contfile != NULL) {
BIO_free(indata);
- if ((flags & CMS_BINARY) == 0)
- warn_binary(contfile);
if ((indata = BIO_new_file(contfile, "rb")) == NULL) {
BIO_printf(bio_err, "Can't read content file %s\n", contfile);
goto end;
ret = 5;
goto end;
}
- sk_X509_pop_free(allcerts, X509_free);
+ OSSL_STACK_OF_X509_free(allcerts);
}
}
goto end;
}
- rcms = load_content_info(rctformat, rctin, 0, NULL, "recipient");
+ rcms = load_content_info(rctformat, rctin, 0, NULL, "receipt");
if (rcms == NULL)
goto end;
}
} else if (operation & SMIME_SIGNERS) {
int i;
/*
- * If detached data content we enable streaming if S/MIME output
- * format.
+ * If detached data content and not signing pre-computed digest, we
+ * enable streaming if S/MIME output format.
*/
if (operation == SMIME_SIGN) {
- if (flags & CMS_DETACHED) {
+ if ((flags & CMS_DETACHED) != 0 && digestbin == NULL) {
if (outformat == FORMAT_SMIME)
flags |= CMS_STREAM;
}
key = NULL;
}
/* If not streaming or resigning finalize structure */
- if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) {
+ if (operation == SMIME_SIGN && digestbin != NULL
+ && (flags & CMS_STREAM) == 0) {
+ /* Use pre-computed digest instead of content */
+ if (!CMS_final_digest(cms, digestbin, digestlen, NULL, flags))
+ goto end;
+ } else if (operation == SMIME_SIGN && (flags & CMS_STREAM) == 0) {
if (!CMS_final(cms, in, NULL, flags))
goto end;
}
end:
if (ret)
ERR_print_errors(bio_err);
- sk_X509_pop_free(encerts, X509_free);
- sk_X509_pop_free(other, X509_free);
+ OSSL_STACK_OF_X509_free(encerts);
+ OSSL_STACK_OF_X509_free(other);
X509_VERIFY_PARAM_free(vpm);
sk_OPENSSL_STRING_free(sksigners);
sk_OPENSSL_STRING_free(skkeys);
BIO_free(in);
BIO_free(indata);
BIO_free_all(out);
+ OPENSSL_free(digestbin);
OPENSSL_free(passin);
NCONF_free(conf);
return ret;