Tidy up of S/MIME code and add new functions which will make is easier
to create S/MIME signed data with multiple signers.
This commit is contained in:
parent
ae519a247f
commit
60f20632e2
3 changed files with 137 additions and 81 deletions
|
@ -67,89 +67,148 @@ 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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!(p7 = PKCS7_new())) {
|
||||
if(!(p7 = PKCS7_new()))
|
||||
{
|
||||
PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||
if (!PKCS7_set_type(p7, NID_pkcs7_signed))
|
||||
goto err;
|
||||
|
||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||
if (!PKCS7_content_new(p7, NID_pkcs7_data))
|
||||
goto err;
|
||||
|
||||
if (!(si = PKCS7_add_signature(p7,signcert,pkey,NULL))) {
|
||||
PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
|
||||
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));
|
||||
}
|
||||
|
||||
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))
|
||||
if (pkey && !PKCS7_sign_add_signer(p7, signcert, pkey, NULL, flags))
|
||||
{
|
||||
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_SIGN,PKCS7_R_PKCS7_ADD_SIGNER_ERROR);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & PKCS7_STREAM)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & (PKCS7_STREAM|PKCS7_PARTIAL))
|
||||
return p7;
|
||||
|
||||
if (!(p7bio = PKCS7_dataInit(p7, NULL))) {
|
||||
PKCS7err(PKCS7_F_PKCS7_SIGN,ERR_R_MALLOC_FAILURE);
|
||||
PKCS7_free(p7);
|
||||
return NULL;
|
||||
}
|
||||
if (PKCS7_final(p7, data, flags))
|
||||
return p7;
|
||||
|
||||
err:
|
||||
PKCS7_free(p7);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
SMIME_crlf_copy(data, p7bio, flags);
|
||||
|
||||
if(flags & PKCS7_DETACHED)PKCS7_set_detached(p7, 1);
|
||||
if(PKCS7_type_is_signed(p7) && (flags & PKCS7_DETACHED))
|
||||
PKCS7_set_detached(p7, 1);
|
||||
|
||||
if (!PKCS7_dataFinal(p7,p7bio))
|
||||
{
|
||||
PKCS7err(PKCS7_F_PKCS7_FINAL,PKCS7_R_PKCS7_DATASIGN);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
BIO_free_all(p7bio);
|
||||
|
||||
return ret;
|
||||
|
||||
if (!PKCS7_dataFinal(p7,p7bio)) {
|
||||
PKCS7err(PKCS7_F_PKCS7_SIGN,PKCS7_R_PKCS7_DATASIGN);
|
||||
PKCS7_free(p7);
|
||||
BIO_free_all(p7bio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BIO_free_all(p7bio);
|
||||
return p7;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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 (!(si = PKCS7_add_signature(p7,signcert,pkey, md)))
|
||||
{
|
||||
PKCS7err(PKCS7_F_PKCS7_ADD_SIGNER,
|
||||
PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* si is now part of p7 so don't free it on error */
|
||||
|
||||
si_free = 0;
|
||||
|
||||
if(!(flags & PKCS7_NOCERTS))
|
||||
{
|
||||
if (!PKCS7_add_certificate(p7, signcert))
|
||||
goto err;
|
||||
}
|
||||
|
||||
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,
|
||||
BIO *indata, BIO *out, int flags)
|
||||
|
@ -400,22 +459,8 @@ 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);
|
||||
|
||||
return p7;
|
||||
if (PKCS7_final(p7, in, flags))
|
||||
return p7;
|
||||
|
||||
err:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
Loading…
Reference in a new issue