Backport of password based CMS support from HEAD.
authorDr. Stephen Henson <steve@openssl.org>
Sun, 9 Oct 2011 15:28:02 +0000 (15:28 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 9 Oct 2011 15:28:02 +0000 (15:28 +0000)
17 files changed:
CHANGES
apps/cms.c
crypto/asn1/asn1.h
crypto/asn1/asn1_err.c
crypto/asn1/p5_pbev2.c
crypto/cms/Makefile
crypto/cms/cms.h
crypto/cms/cms_asn1.c
crypto/cms/cms_env.c
crypto/cms/cms_err.c
crypto/cms/cms_lcl.h
crypto/cms/cms_pwri.c [new file with mode: 0644]
crypto/cms/cms_smime.c
crypto/evp/evp_locl.h
crypto/evp/evp_pbe.c
crypto/evp/p5_crpt2.c
crypto/x509/x509.h

diff --git a/CHANGES b/CHANGES
index c158de9..49733ea 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 1.0.0e and 1.0.1  [xx XXX xxxx]
 
+  *) Experiemental password based recipient info support for CMS library:
+     implementing RFC3211.
+     [Steve Henson]
+
+  *) Split password based encryption into PBES2 and PBKDF2 functions. This
+     neatly separates the code into cipher and PBE sections and is required
+     for some algorithms that split PBES2 into separate pieces (such as
+     password based CMS).
+     [Steve Henson]
+
   *) Session-handling fixes:
      - Fix handling of connections that are resuming with a session ID,
        but also support Session Tickets.
index 3f5ee1b..ee5445d 100644 (file)
@@ -136,6 +136,7 @@ int MAIN(int argc, char **argv)
        char *engine=NULL;
 #endif
        unsigned char *secret_key = NULL, *secret_keyid = NULL;
+       unsigned char *pwri_pass = NULL, *pwri_tmp = NULL;
        size_t secret_keylen = 0, secret_keyidlen = 0;
 
        ASN1_OBJECT *econtent_type = NULL;
@@ -326,6 +327,13 @@ int MAIN(int argc, char **argv)
                                }
                        secret_keyidlen = (size_t)ltmp;
                        }
+               else if (!strcmp(*args,"-pwri_password"))
+                       {
+                       if (!args[1])
+                               goto argerr;
+                       args++;
+                       pwri_pass = (unsigned char *)*args;
+                       }
                else if (!strcmp(*args,"-econtent_type"))
                        {
                        if (!args[1])
@@ -559,7 +567,7 @@ int MAIN(int argc, char **argv)
 
        else if (operation == SMIME_DECRYPT)
                {
-               if (!recipfile && !keyfile && !secret_key)
+               if (!recipfile && !keyfile && !secret_key && !pwri_pass)
                        {
                        BIO_printf(bio_err, "No recipient certificate or key specified\n");
                        badarg = 1;
@@ -567,7 +575,7 @@ int MAIN(int argc, char **argv)
                }
        else if (operation == SMIME_ENCRYPT)
                {
-               if (!*args && !secret_key)
+               if (!*args && !secret_key && !pwri_pass)
                        {
                        BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
                        badarg = 1;
@@ -917,6 +925,17 @@ int MAIN(int argc, char **argv)
                        secret_key = NULL;
                        secret_keyid = NULL;
                        }
+               if (pwri_pass)
+                       {
+                       pwri_tmp = (unsigned char *)BUF_strdup((char *)pwri_pass);
+                       if (!pwri_tmp)
+                               goto end;
+                       if (!CMS_add0_recipient_password(cms,
+                                               -1, NID_undef, NID_undef,
+                                                pwri_tmp, -1, NULL))
+                               goto end;
+                       pwri_tmp = NULL;
+                       }
                if (!(flags & CMS_STREAM))
                        {
                        if (!CMS_final(cms, in, NULL, flags))
@@ -1043,6 +1062,16 @@ int MAIN(int argc, char **argv)
                                }
                        }
 
+               if (pwri_pass)
+                       {
+                       if (!CMS_decrypt_set1_password(cms, pwri_pass, -1))
+                               {
+                               BIO_puts(bio_err,
+                                       "Error decrypting CMS using password\n");
+                               goto end;
+                               }
+                       }
+
                if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags))
                        {
                        BIO_printf(bio_err, "Error decrypting CMS structure\n");
@@ -1167,6 +1196,8 @@ end:
                OPENSSL_free(secret_key);
        if (secret_keyid)
                OPENSSL_free(secret_keyid);
+       if (pwri_tmp)
+               OPENSSL_free(pwri_tmp);
        if (econtent_type)
                ASN1_OBJECT_free(econtent_type);
        if (rr)
index 59540e4..439e760 100644 (file)
@@ -1266,6 +1266,7 @@ void ERR_load_ASN1_strings(void);
 #define ASN1_F_PKCS5_PBE2_SET_IV                        167
 #define ASN1_F_PKCS5_PBE_SET                            202
 #define ASN1_F_PKCS5_PBE_SET0_ALGOR                     215
+#define ASN1_F_PKCS5_PBKDF2_SET                                 219
 #define ASN1_F_SMIME_READ_ASN1                          212
 #define ASN1_F_SMIME_TEXT                               213
 #define ASN1_F_X509_CINF_NEW                            168
index 6e04d08..7e20995 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/asn1/asn1_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2009 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2011 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -179,6 +179,7 @@ static ERR_STRING_DATA ASN1_str_functs[]=
 {ERR_FUNC(ASN1_F_PKCS5_PBE2_SET_IV),   "PKCS5_pbe2_set_iv"},
 {ERR_FUNC(ASN1_F_PKCS5_PBE_SET),       "PKCS5_pbe_set"},
 {ERR_FUNC(ASN1_F_PKCS5_PBE_SET0_ALGOR),        "PKCS5_pbe_set0_algor"},
+{ERR_FUNC(ASN1_F_PKCS5_PBKDF2_SET),    "PKCS5_pbkdf2_set"},
 {ERR_FUNC(ASN1_F_SMIME_READ_ASN1),     "SMIME_read_ASN1"},
 {ERR_FUNC(ASN1_F_SMIME_TEXT),  "SMIME_text"},
 {ERR_FUNC(ASN1_F_X509_CINF_NEW),       "X509_CINF_NEW"},
index 377edaf..b053a6e 100644 (file)
@@ -91,12 +91,10 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
                                 unsigned char *aiv, int prf_nid)
 {
        X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL;
-       int alg_nid;
+       int alg_nid, keylen;
        EVP_CIPHER_CTX ctx;
        unsigned char iv[EVP_MAX_IV_LENGTH];
-       PBKDF2PARAM *kdf = NULL;
        PBE2PARAM *pbe2 = NULL;
-       ASN1_OCTET_STRING *osalt = NULL;
        ASN1_OBJECT *obj;
 
        alg_nid = EVP_CIPHER_type(cipher);
@@ -146,55 +144,19 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
                }
        EVP_CIPHER_CTX_cleanup(&ctx);
 
