1183234Ssimon/* crypto/cms/cms_env.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8183234Ssimon *
9183234Ssimon * Redistribution and use in source and binary forms, with or without
10183234Ssimon * modification, are permitted provided that the following conditions
11183234Ssimon * are met:
12183234Ssimon *
13183234Ssimon * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15183234Ssimon *
16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17183234Ssimon *    notice, this list of conditions and the following disclaimer in
18183234Ssimon *    the documentation and/or other materials provided with the
19183234Ssimon *    distribution.
20183234Ssimon *
21183234Ssimon * 3. All advertising materials mentioning features or use of this
22183234Ssimon *    software must display the following acknowledgment:
23183234Ssimon *    "This product includes software developed by the OpenSSL Project
24183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25183234Ssimon *
26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27183234Ssimon *    endorse or promote products derived from this software without
28183234Ssimon *    prior written permission. For written permission, please contact
29183234Ssimon *    licensing@OpenSSL.org.
30183234Ssimon *
31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
33183234Ssimon *    permission of the OpenSSL Project.
34183234Ssimon *
35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
36183234Ssimon *    acknowledgment:
37183234Ssimon *    "This product includes software developed by the OpenSSL Project
38183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39183234Ssimon *
40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52183234Ssimon * ====================================================================
53183234Ssimon */
54183234Ssimon
55183234Ssimon#include "cryptlib.h"
56183234Ssimon#include <openssl/asn1t.h>
57183234Ssimon#include <openssl/pem.h>
58183234Ssimon#include <openssl/x509v3.h>
59183234Ssimon#include <openssl/err.h>
60183234Ssimon#include <openssl/cms.h>
61183234Ssimon#include <openssl/rand.h>
62183234Ssimon#include <openssl/aes.h>
63183234Ssimon#include "cms_lcl.h"
64238405Sjkim#include "asn1_locl.h"
65183234Ssimon
66183234Ssimon/* CMS EnvelopedData Utilities */
67183234Ssimon
68183234SsimonDECLARE_ASN1_ITEM(CMS_EnvelopedData)
69183234SsimonDECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
70183234SsimonDECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
71183234SsimonDECLARE_ASN1_ITEM(CMS_OtherKeyAttribute)
72183234Ssimon
73183234SsimonDECLARE_STACK_OF(CMS_RecipientInfo)
74183234Ssimon
75238405SjkimCMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
76280304Sjkim{
77280304Sjkim    if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
78280304Sjkim        CMSerr(CMS_F_CMS_GET0_ENVELOPED,
79280304Sjkim               CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
80280304Sjkim        return NULL;
81280304Sjkim    }
82280304Sjkim    return cms->d.envelopedData;
83280304Sjkim}
84183234Ssimon
85183234Ssimonstatic CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
86280304Sjkim{
87280304Sjkim    if (cms->d.other == NULL) {
88280304Sjkim        cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
89280304Sjkim        if (!cms->d.envelopedData) {
90280304Sjkim            CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE);
91280304Sjkim            return NULL;
92280304Sjkim        }
93280304Sjkim        cms->d.envelopedData->version = 0;
94280304Sjkim        cms->d.envelopedData->encryptedContentInfo->contentType =
95280304Sjkim            OBJ_nid2obj(NID_pkcs7_data);
96280304Sjkim        ASN1_OBJECT_free(cms->contentType);
97280304Sjkim        cms->contentType = OBJ_nid2obj(NID_pkcs7_enveloped);
98280304Sjkim        return cms->d.envelopedData;
99280304Sjkim    }
100280304Sjkim    return cms_get0_enveloped(cms);
101280304Sjkim}
102183234Ssimon
103183234SsimonSTACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
104280304Sjkim{
105280304Sjkim    CMS_EnvelopedData *env;
106280304Sjkim    env = cms_get0_enveloped(cms);
107280304Sjkim    if (!env)
108280304Sjkim        return NULL;
109280304Sjkim    return env->recipientInfos;
110280304Sjkim}
111183234Ssimon
112183234Ssimonint CMS_RecipientInfo_type(CMS_RecipientInfo *ri)
113280304Sjkim{
114280304Sjkim    return ri->type;
115280304Sjkim}
116183234Ssimon
117183234SsimonCMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
118280304Sjkim{
119280304Sjkim    CMS_ContentInfo *cms;
120280304Sjkim    CMS_EnvelopedData *env;
121280304Sjkim    cms = CMS_ContentInfo_new();
122280304Sjkim    if (!cms)
123280304Sjkim        goto merr;
124280304Sjkim    env = cms_enveloped_data_init(cms);
125280304Sjkim    if (!env)
126280304Sjkim        goto merr;
127280304Sjkim    if (!cms_EncryptedContent_init(env->encryptedContentInfo,
128280304Sjkim                                   cipher, NULL, 0))
129280304Sjkim        goto merr;
130280304Sjkim    return cms;
131280304Sjkim merr:
132280304Sjkim    if (cms)
133280304Sjkim        CMS_ContentInfo_free(cms);
134280304Sjkim    CMSerr(CMS_F_CMS_ENVELOPEDDATA_CREATE, ERR_R_MALLOC_FAILURE);
135280304Sjkim    return NULL;
136280304Sjkim}
137183234Ssimon
138183234Ssimon/* Key Transport Recipient Info (KTRI) routines */
139183234Ssimon
140280304Sjkim/*
141280304Sjkim * Add a recipient certificate. For now only handle key transport. If we ever
142280304Sjkim * handle key agreement will need updating.
143183234Ssimon */
144183234Ssimon
145183234SsimonCMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
146280304Sjkim                                           X509 *recip, unsigned int flags)
147280304Sjkim{
148280304Sjkim    CMS_RecipientInfo *ri = NULL;
149280304Sjkim    CMS_KeyTransRecipientInfo *ktri;
150280304Sjkim    CMS_EnvelopedData *env;
151280304Sjkim    EVP_PKEY *pk = NULL;
152280304Sjkim    int i, type;
153280304Sjkim    env = cms_get0_enveloped(cms);
154280304Sjkim    if (!env)
155280304Sjkim        goto err;
156183234Ssimon
157280304Sjkim    /* Initialize recipient info */
158280304Sjkim    ri = M_ASN1_new_of(CMS_RecipientInfo);
159280304Sjkim    if (!ri)
160280304Sjkim        goto merr;
161183234Ssimon
162280304Sjkim    /* Initialize and add key transport recipient info */
163183234Ssimon
164280304Sjkim    ri->d.ktri = M_ASN1_new_of(CMS_KeyTransRecipientInfo);
165280304Sjkim    if (!ri->d.ktri)
166280304Sjkim        goto merr;
167280304Sjkim    ri->type = CMS_RECIPINFO_TRANS;
168183234Ssimon
169280304Sjkim    ktri = ri->d.ktri;
170183234Ssimon
171280304Sjkim    X509_check_purpose(recip, -1, -1);
172280304Sjkim    pk = X509_get_pubkey(recip);
173280304Sjkim    if (!pk) {
174280304Sjkim        CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_ERROR_GETTING_PUBLIC_KEY);
175280304Sjkim        goto err;
176280304Sjkim    }
177280304Sjkim    CRYPTO_add(&recip->references, 1, CRYPTO_LOCK_X509);
178280304Sjkim    ktri->pkey = pk;
179280304Sjkim    ktri->recip = recip;
180183234Ssimon
181280304Sjkim    if (flags & CMS_USE_KEYID) {
182280304Sjkim        ktri->version = 2;
183280304Sjkim        if (env->version < 2)
184280304Sjkim            env->version = 2;
185280304Sjkim        type = CMS_RECIPINFO_KEYIDENTIFIER;
186280304Sjkim    } else {
187280304Sjkim        ktri->version = 0;
188280304Sjkim        type = CMS_RECIPINFO_ISSUER_SERIAL;
189280304Sjkim    }
190183234Ssimon
191280304Sjkim    /*
192280304Sjkim     * Not a typo: RecipientIdentifier and SignerIdentifier are the same
193280304Sjkim     * structure.
194280304Sjkim     */
195183234Ssimon
196280304Sjkim    if (!cms_set1_SignerIdentifier(ktri->rid, recip, type))
197280304Sjkim        goto err;
198183234Ssimon
199280304Sjkim    if (pk->ameth && pk->ameth->pkey_ctrl) {
200280304Sjkim        i = pk->ameth->pkey_ctrl(pk, ASN1_PKEY_CTRL_CMS_ENVELOPE, 0, ri);
201280304Sjkim        if (i == -2) {
202280304Sjkim            CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT,
203280304Sjkim                   CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
204280304Sjkim            goto err;
205280304Sjkim        }
206280304Sjkim        if (i <= 0) {
207280304Sjkim            CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, CMS_R_CTRL_FAILURE);
208280304Sjkim            goto err;
209280304Sjkim        }
210280304Sjkim    }
211183234Ssimon
212280304Sjkim    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
213280304Sjkim        goto merr;
214183234Ssimon
215280304Sjkim    return ri;
216183234Ssimon
217280304Sjkim merr:
218280304Sjkim    CMSerr(CMS_F_CMS_ADD1_RECIPIENT_CERT, ERR_R_MALLOC_FAILURE);
219280304Sjkim err:
220280304Sjkim    if (ri)
221280304Sjkim        M_ASN1_free_of(ri, CMS_RecipientInfo);
222280304Sjkim    return NULL;
223183234Ssimon
224280304Sjkim}
225183234Ssimon
226183234Ssimonint CMS_RecipientInfo_ktri_get0_algs(CMS_RecipientInfo *ri,
227280304Sjkim                                     EVP_PKEY **pk, X509 **recip,
228280304Sjkim                                     X509_ALGOR **palg)
229280304Sjkim{
230280304Sjkim    CMS_KeyTransRecipientInfo *ktri;
231280304Sjkim    if (ri->type != CMS_RECIPINFO_TRANS) {
232280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_ALGS,
233280304Sjkim               CMS_R_NOT_KEY_TRANSPORT);
234280304Sjkim        return 0;
235280304Sjkim    }
236183234Ssimon
237280304Sjkim    ktri = ri->d.ktri;
238183234Ssimon
239280304Sjkim    if (pk)
240280304Sjkim        *pk = ktri->pkey;
241280304Sjkim    if (recip)
242280304Sjkim        *recip = ktri->recip;
243280304Sjkim    if (palg)
244280304Sjkim        *palg = ktri->keyEncryptionAlgorithm;
245280304Sjkim    return 1;
246280304Sjkim}
247183234Ssimon
248183234Ssimonint CMS_RecipientInfo_ktri_get0_signer_id(CMS_RecipientInfo *ri,
249280304Sjkim                                          ASN1_OCTET_STRING **keyid,
250280304Sjkim                                          X509_NAME **issuer,
251280304Sjkim                                          ASN1_INTEGER **sno)
252280304Sjkim{
253280304Sjkim    CMS_KeyTransRecipientInfo *ktri;
254280304Sjkim    if (ri->type != CMS_RECIPINFO_TRANS) {
255280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_GET0_SIGNER_ID,
256280304Sjkim               CMS_R_NOT_KEY_TRANSPORT);
257280304Sjkim        return 0;
258280304Sjkim    }
259280304Sjkim    ktri = ri->d.ktri;
260183234Ssimon
261280304Sjkim    return cms_SignerIdentifier_get0_signer_id(ktri->rid, keyid, issuer, sno);
262280304Sjkim}
263183234Ssimon
264183234Ssimonint CMS_RecipientInfo_ktri_cert_cmp(CMS_RecipientInfo *ri, X509 *cert)
265280304Sjkim{
266280304Sjkim    if (ri->type != CMS_RECIPINFO_TRANS) {
267280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_CERT_CMP,
268280304Sjkim               CMS_R_NOT_KEY_TRANSPORT);
269280304Sjkim        return -2;
270280304Sjkim    }
271280304Sjkim    return cms_SignerIdentifier_cert_cmp(ri->d.ktri->rid, cert);
272280304Sjkim}
273183234Ssimon
274183234Ssimonint CMS_RecipientInfo_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pkey)
275280304Sjkim{
276280304Sjkim    if (ri->type != CMS_RECIPINFO_TRANS) {
277280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_PKEY, CMS_R_NOT_KEY_TRANSPORT);
278280304Sjkim        return 0;
279280304Sjkim    }
280280304Sjkim    ri->d.ktri->pkey = pkey;
281280304Sjkim    return 1;
282280304Sjkim}
283183234Ssimon
284183234Ssimon/* Encrypt content key in key transport recipient info */
285183234Ssimon
286183234Ssimonstatic int cms_RecipientInfo_ktri_encrypt(CMS_ContentInfo *cms,
287280304Sjkim                                          CMS_RecipientInfo *ri)
288280304Sjkim{
289280304Sjkim    CMS_KeyTransRecipientInfo *ktri;
290280304Sjkim    CMS_EncryptedContentInfo *ec;
291280304Sjkim    EVP_PKEY_CTX *pctx = NULL;
292280304Sjkim    unsigned char *ek = NULL;
293280304Sjkim    size_t eklen;
294183234Ssimon
295280304Sjkim    int ret = 0;
296183234Ssimon
297280304Sjkim    if (ri->type != CMS_RECIPINFO_TRANS) {
298280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_NOT_KEY_TRANSPORT);
299280304Sjkim        return 0;
300280304Sjkim    }
301280304Sjkim    ktri = ri->d.ktri;
302280304Sjkim    ec = cms->d.envelopedData->encryptedContentInfo;
303183234Ssimon
304280304Sjkim    pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
305280304Sjkim    if (!pctx)
306280304Sjkim        return 0;
307183234Ssimon
308280304Sjkim    if (EVP_PKEY_encrypt_init(pctx) <= 0)
309280304Sjkim        goto err;
310238405Sjkim
311280304Sjkim    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
312280304Sjkim                          EVP_PKEY_CTRL_CMS_ENCRYPT, 0, ri) <= 0) {
313280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, CMS_R_CTRL_ERROR);
314280304Sjkim        goto err;
315280304Sjkim    }
316238405Sjkim
317280304Sjkim    if (EVP_PKEY_encrypt(pctx, NULL, &eklen, ec->key, ec->keylen) <= 0)
318280304Sjkim        goto err;
319238405Sjkim
320280304Sjkim    ek = OPENSSL_malloc(eklen);
321183234Ssimon
322280304Sjkim    if (ek == NULL) {
323280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
324280304Sjkim        goto err;
325280304Sjkim    }
326183234Ssimon
327280304Sjkim    if (EVP_PKEY_encrypt(pctx, ek, &eklen, ec->key, ec->keylen) <= 0)
328280304Sjkim        goto err;
329183234Ssimon
330280304Sjkim    ASN1_STRING_set0(ktri->encryptedKey, ek, eklen);
331280304Sjkim    ek = NULL;
332183234Ssimon
333280304Sjkim    ret = 1;
334183234Ssimon
335280304Sjkim err:
336280304Sjkim    if (pctx)
337280304Sjkim        EVP_PKEY_CTX_free(pctx);
338280304Sjkim    if (ek)
339280304Sjkim        OPENSSL_free(ek);
340280304Sjkim    return ret;
341183234Ssimon
342280304Sjkim}
343183234Ssimon
344183234Ssimon/* Decrypt content key from KTRI */
345183234Ssimon
346183234Ssimonstatic int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
347280304Sjkim                                          CMS_RecipientInfo *ri)
348280304Sjkim{
349280304Sjkim    CMS_KeyTransRecipientInfo *ktri = ri->d.ktri;
350280304Sjkim    EVP_PKEY_CTX *pctx = NULL;
351280304Sjkim    unsigned char *ek = NULL;
352280304Sjkim    size_t eklen;
353280304Sjkim    int ret = 0;
354280304Sjkim    CMS_EncryptedContentInfo *ec;
355280304Sjkim    ec = cms->d.envelopedData->encryptedContentInfo;
356183234Ssimon
357280304Sjkim    if (ktri->pkey == NULL) {
358280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY);
359280304Sjkim        return 0;
360280304Sjkim    }
361183234Ssimon
362280304Sjkim    pctx = EVP_PKEY_CTX_new(ktri->pkey, NULL);
363280304Sjkim    if (!pctx)
364280304Sjkim        return 0;
365183234Ssimon
366280304Sjkim    if (EVP_PKEY_decrypt_init(pctx) <= 0)
367280304Sjkim        goto err;
368238405Sjkim
369280304Sjkim    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
370280304Sjkim                          EVP_PKEY_CTRL_CMS_DECRYPT, 0, ri) <= 0) {
371280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CTRL_ERROR);
372280304Sjkim        goto err;
373280304Sjkim    }
374238405Sjkim
375280304Sjkim    if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
376280304Sjkim                         ktri->encryptedKey->data,
377280304Sjkim                         ktri->encryptedKey->length) <= 0)
378280304Sjkim        goto err;
379238405Sjkim
380280304Sjkim    ek = OPENSSL_malloc(eklen);
381183234Ssimon
382280304Sjkim    if (ek == NULL) {
383280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, ERR_R_MALLOC_FAILURE);
384280304Sjkim        goto err;
385280304Sjkim    }
386183234Ssimon
387280304Sjkim    if (EVP_PKEY_decrypt(pctx, ek, &eklen,
388280304Sjkim                         ktri->encryptedKey->data,
389280304Sjkim                         ktri->encryptedKey->length) <= 0) {
390280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_CMS_LIB);
391280304Sjkim        goto err;
392280304Sjkim    }
393183234Ssimon
394280304Sjkim    ret = 1;
395183234Ssimon
396280304Sjkim    if (ec->key) {
397280304Sjkim        OPENSSL_cleanse(ec->key, ec->keylen);
398280304Sjkim        OPENSSL_free(ec->key);
399280304Sjkim    }
400183234Ssimon
401280304Sjkim    ec->key = ek;
402280304Sjkim    ec->keylen = eklen;
403237657Sjkim
404280304Sjkim err:
405280304Sjkim    if (pctx)
406280304Sjkim        EVP_PKEY_CTX_free(pctx);
407280304Sjkim    if (!ret && ek)
408280304Sjkim        OPENSSL_free(ek);
409183234Ssimon
410280304Sjkim    return ret;
411280304Sjkim}
412183234Ssimon
413183234Ssimon/* Key Encrypted Key (KEK) RecipientInfo routines */
414183234Ssimon
415280304Sjkimint CMS_RecipientInfo_kekri_id_cmp(CMS_RecipientInfo *ri,
416280304Sjkim                                   const unsigned char *id, size_t idlen)
417280304Sjkim{
418280304Sjkim    ASN1_OCTET_STRING tmp_os;
419280304Sjkim    CMS_KEKRecipientInfo *kekri;
420280304Sjkim    if (ri->type != CMS_RECIPINFO_KEK) {
421280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ID_CMP, CMS_R_NOT_KEK);
422280304Sjkim        return -2;
423280304Sjkim    }
424280304Sjkim    kekri = ri->d.kekri;
425280304Sjkim    tmp_os.type = V_ASN1_OCTET_STRING;
426280304Sjkim    tmp_os.flags = 0;
427280304Sjkim    tmp_os.data = (unsigned char *)id;
428280304Sjkim    tmp_os.length = (int)idlen;
429280304Sjkim    return ASN1_OCTET_STRING_cmp(&tmp_os, kekri->kekid->keyIdentifier);
430280304Sjkim}
431183234Ssimon
432183234Ssimon/* For now hard code AES key wrap info */
433183234Ssimon
434183234Ssimonstatic size_t aes_wrap_keylen(int nid)
435280304Sjkim{
436280304Sjkim    switch (nid) {
437280304Sjkim    case NID_id_aes128_wrap:
438280304Sjkim        return 16;
439183234Ssimon
440280304Sjkim    case NID_id_aes192_wrap:
441280304Sjkim        return 24;
442183234Ssimon
443280304Sjkim    case NID_id_aes256_wrap:
444280304Sjkim        return 32;
445183234Ssimon
446280304Sjkim    default:
447280304Sjkim        return 0;
448280304Sjkim    }
449280304Sjkim}
450183234Ssimon
451183234SsimonCMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
452280304Sjkim                                          unsigned char *key, size_t keylen,
453280304Sjkim                                          unsigned char *id, size_t idlen,
454280304Sjkim                                          ASN1_GENERALIZEDTIME *date,
455280304Sjkim                                          ASN1_OBJECT *otherTypeId,
456280304Sjkim                                          ASN1_TYPE *otherType)
457280304Sjkim{
458280304Sjkim    CMS_RecipientInfo *ri = NULL;
459280304Sjkim    CMS_EnvelopedData *env;
460280304Sjkim    CMS_KEKRecipientInfo *kekri;
461280304Sjkim    env = cms_get0_enveloped(cms);
462280304Sjkim    if (!env)
463280304Sjkim        goto err;
464183234Ssimon
465280304Sjkim    if (nid == NID_undef) {
466280304Sjkim        switch (keylen) {
467280304Sjkim        case 16:
468280304Sjkim            nid = NID_id_aes128_wrap;
469280304Sjkim            break;
470183234Ssimon
471280304Sjkim        case 24:
472280304Sjkim            nid = NID_id_aes192_wrap;
473280304Sjkim            break;
474183234Ssimon
475280304Sjkim        case 32:
476280304Sjkim            nid = NID_id_aes256_wrap;
477280304Sjkim            break;
478183234Ssimon
479280304Sjkim        default:
480280304Sjkim            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
481280304Sjkim            goto err;
482280304Sjkim        }
483183234Ssimon
484280304Sjkim    } else {
485183234Ssimon
486280304Sjkim        size_t exp_keylen = aes_wrap_keylen(nid);
487183234Ssimon
488280304Sjkim        if (!exp_keylen) {
489280304Sjkim            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY,
490280304Sjkim                   CMS_R_UNSUPPORTED_KEK_ALGORITHM);
491280304Sjkim            goto err;
492280304Sjkim        }
493183234Ssimon
494280304Sjkim        if (keylen != exp_keylen) {
495280304Sjkim            CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, CMS_R_INVALID_KEY_LENGTH);
496280304Sjkim            goto err;
497280304Sjkim        }
498183234Ssimon
499280304Sjkim    }
500183234Ssimon
501280304Sjkim    /* Initialize recipient info */
502280304Sjkim    ri = M_ASN1_new_of(CMS_RecipientInfo);
503280304Sjkim    if (!ri)
504280304Sjkim        goto merr;
505183234Ssimon
506280304Sjkim    ri->d.kekri = M_ASN1_new_of(CMS_KEKRecipientInfo);
507280304Sjkim    if (!ri->d.kekri)
508280304Sjkim        goto merr;
509280304Sjkim    ri->type = CMS_RECIPINFO_KEK;
510183234Ssimon
511280304Sjkim    kekri = ri->d.kekri;
512183234Ssimon
513280304Sjkim    if (otherTypeId) {
514280304Sjkim        kekri->kekid->other = M_ASN1_new_of(CMS_OtherKeyAttribute);
515280304Sjkim        if (kekri->kekid->other == NULL)
516280304Sjkim            goto merr;
517280304Sjkim    }
518183234Ssimon
519280304Sjkim    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
520280304Sjkim        goto merr;
521183234Ssimon
522280304Sjkim    /* After this point no calls can fail */
523183234Ssimon
524280304Sjkim    kekri->version = 4;
525183234Ssimon
526280304Sjkim    kekri->key = key;
527280304Sjkim    kekri->keylen = keylen;
528183234Ssimon
529280304Sjkim    ASN1_STRING_set0(kekri->kekid->keyIdentifier, id, idlen);
530183234Ssimon
531280304Sjkim    kekri->kekid->date = date;
532183234Ssimon
533280304Sjkim    if (kekri->kekid->other) {
534280304Sjkim        kekri->kekid->other->keyAttrId = otherTypeId;
535280304Sjkim        kekri->kekid->other->keyAttr = otherType;
536280304Sjkim    }
537183234Ssimon
538280304Sjkim    X509_ALGOR_set0(kekri->keyEncryptionAlgorithm,
539280304Sjkim                    OBJ_nid2obj(nid), V_ASN1_UNDEF, NULL);
540183234Ssimon
541280304Sjkim    return ri;
542183234Ssimon
543280304Sjkim merr:
544280304Sjkim    CMSerr(CMS_F_CMS_ADD0_RECIPIENT_KEY, ERR_R_MALLOC_FAILURE);
545280304Sjkim err:
546280304Sjkim    if (ri)
547280304Sjkim        M_ASN1_free_of(ri, CMS_RecipientInfo);
548280304Sjkim    return NULL;
549183234Ssimon
550280304Sjkim}
551183234Ssimon
552183234Ssimonint CMS_RecipientInfo_kekri_get0_id(CMS_RecipientInfo *ri,
553280304Sjkim                                    X509_ALGOR **palg,
554280304Sjkim                                    ASN1_OCTET_STRING **pid,
555280304Sjkim                                    ASN1_GENERALIZEDTIME **pdate,
556280304Sjkim                                    ASN1_OBJECT **potherid,
557280304Sjkim                                    ASN1_TYPE **pothertype)
558280304Sjkim{
559280304Sjkim    CMS_KEKIdentifier *rkid;
560280304Sjkim    if (ri->type != CMS_RECIPINFO_KEK) {
561280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_GET0_ID, CMS_R_NOT_KEK);
562280304Sjkim        return 0;
563280304Sjkim    }
564280304Sjkim    rkid = ri->d.kekri->kekid;
565280304Sjkim    if (palg)
566280304Sjkim        *palg = ri->d.kekri->keyEncryptionAlgorithm;
567280304Sjkim    if (pid)
568280304Sjkim        *pid = rkid->keyIdentifier;
569280304Sjkim    if (pdate)
570280304Sjkim        *pdate = rkid->date;
571280304Sjkim    if (potherid) {
572280304Sjkim        if (rkid->other)
573280304Sjkim            *potherid = rkid->other->keyAttrId;
574280304Sjkim        else
575280304Sjkim            *potherid = NULL;
576280304Sjkim    }
577280304Sjkim    if (pothertype) {
578280304Sjkim        if (rkid->other)
579280304Sjkim            *pothertype = rkid->other->keyAttr;
580280304Sjkim        else
581280304Sjkim            *pothertype = NULL;
582280304Sjkim    }
583280304Sjkim    return 1;
584280304Sjkim}
585183234Ssimon
586280304Sjkimint CMS_RecipientInfo_set0_key(CMS_RecipientInfo *ri,
587280304Sjkim                               unsigned char *key, size_t keylen)
588280304Sjkim{
589280304Sjkim    CMS_KEKRecipientInfo *kekri;
590280304Sjkim    if (ri->type != CMS_RECIPINFO_KEK) {
591280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_SET0_KEY, CMS_R_NOT_KEK);
592280304Sjkim        return 0;
593280304Sjkim    }
594183234Ssimon
595280304Sjkim    kekri = ri->d.kekri;
596280304Sjkim    kekri->key = key;
597280304Sjkim    kekri->keylen = keylen;
598280304Sjkim    return 1;
599280304Sjkim}
600183234Ssimon
601183234Ssimon/* Encrypt content key in KEK recipient info */
602183234Ssimon
603183234Ssimonstatic int cms_RecipientInfo_kekri_encrypt(CMS_ContentInfo *cms,
604280304Sjkim                                           CMS_RecipientInfo *ri)
605280304Sjkim{
606280304Sjkim    CMS_EncryptedContentInfo *ec;
607280304Sjkim    CMS_KEKRecipientInfo *kekri;
608280304Sjkim    AES_KEY actx;
609280304Sjkim    unsigned char *wkey = NULL;
610280304Sjkim    int wkeylen;
611280304Sjkim    int r = 0;
612183234Ssimon
613280304Sjkim    ec = cms->d.envelopedData->encryptedContentInfo;
614183234Ssimon
615280304Sjkim    kekri = ri->d.kekri;
616183234Ssimon
617280304Sjkim    if (!kekri->key) {
618280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_NO_KEY);
619280304Sjkim        return 0;
620280304Sjkim    }
621183234Ssimon
622280304Sjkim    if (AES_set_encrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
623280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT,
624280304Sjkim               CMS_R_ERROR_SETTING_KEY);
625280304Sjkim        goto err;
626280304Sjkim    }
627183234Ssimon
628280304Sjkim    wkey = OPENSSL_malloc(ec->keylen + 8);
629183234Ssimon
630280304Sjkim    if (!wkey) {
631280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, ERR_R_MALLOC_FAILURE);
632280304Sjkim        goto err;
633280304Sjkim    }
634183234Ssimon
635280304Sjkim    wkeylen = AES_wrap_key(&actx, NULL, wkey, ec->key, ec->keylen);
636183234Ssimon
637280304Sjkim    if (wkeylen <= 0) {
638280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_ENCRYPT, CMS_R_WRAP_ERROR);
639280304Sjkim        goto err;
640280304Sjkim    }
641183234Ssimon
642280304Sjkim    ASN1_STRING_set0(kekri->encryptedKey, wkey, wkeylen);
643183234Ssimon
644280304Sjkim    r = 1;
645183234Ssimon
646280304Sjkim err:
647183234Ssimon
648280304Sjkim    if (!r && wkey)
649280304Sjkim        OPENSSL_free(wkey);
650280304Sjkim    OPENSSL_cleanse(&actx, sizeof(actx));
651183234Ssimon
652280304Sjkim    return r;
653183234Ssimon
654280304Sjkim}
655183234Ssimon
656183234Ssimon/* Decrypt content key in KEK recipient info */
657183234Ssimon
658183234Ssimonstatic int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
659280304Sjkim                                           CMS_RecipientInfo *ri)
660280304Sjkim{
661280304Sjkim    CMS_EncryptedContentInfo *ec;
662280304Sjkim    CMS_KEKRecipientInfo *kekri;
663280304Sjkim    AES_KEY actx;
664280304Sjkim    unsigned char *ukey = NULL;
665280304Sjkim    int ukeylen;
666280304Sjkim    int r = 0, wrap_nid;
667183234Ssimon
668280304Sjkim    ec = cms->d.envelopedData->encryptedContentInfo;
669183234Ssimon
670280304Sjkim    kekri = ri->d.kekri;
671183234Ssimon
672280304Sjkim    if (!kekri->key) {
673280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_NO_KEY);
674280304Sjkim        return 0;
675280304Sjkim    }
676183234Ssimon
677280304Sjkim    wrap_nid = OBJ_obj2nid(kekri->keyEncryptionAlgorithm->algorithm);
678280304Sjkim    if (aes_wrap_keylen(wrap_nid) != kekri->keylen) {
679280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
680280304Sjkim               CMS_R_INVALID_KEY_LENGTH);
681280304Sjkim        return 0;
682280304Sjkim    }
683183234Ssimon
684280304Sjkim    /* If encrypted key length is invalid don't bother */
685183234Ssimon
686280304Sjkim    if (kekri->encryptedKey->length < 16) {
687280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
688280304Sjkim               CMS_R_INVALID_ENCRYPTED_KEY_LENGTH);
689280304Sjkim        goto err;
690280304Sjkim    }
691183234Ssimon
692280304Sjkim    if (AES_set_decrypt_key(kekri->key, kekri->keylen << 3, &actx)) {
693280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT,
694280304Sjkim               CMS_R_ERROR_SETTING_KEY);
695280304Sjkim        goto err;
696280304Sjkim    }
697183234Ssimon
698280304Sjkim    ukey = OPENSSL_malloc(kekri->encryptedKey->length - 8);
699183234Ssimon
700280304Sjkim    if (!ukey) {
701280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, ERR_R_MALLOC_FAILURE);
702280304Sjkim        goto err;
703280304Sjkim    }
704183234Ssimon
705280304Sjkim    ukeylen = AES_unwrap_key(&actx, NULL, ukey,
706280304Sjkim                             kekri->encryptedKey->data,
707280304Sjkim                             kekri->encryptedKey->length);
708183234Ssimon
709280304Sjkim    if (ukeylen <= 0) {
710280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_KEKRI_DECRYPT, CMS_R_UNWRAP_ERROR);
711280304Sjkim        goto err;
712280304Sjkim    }
713183234Ssimon
714280304Sjkim    ec->key = ukey;
715280304Sjkim    ec->keylen = ukeylen;
716183234Ssimon
717280304Sjkim    r = 1;
718183234Ssimon
719280304Sjkim err:
720183234Ssimon
721280304Sjkim    if (!r && ukey)
722280304Sjkim        OPENSSL_free(ukey);
723280304Sjkim    OPENSSL_cleanse(&actx, sizeof(actx));
724183234Ssimon
725280304Sjkim    return r;
726183234Ssimon
727280304Sjkim}
728183234Ssimon
729183234Ssimonint CMS_RecipientInfo_decrypt(CMS_ContentInfo *cms, CMS_RecipientInfo *ri)
730280304Sjkim{
731280304Sjkim    switch (ri->type) {
732280304Sjkim    case CMS_RECIPINFO_TRANS:
733280304Sjkim        return cms_RecipientInfo_ktri_decrypt(cms, ri);
734183234Ssimon
735280304Sjkim    case CMS_RECIPINFO_KEK:
736280304Sjkim        return cms_RecipientInfo_kekri_decrypt(cms, ri);
737183234Ssimon
738280304Sjkim    case CMS_RECIPINFO_PASS:
739280304Sjkim        return cms_RecipientInfo_pwri_crypt(cms, ri, 0);
740238405Sjkim
741280304Sjkim    default:
742280304Sjkim        CMSerr(CMS_F_CMS_RECIPIENTINFO_DECRYPT,
743280304Sjkim               CMS_R_UNSUPPORTED_RECPIENTINFO_TYPE);
744280304Sjkim        return 0;
745280304Sjkim    }
746280304Sjkim}
747183234Ssimon
748183234SsimonBIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
749280304Sjkim{
750280304Sjkim    CMS_EncryptedContentInfo *ec;
751280304Sjkim    STACK_OF(CMS_RecipientInfo) *rinfos;
752280304Sjkim    CMS_RecipientInfo *ri;
753280304Sjkim    int i, r, ok = 0;
754280304Sjkim    BIO *ret;
755183234Ssimon
756280304Sjkim    /* Get BIO first to set up key */
757183234Ssimon
758280304Sjkim    ec = cms->d.envelopedData->encryptedContentInfo;
759280304Sjkim    ret = cms_EncryptedContent_init_bio(ec);
760183234Ssimon
761280304Sjkim    /* If error or no cipher end of processing */
762183234Ssimon
763280304Sjkim    if (!ret || !ec->cipher)
764280304Sjkim        return ret;
765183234Ssimon
766280304Sjkim    /* Now encrypt content key according to each RecipientInfo type */
767183234Ssimon
768280304Sjkim    rinfos = cms->d.envelopedData->recipientInfos;
769183234Ssimon
770280304Sjkim    for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) {
771280304Sjkim        ri = sk_CMS_RecipientInfo_value(rinfos, i);
772183234Ssimon
773280304Sjkim        switch (ri->type) {
774280304Sjkim        case CMS_RECIPINFO_TRANS:
775280304Sjkim            r = cms_RecipientInfo_ktri_encrypt(cms, ri);
776280304Sjkim            break;
777183234Ssimon
778280304Sjkim        case CMS_RECIPINFO_KEK:
779280304Sjkim            r = cms_RecipientInfo_kekri_encrypt(cms, ri);
780280304Sjkim            break;
781183234Ssimon
782280304Sjkim        case CMS_RECIPINFO_PASS:
783280304Sjkim            r = cms_RecipientInfo_pwri_crypt(cms, ri, 1);
784280304Sjkim            break;
785238405Sjkim
786280304Sjkim        default:
787280304Sjkim            CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
788280304Sjkim                   CMS_R_UNSUPPORTED_RECIPIENT_TYPE);
789280304Sjkim            goto err;
790280304Sjkim        }
791183234Ssimon
792280304Sjkim        if (r <= 0) {
793280304Sjkim            CMSerr(CMS_F_CMS_ENVELOPEDDATA_INIT_BIO,
794280304Sjkim                   CMS_R_ERROR_SETTING_RECIPIENTINFO);
795280304Sjkim            goto err;
796280304Sjkim        }
797280304Sjkim    }
798183234Ssimon
799280304Sjkim    ok = 1;
800183234Ssimon
801280304Sjkim err:
802280304Sjkim    ec->cipher = NULL;
803280304Sjkim    if (ec->key) {
804280304Sjkim        OPENSSL_cleanse(ec->key, ec->keylen);
805280304Sjkim        OPENSSL_free(ec->key);
806280304Sjkim        ec->key = NULL;
807280304Sjkim        ec->keylen = 0;
808280304Sjkim    }
809280304Sjkim    if (ok)
810280304Sjkim        return ret;
811280304Sjkim    BIO_free(ret);
812280304Sjkim    return NULL;
813183234Ssimon
814280304Sjkim}
815