X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=apps%2Fcms.c;h=30dd296bc022ecb3d9a8ab54b68f2796da7e499f;hp=b757908070851d197fe90735525c9b8f7bb45f06;hb=d5a37b029357b8ed8595f5cefc6654ac15302ae8;hpb=4f1aa191b33f0bbda29c3289d50fee2991b77df0 diff --git a/apps/cms.c b/apps/cms.c index b757908070..30dd296bc0 100644 --- a/apps/cms.c +++ b/apps/cms.c @@ -70,6 +70,9 @@ #define PROG cms_main static int save_certs(char *signerfile, STACK_OF(X509) *signers); static int smime_cb(int ok, X509_STORE_CTX *ctx); +static void receipt_request_print(BIO *out, CMS_ContentInfo *cms); +static CMS_ReceiptRequest *make_receipt_request(STACK *rr_to, int rr_allorfirst, + STACK *rr_from); #define SMIME_OP 0x10 #define SMIME_IP 0x20 @@ -88,6 +91,8 @@ static int smime_cb(int ok, X509_STORE_CTX *ctx); #define SMIME_COMPRESS (12 | SMIME_OP) #define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) #define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP) +#define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP) +#define SMIME_VERIFY_RECEIPT (16 | SMIME_IP) int MAIN(int, char **); @@ -98,33 +103,37 @@ int MAIN(int argc, char **argv) int ret = 0; char **args; const char *inmode = "r", *outmode = "w"; - char *infile = NULL, *outfile = NULL; + char *infile = NULL, *outfile = NULL, *rctfile = NULL; char *signerfile = NULL, *recipfile = NULL; STACK *sksigners = NULL, *skkeys = NULL; char *certfile = NULL, *keyfile = NULL, *contfile=NULL; const EVP_CIPHER *cipher = NULL; - CMS_ContentInfo *cms = NULL; + CMS_ContentInfo *cms = NULL, *rcms = NULL; X509_STORE *store = NULL; X509 *cert = NULL, *recip = NULL, *signer = NULL; EVP_PKEY *key = NULL; STACK_OF(X509) *encerts = NULL, *other = NULL; - BIO *in = NULL, *out = NULL, *indata = NULL; + BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL; int badarg = 0; - int flags = CMS_DETACHED; + int flags = CMS_DETACHED, noout = 0, print = 0; + int rr_print = 0, rr_allorfirst = -1; + STACK *rr_to = NULL, *rr_from = NULL; + CMS_ReceiptRequest *rr = NULL; char *to = NULL, *from = NULL, *subject = NULL; char *CAfile = NULL, *CApath = NULL; char *passargin = NULL, *passin = NULL; char *inrand = NULL; int need_rand = 0; - int indef = 0; const EVP_MD *sign_md = NULL; int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; - int keyform = FORMAT_PEM; + int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; #ifndef OPENSSL_NO_ENGINE char *engine=NULL; #endif - unsigned char *secret_key = NULL; - size_t secret_keylen; + unsigned char *secret_key = NULL, *secret_keyid = NULL; + size_t secret_keylen = 0, secret_keyidlen = 0; + + ASN1_OBJECT *econtent_type = NULL; X509_VERIFY_PARAM *vpm = NULL; @@ -150,10 +159,20 @@ int MAIN(int argc, char **argv) operation = SMIME_DECRYPT; else if (!strcmp (*args, "-sign")) operation = SMIME_SIGN; + else if (!strcmp (*args, "-sign_receipt")) + operation = SMIME_SIGN_RECEIPT; else if (!strcmp (*args, "-resign")) operation = SMIME_RESIGN; else if (!strcmp (*args, "-verify")) operation = SMIME_VERIFY; + else if (!strcmp(*args,"-verify_receipt")) + { + operation = SMIME_VERIFY_RECEIPT; + if (!args[1]) + goto argerr; + args++; + rctfile = *args; + } else if (!strcmp (*args, "-cmsout")) operation = SMIME_CMSOUT; else if (!strcmp (*args, "-data_out")) @@ -232,15 +251,46 @@ int MAIN(int argc, char **argv) else if (!strcmp (*args, "-no_attr_verify")) flags |= CMS_NO_ATTR_VERIFY; else if (!strcmp (*args, "-stream")) - indef = 1; + flags |= CMS_STREAM; else if (!strcmp (*args, "-indef")) - indef = 1; + flags |= CMS_STREAM; else if (!strcmp (*args, "-noindef")) - indef = 0; + flags &= ~CMS_STREAM; else if (!strcmp (*args, "-nooldmime")) flags |= CMS_NOOLDMIMETYPE; else if (!strcmp (*args, "-crlfeol")) flags |= CMS_CRLFEOL; + else if (!strcmp (*args, "-noout")) + noout = 1; + else if (!strcmp (*args, "-receipt_request_print")) + rr_print = 1; + else if (!strcmp (*args, "-receipt_request_all")) + rr_allorfirst = 0; + else if (!strcmp (*args, "-receipt_request_first")) + rr_allorfirst = 1; + else if (!strcmp(*args,"-receipt_request_from")) + { + if (!args[1]) + goto argerr; + args++; + if (!rr_from) + rr_from = sk_new_null(); + sk_push(rr_from, *args); + } + else if (!strcmp(*args,"-receipt_request_to")) + { + if (!args[1]) + goto argerr; + args++; + if (!rr_to) + rr_to = sk_new_null(); + sk_push(rr_to, *args); + } + else if (!strcmp (*args, "-print")) + { + noout = 1; + print = 1; + } else if (!strcmp(*args,"-secretkey")) { long ltmp; @@ -255,6 +305,32 @@ int MAIN(int argc, char **argv) } secret_keylen = (size_t)ltmp; } + else if (!strcmp(*args,"-secretkeyid")) + { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_keyid = string_to_hex(*args, <mp); + if (!secret_keyid) + { + BIO_printf(bio_err, "Invalid id %s\n", *args); + goto argerr; + } + secret_keyidlen = (size_t)ltmp; + } + else if (!strcmp(*args,"-econtent_type")) + { + if (!args[1]) + goto argerr; + args++; + econtent_type = OBJ_txt2obj(*args, 0); + if (!econtent_type) + { + BIO_printf(bio_err, "Invalid OID %s\n", *args); + goto argerr; + } + } else if (!strcmp(*args,"-rand")) { if (!args[1]) @@ -361,6 +437,12 @@ int MAIN(int argc, char **argv) goto argerr; keyform = str2fmt(*++args); } + else if (!strcmp (*args, "-rctform")) + { + if (!args[1]) + goto argerr; + rctformat = str2fmt(*++args); + } else if (!strcmp (*args, "-certfile")) { if (!args[1]) @@ -416,6 +498,17 @@ int MAIN(int argc, char **argv) args++; } + if (((rr_allorfirst != -1) || rr_from) && !rr_to) + { + BIO_puts(bio_err, "No Signed Receipts Recipients\n"); + goto argerr; + } + + if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) + { + BIO_puts(bio_err, "Signed receipts only allowed with -sign\n"); + goto argerr; + } if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) { BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); @@ -424,12 +517,12 @@ int MAIN(int argc, char **argv) if (operation & SMIME_SIGNERS) { - /* Check to see if any final signer needs to be appended */ if (keyfile && !signerfile) { BIO_puts(bio_err, "Illegal -inkey without -signer\n"); goto argerr; } + /* Check to see if any final signer needs to be appended */ if (signerfile) { if (!sksigners) @@ -450,9 +543,10 @@ int MAIN(int argc, char **argv) keyfile = NULL; need_rand = 1; } + else if (operation == SMIME_DECRYPT) { - if (!recipfile && !keyfile) + if (!recipfile && !keyfile && !secret_key) { BIO_printf(bio_err, "No recipient certificate or key specified\n"); badarg = 1; @@ -460,7 +554,7 @@ int MAIN(int argc, char **argv) } else if (operation == SMIME_ENCRYPT) { - if (!*args) + if (!*args && !secret_key) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); badarg = 1; @@ -586,24 +680,27 @@ int MAIN(int argc, char **argv) { if (!cipher) { -#ifndef OPENSSL_NO_RC2 - cipher = EVP_rc2_40_cbc(); +#ifndef OPENSSL_NO_DES + cipher = EVP_des_ede3_cbc(); #else BIO_printf(bio_err, "No cipher selected\n"); goto end; #endif } - encerts = sk_X509_new_null(); + + if (secret_key && !secret_keyid) + { + BIO_printf(bio_err, "No sectre key id\n"); + goto end; + } + + if (*args) + encerts = sk_X509_new_null(); while (*args) { if (!(cert = load_cert(bio_err,*args,FORMAT_PEM, NULL, e, "recipient certificate file"))) - { -#if 0 /* An appropriate message is already printed */ - BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args); -#endif goto end; - } sk_X509_push(encerts, cert); cert = NULL; args++; @@ -630,12 +727,22 @@ int MAIN(int argc, char **argv) } } + if (operation == SMIME_SIGN_RECEIPT) + { + if (!(signer = load_cert(bio_err,signerfile,FORMAT_PEM,NULL, + e, "receipt signer certificate file"))) + { + ERR_print_errors(bio_err); + goto end; + } + } + if (operation == SMIME_DECRYPT) { if (!keyfile) keyfile = recipfile; } - else if (operation == SMIME_SIGN) + else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) { if (!keyfile) keyfile = signerfile; @@ -692,6 +799,35 @@ int MAIN(int argc, char **argv) } } + if (rctfile) + { + char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; + if (!(rctin = BIO_new_file(rctfile, rctmode))) + { + BIO_printf (bio_err, + "Can't open receipt file %s\n", rctfile); + goto end; + } + + if (rctformat == FORMAT_SMIME) + rcms = SMIME_read_CMS(rctin, NULL); + else if (rctformat == FORMAT_PEM) + rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); + else if (rctformat == FORMAT_ASN1) + rcms = d2i_CMS_bio(rctin, NULL); + else + { + BIO_printf(bio_err, "Bad input format for receipt\n"); + goto end; + } + + if (!rcms) + { + BIO_printf(bio_err, "Error reading receipt\n"); + goto end; + } + } + if (outfile) { if (!(out = BIO_new_file(outfile, outmode))) @@ -712,7 +848,7 @@ int MAIN(int argc, char **argv) #endif } - if (operation == SMIME_VERIFY) + if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) { if (!(store = setup_verify(bio_err, CAfile, CApath))) goto end; @@ -726,60 +862,99 @@ int MAIN(int argc, char **argv) if (operation == SMIME_DATA_CREATE) { - if (indef) - flags |= CMS_STREAM; cms = CMS_data_create(in, flags); } else if (operation == SMIME_DIGEST_CREATE) { - if (indef) - flags |= CMS_STREAM; cms = CMS_digest_create(in, sign_md, flags); } else if (operation == SMIME_COMPRESS) { - if (indef) - flags |= CMS_STREAM; cms = CMS_compress(in, -1, flags); } else if (operation == SMIME_ENCRYPT) { - if (indef) - flags |= CMS_STREAM; + flags |= CMS_PARTIAL; cms = CMS_encrypt(encerts, in, cipher, flags); + if (!cms) + goto end; + if (secret_key) + { + if (!CMS_add0_recipient_key(cms, NID_undef, + secret_key, secret_keylen, + secret_keyid, secret_keyidlen, + NULL, NULL, NULL)) + goto end; + /* NULL these because call absorbs them */ + secret_key = NULL; + secret_keyid = NULL; + } + if (!(flags & CMS_STREAM)) + { + if (!CMS_final(cms, in, flags)) + goto end; + } } else if (operation == SMIME_ENCRYPTED_ENCRYPT) { - if (indef) - flags |= CMS_STREAM; cms = CMS_EncryptedData_encrypt(in, cipher, secret_key, secret_keylen, flags); + + } + else if (operation == SMIME_SIGN_RECEIPT) + { + CMS_ContentInfo *srcms = NULL; + STACK_OF(CMS_SignerInfo) *sis; + CMS_SignerInfo *si; + sis = CMS_get0_SignerInfos(cms); + if (!sis) + goto end; + si = sk_CMS_SignerInfo_value(sis, 0); + srcms = CMS_sign_receipt(si, signer, key, other, flags); + if (!srcms) + goto end; + CMS_ContentInfo_free(cms); + cms = srcms; } else if (operation & SMIME_SIGNERS) { int i; - /* If detached data content we only enable streaming if + /* If detached data content we enable streaming if * S/MIME output format. */ if (operation == SMIME_SIGN) { + if (flags & CMS_DETACHED) { if (outformat == FORMAT_SMIME) flags |= CMS_STREAM; } - else if (indef) - flags |= CMS_STREAM; flags |= CMS_PARTIAL; cms = CMS_sign(NULL, NULL, other, in, flags); if (!cms) goto end; + if (econtent_type) + CMS_set1_eContentType(cms, econtent_type); + + if (rr_to) + { + rr = make_receipt_request(rr_to, rr_allorfirst, + rr_from); + if (!rr) + { + BIO_puts(bio_err, + "Signed Receipt Request Creation Error\n"); + goto end; + } + } } else flags |= CMS_REUSE_DIGEST; for (i = 0; i < sk_num(sksigners); i++) { + CMS_SignerInfo *si; signerfile = sk_value(sksigners, i); keyfile = sk_value(skkeys, i); signer = load_cert(bio_err, signerfile,FORMAT_PEM, NULL, @@ -790,7 +965,10 @@ int MAIN(int argc, char **argv) "signing key file"); if (!key) goto end; - if (!CMS_add1_signer(cms, signer, key, sign_md, flags)) + si = CMS_add1_signer(cms, signer, key, sign_md, flags); + if (!si) + goto end; + if (rr && !CMS_add1_ReceiptRequest(si, rr)) goto end; X509_free(signer); signer = NULL; @@ -814,7 +992,30 @@ int MAIN(int argc, char **argv) ret = 4; if (operation == SMIME_DECRYPT) { - if (!CMS_decrypt(cms, key, recip, indata, out, flags)) + + if (secret_key) + { + if (!CMS_decrypt_set1_key(cms, + secret_key, secret_keylen, + secret_keyid, secret_keyidlen)) + { + BIO_puts(bio_err, + "Error decrypting CMS using secret key\n"); + goto end; + } + } + + if (key) + { + if (!CMS_decrypt_set1_pkey(cms, key, recip)) + { + BIO_puts(bio_err, + "Error decrypting CMS using private key\n"); + goto end; + } + } + + if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) { BIO_printf(bio_err, "Error decrypting CMS structure\n"); goto end; @@ -869,10 +1070,28 @@ int MAIN(int argc, char **argv) } sk_X509_free(signers); } + if (rr_print) + receipt_request_print(bio_err, cms); + + } + else if (operation == SMIME_VERIFY_RECEIPT) + { + if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else + { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } } else { - if (outformat == FORMAT_SMIME) + if (noout) + { + if (print) + CMS_ContentInfo_print_ctx(out, cms, 0, NULL); + } + else if (outformat == FORMAT_SMIME) { if (to) BIO_printf(out, "To: %s\n", to); @@ -916,12 +1135,24 @@ end: sk_free(skkeys); if (secret_key) OPENSSL_free(secret_key); + if (secret_keyid) + OPENSSL_free(secret_keyid); + if (econtent_type) + ASN1_OBJECT_free(econtent_type); + if (rr) + CMS_ReceiptRequest_free(rr); + if (rr_to) + sk_free(rr_to); + if (rr_from) + sk_free(rr_from); X509_STORE_free(store); X509_free(cert); X509_free(recip); X509_free(signer); EVP_PKEY_free(key); CMS_ContentInfo_free(cms); + CMS_ContentInfo_free(rcms); + BIO_free(rctin); BIO_free(in); BIO_free(indata); BIO_free_all(out); @@ -962,4 +1193,137 @@ static int smime_cb(int ok, X509_STORE_CTX *ctx) } +static void gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns) + { + STACK_OF(GENERAL_NAME) *gens; + GENERAL_NAME *gen; + int i, j; + for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) + { + gens = sk_GENERAL_NAMES_value(gns, i); + for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) + { + gen = sk_GENERAL_NAME_value(gens, j); + BIO_puts(out, " "); + GENERAL_NAME_print(out, gen); + BIO_puts(out, "\n"); + } + } + return; + } + +static void receipt_request_print(BIO *out, CMS_ContentInfo *cms) + { + STACK_OF(CMS_SignerInfo) *sis; + CMS_SignerInfo *si; + CMS_ReceiptRequest *rr; + int allorfirst; + STACK_OF(GENERAL_NAMES) *rto, *rlist; + ASN1_STRING *scid; + int i, rv; + sis = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) + { + si = sk_CMS_SignerInfo_value(sis, i); + rv = CMS_get1_ReceiptRequest(si, &rr); + BIO_printf(bio_err, "Signer %d:\n", i + 1); + if (rv == 0) + BIO_puts(bio_err, " No Receipt Request\n"); + else if (rv < 0) + { + BIO_puts(bio_err, " Receipt Request Parse Error\n"); + ERR_print_errors(bio_err); + } + else + { + char *id; + int idlen; + CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst, + &rlist, &rto); + BIO_puts(out, " Signed Content ID:\n"); + idlen = ASN1_STRING_length(scid); + id = (char *)ASN1_STRING_data(scid); + BIO_dump_indent(out, id, idlen, 4); + BIO_puts(out, " Receipts From"); + if (rlist) + { + BIO_puts(out, " List:\n"); + gnames_stack_print(out, rlist); + } + else if (allorfirst == 1) + BIO_puts(out, ": First Tier\n"); + else if (allorfirst == 0) + BIO_puts(out, ": All\n"); + else + BIO_printf(out, " Unknown (%d)\n", allorfirst); + BIO_puts(out, " Receipts To:\n"); + gnames_stack_print(out, rto); + } + if (rr) + CMS_ReceiptRequest_free(rr); + } + } + +static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK *ns) + { + int i; + STACK_OF(GENERAL_NAMES) *ret; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen = NULL; + ret = sk_GENERAL_NAMES_new_null(); + if (!ret) + goto err; + for (i = 0; i < sk_num(ns); i++) + { + char *str = sk_value(ns, i); + gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0); + if (!gen) + goto err; + gens = GENERAL_NAMES_new(); + if (!gens) + goto err; + if (!sk_GENERAL_NAME_push(gens, gen)) + goto err; + gen = NULL; + if (!sk_GENERAL_NAMES_push(ret, gens)) + goto err; + gens = NULL; + } + + return ret; + + err: + if (ret) + sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free); + if (gens) + GENERAL_NAMES_free(gens); + if (gen) + GENERAL_NAME_free(gen); + return NULL; + } + + +static CMS_ReceiptRequest *make_receipt_request(STACK *rr_to, int rr_allorfirst, + STACK *rr_from) + { + STACK_OF(GENERAL_NAMES) *rct_to, *rct_from; + CMS_ReceiptRequest *rr; + rct_to = make_names_stack(rr_to); + if (!rct_to) + goto err; + if (rr_from) + { + rct_from = make_names_stack(rr_from); + if (!rct_from) + goto err; + } + else + rct_from = NULL; + rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, + rct_to); + return rr; + err: + return NULL; + } + #endif