-       if(!(kdf = PBKDF2PARAM_new())) goto merr;
-       if(!(osalt = M_ASN1_OCTET_STRING_new())) goto merr;
-
-       if (!saltlen) saltlen = PKCS5_SALT_LEN;
-       if (!(osalt->data = OPENSSL_malloc (saltlen))) goto merr;
-       osalt->length = saltlen;
-       if (salt) memcpy (osalt->data, salt, saltlen);
-       else if (RAND_pseudo_bytes (osalt->data, saltlen) < 0) goto merr;
-
-       if(iter <= 0) iter = PKCS5_DEFAULT_ITER;
-       if(!ASN1_INTEGER_set(kdf->iter, iter)) goto merr;
-
-       /* Now include salt in kdf structure */
-       kdf->salt->value.octet_string = osalt;
-       kdf->salt->type = V_ASN1_OCTET_STRING;
-       osalt = NULL;
-
        /* If its RC2 then we'd better setup the key length */
 
-       if(alg_nid == NID_rc2_cbc) {
-               if(!(kdf->keylength = M_ASN1_INTEGER_new())) goto merr;
-               if(!ASN1_INTEGER_set (kdf->keylength,
-                                EVP_CIPHER_key_length(cipher))) goto merr;
-       }
-
-       /* prf can stay NULL if we are using hmacWithSHA1 */
-       if (prf_nid != NID_hmacWithSHA1)
-               {
-               kdf->prf = X509_ALGOR_new();
-               if (!kdf->prf)
-                       goto merr;
-               X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid),
-                                       V_ASN1_NULL, NULL);
-               }
-
-       /* Now setup the PBE2PARAM keyfunc structure */
+       if(alg_nid == NID_rc2_cbc)
+               keylen = EVP_CIPHER_key_length(cipher);
+       else
+               keylen = -1;
 
-       pbe2->keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2);
+       /* Setup keyfunc */
 
-       /* Encode PBKDF2PARAM into parameter of pbe2 */
+       pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen);
 
-       if(!(pbe2->keyfunc->parameter = ASN1_TYPE_new())) goto merr;
-
-       if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM),
-                        &pbe2->keyfunc->parameter->value.sequence)) goto merr;
-       pbe2->keyfunc->parameter->type = V_ASN1_SEQUENCE;
-
-       PBKDF2PARAM_free(kdf);
-       kdf = NULL;
+       if (!pbe2->keyfunc)
+               goto merr;
 
        /* Now set up top level AlgorithmIdentifier */
 
@@ -220,8 +182,6 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
        err:
        PBE2PARAM_free(pbe2);
        /* Note 'scheme' is freed as part of pbe2 */
-       M_ASN1_OCTET_STRING_free(osalt);
-       PBKDF2PARAM_free(kdf);
        X509_ALGOR_free(kalg);
        X509_ALGOR_free(ret);
 
@@ -234,3 +194,85 @@ X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
        {
        return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1);
        }
+
+X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
+                               int prf_nid, int keylen)
+       {
+       X509_ALGOR *keyfunc = NULL;
+       PBKDF2PARAM *kdf = NULL;
+       ASN1_OCTET_STRING *osalt = NULL;
+
+       if(!(kdf = PBKDF2PARAM_new()))
+               goto merr;
+       if(!(osalt = M_ASN1_OCTET_STRING_new()))
+               goto merr;
+
+       kdf->salt->value.octet_string = osalt;
+       kdf->salt->type = V_ASN1_OCTET_STRING;
+
+       if (!saltlen)
+               saltlen = PKCS5_SALT_LEN;
+       if (!(osalt->data = OPENSSL_malloc (saltlen)))
+               goto merr;
+
+       osalt->length = saltlen;
+
+       if (salt)
+               memcpy (osalt->data, salt, saltlen);
+       else if (RAND_pseudo_bytes (osalt->data, saltlen) < 0)
+               goto merr;
+
+       if(iter <= 0)
+               iter = PKCS5_DEFAULT_ITER;
+
+       if(!ASN1_INTEGER_set(kdf->iter, iter))
+               goto merr;
+
+       /* If have a key len set it up */
+
+       if(keylen > 0) 
+               {
+               if(!(kdf->keylength = M_ASN1_INTEGER_new()))
+                       goto merr;
+               if(!ASN1_INTEGER_set (kdf->keylength, keylen))
+                       goto merr;
+               }
+
+       /* prf can stay NULL if we are using hmacWithSHA1 */
+       if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1)
+               {
+               kdf->prf = X509_ALGOR_new();
+               if (!kdf->prf)
+                       goto merr;
+               X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid),
+                                       V_ASN1_NULL, NULL);
+               }
+
+       /* Finally setup the keyfunc structure */
+
+       keyfunc = X509_ALGOR_new();
+       if (!keyfunc)
+               goto merr;
+
+       keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2);
+
+       /* Encode PBKDF2PARAM into parameter of pbe2 */
+
+       if(!(keyfunc->parameter = ASN1_TYPE_new()))
+               goto merr;
+
+       if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM),
+                        &keyfunc->parameter->value.sequence))
+               goto merr;
+       keyfunc->parameter->type = V_ASN1_SEQUENCE;
+
+       PBKDF2PARAM_free(kdf);
+       return keyfunc;
+
+       merr:
+       ASN1err(ASN1_F_PKCS5_PBKDF2_SET,ERR_R_MALLOC_FAILURE);
+       PBKDF2PARAM_free(kdf);
+       X509_ALGOR_free(keyfunc);
+       return NULL;
+       }
+
index 5837049..03a17cf 100644 (file)
@@ -18,9 +18,11 @@ APPS=
 
 LIB=$(TOP)/libcrypto.a
 LIBSRC= cms_lib.c cms_asn1.c cms_att.c cms_io.c cms_smime.c cms_err.c \
