Reorganise encrypted content info code to avoid duplication and be more
authorDr. Stephen Henson <steve@openssl.org>
Fri, 14 Mar 2008 19:37:56 +0000 (19:37 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Fri, 14 Mar 2008 19:37:56 +0000 (19:37 +0000)
consistent with other content types.

crypto/cms/cms.h
crypto/cms/cms_enc.c
crypto/cms/cms_err.c
crypto/cms/cms_lcl.h
crypto/cms/cms_lib.c
crypto/cms/cms_smime.c

index a95dda9..cfe49ec 100644 (file)
@@ -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
index b395bc4..ccb436f 100644 (file)
 
 /* 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);
        }
index 6fb6939..9674803 100644 (file)
@@ -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"},
index cc22e00..06eeea7 100644 (file)
@@ -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
 }
index f2169e1..606abaf 100644 (file)
@@ -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:
index a1ee0f2..458efbe 100644 (file)
@@ -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,