1139749Simp/* tasn_enc.c */
2119917Swpaul/*
3119917Swpaul * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4139749Simp * 2000.
5119917Swpaul */
6119917Swpaul/* ====================================================================
7119917Swpaul * Copyright (c) 2000-2004 The OpenSSL Project.  All rights reserved.
8119917Swpaul *
9119917Swpaul * Redistribution and use in source and binary forms, with or without
10119917Swpaul * modification, are permitted provided that the following conditions
11119917Swpaul * are met:
12119917Swpaul *
13119917Swpaul * 1. Redistributions of source code must retain the above copyright
14119917Swpaul *    notice, this list of conditions and the following disclaimer.
15119917Swpaul *
16119917Swpaul * 2. Redistributions in binary form must reproduce the above copyright
17119917Swpaul *    notice, this list of conditions and the following disclaimer in
18119917Swpaul *    the documentation and/or other materials provided with the
19119917Swpaul *    distribution.
20119917Swpaul *
21119917Swpaul * 3. All advertising materials mentioning features or use of this
22119917Swpaul *    software must display the following acknowledgment:
23119917Swpaul *    "This product includes software developed by the OpenSSL Project
24119917Swpaul *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25119917Swpaul *
26119917Swpaul * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27119917Swpaul *    endorse or promote products derived from this software without
28119917Swpaul *    prior written permission. For written permission, please contact
29119917Swpaul *    licensing@OpenSSL.org.
30119917Swpaul *
31119917Swpaul * 5. Products derived from this software may not be called "OpenSSL"
32119917Swpaul *    nor may "OpenSSL" appear in their names without prior written
33119917Swpaul *    permission of the OpenSSL Project.
34119917Swpaul *
35119917Swpaul * 6. Redistributions of any form whatsoever must retain the following
36119917Swpaul *    acknowledgment:
37129879Sphk *    "This product includes software developed by the OpenSSL Project
38119917Swpaul *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39119917Swpaul *
40119917Swpaul * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41119917Swpaul * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42119917Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43119917Swpaul * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44119917Swpaul * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45119917Swpaul * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46119917Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47119917Swpaul * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48119917Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49119917Swpaul * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50119917Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51119917Swpaul * OF THE POSSIBILITY OF SUCH DAMAGE.
52119917Swpaul * ====================================================================
53119917Swpaul *
54119917Swpaul * This product includes cryptographic software written by Eric Young
55119917Swpaul * (eay@cryptsoft.com).  This product includes software written by Tim
56119917Swpaul * Hudson (tjh@cryptsoft.com).
57119917Swpaul *
58119917Swpaul */
59119917Swpaul
60119917Swpaul#include <stddef.h>
61119917Swpaul#include <string.h>
62119917Swpaul#include "cryptlib.h"
63119917Swpaul#include <openssl/asn1.h>
64119917Swpaul#include <openssl/asn1t.h>
65119917Swpaul#include <openssl/objects.h>
66119917Swpaul
67119917Swpaulstatic int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
68119917Swpaul                                 const ASN1_ITEM *it, int tag, int aclass);
69119917Swpaulstatic int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
70119917Swpaul                            int skcontlen, const ASN1_ITEM *item,
71119917Swpaul                            int do_sort, int iclass);
72119917Swpaulstatic int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
73119917Swpaul                                const ASN1_TEMPLATE *tt, int tag, int aclass);
74151545Simpstatic int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
75119917Swpaul                               const ASN1_ITEM *it, int flags);
76119917Swpaul
77119917Swpaul/*
78119917Swpaul * Top level i2d equivalents: the 'ndef' variant instructs the encoder to use
79119917Swpaul * indefinite length constructed encoding, where appropriate
80119917Swpaul */
81119917Swpaul
82134590Sdesint ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out,
83134590Sdes                       const ASN1_ITEM *it)
84119917Swpaul{
85119917Swpaul    return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
86119917Swpaul}
87119917Swpaul
88119917Swpaulint ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
89119917Swpaul{
90164456Sjhb    return asn1_item_flags_i2d(val, out, it, 0);
91164456Sjhb}
92119917Swpaul
93119917Swpaul/*
94119917Swpaul * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out'
95136804Smtm * points to a buffer to output the data to. The new i2d has one additional
96119917Swpaul * feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is
97119917Swpaul * allocated and populated with the encoding.
98136804Smtm */
99119917Swpaul
100175787Syongaristatic int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out,
101173839Syongari                               const ASN1_ITEM *it, int flags)
102119917Swpaul{
103119917Swpaul    if (out && !*out) {
104119917Swpaul        unsigned char *p, *buf;
105119917Swpaul        int len;
106119917Swpaul        len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
107119917Swpaul        if (len <= 0)
108119917Swpaul            return len;
109119917Swpaul        buf = OPENSSL_malloc(len);
110119917Swpaul        if (!buf)
111119917Swpaul            return -1;
112119917Swpaul        p = buf;
113119917Swpaul        ASN1_item_ex_i2d(&val, &p, it, -1, flags);
114119917Swpaul        *out = buf;
115119917Swpaul        return len;
116133282Sdes    }
117119917Swpaul
118119917Swpaul    return ASN1_item_ex_i2d(&val, out, it, -1, flags);
119119917Swpaul}
120119917Swpaul
121119917Swpaul/*
122119917Swpaul * Encode an item, taking care of IMPLICIT tagging (if any). This function
123119917Swpaul * performs the normal item handling: it can be used in external types.
124119917Swpaul */
125119917Swpaul
126119917Swpaulint ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
127119917Swpaul                     const ASN1_ITEM *it, int tag, int aclass)
128119917Swpaul{
129119917Swpaul    const ASN1_TEMPLATE *tt = NULL;
130119917Swpaul    unsigned char *p = NULL;
131119917Swpaul    int i, seqcontlen, seqlen, ndef = 1;
132119917Swpaul    const ASN1_COMPAT_FUNCS *cf;
133119917Swpaul    const ASN1_EXTERN_FUNCS *ef;
134119917Swpaul    const ASN1_AUX *aux = it->funcs;
135119917Swpaul    ASN1_aux_cb *asn1_cb = 0;
136119917Swpaul
137119917Swpaul    if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval)
138119917Swpaul        return 0;
139119917Swpaul
140119917Swpaul    if (aux && aux->asn1_cb)
141164456Sjhb        asn1_cb = aux->asn1_cb;
142164456Sjhb
143119917Swpaul    switch (it->itype) {
144119917Swpaul
145119917Swpaul    case ASN1_ITYPE_PRIMITIVE:
146119917Swpaul        if (it->templates)
147119917Swpaul            return asn1_template_ex_i2d(pval, out, it->templates,
148119917Swpaul                                        tag, aclass);
149119917Swpaul        return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
150119917Swpaul        break;
151119917Swpaul
152119917Swpaul    case ASN1_ITYPE_MSTRING:
153119917Swpaul        return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
154119917Swpaul
155119917Swpaul    case ASN1_ITYPE_CHOICE:
156119917Swpaul        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
157119917Swpaul            return 0;
158119917Swpaul        i = asn1_get_choice_selector(pval, it);
159119917Swpaul        if ((i >= 0) && (i < it->tcount)) {
160119917Swpaul            ASN1_VALUE **pchval;
161119917Swpaul            const ASN1_TEMPLATE *chtt;
162119917Swpaul            chtt = it->templates + i;
163119917Swpaul            pchval = asn1_get_field_ptr(pval, chtt);
164119917Swpaul            return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass);
165119917Swpaul        }
166119917Swpaul        /* Fixme: error condition if selector out of range */
167119917Swpaul        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
168133282Sdes            return 0;
169119917Swpaul        break;
170119917Swpaul
171119917Swpaul    case ASN1_ITYPE_EXTERN:
172119917Swpaul        /* If new style i2d it does all the work */
173119917Swpaul        ef = it->funcs;
174119917Swpaul        return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
175119917Swpaul
176119917Swpaul    case ASN1_ITYPE_COMPAT:
177180954Syongari        /* old style hackery... */
178181556Syongari        cf = it->funcs;
179181556Syongari        if (out)
180119917Swpaul            p = *out;
181143163Simp        i = cf->asn1_i2d(*pval, out);
182119917Swpaul        /*
183119917Swpaul         * Fixup for IMPLICIT tag: note this messes up for tags > 30, but so
184119917Swpaul         * did the old code. Tags > 30 are very rare anyway.
185119917Swpaul         */
186133282Sdes        if (out && (tag != -1))
187119917Swpaul            *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED);
188119917Swpaul        return i;
189119917Swpaul
190119917Swpaul    case ASN1_ITYPE_NDEF_SEQUENCE:
191119917Swpaul        /* Use indefinite length constructed if requested */
192119917Swpaul        if (aclass & ASN1_TFLG_NDEF)
193119917Swpaul            ndef = 2;
194119917Swpaul        /* fall through */
195119917Swpaul
196119917Swpaul    case ASN1_ITYPE_SEQUENCE:
197158075Sscottl        i = asn1_enc_restore(&seqcontlen, out, pval, it);
198158075Sscottl        /* An error occurred */
199158075Sscottl        if (i < 0)
200158075Sscottl            return 0;
201119917Swpaul        /* We have a valid cached encoding... */
202159013Ssilby        if (i > 0)
203158103Ssilby            return seqcontlen;
204158075Sscottl        /* Otherwise carry on */
205119917Swpaul        seqcontlen = 0;
206119917Swpaul        /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
207119917Swpaul        if (tag == -1) {
208119917Swpaul            tag = V_ASN1_SEQUENCE;
209159021Ssilby            /* Retain any other flags in aclass */
210119917Swpaul            aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
211119917Swpaul                | V_ASN1_UNIVERSAL;
212119917Swpaul        }
213119917Swpaul        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
214126470Sjulian            return 0;
215159013Ssilby        /* First work out sequence content length */
216126470Sjulian        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
217133282Sdes            const ASN1_TEMPLATE *seqtt;
218126470Sjulian            ASN1_VALUE **pseqval;
219126470Sjulian            seqtt = asn1_do_adb(pval, tt, 1);
220126470Sjulian            if (!seqtt)
221126470Sjulian                return 0;
222159021Ssilby            pseqval = asn1_get_field_ptr(pval, seqtt);
223126470Sjulian            /* FIXME: check for errors in enhanced version */
224126470Sjulian            seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt,
225119917Swpaul                                               -1, aclass);
226119917Swpaul        }
227119917Swpaul
228133282Sdes        seqlen = ASN1_object_size(ndef, seqcontlen, tag);
229119917Swpaul        if (!out)
230119917Swpaul            return seqlen;
231119917Swpaul        /* Output SEQUENCE header */
232126470Sjulian        ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
233159013Ssilby        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
234126470Sjulian            const ASN1_TEMPLATE *seqtt;
235126470Sjulian            ASN1_VALUE **pseqval;
236126470Sjulian            seqtt = asn1_do_adb(pval, tt, 1);
237126470Sjulian            if (!seqtt)
238126470Sjulian                return 0;
239126470Sjulian            pseqval = asn1_get_field_ptr(pval, seqtt);
240159021Ssilby            /* FIXME: check for errors in enhanced version */
241126470Sjulian            asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
242126470Sjulian        }
243119917Swpaul        if (ndef == 2)
244119917Swpaul            ASN1_put_eoc(out);
245119917Swpaul        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
246133282Sdes            return 0;
247119917Swpaul        return seqlen;
248119917Swpaul
249119917Swpaul    default:
250126470Sjulian        return 0;
251126470Sjulian
252126470Sjulian    }
253126470Sjulian    return 0;
254126470Sjulian}
255126470Sjulian
256126470Sjulianint ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out,
257126470Sjulian                      const ASN1_TEMPLATE *tt)
258158075Sscottl{
259126470Sjulian    return asn1_template_ex_i2d(pval, out, tt, -1, 0);
260126470Sjulian}
261119917Swpaul
262119917Swpaulstatic int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
263119917Swpaul                                const ASN1_TEMPLATE *tt, int tag, int iclass)
264133282Sdes{
265119917Swpaul    int i, ret, flags, ttag, tclass, ndef;
266119917Swpaul    flags = tt->flags;
267119917Swpaul    /*
268119917Swpaul     * Work out tag and class to use: tagging may come either from the
269126470Sjulian     * template or the arguments, not both because this would create
270126470Sjulian     * ambiguity. Additionally the iclass argument may contain some
271119917Swpaul     * additional flags which should be noted and passed down to other
272119917Swpaul     * levels.
273133282Sdes     */
274119917Swpaul    if (flags & ASN1_TFLG_TAG_MASK) {
275119917Swpaul        /* Error if argument and template tagging */
276119917Swpaul        if (tag != -1)
277119917Swpaul            /* FIXME: error code here */
278119917Swpaul            return -1;
279126470Sjulian        /* Get tagging from template */
280126470Sjulian        ttag = tt->tag;
281119917Swpaul        tclass = flags & ASN1_TFLG_TAG_CLASS;
282119917Swpaul    } else if (tag != -1) {
283133282Sdes        /* No template tagging, get from arguments */
284119917Swpaul        ttag = tag;
285119917Swpaul        tclass = iclass & ASN1_TFLG_TAG_CLASS;
286119917Swpaul    } else {
287119917Swpaul        ttag = -1;
288119917Swpaul        tclass = 0;
289119917Swpaul    }
290119917Swpaul    /*
291180954Syongari     * Remove any class mask from iflag.
292133282Sdes     */
293119917Swpaul    iclass &= ~ASN1_TFLG_TAG_CLASS;
294119917Swpaul
295119917Swpaul    /*
296119917Swpaul     * At this point 'ttag' contains the outer tag to use, 'tclass' is the
297158285Ssilby     * class and iclass is any flags passed to this function.
298119917Swpaul     */
299180954Syongari
300133282Sdes    /* if template and arguments require ndef, use it */
301119917Swpaul    if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
302158102Ssilby        ndef = 2;
303119917Swpaul    else
304133282Sdes        ndef = 1;
305119917Swpaul
306133282Sdes    if (flags & ASN1_TFLG_SK_MASK) {
307133282Sdes        /* SET OF, SEQUENCE OF */
308119917Swpaul        STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
309119917Swpaul        int isset, sktag, skaclass;
310133282Sdes        int skcontlen, sklen;
311133282Sdes        ASN1_VALUE *skitem;
312158285Ssilby
313180954Syongari        if (!*pval)
314133282Sdes            return 0;
315119917Swpaul
316119917Swpaul        if (flags & ASN1_TFLG_SET_OF) {
317158102Ssilby            isset = 1;
318119917Swpaul            /* 2 means we reorder */
319133282Sdes            if (flags & ASN1_TFLG_SEQUENCE_OF)
320119917Swpaul                isset = 2;
321119917Swpaul        } else
322119917Swpaul            isset = 0;
323119917Swpaul
324119917Swpaul        /*
325147256Sbrooks         * Work out inner tag value: if EXPLICIT or no tagging use underlying
326119917Swpaul         * type.
327180950Syongari         */
328119917Swpaul        if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
329119917Swpaul            sktag = ttag;
330119917Swpaul            skaclass = tclass;
331136804Smtm        } else {
332175787Syongari            skaclass = V_ASN1_UNIVERSAL;
333119917Swpaul            if (isset)
334119917Swpaul                sktag = V_ASN1_SET;
335119917Swpaul            else
336119917Swpaul                sktag = V_ASN1_SEQUENCE;
337119917Swpaul        }
338119917Swpaul
339119917Swpaul        /* Determine total length of items */
340119917Swpaul        skcontlen = 0;
341119917Swpaul        for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
342127135Snjl            skitem = sk_ASN1_VALUE_value(sk, i);
343119917Swpaul            skcontlen += ASN1_item_ex_i2d(&skitem, NULL,
344119917Swpaul                                          ASN1_ITEM_ptr(tt->item),
345180950Syongari                                          -1, iclass);
346119917Swpaul        }
347119917Swpaul        sklen = ASN1_object_size(ndef, skcontlen, sktag);
348119917Swpaul        /* If EXPLICIT need length of surrounding tag */
349119917Swpaul        if (flags & ASN1_TFLG_EXPTAG)
350119917Swpaul            ret = ASN1_object_size(ndef, sklen, ttag);
351119917Swpaul        else
352119917Swpaul            ret = sklen;
353119917Swpaul
354119917Swpaul        if (!out)
355119917Swpaul            return ret;
356119917Swpaul
357127135Snjl        /* Now encode this lot... */
358119917Swpaul        /* EXPLICIT tag */
359119917Swpaul        if (flags & ASN1_TFLG_EXPTAG)
360180950Syongari            ASN1_put_object(out, ndef, sklen, ttag, tclass);
361119917Swpaul        /* SET or SEQUENCE and IMPLICIT tag */
362119917Swpaul        ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
363119917Swpaul        /* And the stuff itself */
364119917Swpaul        asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
365119917Swpaul                         isset, iclass);
366180950Syongari        if (ndef == 2) {
367119917Swpaul            ASN1_put_eoc(out);
368119917Swpaul            if (flags & ASN1_TFLG_EXPTAG)
369119917Swpaul                ASN1_put_eoc(out);
370119917Swpaul        }
371119917Swpaul
372147256Sbrooks        return ret;
373147256Sbrooks    }
374180950Syongari
375147256Sbrooks    if (flags & ASN1_TFLG_EXPTAG) {
376147256Sbrooks        /* EXPLICIT tagging */
377147256Sbrooks        /* Find length of tagged item */
378119917Swpaul        i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass);
379121816Sbrooks        if (!i)
380119917Swpaul            return 0;
381119917Swpaul        /* Find length of EXPLICIT tag */
382119917Swpaul        ret = ASN1_object_size(ndef, i, ttag);
383119917Swpaul        if (out) {
384119917Swpaul            /* Output tag and item */
385131455Smlaier            ASN1_put_object(out, ndef, i, ttag, tclass);
386131455Smlaier            ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass);
387131455Smlaier            if (ndef == 2)
388119917Swpaul                ASN1_put_eoc(out);
389119917Swpaul        }
390119917Swpaul        return ret;
391119917Swpaul    }
392136804Smtm
393119917Swpaul    /* Either normal or IMPLICIT tagging: combine class and flags */
394136804Smtm    return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
395119917Swpaul                            ttag, tclass | iclass);
396119917Swpaul
397119917Swpaul}
398180950Syongari
399119917Swpaul/* Temporary structure used to hold DER encoding of items for SET OF */
400119917Swpaul
401119917Swpaultypedef struct {
402119917Swpaul    unsigned char *data;
403147256Sbrooks    int length;
404119917Swpaul    ASN1_VALUE *field;
405119917Swpaul} DER_ENC;
406129708Sdes
407129708Sdesstatic int der_cmp(const void *a, const void *b)
408129708Sdes{
409129708Sdes    const DER_ENC *d1 = a, *d2 = b;
410129709Sdes    int cmplen, i;
411129708Sdes    cmplen = (d1->length < d2->length) ? d1->length : d2->length;
412129708Sdes    i = memcmp(d1->data, d2->data, cmplen);
413119917Swpaul    if (i)
414119917Swpaul        return i;
415136804Smtm    return d1->length - d2->length;
416166901Spiso}
417119917Swpaul
418119917Swpaul/* Output the content octets of SET OF or SEQUENCE OF */
419180950Syongari
420119917Swpaulstatic int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
421119917Swpaul                            int skcontlen, const ASN1_ITEM *item,
422119917Swpaul                            int do_sort, int iclass)
423150215Sru{
424119917Swpaul    int i;
425133282Sdes    ASN1_VALUE *skitem;
426119917Swpaul    unsigned char *tmpdat = NULL, *p = NULL;
427119917Swpaul    DER_ENC *derlst = NULL, *tder;
428119917Swpaul    if (do_sort) {
429119917Swpaul        /* Don't need to sort less than 2 items */
430119917Swpaul        if (sk_ASN1_VALUE_num(sk) < 2)
431119917Swpaul            do_sort = 0;
432119917Swpaul        else {
433119917Swpaul            derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk)
434119917Swpaul                                    * sizeof(*derlst));
435119917Swpaul            if (!derlst)
436119917Swpaul                return 0;
437119917Swpaul            tmpdat = OPENSSL_malloc(skcontlen);
438147256Sbrooks            if (!tmpdat) {
439119917Swpaul                OPENSSL_free(derlst);
440119917Swpaul                return 0;
441175787Syongari            }
442119917Swpaul        }
443175787Syongari    }
444175787Syongari    /* If not sorting just output each item */
445175787Syongari    if (!do_sort) {
446175787Syongari        for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
447119917Swpaul            skitem = sk_ASN1_VALUE_value(sk, i);
448119917Swpaul            ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
449119917Swpaul        }
450119917Swpaul        return 1;
451119917Swpaul    }
452180954Syongari    p = tmpdat;
453119917Swpaul
454119917Swpaul    /* Doing sort: build up a list of each member's DER encoding */
455119917Swpaul    for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
456119917Swpaul        skitem = sk_ASN1_VALUE_value(sk, i);
457119917Swpaul        tder->data = p;
458133282Sdes        tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
459119917Swpaul        tder->field = skitem;
460119917Swpaul    }
461119917Swpaul
462119917Swpaul    /* Now sort them */
463119917Swpaul    qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
464119917Swpaul    /* Output sorted DER encoding */
465173839Syongari    p = *out;
466119917Swpaul    for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
467119917Swpaul        memcpy(p, tder->data, tder->length);
468119917Swpaul        p += tder->length;
469119917Swpaul    }
470119917Swpaul    *out = p;
471119917Swpaul    /* If do_sort is 2 then reorder the STACK */
472133282Sdes    if (do_sort == 2) {
473119917Swpaul        for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++)
474119917Swpaul            (void)sk_ASN1_VALUE_set(sk, i, tder->field);
475173839Syongari    }
476173839Syongari    OPENSSL_free(derlst);
477119917Swpaul    OPENSSL_free(tmpdat);
478119917Swpaul    return 1;
479119917Swpaul}
480164456Sjhb
481164456Sjhbstatic int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
482164456Sjhb                                 const ASN1_ITEM *it, int tag, int aclass)
483164456Sjhb{
484164456Sjhb    int len;
485164456Sjhb    int utype;
486164456Sjhb    int usetag;
487164456Sjhb    int ndef = 0;
488164456Sjhb
489164456Sjhb    utype = it->utype;
490164456Sjhb
491164456Sjhb    /*
492164456Sjhb     * Get length of content octets and maybe find out the underlying type.
493164456Sjhb     */
494164456Sjhb
495164456Sjhb    len = asn1_ex_i2c(pval, NULL, &utype, it);
496164456Sjhb
497164456Sjhb    /*
498164456Sjhb     * If SEQUENCE, SET or OTHER then header is included in pseudo content
499164456Sjhb     * octets so don't include tag+length. We need to check here because the
500164456Sjhb     * call to asn1_ex_i2c() could change utype.
501164456Sjhb     */
502164456Sjhb    if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
503164456Sjhb        (utype == V_ASN1_OTHER))
504164456Sjhb        usetag = 0;
505164456Sjhb    else
506164456Sjhb        usetag = 1;
507164456Sjhb
508164456Sjhb    /* -1 means omit type */
509164456Sjhb
510164456Sjhb    if (len == -1)
511164456Sjhb        return 0;
512164456Sjhb
513164456Sjhb    /* -2 return is special meaning use ndef */
514119917Swpaul    if (len == -2) {
515119917Swpaul        ndef = 2;
516119917Swpaul        len = 0;
517119917Swpaul    }
518119917Swpaul
519119917Swpaul    /* If not implicitly tagged get tag from underlying type */
520180954Syongari    if (tag == -1)
521133282Sdes        tag = utype;
522119917Swpaul
523119917Swpaul    /* Output tag+length followed by content octets */
524133282Sdes    if (out) {
525119917Swpaul        if (usetag)
526119917Swpaul            ASN1_put_object(out, ndef, len, tag, aclass);
527119917Swpaul        asn1_ex_i2c(pval, *out, &utype, it);
528119917Swpaul        if (ndef)
529119917Swpaul            ASN1_put_eoc(out);
530119917Swpaul        else
531119917Swpaul            *out += len;
532119917Swpaul    }
533180954Syongari
534133282Sdes    if (usetag)
535133282Sdes        return ASN1_object_size(ndef, len, tag);
536119917Swpaul    return len;
537133282Sdes}
538119917Swpaul
539119917Swpaul/* Produce content octets from a structure */
540119917Swpaul
541119917Swpaulint asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
542119917Swpaul                const ASN1_ITEM *it)
543175787Syongari{
544175787Syongari    ASN1_BOOLEAN *tbool = NULL;
545175787Syongari    ASN1_STRING *strtmp;
546175787Syongari    ASN1_OBJECT *otmp;
547175787Syongari    int utype;
548175787Syongari    const unsigned char *cont;
549175787Syongari    unsigned char c;
550175787Syongari    int len;
551175787Syongari    const ASN1_PRIMITIVE_FUNCS *pf;
552175787Syongari    pf = it->funcs;
553175787Syongari    if (pf && pf->prim_i2c)
554175787Syongari        return pf->prim_i2c(pval, cout, putype, it);
555175787Syongari
556175787Syongari    /* Should type be omitted? */
557175787Syongari    if ((it->itype != ASN1_ITYPE_PRIMITIVE)
558175787Syongari        || (it->utype != V_ASN1_BOOLEAN)) {
559175787Syongari        if (!*pval)
560175787Syongari            return -1;
561175787Syongari    }
562175787Syongari
563175787Syongari    if (it->itype == ASN1_ITYPE_MSTRING) {
564175787Syongari        /* If MSTRING type set the underlying type */
565175787Syongari        strtmp = (ASN1_STRING *)*pval;
566175787Syongari        utype = strtmp->type;
567175787Syongari        *putype = utype;
568175787Syongari    } else if (it->utype == V_ASN1_ANY) {
569175787Syongari        /* If ANY set type and pointer to value */
570175787Syongari        ASN1_TYPE *typ;
571175787Syongari        typ = (ASN1_TYPE *)*pval;
572175787Syongari        utype = typ->type;
573175787Syongari        *putype = utype;
574175787Syongari        pval = &typ->value.asn1_value;
575175787Syongari    } else
576175787Syongari        utype = *putype;
577175787Syongari
578175787Syongari    switch (utype) {
579119917Swpaul    case V_ASN1_OBJECT:
580119917Swpaul        otmp = (ASN1_OBJECT *)*pval;
581119917Swpaul        cont = otmp->data;
582119917Swpaul        len = otmp->length;
583119917Swpaul        break;
584126470Sjulian
585133282Sdes    case V_ASN1_NULL:
586126470Sjulian        cont = NULL;
587180954Syongari        len = 0;
588126470Sjulian        break;
589126470Sjulian
590126470Sjulian    case V_ASN1_BOOLEAN:
591126470Sjulian        tbool = (ASN1_BOOLEAN *)pval;
592126470Sjulian        if (*tbool == -1)
593126470Sjulian            return -1;
594126470Sjulian        if (it->utype != V_ASN1_ANY) {
595158102Ssilby            /*
596119917Swpaul             * Default handling if value == size field then omit
597119917Swpaul             */
598119917Swpaul            if (*tbool && (it->size > 0))
599119917Swpaul                return -1;
600119917Swpaul            if (!*tbool && !it->size)
601119917Swpaul                return -1;
602119917Swpaul        }
603119917Swpaul        c = (unsigned char)*tbool;
604119917Swpaul        cont = &c;
605119917Swpaul        len = 1;
606119917Swpaul        break;
607119917Swpaul
608119917Swpaul    case V_ASN1_BIT_STRING:
609119917Swpaul        return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval,
610119917Swpaul                                   cout ? &cout : NULL);
611119917Swpaul        break;
612158102Ssilby
613119917Swpaul    case V_ASN1_INTEGER:
614119917Swpaul    case V_ASN1_ENUMERATED:
615133282Sdes        /*
616119917Swpaul         * These are all have the same content format as ASN1_INTEGER
617119917Swpaul         */
618119917Swpaul        return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL);
619119917Swpaul        break;
620119917Swpaul
621180954Syongari    case V_ASN1_OCTET_STRING:
622133282Sdes    case V_ASN1_NUMERICSTRING:
623119917Swpaul    case V_ASN1_PRINTABLESTRING:
624119917Swpaul    case V_ASN1_T61STRING:
625158102Ssilby    case V_ASN1_VIDEOTEXSTRING:
626119917Swpaul    case V_ASN1_IA5STRING:
627119917Swpaul    case V_ASN1_UTCTIME:
628119917Swpaul    case V_ASN1_GENERALIZEDTIME:
629119917Swpaul    case V_ASN1_GRAPHICSTRING:
630133282Sdes    case V_ASN1_VISIBLESTRING:
631119917Swpaul    case V_ASN1_GENERALSTRING:
632119917Swpaul    case V_ASN1_UNIVERSALSTRING:
633119917Swpaul    case V_ASN1_BMPSTRING:
634119917Swpaul    case V_ASN1_UTF8STRING:
635119917Swpaul    case V_ASN1_SEQUENCE:
636119917Swpaul    case V_ASN1_SET:
637119917Swpaul    default:
638119917Swpaul        /* All based on ASN1_STRING and handled the same */
639119917Swpaul        strtmp = (ASN1_STRING *)*pval;
640178687Syongari        /* Special handling for NDEF */
641119917Swpaul        if ((it->size == ASN1_TFLG_NDEF)
642119917Swpaul            && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) {
643133282Sdes            if (cout) {
644119917Swpaul                strtmp->data = cout;
645178687Syongari                strtmp->length = 0;
646180954Syongari            }
647119917Swpaul            /* Special return code */
648180954Syongari            return -2;
649133282Sdes        }
650119917Swpaul        cont = strtmp->data;
651178687Syongari        len = strtmp->length;
652119917Swpaul
653119917Swpaul        break;
654119917Swpaul
655119917Swpaul    }
656119917Swpaul    if (cout && len)
657119917Swpaul        memcpy(cout, cont, len);
658119917Swpaul    return len;
659119917Swpaul}
660119917Swpaul