-       cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c
+       cms_sd.c cms_dd.c cms_cd.c cms_env.c cms_enc.c cms_ess.c \
+       cms_pwri.c
 LIBOBJ= cms_lib.o cms_asn1.o cms_att.o cms_io.o cms_smime.o cms_err.o \
-       cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o cms_ess.o
+       cms_sd.o cms_dd.o cms_cd.o cms_env.o cms_enc.o cms_ess.o \
+       cms_pwri.o
 
 SRC= $(LIBSRC)
 
index 09c45d0..8d23021 100644 (file)
@@ -184,6 +184,8 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert);
 int CMS_decrypt_set1_key(CMS_ContentInfo *cms, 
                                unsigned char *key, size_t keylen,
                                unsigned char *id, size_t idlen);
+int CMS_decrypt_set1_password(CMS_ContentInfo *cms, 
+                               unsigned char *pass, ssize_t passlen);
 
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
 int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
@@ -219,6 +221,14 @@ int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
 int CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri, 
                                        const unsigned char *id, size_t idlen);
 
+int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, 
+                                       unsigned char *pass, ssize_t passlen);
+
+CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
+                                       int iter, int wrap_nid, int pbe_nid,
+                                       unsigned char *pass, ssize_t passlen,
+                                       const EVP_CIPHER *kekciph);
+
 int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
        
 int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
@@ -330,6 +340,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CHECK_CONTENT                             99
 #define CMS_F_CMS_ADD0_CERT                             164
 #define CMS_F_CMS_ADD0_RECIPIENT_KEY                    100
+#define CMS_F_CMS_ADD0_RECIPIENT_PASSWORD               165
 #define CMS_F_CMS_ADD1_RECEIPTREQUEST                   158
 #define CMS_F_CMS_ADD1_RECIPIENT_CERT                   101
 #define CMS_F_CMS_ADD1_SIGNER                           102
@@ -344,6 +355,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_DATAINIT                              111
 #define CMS_F_CMS_DECRYPT                               112
 #define CMS_F_CMS_DECRYPT_SET1_KEY                      113
+#define CMS_F_CMS_DECRYPT_SET1_PASSWORD                         166
 #define CMS_F_CMS_DECRYPT_SET1_PKEY                     114
 #define CMS_F_CMS_DIGESTALGORITHM_FIND_CTX              115
 #define CMS_F_CMS_DIGESTALGORITHM_INIT_BIO              116
@@ -378,7 +390,9 @@ void ERR_load_CMS_strings(void);
 #define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT            141
 #define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS          142
 #define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID     143
+#define CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT              167
 #define CMS_F_CMS_RECIPIENTINFO_SET0_KEY                144
+#define CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD           168
 #define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY               145
 #define CMS_F_CMS_SET1_SIGNERIDENTIFIER                         146
 #define CMS_F_CMS_SET_DETACHED                          147
@@ -419,6 +433,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_ERROR_SETTING_KEY                                 115
 #define CMS_R_ERROR_SETTING_RECIPIENTINFO               116
 #define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH              117
+#define CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER          176
 #define CMS_R_INVALID_KEY_LENGTH                        118
 #define CMS_R_MD_BIO_INIT_ERROR                                 119
 #define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH      120
@@ -431,6 +446,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_NOT_ENCRYPTED_DATA                        122
 #define CMS_R_NOT_KEK                                   123
 #define CMS_R_NOT_KEY_TRANSPORT                                 124
+#define CMS_R_NOT_PWRI                                  177
 #define CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE           125
 #define CMS_R_NO_CIPHER                                         126
 #define CMS_R_NO_CONTENT                                127
@@ -443,6 +459,7 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_NO_MATCHING_RECIPIENT                     132
 #define CMS_R_NO_MATCHING_SIGNATURE                     166
 #define CMS_R_NO_MSGSIGDIGEST                           167
+#define CMS_R_NO_PASSWORD                               178
 #define CMS_R_NO_PRIVATE_KEY                            133
 #define CMS_R_NO_PUBLIC_KEY                             134
 #define CMS_R_NO_RECEIPT_REQUEST                        168
@@ -466,10 +483,12 @@ void ERR_load_CMS_strings(void);
 #define CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM                 151
 #define CMS_R_UNSUPPORTED_CONTENT_TYPE                  152
 #define CMS_R_UNSUPPORTED_KEK_ALGORITHM                         153
+#define CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM      179
 #define CMS_R_UNSUPPORTED_RECIPIENT_TYPE                154
 #define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE             155
 #define CMS_R_UNSUPPORTED_TYPE                          156
 #define CMS_R_UNWRAP_ERROR                              157
+#define CMS_R_UNWRAP_FAILURE                            180
 #define CMS_R_VERIFICATION_FAILURE                      158
 #define CMS_R_WRAP_ERROR                                159
 
index fcba4dc..cfe67fb 100644 (file)
@@ -237,6 +237,15 @@ static int cms_ri_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                                OPENSSL_free(kekri->key);
                                }
                        }
+               else if (ri->type == CMS_RECIPINFO_PASS)
+                       {
+                       CMS_PasswordRecipientInfo *pwri = ri->d.pwri;
+                       if (pwri->pass)
+                               {
+                               OPENSSL_cleanse(pwri->pass, pwri->passlen);
+                               OPENSSL_free(pwri->pass);
+                               }
+                       }
                }
        return 1;
        }
index b3237d4..87d67d3 100644 (file)
 /* CMS EnvelopedData Utilities */
 
 DECLARE_ASN1_ITEM(CMS_EnvelopedData)
