Commit 60f20632 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Tidy up of S/MIME code and add new functions which will make is easier

to create S/MIME signed data with multiple signers.
parent ae519a24
Loading
Loading
Loading
Loading
+124 −79
Original line number Diff line number Diff line
@@ -67,88 +67,147 @@ PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
		  BIO *data, int flags)
{
	PKCS7 *p7;
	PKCS7_SIGNER_INFO *si;
	BIO *p7bio;
	STACK_OF(X509_ALGOR) *smcap;
	int i;

	if(!X509_check_private_key(signcert, pkey)) {
		PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
	if(!(p7 = PKCS7_new()))
		{
		PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
		return NULL;
		}

	if(!(p7 = PKCS7_new())) {
		PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
		return NULL;
	if (!PKCS7_set_type(p7, NID_pkcs7_signed))
		goto err;

	if (!PKCS7_content_new(p7, NID_pkcs7_data))
		goto err;

    	if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags))
		{
		PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
		goto err;
		}

	if(!(flags & PKCS7_NOCERTS))
		{
		for(i = 0; i < sk_X509_num(certs); i++)
			{
			if (!PKCS7_add_certificate(p7, sk_X509_value(certs, i)))
				goto err;
			}
		}

	PKCS7_set_type(p7, NID_pkcs7_signed);
	if (flags & (PKCS7_STREAM|PKCS7_PARTIAL))
		return p7;

	PKCS7_content_new(p7, NID_pkcs7_data);
	if (PKCS7_final(p7, data, flags))
		return p7;

    	if (!(si = PKCS7_add_signature(p7,signcert,pkey,NULL))) {
		PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
	err:
	PKCS7_free(p7);
	return NULL;
}

	if(!(flags & PKCS7_NOCERTS)) {
		PKCS7_add_certificate(p7, signcert);
		if(certs) for(i = 0; i < sk_X509_num(certs); i++)
			PKCS7_add_certificate(p7, sk_X509_value(certs, i));
int PKCS7_final(PKCS7 *p7, BIO *data, int flags)
	{
	BIO *p7bio;
	int ret;
	if (!(p7bio = PKCS7_dataInit(p7, NULL)))
		{
		PKCS7err(PKCS7_F_PKCS7_FINAL,ERR_R_MALLOC_FAILURE);
		return 0;
		}

	if(!(flags & PKCS7_NOATTR)) {
		PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
				V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
		/* Add SMIMECapabilities */
		if(!(flags & PKCS7_NOSMIMECAP))
	SMIME_crlf_copy(data, p7bio, flags);

	if(PKCS7_type_is_signed(p7) && (flags & PKCS7_DETACHED))
		PKCS7_set_detached(p7, 1);

        if (!PKCS7_dataFinal(p7,p7bio))
		{
		if(!(smcap = sk_X509_ALGOR_new_null())) {
			PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
			PKCS7_free(p7);
			return NULL;
		PKCS7err(PKCS7_F_PKCS7_FINAL,PKCS7_R_PKCS7_DATASIGN);
		goto err;
		}
#ifndef OPENSSL_NO_DES
		PKCS7_simple_smimecap (smcap, NID_des_ede3_cbc, -1);
#endif
#ifndef OPENSSL_NO_RC2
		PKCS7_simple_smimecap (smcap, NID_rc2_cbc, 128);
		PKCS7_simple_smimecap (smcap, NID_rc2_cbc, 64);
#endif
#ifndef OPENSSL_NO_DES
		PKCS7_simple_smimecap (smcap, NID_des_cbc, -1);
#endif
#ifndef OPENSSL_NO_RC2
		PKCS7_simple_smimecap (smcap, NID_rc2_cbc, 40);
#endif
		PKCS7_add_attrib_smimecap (si, smcap);
		sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);

	ret = 1;

	err:
	BIO_free_all(p7bio);

	return ret;

	}

/* Check to see if a cipher exists and if so add S/MIME capabilities */

static int add_cipher_smcap(STACK_OF(X509_ALGOR) *sk, int nid, int arg)
	{
	if (EVP_get_cipherbynid(nid))
		return PKCS7_simple_smimecap(sk, nid, arg);
	return 1;
	}

	if (flags & PKCS7_STREAM)
		return p7;
PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7, X509 *signcert,
					EVP_PKEY *pkey, const EVP_MD *md,
					int flags)
	{
	PKCS7_SIGNER_INFO *si = NULL;
	int si_free = 1;
	STACK_OF(X509_ALGOR) *smcap = NULL;
	if(!X509_check_private_key(signcert, pkey))
		{
		PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,
			PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
                return NULL;
		}

	if (!(p7bio = PKCS7_dataInit(p7, NULL))) {
		PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
		PKCS7_free(p7);
    	if (!(si = PKCS7_add_signature(p7,signcert,pkey, md)))
		{
		PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,
				PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
		return NULL;
		}

	SMIME_crlf_copy(data, p7bio, flags);
	/* si is now part of p7 so don't free it on error */

	if(flags & PKCS7_DETACHED)PKCS7_set_detached(p7, 1);
	si_free = 0;

        if (!PKCS7_dataFinal(p7,p7bio)) {
		PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_DATASIGN);
		PKCS7_free(p7);
		BIO_free_all(p7bio);
		return NULL;
	if(!(flags & PKCS7_NOCERTS))
		{
		if (!PKCS7_add_certificate(p7, signcert))
			goto err;
		}

	BIO_free_all(p7bio);
	return p7;
	if(!(flags & PKCS7_NOATTR))
		{
		if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
				V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data)))
			goto err;
		/* Add SMIMECapabilities */
		if(!(flags & PKCS7_NOSMIMECAP))
			{
			if(!(smcap = sk_X509_ALGOR_new_null()))
				{
				PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,
					ERR_R_MALLOC_FAILURE);
				goto err;
				}
			if (!add_cipher_smcap(smcap, NID_des_ede3_cbc, -1)
				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 128)
				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 64)
				|| !add_cipher_smcap(smcap, NID_des_cbc, -1)
				|| !add_cipher_smcap(smcap, NID_rc2_cbc, 40)
				|| !PKCS7_add_attrib_smimecap (si, smcap))
				goto err;
			sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
			}
		}
	return si;
	err:
	if (smcap)
		sk_X509_ALGOR_pop_free(smcap, X509_ALGOR_free);
	if (si && si_free)
		PKCS7_SIGNER_INFO_free(si);
	return NULL;
	}

