LIB=$(TOP)/libcrypto.a
LIBSRC=aes_core.c aes_misc.c aes_ecb.c aes_cbc.c aes_cfb.c aes_ofb.c \
- aes_ctr.c aes_ige.c
-LIBOBJ=aes_misc.o aes_ecb.o aes_cfb.o aes_ofb.o aes_ctr.o aes_ige.o \
+ aes_ctr.c aes_ige.c aes_wrap.c
+LIBOBJ=aes_misc.o aes_ecb.o aes_cfb.o aes_ofb.o aes_ctr.o aes_ige.o aes_wrap.o \
$(AES_ENC)
SRC= $(LIBSRC)
const AES_KEY *key2, const unsigned char *ivec,
const int enc);
+int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
+ unsigned char *out,
+ const unsigned char *in, unsigned int inlen);
+int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
+ unsigned char *out,
+ const unsigned char *in, unsigned int inlen);
+
#ifdef __cplusplus
}
#include <openssl/aes.h>
#include <openssl/bio.h>
+static const unsigned char default_iv[] = {
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+};
+
int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
unsigned char *out,
const unsigned char *in, unsigned int inlen)
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
-static const unsigned char default_iv[] = {
- 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
-};
-
static const unsigned char e1[] = {
0x1f, 0xa6, 0x8b, 0x0a, 0x81, 0x12, 0xb4, 0x47,
0xae, 0xf3, 0x4b, 0xd8, 0xfb, 0x5a, 0x7b, 0x82,
CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
X509 *recip, unsigned int flags);
+int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey);
int CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert);
int CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
EVP_PKEY **pk, X509 **recip,
ASN1_OCTET_STRING **keyid,
X509_NAME **issuer, ASN1_INTEGER **sno);
-int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
- EVP_PKEY *pkey);
+int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri);
int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
unsigned int flags);
#define CMS_F_CMS_GET0_REVOCATION_CHOICES 120
#define CMS_F_CMS_GET0_SIGNED 121
#define CMS_F_CMS_RECIPIENTINFO_DECRYPT 150
+#define CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT 161
+#define CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT 162
#define CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID 158
#define CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP 122
+#define CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT 160
#define CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT 155
#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS 123
#define CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID 124
+#define CMS_F_CMS_RECIPIENTINFO_SET0_KEY 163
+#define CMS_F_CMS_RECIPIENTINFO_SET0_PKEY 159
#define CMS_F_CMS_SET1_SIGNERIDENTIFIER 125
#define CMS_F_CMS_SET_DETACHED 126
#define CMS_F_CMS_SIGN 127
#define CMS_R_CTRL_FAILURE 108
#define CMS_R_ERROR_GETTING_PUBLIC_KEY 109
#define CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE 110
+#define CMS_R_ERROR_SETTING_KEY 155
#define CMS_R_ERROR_SETTING_RECIPIENTINFO 150
+#define CMS_R_INVALID_ENCRYPTED_KEY_LENGTH 156
#define CMS_R_INVALID_KEY_LENGTH 140
#define CMS_R_MD_BIO_INIT_ERROR 111
#define CMS_R_MESSAGEDIGEST_ATTRIBUTE_WRONG_LENGTH 112
#define CMS_R_UNSUPPORTED_CONTENT_TYPE 135
#define CMS_R_UNSUPPORTED_KEK_ALGORITHM 153
#define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 151
+#define CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE 154
#define CMS_R_UNSUPPORTED_TYPE 136
+#define CMS_R_UNWRAP_ERROR 157
#define CMS_R_VERIFICATION_FAILURE 137
+#define CMS_R_WRAP_ERROR 158
#ifdef __cplusplus
}
#include <openssl/err.h>
#include <openssl/cms.h>
#include <openssl/rand.h>
+#include <openssl/aes.h>
#include "cms_lcl.h"
#include "asn1_locl.h"
return 1;
}
+/* For now hard code AES key wrap info */
+
+static int aes_wrap_keylen(int nid)
+ {
+ switch (nid)
+ {
+ case NID_id_aes128_wrap:
+ return 16;
+
+ case NID_id_aes192_wrap:
+ return 24;
+
+ case NID_id_aes256_wrap:
+ return 32;
+
+ default:
+ return 0;
+ }
+ }
+
CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
unsigned char *key, size_t keylen,
if (!env)
goto err;
- /* For now hard code checks on nids */
- switch (nid)
- {
- case NID_id_aes128_wrap:
- exp_keylen = 16;
- break;
+ exp_keylen = aes_wrap_keylen(nid);
- case NID_id_aes192_wrap:
- exp_keylen = 24;
- break;
-
- case NID_id_aes256_wrap:
- exp_keylen = 32;
- break;
-
- default:
+ if (!exp_keylen)
+ {
CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
CMS_R_UNSUPPORTED_KEK_ALGORITHM);
goto err;
}
- if (exp_keylen && (keylen != exp_keylen))
+ if (keylen != exp_keylen)
{
- CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
- CMS_R_INVALID_KEY_LENGTH);
+ CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
goto err;
}
CMS_R_NOT_KEY_TRANSPORT);
return -2;
}
-
return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
}
+int CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
+ {
+ if (ri->type != CMS_RECIPINFO_TRANS)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY,
+ CMS_R_NOT_KEY_TRANSPORT);
+ return 0;
+ }
+ ri->d.ktri->pkey = pkey;
+ return 1;
+ }
+
+int CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
+ unsigned char *key, size_t keylen)
+ {
+ CMS_KEKRecipientInfo *kekri;
+ int wrap_nid;
+ if (ri->type != CMS_RECIPINFO_KEK)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK);
+ return 0;
+ }
+ wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
+ if (aes_wrap_keylen(wrap_nid) != keylen)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY,
+ CMS_R_INVALID_KEY_LENGTH);
+ return 0;
+ }
+ kekri->key = key;
+ kekri->keylen = keylen;
+ return 1;
+ }
+
/* Encrypt content key in key transport recipient info */
static int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
}
-int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
- EVP_PKEY *pkey)
+static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
{
- CMS_KeyTransRecipientInfo *ktri;
+ CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
EVP_PKEY_CTX *pctx = NULL;
unsigned char *ek = NULL;
size_t eklen;
+ int ret;
- int ret = 0;
-
- if (ri->type != CMS_RECIPINFO_TRANS)
+ if (ktri->pkey == NULL)
{
- CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
- CMS_R_NOT_KEY_TRANSPORT);
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
+ CMS_R_NO_PRIVATE_KEY);
return 0;
}
- ktri = ri->d.ktri;
- pctx = EVP_PKEY_CTX_new(pkey, NULL);
+ pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
if (!pctx)
return 0;
if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0)
{
- CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, CMS_R_CTRL_ERROR);
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
goto err;
}
if (ek == NULL)
{
- CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, ERR_R_MALLOC_FAILURE);
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT,
+ ERR_R_MALLOC_FAILURE);
goto err;
}
ktri->encryptedKey->data,
ktri->encryptedKey->length) <= 0)
{
- CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT, CMS_R_CMS_LIB);
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
goto err;
}
return ret;
}
+
+/* Encrypt content key in KEK recipient info */
+
+static int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_EncryptedContentInfo *ec;
+ CMS_KEKRecipientInfo *kekri;
+ AES_KEY actx;
+ unsigned char *wkey = NULL;
+ int wkeylen;
+ int r = 0;
+
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ kekri = ri->d.kekri;
+
+ if (!kekri->key)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
+ return 0;
+ }
+
+ if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx))
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
+ CMS_R_ERROR_SETTING_KEY);
+ goto err;
+ }
+
+ wkey = OPENSSL_malloc(ec->keylen + 8);
+
+ if (!wkey)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
+
+ if (wkeylen <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
+ goto err;
+ }
+
+ ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
+
+ r = 1;
+
+ err:
+
+ if (!r && wkey)
+ OPENSSL_free(wkey);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+
+ return r;
+
+ }
+
+static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
+ CMS_RecipientInfo *ri)
+ {
+ CMS_EncryptedContentInfo *ec;
+ CMS_KEKRecipientInfo *kekri;
+ AES_KEY actx;
+ unsigned char *ukey = NULL;
+ int ukeylen;
+ int r = 0;
+
+ ec = cms->d.envelopedData->encryptedContentInfo;
+
+ kekri = ri->d.kekri;
+
+ if (!kekri->key)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY);
+ return 0;
+ }
+
+ /* If encrypted key length is invalid don't bother */
+
+ if (kekri->encryptedKey->length < 16)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
+ goto err;
+ }
+
+ if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx))
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_ERROR_SETTING_KEY);
+ goto err;
+ }
+
+ ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
+
+ if (!ukey)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ ukeylen = AES_unwrap_key(&actx, NULL, ukey,
+ kekri->encryptedKey->data,
+ kekri->encryptedKey->length);
+
+ if (ukeylen <= 0)
+ {
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
+ CMS_R_UNWRAP_ERROR);
+ goto err;
+ }
+
+ ec->key = ukey;
+ ec->keylen = ukeylen;
+
+ r = 1;
+
+ err:
+
+ if (!r && ukey)
+ OPENSSL_free(ukey);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+
+ return r;
+
+ }
+
+int CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
+ {
+ switch(ri->type)
+ {
+ case CMS_RECIPINFO_TRANS:
+ return cms_RecipientInfo_ktri_decrypt(cms, ri);
+
+ case CMS_RECIPINFO_KEK:
+ return cms_RecipientInfo_kekri_decrypt(cms, ri);
+
+ default:
+ CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
+ CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
+ return 0;
+ }
+ }
+
BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
{
CMS_EncryptedContentInfo *ec;
if (!ret || !ec->cipher)
return ret;
-
rinfos = cms->d.envelopedData->recipientInfos;
for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++)
{
ri = sk_CMS_RecipientInfo_value(rinfos, i);
- if (ri->type == CMS_RECIPINFO_TRANS)
- r = cms_RecipientInfo_ktri_encrypt(cms, ri);
- else
+
+ switch (ri->type)
{
+ case CMS_RECIPINFO_TRANS:
+ r = cms_RecipientInfo_ktri_encrypt(cms, ri);
+ break;
+
+ case CMS_RECIPINFO_KEK:
+ r = cms_RecipientInfo_kekri_encrypt(cms, ri);
+ break;
+
+ default:
CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
goto err;
}
+
if (r <= 0)
{
CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
{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_RECIPIENTINFO_DECRYPT), "CMS_RecipientInfo_decrypt"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT), "CMS_RECIPIENTINFO_KEKRI_DECRYPT"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT), "CMS_RECIPIENTINFO_KEKRI_ENCRYPT"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID), "CMS_RECIPIENTINFO_KEKRI_GET0_ID"},
{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP), "CMS_RecipientInfo_ktri_cert_cmp"},
+{ERR_FUNC(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT), "CMS_RECIPIENTINFO_KTRI_DECRYPT"},
{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_SET0_KEY), "CMS_RECIPIENTINFO_SET0_KEY"},
+{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"},
{ERR_FUNC(CMS_F_CMS_SIGN), "CMS_sign"},
{ERR_REASON(CMS_R_CTRL_FAILURE) ,"ctrl failure"},
{ERR_REASON(CMS_R_ERROR_GETTING_PUBLIC_KEY),"error getting public key"},
{ERR_REASON(CMS_R_ERROR_READING_MESSAGEDIGEST_ATTRIBUTE),"error reading messagedigest attribute"},
+{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_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"},
{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_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_VERIFICATION_FAILURE) ,"verification failure"},
+{ERR_REASON(CMS_R_WRAP_ERROR) ,"wrap error"},
{0,NULL}
};
BIO *dcont, BIO *out,
unsigned int flags)
{
- STACK_OF(CMS_RecipientInfo) *ris;
- CMS_RecipientInfo *ri;
int i, r;
BIO *cont;
if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped)
}
if (!dcont && !check_content(cms))
return 0;
- ris = CMS_get0_RecipientInfos(cms);
- for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
+ if (pk)
{
- ri = sk_CMS_RecipientInfo_value(ris, i);
- if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
- continue;
- /* If we have a cert try matching RecipientInfo otherwise
- * try them all.
- */
- if (!cert || (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
+ STACK_OF(CMS_RecipientInfo) *ris;
+ CMS_RecipientInfo *ri;
+ ris = CMS_get0_RecipientInfos(cms);
+ for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++)
{
- if (CMS_RecipientInfo_decrypt(cms, ri, pk) > 0)
- break;
- else if (cert)
- return 0;
+ ri = sk_CMS_RecipientInfo_value(ris, i);
+ if (CMS_RecipientInfo_type(ri) != CMS_RECIPINFO_TRANS)
+ continue;
+ /* If we have a cert try matching RecipientInfo
+ * otherwise try them all.
+ */
+ if (!cert ||
+ (CMS_RecipientInfo_ktri_cert_cmp(ri, cert) == 0))
+ {
+ CMS_RecipientInfo_set0_pkey(ri, pk);
+ r = CMS_RecipientInfo_decrypt(cms, ri);
+ CMS_RecipientInfo_set0_pkey(ri, NULL);
+ if (r > 0)
+ break;
+ if (cert)
+ return 0;
+ }
}
- }
- if (i == sk_CMS_RecipientInfo_num(ris))
- {
- CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT);
- return 0;
+ if (i == sk_CMS_RecipientInfo_num(ris))
+ {
+ CMSerr(CMS_F_CMS_DECRYPT, CMS_R_NO_MATCHING_RECIPIENT);
+ return 0;
+ }
}
cont = CMS_dataInit(cms, dcont);
if (!cont)