-DECLARE_ASN1_ITEM(CMS_RecipientInfo)
 DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
 DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
 DECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
 
 DECLARE_STACK_OF(CMS_RecipientInfo)
 
-static CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
+CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
        {
        if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped)
                {
@@ -786,6 +785,9 @@ int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
                case CMS_RECIPINFO_KEK:
                return cms_RecipientInfo_kekri_decrypt(cms, ri);
 
+               case CMS_RECIPINFO_PASS:
+               return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
+
                default:
                CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
                        CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
@@ -829,6 +831,10 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
                        r = cms_RecipientInfo_kekri_encrypt(cms, ri);
                        break;
 
+                       case CMS_RECIPINFO_PASS:
+                       r = cms_RecipientInfo_pwri_crypt(cms, ri, 1);
+                       break;
+
                        default:
                        CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
                                CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
index ff7b030..8330ead 100644 (file)
@@ -1,6 +1,6 @@
 /* crypto/cms/cms_err.c */
 /* ====================================================================
- * Copyright (c) 1999-2007 The OpenSSL Project.  All rights reserved.
+ * Copyright (c) 1999-2009 The OpenSSL Project.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -73,6 +73,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CHECK_CONTENT),        "CHECK_CONTENT"},
 {ERR_FUNC(CMS_F_CMS_ADD0_CERT),        "CMS_add0_cert"},
 {ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_KEY),       "CMS_add0_recipient_key"},
+{ERR_FUNC(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD),  "CMS_add0_recipient_password"},
 {ERR_FUNC(CMS_F_CMS_ADD1_RECEIPTREQUEST),      "CMS_add1_ReceiptRequest"},
 {ERR_FUNC(CMS_F_CMS_ADD1_RECIPIENT_CERT),      "CMS_add1_recipient_cert"},
 {ERR_FUNC(CMS_F_CMS_ADD1_SIGNER),      "CMS_add1_signer"},
@@ -87,6 +88,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_DATAINIT), "CMS_dataInit"},
 {ERR_FUNC(CMS_F_CMS_DECRYPT),  "CMS_decrypt"},
 {ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_KEY), "CMS_decrypt_set1_key"},
+{ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PASSWORD),    "CMS_decrypt_set1_password"},
 {ERR_FUNC(CMS_F_CMS_DECRYPT_SET1_PKEY),        "CMS_decrypt_set1_pkey"},
 {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_FIND_CTX), "cms_DigestAlgorithm_find_ctx"},
 {ERR_FUNC(CMS_F_CMS_DIGESTALGORITHM_INIT_BIO), "cms_DigestAlgorithm_init_bio"},
@@ -105,7 +107,7 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_GET0_CERTIFICATE_CHOICES), "CMS_GET0_CERTIFICATE_CHOICES"},
 {ERR_FUNC(CMS_F_CMS_GET0_CONTENT),     "CMS_get0_content"},
 {ERR_FUNC(CMS_F_CMS_GET0_ECONTENT_TYPE),       "CMS_GET0_ECONTENT_TYPE"},
-{ERR_FUNC(CMS_F_CMS_GET0_ENVELOPED),   "CMS_GET0_ENVELOPED"},
+{ERR_FUNC(CMS_F_CMS_GET0_ENVELOPED),   "cms_get0_enveloped"},
 {ERR_FUNC(CMS_F_CMS_GET0_REVOCATION_CHOICES),  "CMS_GET0_REVOCATION_CHOICES"},
 {ERR_FUNC(CMS_F_CMS_GET0_SIGNED),      "CMS_GET0_SIGNED"},
 {ERR_FUNC(CMS_F_CMS_MSGSIGDIGEST_ADD1),        "cms_msgSigDigest_add1"},
@@ -121,7 +123,9 @@ static ERR_STRING_DATA CMS_str_functs[]=
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT),       "CMS_RECIPIENTINFO_KTRI_ENCRYPT"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS),     "CMS_RecipientInfo_ktri_get0_algs"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID),        "CMS_RecipientInfo_ktri_get0_signer_id"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT), "cms_RecipientInfo_pwri_crypt"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_KEY),   "CMS_RecipientInfo_set0_key"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD),      "CMS_RecipientInfo_set0_password"},
 {ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY),  "CMS_RecipientInfo_set0_pkey"},
 {ERR_FUNC(CMS_F_CMS_SET1_SIGNERIDENTIFIER),    "cms_set1_SignerIdentifier"},
 {ERR_FUNC(CMS_F_CMS_SET_DETACHED),     "CMS_set_detached"},
@@ -165,6 +169,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {ERR_REASON(CMS_R_ERROR_SETTING_KEY)     ,"error setting key"},
 {ERR_REASON(CMS_R_ERROR_SETTING_RECIPIENTINFO),"error setting recipientinfo"},
 {ERR_REASON(CMS_R_INVALID_ENCRYPTED_KEY_LENGTH),"invalid encrypted key length"},
+{ERR_REASON(CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER),"invalid key encryption parameter"},
 {ERR_REASON(CMS_R_INVALID_KEY_LENGTH)    ,"invalid key length"},
 {ERR_REASON(CMS_R_MD_BIO_INIT_ERROR)     ,"md bio init error"},
 {ERR_REASON(CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH),"messagedigest attribute wrong length"},
@@ -177,6 +182,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {ERR_REASON(CMS_R_NOT_ENCRYPTED_DATA)    ,"not encrypted data"},
 {ERR_REASON(CMS_R_NOT_KEK)               ,"not kek"},
 {ERR_REASON(CMS_R_NOT_KEY_TRANSPORT)     ,"not key transport"},
+{ERR_REASON(CMS_R_NOT_PWRI)              ,"not pwri"},
 {ERR_REASON(CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE),"not supported for this key type"},
 {ERR_REASON(CMS_R_NO_CIPHER)             ,"no cipher"},
 {ERR_REASON(CMS_R_NO_CONTENT)            ,"no content"},
@@ -189,6 +195,7 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {ERR_REASON(CMS_R_NO_MATCHING_RECIPIENT) ,"no matching recipient"},
 {ERR_REASON(CMS_R_NO_MATCHING_SIGNATURE) ,"no matching signature"},
 {ERR_REASON(CMS_R_NO_MSGSIGDIGEST)       ,"no msgsigdigest"},
+{ERR_REASON(CMS_R_NO_PASSWORD)           ,"no password"},
 {ERR_REASON(CMS_R_NO_PRIVATE_KEY)        ,"no private key"},
 {ERR_REASON(CMS_R_NO_PUBLIC_KEY)         ,"no public key"},
 {ERR_REASON(CMS_R_NO_RECEIPT_REQUEST)    ,"no receipt request"},
@@ -212,10 +219,12 @@ static ERR_STRING_DATA CMS_str_reasons[]=
 {ERR_REASON(CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM),"unsupported compression algorithm"},
 {ERR_REASON(CMS_R_UNSUPPORTED_CONTENT_TYPE),"unsupported content type"},
 {ERR_REASON(CMS_R_UNSUPPORTED_KEK_ALGORITHM),"unsupported kek algorithm"},
+{ERR_REASON(CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM),"unsupported key encryption algorithm"},
 {ERR_REASON(CMS_R_UNSUPPORTED_RECIPIENT_TYPE),"unsupported recipient type"},
 {ERR_REASON(CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE),"unsupported recpientinfo type"},
 {ERR_REASON(CMS_R_UNSUPPORTED_TYPE)      ,"unsupported type"},
 {ERR_REASON(CMS_R_UNWRAP_ERROR)          ,"unwrap error"},
+{ERR_REASON(CMS_R_UNWRAP_FAILURE)        ,"unwrap failure"},
 {ERR_REASON(CMS_R_VERIFICATION_FAILURE)  ,"verification failure"},
 {ERR_REASON(CMS_R_WRAP_ERROR)            ,"wrap error"},
 {0,NULL}
index c8ecfa7..5aea7f8 100644 (file)
@@ -273,6 +273,9 @@ struct CMS_PasswordRecipientInfo_st
        X509_ALGOR *keyDerivationAlgorithm;
        X509_ALGOR *keyEncryptionAlgorithm;
        ASN1_OCTET_STRING *encryptedKey;
+       /* Extra info: password to use */
+       unsigned char *pass;
+       size_t passlen;
        };
 
 struct CMS_OtherRecipientInfo_st