int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
@@ -400,21 +459,7 @@ PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
		}
	}

	if(!(p7bio = PKCS7_dataInit(p7, NULL))) {
		PKCS7err(PKCS7_F_PKCS7_ENCRYPT,ERR_R_MALLOC_FAILURE);
		goto err;
	}

	SMIME_crlf_copy(in, p7bio, flags);

	BIO_flush(p7bio);

        if (!PKCS7_dataFinal(p7,p7bio)) {
		PKCS7err(PKCS7_F_PKCS7_ENCRYPT,PKCS7_R_PKCS7_DATAFINAL_ERROR);
		goto err;
	}
        BIO_free_all(p7bio);

	if (PKCS7_final(p7, in, flags))
		return p7;

	err:
+9 −0
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ DECLARE_PKCS12_STACK_OF(PKCS7)
#define PKCS7_CRLFEOL		0x800
#define PKCS7_STREAM		0x1000
#define PKCS7_NOCRL		0x2000
#define PKCS7_PARTIAL		0x4000

/* Flags: for compatibility with older code */

@@ -362,6 +363,12 @@ int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk);

PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
							BIO *data, int flags);

PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *p7,
			X509 *signcert, EVP_PKEY *pkey, const EVP_MD *md,
			int flags);

int PKCS7_final(PKCS7 *p7, BIO *data, int flags);
int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
					BIO *indata, BIO *out, int flags);
STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
@@ -407,6 +414,7 @@ void ERR_load_PKCS7_strings(void);
#define PKCS7_F_PKCS7_DECRYPT_RINFO			 133
#define PKCS7_F_PKCS7_ENCODE_RINFO			 132
#define PKCS7_F_PKCS7_ENCRYPT				 115
#define PKCS7_F_PKCS7_FINAL				 134
#define PKCS7_F_PKCS7_FIND_DIGEST			 127
#define PKCS7_F_PKCS7_GET0_SIGNERS			 124
#define PKCS7_F_PKCS7_RECIP_INFO_SET			 130
@@ -454,6 +462,7 @@ void ERR_load_PKCS7_strings(void);
#define PKCS7_R_NO_SIG_CONTENT_TYPE			 138
#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE	 104
#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR		 124
#define PKCS7_R_PKCS7_ADD_SIGNER_ERROR			 153
#define PKCS7_R_PKCS7_DATAFINAL				 126
#define PKCS7_R_PKCS7_DATAFINAL_ERROR			 125
#define PKCS7_R_PKCS7_DATASIGN				 145
+2 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ static ERR_STRING_DATA PKCS7_str_functs[]=
{ERR_FUNC(PKCS7_F_PKCS7_DECRYPT_RINFO),	"PKCS7_DECRYPT_RINFO"},
{ERR_FUNC(PKCS7_F_PKCS7_ENCODE_RINFO),	"PKCS7_ENCODE_RINFO"},
{ERR_FUNC(PKCS7_F_PKCS7_ENCRYPT),	"PKCS7_encrypt"},
{ERR_FUNC(PKCS7_F_PKCS7_FINAL),	"PKCS7_final"},
{ERR_FUNC(PKCS7_F_PKCS7_FIND_DIGEST),	"PKCS7_FIND_DIGEST"},
{ERR_FUNC(PKCS7_F_PKCS7_GET0_SIGNERS),	"PKCS7_GET0_SIGNERS"},
{ERR_FUNC(PKCS7_F_PKCS7_RECIP_INFO_SET),	"PKCS7_RECIP_INFO_set"},
@@ -139,6 +140,7 @@ static ERR_STRING_DATA PKCS7_str_reasons[]=
{ERR_REASON(PKCS7_R_NO_SIG_CONTENT_TYPE) ,"no sig content type"},
{ERR_REASON(PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE),"operation not supported on this type"},
{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR),"pkcs7 add signature error"},
{ERR_REASON(PKCS7_R_PKCS7_ADD_SIGNER_ERROR),"pkcs7 add signer error"},
{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL)     ,"pkcs7 datafinal"},
{ERR_REASON(PKCS7_R_PKCS7_DATAFINAL_ERROR),"pkcs7 datafinal error"},
{ERR_REASON(PKCS7_R_PKCS7_DATASIGN)      ,"pkcs7 datasign"},