X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Fcms.c;h=76c7896719376f106754b15565a0014b92959dff;hp=18671fdc308e843747b31917aae0b90ed85e288d;hb=HEAD;hpb=d9f073575fdb07b486cd1b38974cd177687ccc1e diff --git a/apps/cms.c b/apps/cms.c index 18671fdc30..f93c98ac92 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2008-2023 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 @@ -66,7 +66,7 @@ typedef enum OPTION_choice { 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, @@ -106,6 +106,7 @@ const OPTIONS cms_options[] = { "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, '-', @@ -293,6 +294,9 @@ int cms_main(int argc, char **argv) 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; @@ -314,6 +318,7 @@ int cms_main(int argc, char **argv) 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) { @@ -366,6 +371,9 @@ int cms_main(int argc, char **argv) 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; @@ -620,7 +628,8 @@ int cms_main(int argc, char **argv) "recipient certificate file"); if (cert == NULL) goto end; - sk_X509_push(encerts, cert); + if (!sk_X509_push(encerts, cert)) + goto end; cert = NULL; } else { recipfile = opt_arg(); @@ -794,6 +803,9 @@ int cms_main(int argc, char **argv) if ((operation & SMIME_IP) == 0 && contfile != NULL) BIO_printf(bio_err, "Warning: -contfile option is ignored for the given operation\n"); + if (operation != SMIME_ENCRYPT && *argv != NULL) + BIO_printf(bio_err, + "Warning: recipient certificate file parameters ignored for operation other than -encrypt\n"); if ((flags & CMS_BINARY) != 0) { if (!(operation & SMIME_OP)) @@ -821,19 +833,14 @@ int cms_main(int argc, char **argv) goto end; } - if (*argv != NULL) { - if (operation == SMIME_ENCRYPT) { - for (; *argv != NULL; argv++) { - cert = load_cert(*argv, FORMAT_UNDEF, - "recipient certificate file"); - if (cert == NULL) - goto end; - sk_X509_push(encerts, cert); - cert = NULL; - } - } else { - BIO_printf(bio_err, "Warning: recipient certificate file parameters ignored for operation other than -encrypt\n"); - } + for (; *argv != NULL; argv++) { + cert = load_cert(*argv, FORMAT_UNDEF, + "recipient certificate file"); + if (cert == NULL) + goto end; + if (!sk_X509_push(encerts, cert)) + goto end; + cert = NULL; } } @@ -884,10 +891,31 @@ int cms_main(int argc, char **argv) goto end; } - 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"); @@ -909,7 +937,7 @@ int cms_main(int argc, char **argv) ret = 5; goto end; } - sk_X509_pop_free(allcerts, X509_free); + OSSL_STACK_OF_X509_free(allcerts); } } @@ -988,7 +1016,8 @@ int cms_main(int argc, char **argv) && wrap_cipher != NULL) { EVP_CIPHER_CTX *wctx; wctx = CMS_RecipientInfo_kari_get0_ctx(ri); - EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL); + if (EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL) != 1) + goto end; } } @@ -1036,12 +1065,12 @@ int cms_main(int argc, char **argv) } 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; } @@ -1102,7 +1131,12 @@ int cms_main(int argc, char **argv) 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; } @@ -1237,8 +1271,8 @@ int cms_main(int argc, char **argv) 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); @@ -1271,6 +1305,7 @@ int cms_main(int argc, char **argv) BIO_free(in); BIO_free(indata); BIO_free_all(out); + OPENSSL_free(digestbin); OPENSSL_free(passin); NCONF_free(conf); return ret; @@ -1414,6 +1449,7 @@ static CMS_ReceiptRequest STACK_OF(OPENSSL_STRING) *rr_from) { STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL; + CMS_ReceiptRequest *rr; rct_to = make_names_stack(rr_to); if (rct_to == NULL) @@ -1425,10 +1461,14 @@ static CMS_ReceiptRequest } else { rct_from = NULL; } - return CMS_ReceiptRequest_create0_ex(NULL, -1, rr_allorfirst, rct_from, - rct_to, app_get0_libctx()); + rr = CMS_ReceiptRequest_create0_ex(NULL, -1, rr_allorfirst, rct_from, + rct_to, app_get0_libctx()); + if (rr == NULL) + goto err; + return rr; err: sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free); + sk_GENERAL_NAMES_pop_free(rct_from, GENERAL_NAMES_free); return NULL; }