@@ -411,6 +414,8 @@ DECLARE_ASN1_ITEM(CMS_SignerInfo)
 DECLARE_ASN1_ITEM(CMS_IssuerAndSerialNumber)
 DECLARE_ASN1_ITEM(CMS_Attributes_Sign)
 DECLARE_ASN1_ITEM(CMS_Attributes_Verify)
+DECLARE_ASN1_ITEM(CMS_RecipientInfo)
+DECLARE_ASN1_ITEM(CMS_PasswordRecipientInfo)
 DECLARE_ASN1_ALLOC_FUNCTIONS(CMS_IssuerAndSerialNumber)
 
 #define CMS_SIGNERINFO_ISSUER_SERIAL   0
@@ -454,6 +459,11 @@ int cms_msgSigDigest_add1(CMS_SignerInfo *dest, CMS_SignerInfo *src);
 ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
 
 BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
+CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms);
+
+/* PWRI routines */
+int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
+                                                       int en_de);
        
 #ifdef  __cplusplus
 }
diff --git a/crypto/cms/cms_pwri.c b/crypto/cms/cms_pwri.c
new file mode 100644 (file)
index 0000000..5fe7f49
--- /dev/null
@@ -0,0 +1,453 @@
+/* crypto/cms/cms_pwri.c */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 2009 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+#include "cryptlib.h"
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/cms.h>
+#include <openssl/rand.h>
+#include <openssl/aes.h>
+#include "cms_lcl.h"
+#include "asn1_locl.h"
+
+int CMS_RecipientInfo_set0_password(CMS_RecipientInfo *ri, 
+                               unsigned char *pass, ssize_t passlen)
+       {
+       CMS_PasswordRecipientInfo *pwri;
+       if (ri->type != CMS_RECIPINFO_PASS)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PASSWORD, CMS_R_NOT_PWRI);
+               return 0;
+               }
+
+       pwri = ri->d.pwri;
+       pwri->pass = pass;
+       if (pass && passlen < 0)
+               passlen = strlen((char *)pass);
+       pwri->passlen = passlen;
+       return 1;
+       }
+
+CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
+                                       int iter, int wrap_nid, int pbe_nid,
+                                       unsigned char *pass, ssize_t passlen,
+                                       const EVP_CIPHER *kekciph)
+       {
+       CMS_RecipientInfo *ri = NULL;
+       CMS_EnvelopedData *env;
+       CMS_PasswordRecipientInfo *pwri;
+       EVP_CIPHER_CTX ctx;
+       X509_ALGOR *encalg = NULL;
+       unsigned char iv[EVP_MAX_IV_LENGTH];
+       int ivlen;
+       env = cms_get0_enveloped(cms);
+       if (!env)
+               goto err;
+
+       if (wrap_nid <= 0)
+               wrap_nid = NID_id_alg_PWRI_KEK;
+
+       if (pbe_nid <= 0)
+               pbe_nid = NID_id_pbkdf2;
+
+       /* Get from enveloped data */
+       if (kekciph == NULL)
+               kekciph = env->encryptedContentInfo->cipher;
+
+       if (kekciph == NULL)
+               {
+               CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);
+               return NULL;
+               }
+       if (wrap_nid != NID_id_alg_PWRI_KEK)
+               {
+               CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
+                               CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
+               return NULL;
+               }
+
+       /* Setup algorithm identifier for cipher */
+       encalg = X509_ALGOR_new();
+       EVP_CIPHER_CTX_init(&ctx);
+
+       if (EVP_EncryptInit_ex(&ctx, kekciph, NULL, NULL, NULL) <= 0)
+               {
+               CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_EVP_LIB);
+               goto err;
+               }
+
+       ivlen = EVP_CIPHER_CTX_iv_length(&ctx);
+
+       if (ivlen > 0)
+               {
+               if (RAND_pseudo_bytes(iv, ivlen) <= 0)
+                       goto err;
+               if (EVP_EncryptInit_ex(&ctx, NULL, NULL, NULL, iv) <= 0)
+                       {
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
+                                                       ERR_R_EVP_LIB);
+                       goto err;
+                       }
+               encalg->parameter = ASN1_TYPE_new();
+               if (!encalg->parameter)
+                       {
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
+                                                       ERR_R_MALLOC_FAILURE);
+                       goto err;
+                       }
+               if (EVP_CIPHER_param_to_asn1(&ctx, encalg->parameter) <= 0)
+                       {
+                       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD,
+                               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
+                       goto err;
+                       }
+               }
+
+
+       encalg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(&ctx));
+
+       EVP_CIPHER_CTX_cleanup(&ctx);
+
+       /* Initialize recipient info */
+       ri = M_ASN1_new_of(CMS_RecipientInfo);
+       if (!ri)
+               goto merr;
+
+       ri->d.pwri = M_ASN1_new_of(CMS_PasswordRecipientInfo);
+       if (!ri->d.pwri)
+               goto merr;
+       ri->type = CMS_RECIPINFO_PASS;
+
+       pwri = ri->d.pwri;
+       /* Since this is overwritten, free up empty structure already there */
+       X509_ALGOR_free(pwri->keyEncryptionAlgorithm);
+       pwri->keyEncryptionAlgorithm = X509_ALGOR_new();
+       if (!pwri->keyEncryptionAlgorithm)
+               goto merr;
+       pwri->keyEncryptionAlgorithm->algorithm = OBJ_nid2obj(wrap_nid);
+       pwri->keyEncryptionAlgorithm->parameter = ASN1_TYPE_new();
+       if (!pwri->keyEncryptionAlgorithm->parameter)
+               goto merr;
+
+        if(!ASN1_item_pack(encalg, ASN1_ITEM_rptr(X509_ALGOR),
+           &pwri->keyEncryptionAlgorithm->parameter->value.sequence))
+               goto merr;
+        pwri->keyEncryptionAlgorithm->parameter->type = V_ASN1_SEQUENCE;
+
+       X509_ALGOR_free(encalg);
+       encalg = NULL;
+
+       /* Setup PBE algorithm */
+
+       pwri->keyDerivationAlgorithm = PKCS5_pbkdf2_set(iter, NULL, 0, -1, -1);
+
+       if (!pwri->keyDerivationAlgorithm)
+               goto err;
+
+       CMS_RecipientInfo_set0_password(ri, pass, passlen);
+       pwri->version = 0;
+
+       if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+               goto merr;
+
+       return ri;
+
+       merr:
+       CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, ERR_R_MALLOC_FAILURE);
+       err:
+       EVP_CIPHER_CTX_cleanup(&ctx);
+       if (ri)
+               M_ASN1_free_of(ri, CMS_RecipientInfo);
+       if (encalg)
+               X509_ALGOR_free(encalg);
+       return NULL;
+
+       }
+
+/* This is an implementation of the key wrapping mechanism in RFC3211,
+ * at some point this should go into EVP.
+ */
+
+static int kek_unwrap_key(unsigned char *out, size_t *outlen,
+               const unsigned char *in, size_t inlen, EVP_CIPHER_CTX *ctx)
+       {
+       size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
+       unsigned char *tmp;
+       int outl, rv = 0;
+       if (inlen < 2 * blocklen)
+               {
+               /* too small */
+               return 0;
+               }
+       if (inlen % blocklen)
+               {
+               /* Invalid size */
+               return 0;
+               }
+       tmp = OPENSSL_malloc(inlen);
+       /* setup IV by decrypting last two blocks */
+       EVP_DecryptUpdate(ctx, tmp + inlen - 2 * blocklen, &outl,
+                               in  + inlen - 2 * blocklen, blocklen * 2);
+       /* Do a decrypt of last decrypted block to set IV to correct value
+        * output it to start of buffer so we don't corrupt decrypted block
+        * this works because buffer is at least two block lengths long.
+        */
+       EVP_DecryptUpdate(ctx, tmp, &outl,
+                               tmp  + inlen - blocklen, blocklen);
+       /* Can now decrypt first n - 1 blocks */
+       EVP_DecryptUpdate(ctx, tmp, &outl, in, inlen - blocklen);
+
+       /* Reset IV to original value */
+       EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, NULL);
+       /* Decrypt again */
+       EVP_DecryptUpdate(ctx, tmp, &outl, tmp, inlen);
+       /* Check check bytes */
+       if (((tmp[1] ^ tmp[4]) & (tmp[2] ^ tmp[5]) & (tmp[3] ^ tmp[6])) != 0xff)
+               {
+               /* Check byte failure */
+               goto err;
+               }
+       if (inlen < (size_t)(tmp[0] - 4 ))
+               {
+               /* Invalid length value */
+               goto err;
+               }
+       *outlen = (size_t)tmp[0];
+       memcpy(out, tmp + 4, *outlen);
+       rv = 1;
+       err:
+       OPENSSL_cleanse(tmp, inlen);
+       OPENSSL_free(tmp);
+       return rv;
+
+       }
+
+static int kek_wrap_key(unsigned char *out, size_t *outlen,
+               const unsigned char *in, size_t inlen, EVP_CIPHER_CTX *ctx)
+       {
+       size_t blocklen = EVP_CIPHER_CTX_block_size(ctx);
+       size_t olen;
+       int dummy;
+       /* First decide length of output buffer: need header and round up to
+        * multiple of block length.
+        */
+       olen = (inlen + 4 + blocklen - 1)/blocklen;
+       olen *= blocklen;
+       if (olen < 2 * blocklen)
+               {
+               /* Key too small */
+               return 0;
+               }
+       if (inlen > 0xFF)
+               {
+               /* Key too large */
+               return 0;
+               }
+       if (out)
+               {
+               /* Set header */
+               out[0] = (unsigned char)inlen;
+               out[1] = in[0] ^ 0xFF;
+               out[2] = in[1] ^ 0xFF;
+               out[3] = in[2] ^ 0xFF;
+               memcpy(out + 4, in, inlen);
+               /* Add random padding to end */
+               if (olen > inlen + 4)
+                       RAND_pseudo_bytes(out + 4 + inlen, olen - 4 - inlen);
+               /* Encrypt twice */
+               EVP_EncryptUpdate(ctx, out, &dummy, out, olen);
+               EVP_EncryptUpdate(ctx, out, &dummy, out, olen);
+               }
+
+       *outlen = olen;
+
+       return 1;
+       }
+
+/* Encrypt/Decrypt content key in PWRI recipient info */
+
+int cms_RecipientInfo_pwri_crypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
+                                                       int en_de)
+       {
+       CMS_EncryptedContentInfo *ec;
+       CMS_PasswordRecipientInfo *pwri;
+       const unsigned char *p = NULL;
+       int plen;
+       int r = 0;
+       X509_ALGOR *algtmp, *kekalg = NULL;
+       EVP_CIPHER_CTX kekctx;
+       const EVP_CIPHER *kekcipher;
+       unsigned char *key = NULL;
+       size_t keylen;
+
+       ec = cms->d.envelopedData->encryptedContentInfo;
+
+       pwri = ri->d.pwri;
+       EVP_CIPHER_CTX_init(&kekctx);
+
+       if (!pwri->pass)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, CMS_R_NO_PASSWORD);
+               return 0;
+               }
+       algtmp = pwri->keyEncryptionAlgorithm;
+
+       if (!algtmp || OBJ_obj2nid(algtmp->algorithm) != NID_id_alg_PWRI_KEK)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                               CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
+               return 0;
+               }
+
+       if (algtmp->parameter->type == V_ASN1_SEQUENCE)
+               {
+               p = algtmp->parameter->value.sequence->data;
+               plen = algtmp->parameter->value.sequence->length;
+               kekalg = d2i_X509_ALGOR(NULL, &p, plen);
+               }
+       if (kekalg == NULL)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                               CMS_R_INVALID_KEY_ENCRYPTION_PARAMETER);
+               return 0;
+               }
+
+       kekcipher = EVP_get_cipherbyobj(kekalg->algorithm);
+               
+       if(!kekcipher)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                               CMS_R_UNKNOWN_CIPHER);
+               goto err;
+               }
+
+       /* Fixup cipher based on AlgorithmIdentifier to set IV etc */
+       if (!EVP_CipherInit_ex(&kekctx, kekcipher, NULL, NULL, NULL, en_de))
+               goto err;
+       EVP_CIPHER_CTX_set_padding(&kekctx, 0);
+       if(EVP_CIPHER_asn1_to_param(&kekctx, kekalg->parameter) < 0)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
+               goto err;
+               }
+
+       algtmp = pwri->keyDerivationAlgorithm;
+
+       /* Finish password based key derivation to setup key in "ctx" */
+
+       if (EVP_PBE_CipherInit(algtmp->algorithm,
+                               (char *)pwri->pass, pwri->passlen,
+                               algtmp->parameter, &kekctx, en_de) < 0)
+               {
+               CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT, ERR_R_EVP_LIB);
+               goto err;
+               }
+
+       /* Finally wrap/unwrap the key */
+
+       if (en_de)
+               {
+
+               if (!kek_wrap_key(NULL, &keylen, ec->key, ec->keylen, &kekctx))
+                       goto err;
+
+               key = OPENSSL_malloc(keylen);
+
+               if (!key)
+                       goto err;
+
+               if (!kek_wrap_key(key, &keylen, ec->key, ec->keylen, &kekctx))
+                       goto err;
+               pwri->encryptedKey->data = key;
+               pwri->encryptedKey->length = keylen;
+               }
+       else
+               {
+               key = OPENSSL_malloc(pwri->encryptedKey->length);
+
+               if (!key)
+                       {
+                       CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                                                       ERR_R_MALLOC_FAILURE);
+                       goto err;
+                       }
+               if (!kek_unwrap_key(key, &keylen,
+                                       pwri->encryptedKey->data,
+                                       pwri->encryptedKey->length, &kekctx))
+                       {
+                       CMSerr(CMS_F_CMS_RECIPIENTINFO_PWRI_CRYPT,
+                                                       CMS_R_UNWRAP_FAILURE);
+                       goto err;
+                       }
+
+               ec->key = key;
+               ec->keylen = keylen;
+
+               }
+
+       r = 1;
+
+       err:
+
+       EVP_CIPHER_CTX_cleanup(&kekctx);
+
+       if (!r && key)
+               OPENSSL_free(key);
+       X509_ALGOR_free(kekalg);
+
+       return r;
+
+       }
index 4a799eb..ab38a25 100644 (file)
@@ -680,6 +680,30 @@ int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
        return 0;
 
        }
