Backport of password based CMS support from HEAD.

This commit is contained in:
Dr. Stephen Henson 2011-10-09 15:28:02 +00:00
parent 6f6b31dadc
commit dc100d87b5
17 changed files with 733 additions and 93 deletions

10
CHANGES
View File

@ -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.

View 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)

View 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

View 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"},

View 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;
}
if(alg_nid == NID_rc2_cbc)
keylen = EVP_CIPHER_key_length(cipher);
else
keylen = -1;
/* 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);
}
/* Setup keyfunc */
/* Now setup the PBE2PARAM keyfunc structure */
pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen);
pbe2->keyfunc->algorithm = OBJ_nid2obj(NID_id_pbkdf2);
/* Encode PBKDF2PARAM into parameter of pbe2 */
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;
}

View 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)

View 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

View 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;
}

View File

@ -65,14 +65,13 @@
/* 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);

View 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}

View 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
}

453
crypto/cms/cms_pwri.c Normal file
View File

@ -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;
}

View 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,

View 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

View 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,

View 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;
}
rv = EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, en_de);
err:
OPENSSL_cleanse(key, keylen);
PBKDF2PARAM_free(kdf);
return 1;
err:
PBE2PARAM_free(pbe2);
PBKDF2PARAM_free(kdf);
return 0;
return rv;
}
#ifdef DEBUG_PKCS5V2

View 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)