Skip to content
cms.c 33.6 KiB
Newer Older
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
		/* If not streaming or resigning finalize structure */
		if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM))
			{
			if (!CMS_final(cms, in, NULL, flags))
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
				goto end;
			}
		}

	if (!cms)
		{
		BIO_printf(bio_err, "Error creating CMS structure\n");
		goto end;
		}

	ret = 4;
	if (operation == SMIME_DECRYPT)
		{

		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))
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
			{
			BIO_printf(bio_err, "Error decrypting CMS structure\n");
			goto end;
			}
		}
	else if (operation == SMIME_DATAOUT)
		{
		if (!CMS_data(cms, out, flags))
			goto end;
		}
	else if (operation == SMIME_UNCOMPRESS)
		{
		if (!CMS_uncompress(cms, indata, out, flags))
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
			goto end;
		}
	else if (operation == SMIME_DIGEST_VERIFY)
		{
		if (CMS_digest_verify(cms, indata, out, flags) > 0)
			BIO_printf(bio_err, "Verification successful\n");
		else
			{
			BIO_printf(bio_err, "Verification failure\n");
			goto end;
			}
		}
	else if (operation == SMIME_ENCRYPTED_DECRYPT)
		{
		if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen,
						indata, out, flags))
			goto end;
		}
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	else if (operation == SMIME_VERIFY)
		{
		if (CMS_verify(cms, other, store, indata, out, flags) > 0)
			BIO_printf(bio_err, "Verification successful\n");
		else
			{
			BIO_printf(bio_err, "Verification failure\n");
			goto end;
			}
		if (signerfile)
			{
			STACK_OF(X509) *signers;
			signers = CMS_get0_signers(cms);
			if (!save_certs(signerfile, signers))
				{
				BIO_printf(bio_err,
						"Error writing signers to %s\n",
								signerfile);
				ret = 5;
				goto end;
				}
			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;
			}
		}
		if (noout)
			{
			if (print)
				CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
			}
		else if (outformat == FORMAT_SMIME)
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
			{
			if (to)
				BIO_printf(out, "To: %s\n", to);
			if (from)
				BIO_printf(out, "From: %s\n", from);
			if (subject)
				BIO_printf(out, "Subject: %s\n", subject);
			if (operation == SMIME_RESIGN)
				ret = SMIME_write_CMS(out, cms, indata, flags);
			else
				ret = SMIME_write_CMS(out, cms, in, flags);
			}
		else if (outformat == FORMAT_PEM) 
			ret = PEM_write_bio_CMS_stream(out, cms, in, flags);
		else if (outformat == FORMAT_ASN1) 
			ret = i2d_CMS_bio_stream(out,cms, in, flags);
		else
			{
			BIO_printf(bio_err, "Bad output format for CMS file\n");
			goto end;
			}
		if (ret <= 0)
			{
			ret = 6;
			goto end;
			}
		}
	ret = 0;
end:
	if (ret)
		ERR_print_errors(bio_err);
	if (need_rand)
		app_RAND_write_file(NULL, bio_err);
	sk_X509_pop_free(encerts, X509_free);
	sk_X509_pop_free(other, X509_free);
	if (vpm)
		X509_VERIFY_PARAM_free(vpm);
	if (sksigners)
Ben Laurie's avatar
Ben Laurie committed
		sk_STRING_free(sksigners);
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	if (skkeys)
Ben Laurie's avatar
Ben Laurie committed
		sk_STRING_free(skkeys);
	if (secret_keyid)
		OPENSSL_free(secret_keyid);
	if (econtent_type)
		ASN1_OBJECT_free(econtent_type);
	if (rr)
		CMS_ReceiptRequest_free(rr);
	if (rr_to)
Ben Laurie's avatar
Ben Laurie committed
		sk_STRING_free(rr_to);
Ben Laurie's avatar
Ben Laurie committed
		sk_STRING_free(rr_from);
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	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);
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	BIO_free(in);
	BIO_free(indata);
	BIO_free_all(out);
	if (passin) OPENSSL_free(passin);
	return (ret);
}

static int save_certs(char *signerfile, STACK_OF(X509) *signers)
	{
	int i;
	BIO *tmp;
	if (!signerfile)
		return 1;
	tmp = BIO_new_file(signerfile, "w");
	if (!tmp) return 0;
	for(i = 0; i < sk_X509_num(signers); i++)
		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
	BIO_free(tmp);
	return 1;
	}
	

/* Minimal callback just to output policy info (if any) */

static int cms_cb(int ok, X509_STORE_CTX *ctx)
Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
	{
	int error;

	error = X509_STORE_CTX_get_error(ctx);

	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
		&& ((error != X509_V_OK) || (ok != 2)))
		return ok;

	policies_print(NULL, ctx);

	return ok;

	}

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);
		}
	}

Ben Laurie's avatar
Ben Laurie committed
static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(STRING) *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;
Ben Laurie's avatar
Ben Laurie committed
	for (i = 0; i < sk_STRING_num(ns); i++)
Ben Laurie's avatar
Ben Laurie committed
		char *str = sk_STRING_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;
	}


Ben Laurie's avatar
Ben Laurie committed
static CMS_ReceiptRequest *make_receipt_request(STACK_OF(STRING) *rr_to,
						int rr_allorfirst,
						STACK_OF(STRING) *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;
	}

Dr. Stephen Henson's avatar
Dr. Stephen Henson committed
#endif