+
+int CMS_decrypt_set1_password(CMS_ContentInfo *cms, 
+                               unsigned char *pass, ssize_t passlen)
+       {
+       STACK_OF(CMS_RecipientInfo) *ris;
+       CMS_RecipientInfo *ri;
+       int i, r;
+       ris = CMS_get0_RecipientInfos(cms);
+       for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+               {
+               ri = sk_CMS_RecipientInfo_value(ris, i);
+               if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_PASS)
+                               continue;
+               CMS_RecipientInfo_set0_password(ri, pass, passlen);
+               r = CMS_RecipientInfo_decrypt(cms, ri);
+               CMS_RecipientInfo_set0_password(ri, NULL, 0);
+               if (r > 0)
+                       return 1;
+               }
+
+       CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
+       return 0;
+
+       }
        
 int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
                                BIO *dcont, BIO *out,
index 3f018f7..620c551 100644 (file)
@@ -344,6 +344,10 @@ struct evp_pkey_method_st
 
 void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
 
+int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+                            ASN1_TYPE *param,
+                            const EVP_CIPHER *c, const EVP_MD *md, int en_de);
+
 #ifdef OPENSSL_FIPS
 #define RIPEMD160_Init private_RIPEMD160_Init
 #define WHIRLPOOL_Init private_WHIRLPOOL_Init
