155714Skris/* crypto/pkcs7/pk7_doit.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296341Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296341Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296341Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296341Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296341Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296341Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include "cryptlib.h"
6155714Skris#include <openssl/rand.h>
6255714Skris#include <openssl/objects.h>
6355714Skris#include <openssl/x509.h>
6459191Skris#include <openssl/x509v3.h>
65160814Ssimon#include <openssl/err.h>
6655714Skris
6755714Skrisstatic int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
68296341Sdelphij                         void *value);
6955714Skrisstatic ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid);
7055714Skris
71296341Sdelphijstatic int PKCS7_type_is_other(PKCS7 *p7)
72296341Sdelphij{
73296341Sdelphij    int isOther = 1;
74100928Snectar
75296341Sdelphij    int nid = OBJ_obj2nid(p7->type);
76100928Snectar
77296341Sdelphij    switch (nid) {
78296341Sdelphij    case NID_pkcs7_data:
79296341Sdelphij    case NID_pkcs7_signed:
80296341Sdelphij    case NID_pkcs7_enveloped:
81296341Sdelphij    case NID_pkcs7_signedAndEnveloped:
82296341Sdelphij    case NID_pkcs7_digest:
83296341Sdelphij    case NID_pkcs7_encrypted:
84296341Sdelphij        isOther = 0;
85296341Sdelphij        break;
86296341Sdelphij    default:
87296341Sdelphij        isOther = 1;
88296341Sdelphij    }
89100928Snectar
90296341Sdelphij    return isOther;
91100928Snectar
92296341Sdelphij}
93296341Sdelphij
94127128Snectarstatic ASN1_OCTET_STRING *PKCS7_get_octet_string(PKCS7 *p7)
95296341Sdelphij{
96296341Sdelphij    if (PKCS7_type_is_data(p7))
97296341Sdelphij        return p7->d.data;
98296341Sdelphij    if (PKCS7_type_is_other(p7) && p7->d.other
99296341Sdelphij        && (p7->d.other->type == V_ASN1_OCTET_STRING))
100296341Sdelphij        return p7->d.other->value.octet_string;
101296341Sdelphij    return NULL;
102296341Sdelphij}
103100928Snectar
104160814Ssimonstatic int PKCS7_bio_add_digest(BIO **pbio, X509_ALGOR *alg)
105296341Sdelphij{
106296341Sdelphij    BIO *btmp;
107296341Sdelphij    const EVP_MD *md;
108296341Sdelphij    if ((btmp = BIO_new(BIO_f_md())) == NULL) {
109296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB);
110296341Sdelphij        goto err;
111296341Sdelphij    }
112160814Ssimon
113296341Sdelphij    md = EVP_get_digestbyobj(alg->algorithm);
114296341Sdelphij    if (md == NULL) {
115296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, PKCS7_R_UNKNOWN_DIGEST_TYPE);
116296341Sdelphij        goto err;
117296341Sdelphij    }
118160814Ssimon
119296341Sdelphij    BIO_set_md(btmp, md);
120296341Sdelphij    if (*pbio == NULL)
121296341Sdelphij        *pbio = btmp;
122296341Sdelphij    else if (!BIO_push(*pbio, btmp)) {
123296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_BIO_ADD_DIGEST, ERR_R_BIO_LIB);
124296341Sdelphij        goto err;
125296341Sdelphij    }
126296341Sdelphij    btmp = NULL;
127160814Ssimon
128296341Sdelphij    return 1;
129160814Ssimon
130296341Sdelphij err:
131296341Sdelphij    if (btmp)
132296341Sdelphij        BIO_free(btmp);
133296341Sdelphij    return 0;
134160814Ssimon
135296341Sdelphij}
136160814Ssimon
137238405Sjkimstatic int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri,
138296341Sdelphij                              unsigned char *key, int keylen)
139296341Sdelphij{
140296341Sdelphij    EVP_PKEY_CTX *pctx = NULL;
141296341Sdelphij    EVP_PKEY *pkey = NULL;
142296341Sdelphij    unsigned char *ek = NULL;
143296341Sdelphij    int ret = 0;
144296341Sdelphij    size_t eklen;
145238405Sjkim
146296341Sdelphij    pkey = X509_get_pubkey(ri->cert);
147238405Sjkim
148296341Sdelphij    if (!pkey)
149296341Sdelphij        return 0;
150238405Sjkim
151296341Sdelphij    pctx = EVP_PKEY_CTX_new(pkey, NULL);
152296341Sdelphij    if (!pctx)
153296341Sdelphij        return 0;
154238405Sjkim
155296341Sdelphij    if (EVP_PKEY_encrypt_init(pctx) <= 0)
156296341Sdelphij        goto err;
157238405Sjkim
158296341Sdelphij    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_ENCRYPT,
159296341Sdelphij                          EVP_PKEY_CTRL_PKCS7_ENCRYPT, 0, ri) <= 0) {
160296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, PKCS7_R_CTRL_ERROR);
161296341Sdelphij        goto err;
162296341Sdelphij    }
163238405Sjkim
164296341Sdelphij    if (EVP_PKEY_encrypt(pctx, NULL, &eklen, key, keylen) <= 0)
165296341Sdelphij        goto err;
166238405Sjkim
167296341Sdelphij    ek = OPENSSL_malloc(eklen);
168238405Sjkim
169296341Sdelphij    if (ek == NULL) {
170296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_ENCODE_RINFO, ERR_R_MALLOC_FAILURE);
171296341Sdelphij        goto err;
172296341Sdelphij    }
173238405Sjkim
174296341Sdelphij    if (EVP_PKEY_encrypt(pctx, ek, &eklen, key, keylen) <= 0)
175296341Sdelphij        goto err;
176238405Sjkim
177296341Sdelphij    ASN1_STRING_set0(ri->enc_key, ek, eklen);
178296341Sdelphij    ek = NULL;
179238405Sjkim
180296341Sdelphij    ret = 1;
181238405Sjkim
182296341Sdelphij err:
183296341Sdelphij    if (pkey)
184296341Sdelphij        EVP_PKEY_free(pkey);
185296341Sdelphij    if (pctx)
186296341Sdelphij        EVP_PKEY_CTX_free(pctx);
187296341Sdelphij    if (ek)
188296341Sdelphij        OPENSSL_free(ek);
189296341Sdelphij    return ret;
190238405Sjkim
191296341Sdelphij}
192238405Sjkim
193238405Sjkimstatic int pkcs7_decrypt_rinfo(unsigned char **pek, int *peklen,
194296341Sdelphij                               PKCS7_RECIP_INFO *ri, EVP_PKEY *pkey)
195296341Sdelphij{
196296341Sdelphij    EVP_PKEY_CTX *pctx = NULL;
197296341Sdelphij    unsigned char *ek = NULL;
198296341Sdelphij    size_t eklen;
199238405Sjkim
200296341Sdelphij    int ret = -1;
201238405Sjkim
202296341Sdelphij    pctx = EVP_PKEY_CTX_new(pkey, NULL);
203296341Sdelphij    if (!pctx)
204296341Sdelphij        return -1;
205238405Sjkim
206296341Sdelphij    if (EVP_PKEY_decrypt_init(pctx) <= 0)
207296341Sdelphij        goto err;
208238405Sjkim
209296341Sdelphij    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DECRYPT,
210296341Sdelphij                          EVP_PKEY_CTRL_PKCS7_DECRYPT, 0, ri) <= 0) {
211296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, PKCS7_R_CTRL_ERROR);
212296341Sdelphij        goto err;
213296341Sdelphij    }
214238405Sjkim
215296341Sdelphij    if (EVP_PKEY_decrypt(pctx, NULL, &eklen,
216296341Sdelphij                         ri->enc_key->data, ri->enc_key->length) <= 0)
217296341Sdelphij        goto err;
218238405Sjkim
219296341Sdelphij    ek = OPENSSL_malloc(eklen);
220238405Sjkim
221296341Sdelphij    if (ek == NULL) {
222296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_MALLOC_FAILURE);
223296341Sdelphij        goto err;
224296341Sdelphij    }
225238405Sjkim
226296341Sdelphij    if (EVP_PKEY_decrypt(pctx, ek, &eklen,
227296341Sdelphij                         ri->enc_key->data, ri->enc_key->length) <= 0) {
228296341Sdelphij        ret = 0;
229296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DECRYPT_RINFO, ERR_R_EVP_LIB);
230296341Sdelphij        goto err;
231296341Sdelphij    }
232238405Sjkim
233296341Sdelphij    ret = 1;
234238405Sjkim
235296341Sdelphij    if (*pek) {
236296341Sdelphij        OPENSSL_cleanse(*pek, *peklen);
237296341Sdelphij        OPENSSL_free(*pek);
238296341Sdelphij    }
239238405Sjkim
240296341Sdelphij    *pek = ek;
241296341Sdelphij    *peklen = eklen;
242238405Sjkim
243296341Sdelphij err:
244296341Sdelphij    if (pctx)
245296341Sdelphij        EVP_PKEY_CTX_free(pctx);
246296341Sdelphij    if (!ret && ek)
247296341Sdelphij        OPENSSL_free(ek);
248238405Sjkim
249296341Sdelphij    return ret;
250296341Sdelphij}
251238405Sjkim
25255714SkrisBIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
253296341Sdelphij{
254296341Sdelphij    int i;
255296341Sdelphij    BIO *out = NULL, *btmp = NULL;
256296341Sdelphij    X509_ALGOR *xa = NULL;
257296341Sdelphij    const EVP_CIPHER *evp_cipher = NULL;
258296341Sdelphij    STACK_OF(X509_ALGOR) *md_sk = NULL;
259296341Sdelphij    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
260296341Sdelphij    X509_ALGOR *xalg = NULL;
261296341Sdelphij    PKCS7_RECIP_INFO *ri = NULL;
262296341Sdelphij    ASN1_OCTET_STRING *os = NULL;
26355714Skris
264296341Sdelphij    if (p7 == NULL) {
265296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER);
266296341Sdelphij        return NULL;
267296341Sdelphij    }
268296341Sdelphij    /*
269296341Sdelphij     * The content field in the PKCS7 ContentInfo is optional, but that really
270296341Sdelphij     * only applies to inner content (precisely, detached signatures).
271296341Sdelphij     *
272296341Sdelphij     * When reading content, missing outer content is therefore treated as an
273296341Sdelphij     * error.
274296341Sdelphij     *
275296341Sdelphij     * When creating content, PKCS7_content_new() must be called before
276296341Sdelphij     * calling this method, so a NULL p7->d is always an error.
277296341Sdelphij     */
278296341Sdelphij    if (p7->d.ptr == NULL) {
279296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT);
280296341Sdelphij        return NULL;
281296341Sdelphij    }
282280268Sdelphij
283296341Sdelphij    i = OBJ_obj2nid(p7->type);
284296341Sdelphij    p7->state = PKCS7_S_HEADER;
28555714Skris
286296341Sdelphij    switch (i) {
287296341Sdelphij    case NID_pkcs7_signed:
288296341Sdelphij        md_sk = p7->d.sign->md_algs;
289296341Sdelphij        os = PKCS7_get_octet_string(p7->d.sign->contents);
290296341Sdelphij        break;
291296341Sdelphij    case NID_pkcs7_signedAndEnveloped:
292296341Sdelphij        rsk = p7->d.signed_and_enveloped->recipientinfo;
293296341Sdelphij        md_sk = p7->d.signed_and_enveloped->md_algs;
294296341Sdelphij        xalg = p7->d.signed_and_enveloped->enc_data->algorithm;
295296341Sdelphij        evp_cipher = p7->d.signed_and_enveloped->enc_data->cipher;
296296341Sdelphij        if (evp_cipher == NULL) {
297296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
298296341Sdelphij            goto err;
299296341Sdelphij        }
300296341Sdelphij        break;
301296341Sdelphij    case NID_pkcs7_enveloped:
302296341Sdelphij        rsk = p7->d.enveloped->recipientinfo;
303296341Sdelphij        xalg = p7->d.enveloped->enc_data->algorithm;
304296341Sdelphij        evp_cipher = p7->d.enveloped->enc_data->cipher;
305296341Sdelphij        if (evp_cipher == NULL) {
306296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_CIPHER_NOT_INITIALIZED);
307296341Sdelphij            goto err;
308296341Sdelphij        }
309296341Sdelphij        break;
310296341Sdelphij    case NID_pkcs7_digest:
311296341Sdelphij        xa = p7->d.digest->md;
312296341Sdelphij        os = PKCS7_get_octet_string(p7->d.digest->contents);
313296341Sdelphij        break;
314296341Sdelphij    case NID_pkcs7_data:
315296341Sdelphij        break;
316296341Sdelphij    default:
317296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
318296341Sdelphij        goto err;
319296341Sdelphij    }
32055714Skris
321296341Sdelphij    for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++)
322296341Sdelphij        if (!PKCS7_bio_add_digest(&out, sk_X509_ALGOR_value(md_sk, i)))
323296341Sdelphij            goto err;
32455714Skris
325296341Sdelphij    if (xa && !PKCS7_bio_add_digest(&out, xa))
326296341Sdelphij        goto err;
32755714Skris
328296341Sdelphij    if (evp_cipher != NULL) {
329296341Sdelphij        unsigned char key[EVP_MAX_KEY_LENGTH];
330296341Sdelphij        unsigned char iv[EVP_MAX_IV_LENGTH];
331296341Sdelphij        int keylen, ivlen;
332296341Sdelphij        EVP_CIPHER_CTX *ctx;
33355714Skris
334296341Sdelphij        if ((btmp = BIO_new(BIO_f_cipher())) == NULL) {
335296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATAINIT, ERR_R_BIO_LIB);
336296341Sdelphij            goto err;
337296341Sdelphij        }
338296341Sdelphij        BIO_get_cipher_ctx(btmp, &ctx);
339296341Sdelphij        keylen = EVP_CIPHER_key_length(evp_cipher);
340296341Sdelphij        ivlen = EVP_CIPHER_iv_length(evp_cipher);
341296341Sdelphij        xalg->algorithm = OBJ_nid2obj(EVP_CIPHER_type(evp_cipher));
342296341Sdelphij        if (ivlen > 0)
343296341Sdelphij            if (RAND_pseudo_bytes(iv, ivlen) <= 0)
344296341Sdelphij                goto err;
345296341Sdelphij        if (EVP_CipherInit_ex(ctx, evp_cipher, NULL, NULL, NULL, 1) <= 0)
346296341Sdelphij            goto err;
347296341Sdelphij        if (EVP_CIPHER_CTX_rand_key(ctx, key) <= 0)
348296341Sdelphij            goto err;
349296341Sdelphij        if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, 1) <= 0)
350296341Sdelphij            goto err;
35155714Skris
352296341Sdelphij        if (ivlen > 0) {
353296341Sdelphij            if (xalg->parameter == NULL) {
354296341Sdelphij                xalg->parameter = ASN1_TYPE_new();
355296341Sdelphij                if (xalg->parameter == NULL)
356296341Sdelphij                    goto err;
357296341Sdelphij            }
358296341Sdelphij            if (EVP_CIPHER_param_to_asn1(ctx, xalg->parameter) < 0)
359296341Sdelphij                goto err;
360296341Sdelphij        }
36155714Skris
362296341Sdelphij        /* Lets do the pub key stuff :-) */
363296341Sdelphij        for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
364296341Sdelphij            ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
365296341Sdelphij            if (pkcs7_encode_rinfo(ri, key, keylen) <= 0)
366296341Sdelphij                goto err;
367296341Sdelphij        }
368296341Sdelphij        OPENSSL_cleanse(key, keylen);
36955714Skris
370296341Sdelphij        if (out == NULL)
371296341Sdelphij            out = btmp;
372296341Sdelphij        else
373296341Sdelphij            BIO_push(out, btmp);
374296341Sdelphij        btmp = NULL;
375296341Sdelphij    }
37655714Skris
377296341Sdelphij    if (bio == NULL) {
378296341Sdelphij        if (PKCS7_is_detached(p7))
379296341Sdelphij            bio = BIO_new(BIO_s_null());
380296341Sdelphij        else if (os && os->length > 0)
381296341Sdelphij            bio = BIO_new_mem_buf(os->data, os->length);
382296341Sdelphij        if (bio == NULL) {
383296341Sdelphij            bio = BIO_new(BIO_s_mem());
384296341Sdelphij            if (bio == NULL)
385296341Sdelphij                goto err;
386296341Sdelphij            BIO_set_mem_eof_return(bio, 0);
387296341Sdelphij        }
388296341Sdelphij    }
389296341Sdelphij    if (out)
390296341Sdelphij        BIO_push(out, bio);
391296341Sdelphij    else
392296341Sdelphij        out = bio;
393296341Sdelphij    bio = NULL;
394296341Sdelphij    if (0) {
395296341Sdelphij err:
396296341Sdelphij        if (out != NULL)
397296341Sdelphij            BIO_free_all(out);
398296341Sdelphij        if (btmp != NULL)
399296341Sdelphij            BIO_free_all(btmp);
400296341Sdelphij        out = NULL;
401296341Sdelphij    }
402296341Sdelphij    return (out);
403296341Sdelphij}
40455714Skris
405160814Ssimonstatic int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert)
406296341Sdelphij{
407296341Sdelphij    int ret;
408296341Sdelphij    ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
409296341Sdelphij                        pcert->cert_info->issuer);
410296341Sdelphij    if (ret)
411296341Sdelphij        return ret;
412296341Sdelphij    return M_ASN1_INTEGER_cmp(pcert->cert_info->serialNumber,
413296341Sdelphij                              ri->issuer_and_serial->serial);
414296341Sdelphij}
415160814Ssimon
41655714Skris/* int */
41755714SkrisBIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert)
418296341Sdelphij{
419296341Sdelphij    int i, j;
420296341Sdelphij    BIO *out = NULL, *btmp = NULL, *etmp = NULL, *bio = NULL;
421296341Sdelphij    X509_ALGOR *xa;
422296341Sdelphij    ASN1_OCTET_STRING *data_body = NULL;
423296341Sdelphij    const EVP_MD *evp_md;
424296341Sdelphij    const EVP_CIPHER *evp_cipher = NULL;
425296341Sdelphij    EVP_CIPHER_CTX *evp_ctx = NULL;
426296341Sdelphij    X509_ALGOR *enc_alg = NULL;
427296341Sdelphij    STACK_OF(X509_ALGOR) *md_sk = NULL;
428296341Sdelphij    STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL;
429296341Sdelphij    PKCS7_RECIP_INFO *ri = NULL;
430296341Sdelphij    unsigned char *ek = NULL, *tkey = NULL;
431296341Sdelphij    int eklen = 0, tkeylen = 0;
43255714Skris
433296341Sdelphij    if (p7 == NULL) {
434296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
435296341Sdelphij        return NULL;
436296341Sdelphij    }
437280268Sdelphij
438296341Sdelphij    if (p7->d.ptr == NULL) {
439296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
440296341Sdelphij        return NULL;
441296341Sdelphij    }
442280268Sdelphij
443296341Sdelphij    i = OBJ_obj2nid(p7->type);
444296341Sdelphij    p7->state = PKCS7_S_HEADER;
44555714Skris
446296341Sdelphij    switch (i) {
447296341Sdelphij    case NID_pkcs7_signed:
448296341Sdelphij        /*
449296341Sdelphij         * p7->d.sign->contents is a PKCS7 structure consisting of a contentType
450296341Sdelphij         * field and optional content.
451296341Sdelphij         * data_body is NULL if that structure has no (=detached) content
452296341Sdelphij         * or if the contentType is wrong (i.e., not "data").
453296341Sdelphij         */
454296341Sdelphij        data_body = PKCS7_get_octet_string(p7->d.sign->contents);
455296341Sdelphij        if (!PKCS7_is_detached(p7) && data_body == NULL) {
456296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
457296341Sdelphij                     PKCS7_R_INVALID_SIGNED_DATA_TYPE);
458296341Sdelphij            goto err;
459296341Sdelphij        }
460296341Sdelphij        md_sk = p7->d.sign->md_algs;
461296341Sdelphij        break;
462296341Sdelphij    case NID_pkcs7_signedAndEnveloped:
463296341Sdelphij        rsk = p7->d.signed_and_enveloped->recipientinfo;
464296341Sdelphij        md_sk = p7->d.signed_and_enveloped->md_algs;
465296341Sdelphij        /* data_body is NULL if the optional EncryptedContent is missing. */
466296341Sdelphij        data_body = p7->d.signed_and_enveloped->enc_data->enc_data;
467296341Sdelphij        enc_alg = p7->d.signed_and_enveloped->enc_data->algorithm;
468296341Sdelphij        evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
469296341Sdelphij        if (evp_cipher == NULL) {
470296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
471296341Sdelphij                     PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
472296341Sdelphij            goto err;
473296341Sdelphij        }
474296341Sdelphij        break;
475296341Sdelphij    case NID_pkcs7_enveloped:
476296341Sdelphij        rsk = p7->d.enveloped->recipientinfo;
477296341Sdelphij        enc_alg = p7->d.enveloped->enc_data->algorithm;
478296341Sdelphij        /* data_body is NULL if the optional EncryptedContent is missing. */
479296341Sdelphij        data_body = p7->d.enveloped->enc_data->enc_data;
480296341Sdelphij        evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
481296341Sdelphij        if (evp_cipher == NULL) {
482296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATADECODE,
483296341Sdelphij                     PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
484296341Sdelphij            goto err;
485296341Sdelphij        }
486296341Sdelphij        break;
487296341Sdelphij    default:
488296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
489296341Sdelphij        goto err;
490296341Sdelphij    }
49155714Skris
492284295Sdelphij    /* Detached content must be supplied via in_bio instead. */
493284295Sdelphij    if (data_body == NULL && in_bio == NULL) {
494284295Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
495284295Sdelphij        goto err;
496284295Sdelphij    }
497284295Sdelphij
498296341Sdelphij    /* We will be checking the signature */
499296341Sdelphij    if (md_sk != NULL) {
500296341Sdelphij        for (i = 0; i < sk_X509_ALGOR_num(md_sk); i++) {
501296341Sdelphij            xa = sk_X509_ALGOR_value(md_sk, i);
502296341Sdelphij            if ((btmp = BIO_new(BIO_f_md())) == NULL) {
503296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
504296341Sdelphij                goto err;
505296341Sdelphij            }
50655714Skris
507296341Sdelphij            j = OBJ_obj2nid(xa->algorithm);
508296341Sdelphij            evp_md = EVP_get_digestbynid(j);
509296341Sdelphij            if (evp_md == NULL) {
510296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
511296341Sdelphij                         PKCS7_R_UNKNOWN_DIGEST_TYPE);
512296341Sdelphij                goto err;
513296341Sdelphij            }
51455714Skris
515296341Sdelphij            BIO_set_md(btmp, evp_md);
516296341Sdelphij            if (out == NULL)
517296341Sdelphij                out = btmp;
518296341Sdelphij            else
519296341Sdelphij                BIO_push(out, btmp);
520296341Sdelphij            btmp = NULL;
521296341Sdelphij        }
522296341Sdelphij    }
52355714Skris
524296341Sdelphij    if (evp_cipher != NULL) {
52555714Skris#if 0
526296341Sdelphij        unsigned char key[EVP_MAX_KEY_LENGTH];
527296341Sdelphij        unsigned char iv[EVP_MAX_IV_LENGTH];
528296341Sdelphij        unsigned char *p;
529296341Sdelphij        int keylen, ivlen;
530296341Sdelphij        int max;
531296341Sdelphij        X509_OBJECT ret;
53255714Skris#endif
53355714Skris
534296341Sdelphij        if ((etmp = BIO_new(BIO_f_cipher())) == NULL) {
535296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_BIO_LIB);
536296341Sdelphij            goto err;
537296341Sdelphij        }
53855714Skris
539296341Sdelphij        /*
540296341Sdelphij         * It was encrypted, we need to decrypt the secret key with the
541296341Sdelphij         * private key
542296341Sdelphij         */
54355714Skris
544296341Sdelphij        /*
545296341Sdelphij         * Find the recipientInfo which matches the passed certificate (if
546296341Sdelphij         * any)
547296341Sdelphij         */
54855714Skris
549296341Sdelphij        if (pcert) {
550296341Sdelphij            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
551296341Sdelphij                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
552296341Sdelphij                if (!pkcs7_cmp_ri(ri, pcert))
553296341Sdelphij                    break;
554296341Sdelphij                ri = NULL;
555296341Sdelphij            }
556296341Sdelphij            if (ri == NULL) {
557296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATADECODE,
558296341Sdelphij                         PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
559296341Sdelphij                goto err;
560296341Sdelphij            }
561296341Sdelphij        }
56255714Skris
563296341Sdelphij        /* If we haven't got a certificate try each ri in turn */
564296341Sdelphij        if (pcert == NULL) {
565296341Sdelphij            /*
566296341Sdelphij             * Always attempt to decrypt all rinfo even after sucess as a
567296341Sdelphij             * defence against MMA timing attacks.
568296341Sdelphij             */
569296341Sdelphij            for (i = 0; i < sk_PKCS7_RECIP_INFO_num(rsk); i++) {
570296341Sdelphij                ri = sk_PKCS7_RECIP_INFO_value(rsk, i);
57155714Skris
572296341Sdelphij                if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
573296341Sdelphij                    goto err;
574296341Sdelphij                ERR_clear_error();
575296341Sdelphij            }
576296341Sdelphij        } else {
577296341Sdelphij            /* Only exit on fatal errors, not decrypt failure */
578296341Sdelphij            if (pkcs7_decrypt_rinfo(&ek, &eklen, ri, pkey) < 0)
579296341Sdelphij                goto err;
580296341Sdelphij            ERR_clear_error();
581296341Sdelphij        }
58255714Skris
583296341Sdelphij        evp_ctx = NULL;
584296341Sdelphij        BIO_get_cipher_ctx(etmp, &evp_ctx);
585296341Sdelphij        if (EVP_CipherInit_ex(evp_ctx, evp_cipher, NULL, NULL, NULL, 0) <= 0)
586296341Sdelphij            goto err;
587296341Sdelphij        if (EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) < 0)
588296341Sdelphij            goto err;
589296341Sdelphij        /* Generate random key as MMA defence */
590296341Sdelphij        tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx);
591296341Sdelphij        tkey = OPENSSL_malloc(tkeylen);
592296341Sdelphij        if (!tkey)
593296341Sdelphij            goto err;
594296341Sdelphij        if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0)
595296341Sdelphij            goto err;
596296341Sdelphij        if (ek == NULL) {
597296341Sdelphij            ek = tkey;
598296341Sdelphij            eklen = tkeylen;
599296341Sdelphij            tkey = NULL;
600296341Sdelphij        }
60155714Skris
602296341Sdelphij        if (eklen != EVP_CIPHER_CTX_key_length(evp_ctx)) {
603296341Sdelphij            /*
604296341Sdelphij             * Some S/MIME clients don't use the same key and effective key
605296341Sdelphij             * length. The key length is determined by the size of the
606296341Sdelphij             * decrypted RSA key.
607296341Sdelphij             */
608296341Sdelphij            if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, eklen)) {
609296341Sdelphij                /* Use random key as MMA defence */
610296341Sdelphij                OPENSSL_cleanse(ek, eklen);
611296341Sdelphij                OPENSSL_free(ek);
612296341Sdelphij                ek = tkey;
613296341Sdelphij                eklen = tkeylen;
614296341Sdelphij                tkey = NULL;
615296341Sdelphij            }
616296341Sdelphij        }
617296341Sdelphij        /* Clear errors so we don't leak information useful in MMA */
618296341Sdelphij        ERR_clear_error();
619296341Sdelphij        if (EVP_CipherInit_ex(evp_ctx, NULL, NULL, ek, NULL, 0) <= 0)
620296341Sdelphij            goto err;
621234954Sbz
622296341Sdelphij        if (ek) {
623296341Sdelphij            OPENSSL_cleanse(ek, eklen);
624296341Sdelphij            OPENSSL_free(ek);
625296341Sdelphij            ek = NULL;
626296341Sdelphij        }
627296341Sdelphij        if (tkey) {
628296341Sdelphij            OPENSSL_cleanse(tkey, tkeylen);
629296341Sdelphij            OPENSSL_free(tkey);
630296341Sdelphij            tkey = NULL;
631296341Sdelphij        }
63255714Skris
633296341Sdelphij        if (out == NULL)
634296341Sdelphij            out = etmp;
635296341Sdelphij        else
636296341Sdelphij            BIO_push(out, etmp);
637296341Sdelphij        etmp = NULL;
638296341Sdelphij    }
63955714Skris#if 1
640296341Sdelphij    if (in_bio != NULL) {
641296341Sdelphij        bio = in_bio;
642296341Sdelphij    } else {
643296341Sdelphij# if 0
644296341Sdelphij        bio = BIO_new(BIO_s_mem());
645296341Sdelphij        /*
646296341Sdelphij         * We need to set this so that when we have read all the data, the
647296341Sdelphij         * encrypt BIO, if present, will read EOF and encode the last few
648296341Sdelphij         * bytes
649296341Sdelphij         */
650296341Sdelphij        BIO_set_mem_eof_return(bio, 0);
65155714Skris
652296341Sdelphij        if (data_body->length > 0)
653296341Sdelphij            BIO_write(bio, (char *)data_body->data, data_body->length);
654296341Sdelphij# else
655296341Sdelphij        if (data_body->length > 0)
656296341Sdelphij            bio = BIO_new_mem_buf(data_body->data, data_body->length);
657296341Sdelphij        else {
658296341Sdelphij            bio = BIO_new(BIO_s_mem());
659296341Sdelphij            BIO_set_mem_eof_return(bio, 0);
660296341Sdelphij        }
661296341Sdelphij        if (bio == NULL)
662296341Sdelphij            goto err;
663296341Sdelphij# endif
664296341Sdelphij    }
665296341Sdelphij    BIO_push(out, bio);
666296341Sdelphij    bio = NULL;
66759191Skris#endif
668296341Sdelphij    if (0) {
669296341Sdelphij err:
670296341Sdelphij        if (ek) {
671296341Sdelphij            OPENSSL_cleanse(ek, eklen);
672296341Sdelphij            OPENSSL_free(ek);
673296341Sdelphij        }
674296341Sdelphij        if (tkey) {
675296341Sdelphij            OPENSSL_cleanse(tkey, tkeylen);
676296341Sdelphij            OPENSSL_free(tkey);
677296341Sdelphij        }
678296341Sdelphij        if (out != NULL)
679296341Sdelphij            BIO_free_all(out);
680296341Sdelphij        if (btmp != NULL)
681296341Sdelphij            BIO_free_all(btmp);
682296341Sdelphij        if (etmp != NULL)
683296341Sdelphij            BIO_free_all(etmp);
684296341Sdelphij        if (bio != NULL)
685296341Sdelphij            BIO_free_all(bio);
686296341Sdelphij        out = NULL;
687296341Sdelphij    }
688296341Sdelphij    return (out);
689296341Sdelphij}
69055714Skris
691160814Ssimonstatic BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid)
692296341Sdelphij{
693296341Sdelphij    for (;;) {
694296341Sdelphij        bio = BIO_find_type(bio, BIO_TYPE_MD);
695296341Sdelphij        if (bio == NULL) {
696296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST,
697296341Sdelphij                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
698296341Sdelphij            return NULL;
699296341Sdelphij        }
700296341Sdelphij        BIO_get_md_ctx(bio, pmd);
701296341Sdelphij        if (*pmd == NULL) {
702296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_FIND_DIGEST, ERR_R_INTERNAL_ERROR);
703296341Sdelphij            return NULL;
704296341Sdelphij        }
705296341Sdelphij        if (EVP_MD_CTX_type(*pmd) == nid)
706296341Sdelphij            return bio;
707296341Sdelphij        bio = BIO_next(bio);
708296341Sdelphij    }
709296341Sdelphij    return NULL;
710296341Sdelphij}
711160814Ssimon
712238405Sjkimstatic int do_pkcs7_signed_attrib(PKCS7_SIGNER_INFO *si, EVP_MD_CTX *mctx)
713296341Sdelphij{
714296341Sdelphij    unsigned char md_data[EVP_MAX_MD_SIZE];
715296341Sdelphij    unsigned int md_len;
716238405Sjkim
717296341Sdelphij    /* Add signing time if not already present */
718296341Sdelphij    if (!PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime)) {
719296341Sdelphij        if (!PKCS7_add0_attrib_signing_time(si, NULL)) {
720296341Sdelphij            PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
721296341Sdelphij            return 0;
722296341Sdelphij        }
723296341Sdelphij    }
724238405Sjkim
725296341Sdelphij    /* Add digest */
726296341Sdelphij    if (!EVP_DigestFinal_ex(mctx, md_data, &md_len)) {
727296341Sdelphij        PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_EVP_LIB);
728296341Sdelphij        return 0;
729296341Sdelphij    }
730296341Sdelphij    if (!PKCS7_add1_attrib_digest(si, md_data, md_len)) {
731296341Sdelphij        PKCS7err(PKCS7_F_DO_PKCS7_SIGNED_ATTRIB, ERR_R_MALLOC_FAILURE);
732296341Sdelphij        return 0;
733296341Sdelphij    }
734238405Sjkim
735296341Sdelphij    /* Now sign the attributes */
736296341Sdelphij    if (!PKCS7_SIGNER_INFO_sign(si))
737296341Sdelphij        return 0;
738238405Sjkim
739296341Sdelphij    return 1;
740296341Sdelphij}
741296341Sdelphij
74255714Skrisint PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
743296341Sdelphij{
744296341Sdelphij    int ret = 0;
745296341Sdelphij    int i, j;
746296341Sdelphij    BIO *btmp;
747296341Sdelphij    PKCS7_SIGNER_INFO *si;
748296341Sdelphij    EVP_MD_CTX *mdc, ctx_tmp;
749296341Sdelphij    STACK_OF(X509_ATTRIBUTE) *sk;
750296341Sdelphij    STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
751296341Sdelphij    ASN1_OCTET_STRING *os = NULL;
75255714Skris
753296341Sdelphij    if (p7 == NULL) {
754296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER);
755296341Sdelphij        return 0;
756296341Sdelphij    }
757280268Sdelphij
758296341Sdelphij    if (p7->d.ptr == NULL) {
759296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT);
760296341Sdelphij        return 0;
761296341Sdelphij    }
762280268Sdelphij
763296341Sdelphij    EVP_MD_CTX_init(&ctx_tmp);
764296341Sdelphij    i = OBJ_obj2nid(p7->type);
765296341Sdelphij    p7->state = PKCS7_S_HEADER;
76655714Skris
767296341Sdelphij    switch (i) {
768296341Sdelphij    case NID_pkcs7_data:
769296341Sdelphij        os = p7->d.data;
770296341Sdelphij        break;
771296341Sdelphij    case NID_pkcs7_signedAndEnveloped:
772296341Sdelphij        /* XXXXXXXXXXXXXXXX */
773296341Sdelphij        si_sk = p7->d.signed_and_enveloped->signer_info;
774296341Sdelphij        os = p7->d.signed_and_enveloped->enc_data->enc_data;
775296341Sdelphij        if (!os) {
776296341Sdelphij            os = M_ASN1_OCTET_STRING_new();
777296341Sdelphij            if (!os) {
778296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
779296341Sdelphij                goto err;
780296341Sdelphij            }
781296341Sdelphij            p7->d.signed_and_enveloped->enc_data->enc_data = os;
782296341Sdelphij        }
783296341Sdelphij        break;
784296341Sdelphij    case NID_pkcs7_enveloped:
785296341Sdelphij        /* XXXXXXXXXXXXXXXX */
786296341Sdelphij        os = p7->d.enveloped->enc_data->enc_data;
787296341Sdelphij        if (!os) {
788296341Sdelphij            os = M_ASN1_OCTET_STRING_new();
789296341Sdelphij            if (!os) {
790296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_MALLOC_FAILURE);
791296341Sdelphij                goto err;
792296341Sdelphij            }
793296341Sdelphij            p7->d.enveloped->enc_data->enc_data = os;
794296341Sdelphij        }
795296341Sdelphij        break;
796296341Sdelphij    case NID_pkcs7_signed:
797296341Sdelphij        si_sk = p7->d.sign->signer_info;
798296341Sdelphij        os = PKCS7_get_octet_string(p7->d.sign->contents);
799296341Sdelphij        /* If detached data then the content is excluded */
800296341Sdelphij        if (PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
801296341Sdelphij            M_ASN1_OCTET_STRING_free(os);
802296341Sdelphij            os = NULL;
803296341Sdelphij            p7->d.sign->contents->d.data = NULL;
804296341Sdelphij        }
805296341Sdelphij        break;
806160814Ssimon
807296341Sdelphij    case NID_pkcs7_digest:
808296341Sdelphij        os = PKCS7_get_octet_string(p7->d.digest->contents);
809296341Sdelphij        /* If detached data then the content is excluded */
810296341Sdelphij        if (PKCS7_type_is_data(p7->d.digest->contents) && p7->detached) {
811296341Sdelphij            M_ASN1_OCTET_STRING_free(os);
812296341Sdelphij            os = NULL;
813296341Sdelphij            p7->d.digest->contents->d.data = NULL;
814296341Sdelphij        }
815296341Sdelphij        break;
816160814Ssimon
817296341Sdelphij    default:
818296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
819296341Sdelphij        goto err;
820296341Sdelphij    }
82155714Skris
822296341Sdelphij    if (si_sk != NULL) {
823296341Sdelphij        for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(si_sk); i++) {
824296341Sdelphij            si = sk_PKCS7_SIGNER_INFO_value(si_sk, i);
825296341Sdelphij            if (si->pkey == NULL)
826296341Sdelphij                continue;
82755714Skris
828296341Sdelphij            j = OBJ_obj2nid(si->digest_alg->algorithm);
82955714Skris
830296341Sdelphij            btmp = bio;
831160814Ssimon
832296341Sdelphij            btmp = PKCS7_find_digest(&mdc, btmp, j);
833160814Ssimon
834296341Sdelphij            if (btmp == NULL)
835296341Sdelphij                goto err;
836160814Ssimon
837296341Sdelphij            /*
838296341Sdelphij             * We now have the EVP_MD_CTX, lets do the signing.
839296341Sdelphij             */
840296341Sdelphij            if (!EVP_MD_CTX_copy_ex(&ctx_tmp, mdc))
841296341Sdelphij                goto err;
84255714Skris
843296341Sdelphij            sk = si->auth_attr;
84455714Skris
845296341Sdelphij            /*
846296341Sdelphij             * If there are attributes, we add the digest attribute and only
847296341Sdelphij             * sign the attributes
848296341Sdelphij             */
849296341Sdelphij            if (sk_X509_ATTRIBUTE_num(sk) > 0) {
850296341Sdelphij                if (!do_pkcs7_signed_attrib(si, &ctx_tmp))
851296341Sdelphij                    goto err;
852296341Sdelphij            } else {
853296341Sdelphij                unsigned char *abuf = NULL;
854296341Sdelphij                unsigned int abuflen;
855296341Sdelphij                abuflen = EVP_PKEY_size(si->pkey);
856296341Sdelphij                abuf = OPENSSL_malloc(abuflen);
857296341Sdelphij                if (!abuf)
858296341Sdelphij                    goto err;
85955714Skris
860296341Sdelphij                if (!EVP_SignFinal(&ctx_tmp, abuf, &abuflen, si->pkey)) {
861296341Sdelphij                    PKCS7err(PKCS7_F_PKCS7_DATAFINAL, ERR_R_EVP_LIB);
862296341Sdelphij                    goto err;
863296341Sdelphij                }
864296341Sdelphij                ASN1_STRING_set0(si->enc_digest, abuf, abuflen);
865296341Sdelphij            }
866296341Sdelphij        }
867296341Sdelphij    } else if (i == NID_pkcs7_digest) {
868296341Sdelphij        unsigned char md_data[EVP_MAX_MD_SIZE];
869296341Sdelphij        unsigned int md_len;
870296341Sdelphij        if (!PKCS7_find_digest(&mdc, bio,
871296341Sdelphij                               OBJ_obj2nid(p7->d.digest->md->algorithm)))
872296341Sdelphij            goto err;
873296341Sdelphij        if (!EVP_DigestFinal_ex(mdc, md_data, &md_len))
874296341Sdelphij            goto err;
875296341Sdelphij        M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
876296341Sdelphij    }
87755714Skris
878296341Sdelphij    if (!PKCS7_is_detached(p7)) {
879296341Sdelphij        /*
880296341Sdelphij         * NOTE(emilia): I think we only reach os == NULL here because detached
881296341Sdelphij         * digested data support is broken.
882296341Sdelphij         */
883296341Sdelphij        if (os == NULL)
884296341Sdelphij            goto err;
885296341Sdelphij        if (!(os->flags & ASN1_STRING_FLAG_NDEF)) {
886296341Sdelphij            char *cont;
887296341Sdelphij            long contlen;
888296341Sdelphij            btmp = BIO_find_type(bio, BIO_TYPE_MEM);
889296341Sdelphij            if (btmp == NULL) {
890296341Sdelphij                PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
891296341Sdelphij                goto err;
892296341Sdelphij            }
893296341Sdelphij            contlen = BIO_get_mem_data(btmp, &cont);
894296341Sdelphij            /*
895296341Sdelphij             * Mark the BIO read only then we can use its copy of the data
896296341Sdelphij             * instead of making an extra copy.
897296341Sdelphij             */
898296341Sdelphij            BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
899296341Sdelphij            BIO_set_mem_eof_return(btmp, 0);
900296341Sdelphij            ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
901296341Sdelphij        }
902296341Sdelphij    }
903296341Sdelphij    ret = 1;
904296341Sdelphij err:
905296341Sdelphij    EVP_MD_CTX_cleanup(&ctx_tmp);
906296341Sdelphij    return (ret);
907296341Sdelphij}
90855714Skris
909238405Sjkimint PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si)
910296341Sdelphij{
911296341Sdelphij    EVP_MD_CTX mctx;
912296341Sdelphij    EVP_PKEY_CTX *pctx;
913296341Sdelphij    unsigned char *abuf = NULL;
914296341Sdelphij    int alen;
915296341Sdelphij    size_t siglen;
916296341Sdelphij    const EVP_MD *md = NULL;
917238405Sjkim
918296341Sdelphij    md = EVP_get_digestbyobj(si->digest_alg->algorithm);
919296341Sdelphij    if (md == NULL)
920296341Sdelphij        return 0;
921238405Sjkim
922296341Sdelphij    EVP_MD_CTX_init(&mctx);
923296341Sdelphij    if (EVP_DigestSignInit(&mctx, &pctx, md, NULL, si->pkey) <= 0)
924296341Sdelphij        goto err;
925238405Sjkim
926296341Sdelphij    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
927296341Sdelphij                          EVP_PKEY_CTRL_PKCS7_SIGN, 0, si) <= 0) {
928296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
929296341Sdelphij        goto err;
930296341Sdelphij    }
931238405Sjkim
932296341Sdelphij    alen = ASN1_item_i2d((ASN1_VALUE *)si->auth_attr, &abuf,
933296341Sdelphij                         ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
934296341Sdelphij    if (!abuf)
935296341Sdelphij        goto err;
936296341Sdelphij    if (EVP_DigestSignUpdate(&mctx, abuf, alen) <= 0)
937296341Sdelphij        goto err;
938296341Sdelphij    OPENSSL_free(abuf);
939296341Sdelphij    abuf = NULL;
940296341Sdelphij    if (EVP_DigestSignFinal(&mctx, NULL, &siglen) <= 0)
941296341Sdelphij        goto err;
942296341Sdelphij    abuf = OPENSSL_malloc(siglen);
943296341Sdelphij    if (!abuf)
944296341Sdelphij        goto err;
945296341Sdelphij    if (EVP_DigestSignFinal(&mctx, abuf, &siglen) <= 0)
946296341Sdelphij        goto err;
947238405Sjkim
948296341Sdelphij    if (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN,
949296341Sdelphij                          EVP_PKEY_CTRL_PKCS7_SIGN, 1, si) <= 0) {
950296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_SIGNER_INFO_SIGN, PKCS7_R_CTRL_ERROR);
951296341Sdelphij        goto err;
952296341Sdelphij    }
953238405Sjkim
954296341Sdelphij    EVP_MD_CTX_cleanup(&mctx);
955238405Sjkim
956296341Sdelphij    ASN1_STRING_set0(si->enc_digest, abuf, siglen);
957238405Sjkim
958296341Sdelphij    return 1;
959238405Sjkim
960296341Sdelphij err:
961296341Sdelphij    if (abuf)
962296341Sdelphij        OPENSSL_free(abuf);
963296341Sdelphij    EVP_MD_CTX_cleanup(&mctx);
964296341Sdelphij    return 0;
965238405Sjkim
966296341Sdelphij}
967238405Sjkim
96855714Skrisint PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
969296341Sdelphij                     PKCS7 *p7, PKCS7_SIGNER_INFO *si)
970296341Sdelphij{
971296341Sdelphij    PKCS7_ISSUER_AND_SERIAL *ias;
972296341Sdelphij    int ret = 0, i;
973296341Sdelphij    STACK_OF(X509) *cert;
974296341Sdelphij    X509 *x509;
97555714Skris
976296341Sdelphij    if (p7 == NULL) {
977296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER);
978296341Sdelphij        return 0;
979296341Sdelphij    }
980280268Sdelphij
981296341Sdelphij    if (p7->d.ptr == NULL) {
982296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT);
983296341Sdelphij        return 0;
984296341Sdelphij    }
985280268Sdelphij
986296341Sdelphij    if (PKCS7_type_is_signed(p7)) {
987296341Sdelphij        cert = p7->d.sign->cert;
988296341Sdelphij    } else if (PKCS7_type_is_signedAndEnveloped(p7)) {
989296341Sdelphij        cert = p7->d.signed_and_enveloped->cert;
990296341Sdelphij    } else {
991296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
992296341Sdelphij        goto err;
993296341Sdelphij    }
994296341Sdelphij    /* XXXXXXXXXXXXXXXXXXXXXXX */
995296341Sdelphij    ias = si->issuer_and_serial;
99655714Skris
997296341Sdelphij    x509 = X509_find_by_issuer_and_serial(cert, ias->issuer, ias->serial);
99855714Skris
999296341Sdelphij    /* were we able to find the cert in passed to us */
1000296341Sdelphij    if (x509 == NULL) {
1001296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,
1002296341Sdelphij                 PKCS7_R_UNABLE_TO_FIND_CERTIFICATE);
1003296341Sdelphij        goto err;
1004296341Sdelphij    }
100555714Skris
1006296341Sdelphij    /* Lets verify */
1007296341Sdelphij    if (!X509_STORE_CTX_init(ctx, cert_store, x509, cert)) {
1008296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB);
1009296341Sdelphij        goto err;
1010296341Sdelphij    }
1011296341Sdelphij    X509_STORE_CTX_set_purpose(ctx, X509_PURPOSE_SMIME_SIGN);
1012296341Sdelphij    i = X509_verify_cert(ctx);
1013296341Sdelphij    if (i <= 0) {
1014296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, ERR_R_X509_LIB);
1015296341Sdelphij        X509_STORE_CTX_cleanup(ctx);
1016296341Sdelphij        goto err;
1017296341Sdelphij    }
1018296341Sdelphij    X509_STORE_CTX_cleanup(ctx);
101955714Skris
1020296341Sdelphij    return PKCS7_signatureVerify(bio, p7, si, x509);
1021296341Sdelphij err:
1022296341Sdelphij    return ret;
1023296341Sdelphij}
102455714Skris
102555714Skrisint PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
1026296341Sdelphij                          X509 *x509)
1027296341Sdelphij{
1028296341Sdelphij    ASN1_OCTET_STRING *os;
1029296341Sdelphij    EVP_MD_CTX mdc_tmp, *mdc;
1030296341Sdelphij    int ret = 0, i;
1031296341Sdelphij    int md_type;
1032296341Sdelphij    STACK_OF(X509_ATTRIBUTE) *sk;
1033296341Sdelphij    BIO *btmp;
1034296341Sdelphij    EVP_PKEY *pkey;
103555714Skris
1036296341Sdelphij    EVP_MD_CTX_init(&mdc_tmp);
1037109998Smarkm
1038296341Sdelphij    if (!PKCS7_type_is_signed(p7) && !PKCS7_type_is_signedAndEnveloped(p7)) {
1039296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_WRONG_PKCS7_TYPE);
1040296341Sdelphij        goto err;
1041296341Sdelphij    }
104255714Skris
1043296341Sdelphij    md_type = OBJ_obj2nid(si->digest_alg->algorithm);
104455714Skris
1045296341Sdelphij    btmp = bio;
1046296341Sdelphij    for (;;) {
1047296341Sdelphij        if ((btmp == NULL) ||
1048296341Sdelphij            ((btmp = BIO_find_type(btmp, BIO_TYPE_MD)) == NULL)) {
1049296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
1050296341Sdelphij                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
1051296341Sdelphij            goto err;
1052296341Sdelphij        }
1053296341Sdelphij        BIO_get_md_ctx(btmp, &mdc);
1054296341Sdelphij        if (mdc == NULL) {
1055296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_INTERNAL_ERROR);
1056296341Sdelphij            goto err;
1057296341Sdelphij        }
1058296341Sdelphij        if (EVP_MD_CTX_type(mdc) == md_type)
1059296341Sdelphij            break;
1060296341Sdelphij        /*
1061296341Sdelphij         * Workaround for some broken clients that put the signature OID
1062296341Sdelphij         * instead of the digest OID in digest_alg->algorithm
1063296341Sdelphij         */
1064296341Sdelphij        if (EVP_MD_pkey_type(EVP_MD_CTX_md(mdc)) == md_type)
1065296341Sdelphij            break;
1066296341Sdelphij        btmp = BIO_next(btmp);
1067296341Sdelphij    }
106855714Skris
1069296341Sdelphij    /*
1070296341Sdelphij     * mdc is the digest ctx that we want, unless there are attributes, in
1071296341Sdelphij     * which case the digest is the signed attributes
1072296341Sdelphij     */
1073296341Sdelphij    if (!EVP_MD_CTX_copy_ex(&mdc_tmp, mdc))
1074296341Sdelphij        goto err;
107555714Skris
1076296341Sdelphij    sk = si->auth_attr;
1077296341Sdelphij    if ((sk != NULL) && (sk_X509_ATTRIBUTE_num(sk) != 0)) {
1078296341Sdelphij        unsigned char md_dat[EVP_MAX_MD_SIZE], *abuf = NULL;
1079296341Sdelphij        unsigned int md_len;
1080296341Sdelphij        int alen;
1081296341Sdelphij        ASN1_OCTET_STRING *message_digest;
108255714Skris
1083296341Sdelphij        if (!EVP_DigestFinal_ex(&mdc_tmp, md_dat, &md_len))
1084296341Sdelphij            goto err;
1085296341Sdelphij        message_digest = PKCS7_digest_from_attributes(sk);
1086296341Sdelphij        if (!message_digest) {
1087296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY,
1088296341Sdelphij                     PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST);
1089296341Sdelphij            goto err;
1090296341Sdelphij        }
1091296341Sdelphij        if ((message_digest->length != (int)md_len) ||
1092296341Sdelphij            (memcmp(message_digest->data, md_dat, md_len))) {
109355714Skris#if 0
1094296341Sdelphij            {
1095296341Sdelphij                int ii;
1096296341Sdelphij                for (ii = 0; ii < message_digest->length; ii++)
1097296341Sdelphij                    printf("%02X", message_digest->data[ii]);
1098296341Sdelphij                printf(" sent\n");
1099296341Sdelphij                for (ii = 0; ii < md_len; ii++)
1100296341Sdelphij                    printf("%02X", md_dat[ii]);
1101296341Sdelphij                printf(" calc\n");
1102296341Sdelphij            }
110355714Skris#endif
1104296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_DIGEST_FAILURE);
1105296341Sdelphij            ret = -1;
1106296341Sdelphij            goto err;
1107296341Sdelphij        }
110855714Skris
1109296341Sdelphij        if (!EVP_VerifyInit_ex(&mdc_tmp, EVP_get_digestbynid(md_type), NULL))
1110296341Sdelphij            goto err;
111155714Skris
1112296341Sdelphij        alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
1113296341Sdelphij                             ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY));
1114296341Sdelphij        if (alen <= 0) {
1115296341Sdelphij            PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, ERR_R_ASN1_LIB);
1116296341Sdelphij            ret = -1;
1117296341Sdelphij            goto err;
1118296341Sdelphij        }
1119296341Sdelphij        if (!EVP_VerifyUpdate(&mdc_tmp, abuf, alen))
1120296341Sdelphij            goto err;
1121109998Smarkm
1122296341Sdelphij        OPENSSL_free(abuf);
1123296341Sdelphij    }
112455714Skris
1125296341Sdelphij    os = si->enc_digest;
1126296341Sdelphij    pkey = X509_get_pubkey(x509);
1127296341Sdelphij    if (!pkey) {
1128296341Sdelphij        ret = -1;
1129296341Sdelphij        goto err;
1130296341Sdelphij    }
113155714Skris
1132296341Sdelphij    i = EVP_VerifyFinal(&mdc_tmp, os->data, os->length, pkey);
1133296341Sdelphij    EVP_PKEY_free(pkey);
1134296341Sdelphij    if (i <= 0) {
1135296341Sdelphij        PKCS7err(PKCS7_F_PKCS7_SIGNATUREVERIFY, PKCS7_R_SIGNATURE_FAILURE);
1136296341Sdelphij        ret = -1;
1137296341Sdelphij        goto err;
1138296341Sdelphij    } else
1139296341Sdelphij        ret = 1;
1140296341Sdelphij err:
1141296341Sdelphij    EVP_MD_CTX_cleanup(&mdc_tmp);
1142296341Sdelphij    return (ret);
1143296341Sdelphij}
114455714Skris
114555714SkrisPKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx)
1146296341Sdelphij{
1147296341Sdelphij    STACK_OF(PKCS7_RECIP_INFO) *rsk;
1148296341Sdelphij    PKCS7_RECIP_INFO *ri;
1149296341Sdelphij    int i;
115055714Skris
1151296341Sdelphij    i = OBJ_obj2nid(p7->type);
1152296341Sdelphij    if (i != NID_pkcs7_signedAndEnveloped)
1153296341Sdelphij        return NULL;
1154296341Sdelphij    if (p7->d.signed_and_enveloped == NULL)
1155296341Sdelphij        return NULL;
1156296341Sdelphij    rsk = p7->d.signed_and_enveloped->recipientinfo;
1157296341Sdelphij    if (rsk == NULL)
1158296341Sdelphij        return NULL;
1159296341Sdelphij    ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
1160296341Sdelphij    if (sk_PKCS7_RECIP_INFO_num(rsk) <= idx)
1161296341Sdelphij        return (NULL);
1162296341Sdelphij    ri = sk_PKCS7_RECIP_INFO_value(rsk, idx);
1163296341Sdelphij    return (ri->issuer_and_serial);
1164296341Sdelphij}
116555714Skris
116655714SkrisASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid)
1167296341Sdelphij{
1168296341Sdelphij    return (get_attribute(si->auth_attr, nid));
1169296341Sdelphij}
117055714Skris
117155714SkrisASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid)
1172296341Sdelphij{
1173296341Sdelphij    return (get_attribute(si->unauth_attr, nid));
1174296341Sdelphij}
117555714Skris
117655714Skrisstatic ASN1_TYPE *get_attribute(STACK_OF(X509_ATTRIBUTE) *sk, int nid)
1177296341Sdelphij{
1178296341Sdelphij    int i;
1179296341Sdelphij    X509_ATTRIBUTE *xa;
1180296341Sdelphij    ASN1_OBJECT *o;
118155714Skris
1182296341Sdelphij    o = OBJ_nid2obj(nid);
1183296341Sdelphij    if (!o || !sk)
1184296341Sdelphij        return (NULL);
1185296341Sdelphij    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
1186296341Sdelphij        xa = sk_X509_ATTRIBUTE_value(sk, i);
1187296341Sdelphij        if (OBJ_cmp(xa->object, o) == 0) {
1188296341Sdelphij            if (!xa->single && sk_ASN1_TYPE_num(xa->value.set))
1189296341Sdelphij                return (sk_ASN1_TYPE_value(xa->value.set, 0));
1190296341Sdelphij            else
1191296341Sdelphij                return (NULL);
1192296341Sdelphij        }
1193296341Sdelphij    }
1194296341Sdelphij    return (NULL);
1195296341Sdelphij}
119655714Skris
119755714SkrisASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
119855714Skris{
1199296341Sdelphij    ASN1_TYPE *astype;
1200296341Sdelphij    if (!(astype = get_attribute(sk, NID_pkcs9_messageDigest)))
1201296341Sdelphij        return NULL;
1202296341Sdelphij    return astype->value.octet_string;
120355714Skris}
120455714Skris
120555714Skrisint PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
1206296341Sdelphij                                STACK_OF(X509_ATTRIBUTE) *sk)
1207296341Sdelphij{
1208296341Sdelphij    int i;
120955714Skris
1210296341Sdelphij    if (p7si->auth_attr != NULL)
1211296341Sdelphij        sk_X509_ATTRIBUTE_pop_free(p7si->auth_attr, X509_ATTRIBUTE_free);
1212296341Sdelphij    p7si->auth_attr = sk_X509_ATTRIBUTE_dup(sk);
1213296341Sdelphij    if (p7si->auth_attr == NULL)
1214296341Sdelphij        return 0;
1215296341Sdelphij    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
1216296341Sdelphij        if ((sk_X509_ATTRIBUTE_set(p7si->auth_attr, i,
1217296341Sdelphij                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
1218296341Sdelphij                                                      (sk, i))))
1219296341Sdelphij            == NULL)
1220296341Sdelphij            return (0);
1221296341Sdelphij    }
1222296341Sdelphij    return (1);
1223296341Sdelphij}
122455714Skris
1225296341Sdelphijint PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,
1226296341Sdelphij                         STACK_OF(X509_ATTRIBUTE) *sk)
1227296341Sdelphij{
1228296341Sdelphij    int i;
122955714Skris
1230296341Sdelphij    if (p7si->unauth_attr != NULL)
1231296341Sdelphij        sk_X509_ATTRIBUTE_pop_free(p7si->unauth_attr, X509_ATTRIBUTE_free);
1232296341Sdelphij    p7si->unauth_attr = sk_X509_ATTRIBUTE_dup(sk);
1233296341Sdelphij    if (p7si->unauth_attr == NULL)
1234296341Sdelphij        return 0;
1235296341Sdelphij    for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) {
1236296341Sdelphij        if ((sk_X509_ATTRIBUTE_set(p7si->unauth_attr, i,
1237296341Sdelphij                                   X509_ATTRIBUTE_dup(sk_X509_ATTRIBUTE_value
1238296341Sdelphij                                                      (sk, i))))
1239296341Sdelphij            == NULL)
1240296341Sdelphij            return (0);
1241296341Sdelphij    }
1242296341Sdelphij    return (1);
1243296341Sdelphij}
124455714Skris
124555714Skrisint PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
1246296341Sdelphij                               void *value)
1247296341Sdelphij{
1248296341Sdelphij    return (add_attribute(&(p7si->auth_attr), nid, atrtype, value));
1249296341Sdelphij}
125055714Skris
125155714Skrisint PKCS7_add_attribute(PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
1252296341Sdelphij                        void *value)
1253296341Sdelphij{
1254296341Sdelphij    return (add_attribute(&(p7si->unauth_attr), nid, atrtype, value));
1255296341Sdelphij}
125655714Skris
125755714Skrisstatic int add_attribute(STACK_OF(X509_ATTRIBUTE) **sk, int nid, int atrtype,
1258296341Sdelphij                         void *value)
1259296341Sdelphij{
1260296341Sdelphij    X509_ATTRIBUTE *attr = NULL;
126155714Skris
1262296341Sdelphij    if (*sk == NULL) {
1263296341Sdelphij        *sk = sk_X509_ATTRIBUTE_new_null();
1264296341Sdelphij        if (*sk == NULL)
1265296341Sdelphij            return 0;
1266296341Sdelphij new_attrib:
1267296341Sdelphij        if (!(attr = X509_ATTRIBUTE_create(nid, atrtype, value)))
1268296341Sdelphij            return 0;
1269296341Sdelphij        if (!sk_X509_ATTRIBUTE_push(*sk, attr)) {
1270296341Sdelphij            X509_ATTRIBUTE_free(attr);
1271296341Sdelphij            return 0;
1272296341Sdelphij        }
1273296341Sdelphij    } else {
1274296341Sdelphij        int i;
127555714Skris
1276296341Sdelphij        for (i = 0; i < sk_X509_ATTRIBUTE_num(*sk); i++) {
1277296341Sdelphij            attr = sk_X509_ATTRIBUTE_value(*sk, i);
1278296341Sdelphij            if (OBJ_obj2nid(attr->object) == nid) {
1279296341Sdelphij                X509_ATTRIBUTE_free(attr);
1280296341Sdelphij                attr = X509_ATTRIBUTE_create(nid, atrtype, value);
1281296341Sdelphij                if (attr == NULL)
1282296341Sdelphij                    return 0;
1283296341Sdelphij                if (!sk_X509_ATTRIBUTE_set(*sk, i, attr)) {
1284296341Sdelphij                    X509_ATTRIBUTE_free(attr);
1285296341Sdelphij                    return 0;
1286296341Sdelphij                }
1287296341Sdelphij                goto end;
1288296341Sdelphij            }
1289296341Sdelphij        }
1290296341Sdelphij        goto new_attrib;
1291296341Sdelphij    }
1292296341Sdelphij end:
1293296341Sdelphij    return (1);
1294296341Sdelphij}
1295