From 320bfc1be79513f2a782f9ee8894cf7a7b9ffe2d Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Fri, 14 Mar 2008 19:37:56 +0000 Subject: [PATCH] Reorganise encrypted content info code to avoid duplication and be more consistent with other content types. --- crypto/cms/cms.h | 11 ++- crypto/cms/cms_enc.c | 195 +++++++++++++++++++++++------------------ crypto/cms/cms_err.c | 9 ++ crypto/cms/cms_lcl.h | 14 +-- crypto/cms/cms_lib.c | 8 +- crypto/cms/cms_smime.c | 27 +++++- 6 files changed, 164 insertions(+), 100 deletions(-) diff --git a/crypto/cms/cms.h b/crypto/cms/cms.h index a95dda906e..cfe49ec9f4 100644 --- a/crypto/cms/cms.h +++ b/crypto/cms/cms.h @@ -142,7 +142,7 @@ int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, const unsigned char *key, size_t keylen, BIO *dcont, BIO *out, unsigned int flags); -int CMS_EncryptedData_set1_key(BIO *b, CMS_ContentInfo *cms, +int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, const unsigned char *key, size_t keylen); int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs, @@ -249,6 +249,7 @@ void ERR_load_CMS_strings(void); #define CMS_F_CMS_ADD1_SIGNER 100 #define CMS_F_CMS_ADD1_SIGNINGTIME 101 #define CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT 137 +#define CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT_BIO 142 #define CMS_F_CMS_COMPRESS 102 #define CMS_F_CMS_COMPRESSEDDATA_CREATE 103 #define CMS_F_CMS_COMPRESSEDDATA_INIT_BIO 104 @@ -257,12 +258,19 @@ void ERR_load_CMS_strings(void); #define CMS_F_CMS_DATA 107 #define CMS_F_CMS_DATAFINAL 108 #define CMS_F_CMS_DATAINIT 109 +#define CMS_F_CMS_DECRYPTEDCONTENT_DECRYPT_BIO 145 +#define CMS_F_CMS_DECRYPTEDCONTENT_ENCRYPT_BIO 143 #define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX 110 #define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO 111 #define CMS_F_CMS_DIGESTEDDATA_DO_FINAL 112 #define CMS_F_CMS_DIGEST_VERIFY 113 +#define CMS_F_CMS_ENCRYPTEDCONTENT_DECRYPT_BIO 146 +#define CMS_F_CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO 144 +#define CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO 148 #define CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO 138 #define CMS_F_CMS_ENCRYPTEDDATA_DECRYPT 140 +#define CMS_F_CMS_ENCRYPTEDDATA_INIT_BIO 147 +#define CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY 141 #define CMS_F_CMS_ENCRYPTED_DATA_DECRYPT 139 #define CMS_F_CMS_ENVELOPED_DATA_INIT 114 #define CMS_F_CMS_FINAL 115 @@ -307,6 +315,7 @@ void ERR_load_CMS_strings(void); #define CMS_R_MD_BIO_INIT_ERROR 111 #define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 112 #define CMS_R_MESSAGEDIGEST_WRONG_LENGTH 113 +#define CMS_R_NOT_ENCRYPTED_DATA 143 #define CMS_R_NOT_KEY_TRANSPORT 114 #define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE 115 #define CMS_R_NO_CONTENT 116 diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c index b395bc499b..ccb436f098 100644 --- a/crypto/cms/cms_enc.c +++ b/crypto/cms/cms_enc.c @@ -63,135 +63,164 @@ /* CMS EncryptedData Utilities */ -/* Set up EncryptedContentInfo based on supplied cipher bio */ +DECLARE_ASN1_ITEM(CMS_EncryptedData) -int cms_bio_to_EncryptedContent(CMS_EncryptedContentInfo *ec, - const unsigned char *key, int keylen, - BIO *b) +/* Return BIO based on EncryptedContentInfo and key */ + +BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec) { - EVP_CIPHER_CTX *ctx = NULL; - unsigned char iv[EVP_MAX_IV_LENGTH], *piv; - int ivlen; + BIO *b; + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *ciph; + X509_ALGOR *calg = ec->contentEncryptionAlgorithm; + unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL; - BIO_get_cipher_ctx(b, &ctx); + int enc; - /* If necessary set key length */ + enc = ec->cipher ? 1 : 0; - if (keylen != EVP_CIPHER_CTX_key_length(ctx)) + b = BIO_new(BIO_f_cipher()); + if (!b) { - if (EVP_CIPHER_CTX_set_key_length(ctx, keylen) <= 0) - { - CMSerr(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT, - CMS_R_INVALID_KEY_LENGTH); - return 0; - } + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + ERR_R_MALLOC_FAILURE); + return NULL; } - /* Generate a random IV if we need one */ + BIO_get_cipher_ctx(b, &ctx); - ivlen = EVP_CIPHER_CTX_iv_length(ctx); - if (ivlen > 0) - { - if (RAND_pseudo_bytes(iv, ivlen) <= 0) - return 0; - piv = iv; - } + if (enc) + calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); else - piv = NULL; - - if (EVP_CipherInit_ex(ctx, NULL, NULL, key, piv, 1) <= 0) { - CMSerr(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT, - CMS_R_CIPHER_INITIALISATION_ERROR); - return 0; - } + ciph = EVP_get_cipherbyobj(calg->algorithm); - ec->contentEncryptionAlgorithm->algorithm = - OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx)); - - if (piv) - { - ec->contentEncryptionAlgorithm->parameter = ASN1_TYPE_new(); - if (!ec->contentEncryptionAlgorithm->parameter) - { - CMSerr(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT, - ERR_R_MALLOC_FAILURE); - return 0; - } - if (EVP_CIPHER_param_to_asn1(ctx, - ec->contentEncryptionAlgorithm->parameter) <= 0) + if (!ciph) { - CMSerr(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT, - CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); - return 0; + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_UNKNOWN_CIPHER); + goto err; } } - return 1; - } - -/* Return BIO based on EncryptedContentInfo and key */ - -int cms_EncryptedContent_to_bio(BIO *b, CMS_EncryptedContentInfo *ec, - const unsigned char *key, int keylen) - { - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *ciph; - BIO_get_cipher_ctx(b, &ctx); - - ciph = EVP_get_cipherbyobj(ec->contentEncryptionAlgorithm->algorithm); - - if (!ciph) + if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, enc) <= 0) { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, CMS_R_UNKNOWN_CIPHER); - goto err; - } - - if (EVP_CipherInit_ex(ctx, ciph, NULL, NULL, NULL, 0) <= 0) - { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_INITIALISATION_ERROR); goto err; } /* If necessary set key length */ - if (keylen != EVP_CIPHER_CTX_key_length(ctx)) + if (ec->keylen != EVP_CIPHER_CTX_key_length(ctx)) { - if (EVP_CIPHER_CTX_set_key_length(ctx, keylen) <= 0) + if (EVP_CIPHER_CTX_set_key_length(ctx, ec->keylen) <= 0) { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_INVALID_KEY_LENGTH); goto err; } } - if (EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, 0) <= 0) + if (enc) + { + int ivlen; + /* Generate a random IV if we need one */ + ivlen = EVP_CIPHER_CTX_iv_length(ctx); + if (ivlen > 0) + { + if (RAND_pseudo_bytes(iv, ivlen) <= 0) + goto err; + piv = iv; + } + } + else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); + goto err; + } + + if (EVP_CipherInit_ex(ctx, NULL, NULL, ec->key, piv, enc) <= 0) { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_INITIALISATION_ERROR); goto err; } - if (EVP_CIPHER_asn1_to_param(ctx, - ec->contentEncryptionAlgorithm->parameter) <= 0) + if (piv) + { + calg->parameter = ASN1_TYPE_new(); + if (!calg->parameter) + { + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) { - CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO, + CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR); goto err; } - return 1; + } + return b; err: - return 0; + BIO_free(b); + return NULL; } -int CMS_EncryptedData_set1_key(BIO *b, CMS_ContentInfo *cms, +int cms_EncryptedContent_init(CMS_EncryptedContentInfo *ec, + const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen) + { + ec->cipher = cipher; + ec->key = OPENSSL_malloc(keylen); + if (!ec->key) + return 0; + if (cipher) + ec->contentType = OBJ_nid2obj(NID_pkcs7_data); + memcpy(ec->key, key, keylen); + ec->keylen = keylen; + return 1; + } + +int CMS_EncryptedData_set1_key(CMS_ContentInfo *cms, const EVP_CIPHER *ciph, const unsigned char *key, size_t keylen) { CMS_EncryptedContentInfo *ec; - if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) + if (ciph) + { + cms->d.encryptedData = M_ASN1_new_of(CMS_EncryptedData); + if (!cms->d.encryptedData) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, + ERR_R_MALLOC_FAILURE); + return 0; + } + cms->contentType = OBJ_nid2obj(NID_pkcs7_encrypted); + cms->d.encryptedData->version = 0; + } + else if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY, + CMS_R_NOT_ENCRYPTED_DATA); return 0; + } + ec = cms->d.encryptedData->encryptedContentInfo; + return cms_EncryptedContent_init(ec, ciph, key, keylen); + } + +BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms) + { + CMS_EncryptedContentInfo *ec; + if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_encrypted) + { + CMSerr(CMS_F_CMS_ENCRYPTEDDATA_INIT_BIO, + CMS_R_NOT_ENCRYPTED_DATA); + return NULL; + } ec = cms->d.encryptedData->encryptedContentInfo; - return cms_EncryptedContent_to_bio(b, ec, key, keylen); + return cms_EncryptedContent_init_bio(ec); } diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 6fb6939b93..96748033e1 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -74,6 +74,7 @@ static ERR_STRING_DATA CMS_str_functs[]= {ERR_FUNC(CMS_F_CMS_ADD1_SIGNER), "CMS_add1_signer"}, {ERR_FUNC(CMS_F_CMS_ADD1_SIGNINGTIME), "CMS_ADD1_SIGNINGTIME"}, {ERR_FUNC(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT), "CMS_BIO_TO_ENCRYPTEDCONTENT"}, +{ERR_FUNC(CMS_F_CMS_BIO_TO_ENCRYPTEDCONTENT_BIO), "CMS_BIO_TO_ENCRYPTEDCONTENT_BIO"}, {ERR_FUNC(CMS_F_CMS_COMPRESS), "CMS_compress"}, {ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_CREATE), "CMS_COMPRESSEDDATA_CREATE"}, {ERR_FUNC(CMS_F_CMS_COMPRESSEDDATA_INIT_BIO), "CMS_COMPRESSEDDATA_INIT_BIO"}, @@ -82,12 +83,19 @@ static ERR_STRING_DATA CMS_str_functs[]= {ERR_FUNC(CMS_F_CMS_DATA), "CMS_data"}, {ERR_FUNC(CMS_F_CMS_DATAFINAL), "CMS_dataFinal"}, {ERR_FUNC(CMS_F_CMS_DATAINIT), "CMS_dataInit"}, +{ERR_FUNC(CMS_F_CMS_DECRYPTEDCONTENT_DECRYPT_BIO), "CMS_DECRYPTEDCONTENT_DECRYPT_BIO"}, +{ERR_FUNC(CMS_F_CMS_DECRYPTEDCONTENT_ENCRYPT_BIO), "CMS_DECRYPTEDCONTENT_ENCRYPT_BIO"}, {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX), "CMS_DIGESTALGORITHM_FIND_CTX"}, {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "CMS_DIGESTALGORITHM_INIT_BIO"}, {ERR_FUNC(CMS_F_CMS_DIGESTEDDATA_DO_FINAL), "CMS_DIGESTEDDATA_DO_FINAL"}, {ERR_FUNC(CMS_F_CMS_DIGEST_VERIFY), "CMS_digest_verify"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_DECRYPT_BIO), "CMS_ENCRYPTEDCONTENT_DECRYPT_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO), "CMS_ENCRYPTEDCONTENT_ENCRYPT_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO), "CMS_ENCRYPTEDCONTENT_INIT_BIO"}, {ERR_FUNC(CMS_F_CMS_ENCRYPTEDCONTENT_TO_BIO), "CMS_ENCRYPTEDCONTENT_TO_BIO"}, {ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT), "CMS_EncryptedData_decrypt"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_INIT_BIO), "CMS_ENCRYPTEDDATA_INIT_BIO"}, +{ERR_FUNC(CMS_F_CMS_ENCRYPTEDDATA_SET1_KEY), "CMS_EncryptedData_set1_key"}, {ERR_FUNC(CMS_F_CMS_ENCRYPTED_DATA_DECRYPT), "CMS_ENCRYPTED_DATA_DECRYPT"}, {ERR_FUNC(CMS_F_CMS_ENVELOPED_DATA_INIT), "CMS_ENVELOPED_DATA_INIT"}, {ERR_FUNC(CMS_F_CMS_FINAL), "CMS_final"}, @@ -135,6 +143,7 @@ static ERR_STRING_DATA CMS_str_reasons[]= {ERR_REASON(CMS_R_MD_BIO_INIT_ERROR) ,"md bio init error"}, {ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"}, {ERR_REASON(CMS_R_MESSAGEDIGEST_WRONG_LENGTH),"messagedigest wrong length"}, +{ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA) ,"not encrypted data"}, {ERR_REASON(CMS_R_NOT_KEY_TRANSPORT) ,"not key transport"}, {ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"not supported for this key type"}, {ERR_REASON(CMS_R_NO_CONTENT) ,"no content"}, diff --git a/crypto/cms/cms_lcl.h b/crypto/cms/cms_lcl.h index cc22e00d53..06eeea7eeb 100644 --- a/crypto/cms/cms_lcl.h +++ b/crypto/cms/cms_lcl.h @@ -169,6 +169,10 @@ struct CMS_EncryptedContentInfo_st ASN1_OBJECT *contentType; X509_ALGOR *contentEncryptionAlgorithm; ASN1_OCTET_STRING *encryptedContent; + /* Content encryption algorithm and key */ + const EVP_CIPHER *cipher; + unsigned char *key; + size_t keylen; }; struct CMS_RecipientInfo_st @@ -255,7 +259,7 @@ struct CMS_KEKRecipientInfo_st CMS_KEKIdentifier *kekid; X509_ALGOR *keyEncryptionAlgorithm; ASN1_OCTET_STRING *encryptedKey; - /* Extra Info symmetric key to use */ + /* Extra info: symmetric key to use */ unsigned char *key; size_t keylen; }; @@ -412,11 +416,9 @@ BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm); int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain, X509_ALGOR *mdalg); -int cms_bio_to_EncryptedContent(CMS_EncryptedContentInfo *ec, - const unsigned char *key, int keylen, - BIO *b); -int cms_EncryptedContent_to_bio(BIO *b, CMS_EncryptedContentInfo *ec, - const unsigned char *key, int keylen); +BIO *cms_EncryptedContent_encrypt_bio(CMS_EncryptedContentInfo *ec); +BIO *cms_EncryptedContent_decrypt_bio(CMS_EncryptedContentInfo *ec); +BIO *cms_EncryptedData_init_bio(CMS_ContentInfo *cms); #ifdef __cplusplus } diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c index f2169e138b..606abafccb 100644 --- a/crypto/cms/cms_lib.c +++ b/crypto/cms/cms_lib.c @@ -68,12 +68,6 @@ DECLARE_ASN1_ITEM(CMS_RevocationInfoChoice) DECLARE_STACK_OF(CMS_CertificateChoices) DECLARE_STACK_OF(CMS_RevocationInfoChoice) -#if 0 -IMPLEMENT_ASN1_ALLOC_FUNCTIONS(CMS_CertificateChoices) -IMPLEMENT_ASN1_ALLOC_FUNCTIONS(CMS_RevocationInfoChoice) -#endif - - const ASN1_OBJECT *CMS_get0_type(CMS_ContentInfo *cms) { return cms->contentType; @@ -140,7 +134,7 @@ BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont) #endif case NID_pkcs7_encrypted: - cmsbio = BIO_new(BIO_f_cipher()); + cmsbio = cms_EncryptedData_init_bio(cms); break; default: diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c index a1ee0f24e2..458efbece8 100644 --- a/crypto/cms/cms_smime.c +++ b/crypto/cms/cms_smime.c @@ -212,16 +212,37 @@ int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms, } } + if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0) + return 0; cont = CMS_dataInit(cms, dcont); if (!cont) return 0; - r = CMS_EncryptedData_set1_key(cont, cms, key, keylen); - if (r) - r = cms_copy_content(out, cont, flags); + r = cms_copy_content(out, cont, flags); BIO_free_all(cont); return r; } +CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher, + const unsigned char *key, size_t keylen, + unsigned int flags) + { + CMS_ContentInfo *cms; + cms = CMS_ContentInfo_new(); + if (!cms) + return NULL; + if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen)) + return NULL; + + if(!(flags & CMS_DETACHED)) + CMS_set_detached(cms, 0); + + if ((flags & (CMS_STREAM|CMS_PARTIAL)) || CMS_final(cms, in, flags)) + return cms; + + CMS_ContentInfo_free(cms); + return NULL; + } + static int cms_signerinfo_verify_cert(CMS_SignerInfo *si, X509_STORE *store, STACK_OF(X509) *certs, -- 2.34.1