index c9d932d..f8c32d8 100644 (file)
@@ -61,6 +61,7 @@
 #include <openssl/evp.h>
 #include <openssl/pkcs12.h>
 #include <openssl/x509.h>
+#include "evp_locl.h"
 
 /* Password based encryption (PBE) functions */
 
@@ -87,6 +88,10 @@ static const EVP_PBE_CTL builtin_pbe[] =
        {EVP_PBE_TYPE_OUTER, NID_pbeWithSHA1AndRC2_CBC,
                        NID_rc2_64_cbc, NID_sha1, PKCS5_PBE_keyivgen},
 
+#ifndef OPENSSL_NO_HMAC
+       {EVP_PBE_TYPE_OUTER, NID_id_pbkdf2, -1, -1, PKCS5_v2_PBKDF2_keyivgen},
+#endif
+
        {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And128BitRC4,
                        NID_rc4, NID_sha1, PKCS12_PBE_keyivgen},
        {EVP_PBE_TYPE_OUTER, NID_pbe_WithSHA1And40BitRC4,
index 01b6b50..176e93e 100644 (file)
@@ -62,6 +62,7 @@
 #include <openssl/x509.h>
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
+#include "evp_locl.h"
 
 /* set this to print out info about the keygen algorithm */
 /* #define DEBUG_PKCS5V2 */
@@ -172,27 +173,24 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
                          ASN1_TYPE *param, const EVP_CIPHER *c, const EVP_MD *md,
                          int en_de)
 {
-       unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
        const unsigned char *pbuf;
-       int saltlen, iter, plen;
-       unsigned int keylen;
+       int plen;
        PBE2PARAM *pbe2 = NULL;
        const EVP_CIPHER *cipher;
-       PBKDF2PARAM *kdf = NULL;
-       const EVP_MD *prfmd;
-       int prf_nid, hmac_md_nid;
+
+       int rv = 0;
 
        if (param == NULL || param->type != V_ASN1_SEQUENCE ||
            param->value.sequence == NULL) {
                EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
-               return 0;
+               goto err;
        }
 
        pbuf = param->value.sequence->data;
        plen = param->value.sequence->length;
        if(!(pbe2 = d2i_PBE2PARAM(NULL, &pbuf, plen))) {
                EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
-               return 0;
+               goto err;
        }
 
        /* See if we recognise the key derivation function */
@@ -216,41 +214,62 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
 
        /* Fixup cipher based on AlgorithmIdentifier */
        if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, en_de))
-               {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, ERR_R_EVP_LIB);
                goto err;
-               }
        if(EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter) < 0) {
                EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
                                        EVP_R_CIPHER_PARAMETER_ERROR);
                goto err;
        }
+       rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass, passlen,
+                                       pbe2->keyfunc->parameter, c, md, en_de);
+       err:
+       PBE2PARAM_free(pbe2);
+       return rv;
+}
+
+int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+                         ASN1_TYPE *param,
+                        const EVP_CIPHER *c, const EVP_MD *md, int en_de)
+{
+       unsigned char *salt, key[EVP_MAX_KEY_LENGTH];
+       const unsigned char *pbuf;
+       int saltlen, iter, plen;
+       int rv = 0;
+       unsigned int keylen;
+       int prf_nid, hmac_md_nid;
+       PBKDF2PARAM *kdf = NULL;
+       const EVP_MD *prfmd;
+
+       if (EVP_CIPHER_CTX_cipher(ctx) == NULL)
+               {
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_NO_CIPHER_SET);
+               goto err;
+               }
        keylen = EVP_CIPHER_CTX_key_length(ctx);
        OPENSSL_assert(keylen <= sizeof key);
 
-       /* Now decode key derivation function */
+       /* Decode parameter */
 
-       if(!pbe2->keyfunc->parameter ||
-                (pbe2->keyfunc->parameter->type != V_ASN1_SEQUENCE))
+       if(!param || (param->type != V_ASN1_SEQUENCE))
                {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_DECODE_ERROR);
                goto err;
                }
 
-       pbuf = pbe2->keyfunc->parameter->value.sequence->data;
-       plen = pbe2->keyfunc->parameter->value.sequence->length;
+       pbuf = param->value.sequence->data;
+       plen = param->value.sequence->length;
+
        if(!(kdf = d2i_PBKDF2PARAM(NULL, &pbuf, plen)) ) {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,EVP_R_DECODE_ERROR);
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,EVP_R_DECODE_ERROR);
                goto err;
        }
 
-       PBE2PARAM_free(pbe2);
-       pbe2 = NULL;
+       keylen = EVP_CIPHER_CTX_key_length(ctx);
 
        /* Now check the parameters of the kdf */
 
        if(kdf->keylength && (ASN1_INTEGER_get(kdf->keylength) != (int)keylen)){
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,
                                                EVP_R_UNSUPPORTED_KEYLENGTH);
                goto err;
        }
@@ -262,19 +281,19 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
 
        if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, prf_nid, NULL, &hmac_md_nid, 0))
                {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
                goto err;
                }
 
        prfmd = EVP_get_digestbynid(hmac_md_nid);
        if (prfmd == NULL)
                {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN, EVP_R_UNSUPPORTED_PRF);
                goto err;
                }
 
        if(kdf->salt->type != V_ASN1_OCTET_STRING) {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN,
+               EVPerr(EVP_F_PKCS5_V2_PBKDF2_KEYIVGEN,
                                                EVP_R_UNSUPPORTED_SALT_TYPE);
                goto err;
        }
@@ -286,19 +305,11 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
        if(!PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, prfmd,
                                                   keylen, key))
                goto err;
-       if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de))
-               {
-               EVPerr(EVP_F_PKCS5_V2_PBE_KEYIVGEN, ERR_R_EVP_LIB);
-               goto err;
-               }
-       OPENSSL_cleanse(key, keylen);
-       PBKDF2PARAM_free(kdf);
-       return 1;
-
+       rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
        err:
-       PBE2PARAM_free(pbe2);
+       OPENSSL_cleanse(key, keylen);
        PBKDF2PARAM_free(kdf);
-       return 0;
+       return rv;
 }
 
 #ifdef DEBUG_PKCS5V2
index 62740eb..243748c 100644 (file)
@@ -1162,6 +1162,9 @@ X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
                                 unsigned char *salt, int saltlen,
                                 unsigned char *aiv, int prf_nid);
 
+X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
+                               int prf_nid, int keylen);
+
 /* PKCS#8 utilities */
 
 DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)