1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stddef.h>
11e1051a39Sopenharmony_ci#include <string.h>
12e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
13e1051a39Sopenharmony_ci#include <openssl/asn1.h>
14e1051a39Sopenharmony_ci#include <openssl/asn1t.h>
15e1051a39Sopenharmony_ci#include <openssl/objects.h>
16e1051a39Sopenharmony_ci#include "crypto/asn1.h"
17e1051a39Sopenharmony_ci#include "asn1_local.h"
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_cistatic int asn1_i2d_ex_primitive(const ASN1_VALUE **pval, unsigned char **out,
20e1051a39Sopenharmony_ci                                 const ASN1_ITEM *it, int tag, int aclass);
21e1051a39Sopenharmony_cistatic int asn1_set_seq_out(STACK_OF(const_ASN1_VALUE) *sk,
22e1051a39Sopenharmony_ci                            unsigned char **out,
23e1051a39Sopenharmony_ci                            int skcontlen, const ASN1_ITEM *item,
24e1051a39Sopenharmony_ci                            int do_sort, int iclass);
25e1051a39Sopenharmony_cistatic int asn1_template_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
26e1051a39Sopenharmony_ci                                const ASN1_TEMPLATE *tt, int tag, int aclass);
27e1051a39Sopenharmony_cistatic int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out,
28e1051a39Sopenharmony_ci                               const ASN1_ITEM *it, int flags);
29e1051a39Sopenharmony_cistatic int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype,
30e1051a39Sopenharmony_ci                       const ASN1_ITEM *it);
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci/*
33e1051a39Sopenharmony_ci * Top level i2d equivalents: the 'ndef' variant instructs the encoder to use
34e1051a39Sopenharmony_ci * indefinite length constructed encoding, where appropriate
35e1051a39Sopenharmony_ci */
36e1051a39Sopenharmony_ci
37e1051a39Sopenharmony_ciint ASN1_item_ndef_i2d(const ASN1_VALUE *val, unsigned char **out,
38e1051a39Sopenharmony_ci                       const ASN1_ITEM *it)
39e1051a39Sopenharmony_ci{
40e1051a39Sopenharmony_ci    return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF);
41e1051a39Sopenharmony_ci}
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ciint ASN1_item_i2d(const ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
44e1051a39Sopenharmony_ci{
45e1051a39Sopenharmony_ci    return asn1_item_flags_i2d(val, out, it, 0);
46e1051a39Sopenharmony_ci}
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_ci/*
49e1051a39Sopenharmony_ci * Encode an ASN1 item, this is use by the standard 'i2d' function. 'out'
50e1051a39Sopenharmony_ci * points to a buffer to output the data to. The new i2d has one additional
51e1051a39Sopenharmony_ci * feature. If the output buffer is NULL (i.e. *out == NULL) then a buffer is
52e1051a39Sopenharmony_ci * allocated and populated with the encoding.
53e1051a39Sopenharmony_ci */
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_cistatic int asn1_item_flags_i2d(const ASN1_VALUE *val, unsigned char **out,
56e1051a39Sopenharmony_ci                               const ASN1_ITEM *it, int flags)
57e1051a39Sopenharmony_ci{
58e1051a39Sopenharmony_ci    if (out != NULL && *out == NULL) {
59e1051a39Sopenharmony_ci        unsigned char *p, *buf;
60e1051a39Sopenharmony_ci        int len;
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci        len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags);
63e1051a39Sopenharmony_ci        if (len <= 0)
64e1051a39Sopenharmony_ci            return len;
65e1051a39Sopenharmony_ci        if ((buf = OPENSSL_malloc(len)) == NULL) {
66e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
67e1051a39Sopenharmony_ci            return -1;
68e1051a39Sopenharmony_ci        }
69e1051a39Sopenharmony_ci        p = buf;
70e1051a39Sopenharmony_ci        ASN1_item_ex_i2d(&val, &p, it, -1, flags);
71e1051a39Sopenharmony_ci        *out = buf;
72e1051a39Sopenharmony_ci        return len;
73e1051a39Sopenharmony_ci    }
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci    return ASN1_item_ex_i2d(&val, out, it, -1, flags);
76e1051a39Sopenharmony_ci}
77e1051a39Sopenharmony_ci
78e1051a39Sopenharmony_ci/*
79e1051a39Sopenharmony_ci * Encode an item, taking care of IMPLICIT tagging (if any). This function
80e1051a39Sopenharmony_ci * performs the normal item handling: it can be used in external types.
81e1051a39Sopenharmony_ci */
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ciint ASN1_item_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
84e1051a39Sopenharmony_ci                     const ASN1_ITEM *it, int tag, int aclass)
85e1051a39Sopenharmony_ci{
86e1051a39Sopenharmony_ci    const ASN1_TEMPLATE *tt = NULL;
87e1051a39Sopenharmony_ci    int i, seqcontlen, seqlen, ndef = 1;
88e1051a39Sopenharmony_ci    const ASN1_EXTERN_FUNCS *ef;
89e1051a39Sopenharmony_ci    const ASN1_AUX *aux = it->funcs;
90e1051a39Sopenharmony_ci    ASN1_aux_const_cb *asn1_cb = NULL;
91e1051a39Sopenharmony_ci
92e1051a39Sopenharmony_ci    if ((it->itype != ASN1_ITYPE_PRIMITIVE) && *pval == NULL)
93e1051a39Sopenharmony_ci        return 0;
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci    if (aux != NULL) {
96e1051a39Sopenharmony_ci        asn1_cb = ((aux->flags & ASN1_AFLG_CONST_CB) != 0) ? aux->asn1_const_cb
97e1051a39Sopenharmony_ci            : (ASN1_aux_const_cb *)aux->asn1_cb; /* backward compatibility */
98e1051a39Sopenharmony_ci    }
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci    switch (it->itype) {
101e1051a39Sopenharmony_ci
102e1051a39Sopenharmony_ci    case ASN1_ITYPE_PRIMITIVE:
103e1051a39Sopenharmony_ci        if (it->templates)
104e1051a39Sopenharmony_ci            return asn1_template_ex_i2d(pval, out, it->templates,
105e1051a39Sopenharmony_ci                                        tag, aclass);
106e1051a39Sopenharmony_ci        return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ci    case ASN1_ITYPE_MSTRING:
109e1051a39Sopenharmony_ci        /*
110e1051a39Sopenharmony_ci         * It never makes sense for multi-strings to have implicit tagging, so
111e1051a39Sopenharmony_ci         * if tag != -1, then this looks like an error in the template.
112e1051a39Sopenharmony_ci         */
113e1051a39Sopenharmony_ci        if (tag != -1) {
114e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE);
115e1051a39Sopenharmony_ci            return -1;
116e1051a39Sopenharmony_ci        }
117e1051a39Sopenharmony_ci        return asn1_i2d_ex_primitive(pval, out, it, -1, aclass);
118e1051a39Sopenharmony_ci
119e1051a39Sopenharmony_ci    case ASN1_ITYPE_CHOICE:
120e1051a39Sopenharmony_ci        /*
121e1051a39Sopenharmony_ci         * It never makes sense for CHOICE types to have implicit tagging, so
122e1051a39Sopenharmony_ci         * if tag != -1, then this looks like an error in the template.
123e1051a39Sopenharmony_ci         */
124e1051a39Sopenharmony_ci        if (tag != -1) {
125e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_ASN1, ASN1_R_BAD_TEMPLATE);
126e1051a39Sopenharmony_ci            return -1;
127e1051a39Sopenharmony_ci        }
128e1051a39Sopenharmony_ci        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
129e1051a39Sopenharmony_ci            return 0;
130e1051a39Sopenharmony_ci        i = ossl_asn1_get_choice_selector_const(pval, it);
131e1051a39Sopenharmony_ci        if ((i >= 0) && (i < it->tcount)) {
132e1051a39Sopenharmony_ci            const ASN1_VALUE **pchval;
133e1051a39Sopenharmony_ci            const ASN1_TEMPLATE *chtt;
134e1051a39Sopenharmony_ci            chtt = it->templates + i;
135e1051a39Sopenharmony_ci            pchval = ossl_asn1_get_const_field_ptr(pval, chtt);
136e1051a39Sopenharmony_ci            return asn1_template_ex_i2d(pchval, out, chtt, -1, aclass);
137e1051a39Sopenharmony_ci        }
138e1051a39Sopenharmony_ci        /* Fixme: error condition if selector out of range */
139e1051a39Sopenharmony_ci        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
140e1051a39Sopenharmony_ci            return 0;
141e1051a39Sopenharmony_ci        break;
142e1051a39Sopenharmony_ci
143e1051a39Sopenharmony_ci    case ASN1_ITYPE_EXTERN:
144e1051a39Sopenharmony_ci        /* If new style i2d it does all the work */
145e1051a39Sopenharmony_ci        ef = it->funcs;
146e1051a39Sopenharmony_ci        return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
147e1051a39Sopenharmony_ci
148e1051a39Sopenharmony_ci    case ASN1_ITYPE_NDEF_SEQUENCE:
149e1051a39Sopenharmony_ci        /* Use indefinite length constructed if requested */
150e1051a39Sopenharmony_ci        if (aclass & ASN1_TFLG_NDEF)
151e1051a39Sopenharmony_ci            ndef = 2;
152e1051a39Sopenharmony_ci        /* fall through */
153e1051a39Sopenharmony_ci
154e1051a39Sopenharmony_ci    case ASN1_ITYPE_SEQUENCE:
155e1051a39Sopenharmony_ci        i = ossl_asn1_enc_restore(&seqcontlen, out, pval, it);
156e1051a39Sopenharmony_ci        /* An error occurred */
157e1051a39Sopenharmony_ci        if (i < 0)
158e1051a39Sopenharmony_ci            return 0;
159e1051a39Sopenharmony_ci        /* We have a valid cached encoding... */
160e1051a39Sopenharmony_ci        if (i > 0)
161e1051a39Sopenharmony_ci            return seqcontlen;
162e1051a39Sopenharmony_ci        /* Otherwise carry on */
163e1051a39Sopenharmony_ci        seqcontlen = 0;
164e1051a39Sopenharmony_ci        /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
165e1051a39Sopenharmony_ci        if (tag == -1) {
166e1051a39Sopenharmony_ci            tag = V_ASN1_SEQUENCE;
167e1051a39Sopenharmony_ci            /* Retain any other flags in aclass */
168e1051a39Sopenharmony_ci            aclass = (aclass & ~ASN1_TFLG_TAG_CLASS)
169e1051a39Sopenharmony_ci                | V_ASN1_UNIVERSAL;
170e1051a39Sopenharmony_ci        }
171e1051a39Sopenharmony_ci        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL))
172e1051a39Sopenharmony_ci            return 0;
173e1051a39Sopenharmony_ci        /* First work out sequence content length */
174e1051a39Sopenharmony_ci        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
175e1051a39Sopenharmony_ci            const ASN1_TEMPLATE *seqtt;
176e1051a39Sopenharmony_ci            const ASN1_VALUE **pseqval;
177e1051a39Sopenharmony_ci            int tmplen;
178e1051a39Sopenharmony_ci            seqtt = ossl_asn1_do_adb(*pval, tt, 1);
179e1051a39Sopenharmony_ci            if (!seqtt)
180e1051a39Sopenharmony_ci                return 0;
181e1051a39Sopenharmony_ci            pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt);
182e1051a39Sopenharmony_ci            tmplen = asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, aclass);
183e1051a39Sopenharmony_ci            if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen))
184e1051a39Sopenharmony_ci                return -1;
185e1051a39Sopenharmony_ci            seqcontlen += tmplen;
186e1051a39Sopenharmony_ci        }
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ci        seqlen = ASN1_object_size(ndef, seqcontlen, tag);
189e1051a39Sopenharmony_ci        if (!out || seqlen == -1)
190e1051a39Sopenharmony_ci            return seqlen;
191e1051a39Sopenharmony_ci        /* Output SEQUENCE header */
192e1051a39Sopenharmony_ci        ASN1_put_object(out, ndef, seqcontlen, tag, aclass);
193e1051a39Sopenharmony_ci        for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
194e1051a39Sopenharmony_ci            const ASN1_TEMPLATE *seqtt;
195e1051a39Sopenharmony_ci            const ASN1_VALUE **pseqval;
196e1051a39Sopenharmony_ci            seqtt = ossl_asn1_do_adb(*pval, tt, 1);
197e1051a39Sopenharmony_ci            if (!seqtt)
198e1051a39Sopenharmony_ci                return 0;
199e1051a39Sopenharmony_ci            pseqval = ossl_asn1_get_const_field_ptr(pval, seqtt);
200e1051a39Sopenharmony_ci            /* FIXME: check for errors in enhanced version */
201e1051a39Sopenharmony_ci            asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass);
202e1051a39Sopenharmony_ci        }
203e1051a39Sopenharmony_ci        if (ndef == 2)
204e1051a39Sopenharmony_ci            ASN1_put_eoc(out);
205e1051a39Sopenharmony_ci        if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL))
206e1051a39Sopenharmony_ci            return 0;
207e1051a39Sopenharmony_ci        return seqlen;
208e1051a39Sopenharmony_ci
209e1051a39Sopenharmony_ci    default:
210e1051a39Sopenharmony_ci        return 0;
211e1051a39Sopenharmony_ci
212e1051a39Sopenharmony_ci    }
213e1051a39Sopenharmony_ci    return 0;
214e1051a39Sopenharmony_ci}
215e1051a39Sopenharmony_ci
216e1051a39Sopenharmony_cistatic int asn1_template_ex_i2d(const ASN1_VALUE **pval, unsigned char **out,
217e1051a39Sopenharmony_ci                                const ASN1_TEMPLATE *tt, int tag, int iclass)
218e1051a39Sopenharmony_ci{
219e1051a39Sopenharmony_ci    const int flags = tt->flags;
220e1051a39Sopenharmony_ci    int i, ret, ttag, tclass, ndef, len;
221e1051a39Sopenharmony_ci    const ASN1_VALUE *tval;
222e1051a39Sopenharmony_ci
223e1051a39Sopenharmony_ci    /*
224e1051a39Sopenharmony_ci     * If field is embedded then val needs fixing so it is a pointer to
225e1051a39Sopenharmony_ci     * a pointer to a field.
226e1051a39Sopenharmony_ci     */
227e1051a39Sopenharmony_ci    if (flags & ASN1_TFLG_EMBED) {
228e1051a39Sopenharmony_ci        tval = (ASN1_VALUE *)pval;
229e1051a39Sopenharmony_ci        pval = &tval;
230e1051a39Sopenharmony_ci    }
231e1051a39Sopenharmony_ci    /*
232e1051a39Sopenharmony_ci     * Work out tag and class to use: tagging may come either from the
233e1051a39Sopenharmony_ci     * template or the arguments, not both because this would create
234e1051a39Sopenharmony_ci     * ambiguity. Additionally the iclass argument may contain some
235e1051a39Sopenharmony_ci     * additional flags which should be noted and passed down to other
236e1051a39Sopenharmony_ci     * levels.
237e1051a39Sopenharmony_ci     */
238e1051a39Sopenharmony_ci    if (flags & ASN1_TFLG_TAG_MASK) {
239e1051a39Sopenharmony_ci        /* Error if argument and template tagging */
240e1051a39Sopenharmony_ci        if (tag != -1)
241e1051a39Sopenharmony_ci            /* FIXME: error code here */
242e1051a39Sopenharmony_ci            return -1;
243e1051a39Sopenharmony_ci        /* Get tagging from template */
244e1051a39Sopenharmony_ci        ttag = tt->tag;
245e1051a39Sopenharmony_ci        tclass = flags & ASN1_TFLG_TAG_CLASS;
246e1051a39Sopenharmony_ci    } else if (tag != -1) {
247e1051a39Sopenharmony_ci        /* No template tagging, get from arguments */
248e1051a39Sopenharmony_ci        ttag = tag;
249e1051a39Sopenharmony_ci        tclass = iclass & ASN1_TFLG_TAG_CLASS;
250e1051a39Sopenharmony_ci    } else {
251e1051a39Sopenharmony_ci        ttag = -1;
252e1051a39Sopenharmony_ci        tclass = 0;
253e1051a39Sopenharmony_ci    }
254e1051a39Sopenharmony_ci    /*
255e1051a39Sopenharmony_ci     * Remove any class mask from iflag.
256e1051a39Sopenharmony_ci     */
257e1051a39Sopenharmony_ci    iclass &= ~ASN1_TFLG_TAG_CLASS;
258e1051a39Sopenharmony_ci
259e1051a39Sopenharmony_ci    /*
260e1051a39Sopenharmony_ci     * At this point 'ttag' contains the outer tag to use, 'tclass' is the
261e1051a39Sopenharmony_ci     * class and iclass is any flags passed to this function.
262e1051a39Sopenharmony_ci     */
263e1051a39Sopenharmony_ci
264e1051a39Sopenharmony_ci    /* if template and arguments require ndef, use it */
265e1051a39Sopenharmony_ci    if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF))
266e1051a39Sopenharmony_ci        ndef = 2;
267e1051a39Sopenharmony_ci    else
268e1051a39Sopenharmony_ci        ndef = 1;
269e1051a39Sopenharmony_ci
270e1051a39Sopenharmony_ci    if (flags & ASN1_TFLG_SK_MASK) {
271e1051a39Sopenharmony_ci        /* SET OF, SEQUENCE OF */
272e1051a39Sopenharmony_ci        STACK_OF(const_ASN1_VALUE) *sk = (STACK_OF(const_ASN1_VALUE) *)*pval;
273e1051a39Sopenharmony_ci        int isset, sktag, skaclass;
274e1051a39Sopenharmony_ci        int skcontlen, sklen;
275e1051a39Sopenharmony_ci        const ASN1_VALUE *skitem;
276e1051a39Sopenharmony_ci
277e1051a39Sopenharmony_ci        if (*pval == NULL)
278e1051a39Sopenharmony_ci            return 0;
279e1051a39Sopenharmony_ci
280e1051a39Sopenharmony_ci        if (flags & ASN1_TFLG_SET_OF) {
281e1051a39Sopenharmony_ci            isset = 1;
282e1051a39Sopenharmony_ci            /* 2 means we reorder */
283e1051a39Sopenharmony_ci            if (flags & ASN1_TFLG_SEQUENCE_OF)
284e1051a39Sopenharmony_ci                isset = 2;
285e1051a39Sopenharmony_ci        } else
286e1051a39Sopenharmony_ci            isset = 0;
287e1051a39Sopenharmony_ci
288e1051a39Sopenharmony_ci        /*
289e1051a39Sopenharmony_ci         * Work out inner tag value: if EXPLICIT or no tagging use underlying
290e1051a39Sopenharmony_ci         * type.
291e1051a39Sopenharmony_ci         */
292e1051a39Sopenharmony_ci        if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
293e1051a39Sopenharmony_ci            sktag = ttag;
294e1051a39Sopenharmony_ci            skaclass = tclass;
295e1051a39Sopenharmony_ci        } else {
296e1051a39Sopenharmony_ci            skaclass = V_ASN1_UNIVERSAL;
297e1051a39Sopenharmony_ci            if (isset)
298e1051a39Sopenharmony_ci                sktag = V_ASN1_SET;
299e1051a39Sopenharmony_ci            else
300e1051a39Sopenharmony_ci                sktag = V_ASN1_SEQUENCE;
301e1051a39Sopenharmony_ci        }
302e1051a39Sopenharmony_ci
303e1051a39Sopenharmony_ci        /* Determine total length of items */
304e1051a39Sopenharmony_ci        skcontlen = 0;
305e1051a39Sopenharmony_ci        for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) {
306e1051a39Sopenharmony_ci            skitem = sk_const_ASN1_VALUE_value(sk, i);
307e1051a39Sopenharmony_ci            len = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item),
308e1051a39Sopenharmony_ci                                   -1, iclass);
309e1051a39Sopenharmony_ci            if (len == -1 || (skcontlen > INT_MAX - len))
310e1051a39Sopenharmony_ci                return -1;
311e1051a39Sopenharmony_ci            if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) {
312e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT);
313e1051a39Sopenharmony_ci                return -1;
314e1051a39Sopenharmony_ci            }
315e1051a39Sopenharmony_ci            skcontlen += len;
316e1051a39Sopenharmony_ci        }
317e1051a39Sopenharmony_ci        sklen = ASN1_object_size(ndef, skcontlen, sktag);
318e1051a39Sopenharmony_ci        if (sklen == -1)
319e1051a39Sopenharmony_ci            return -1;
320e1051a39Sopenharmony_ci        /* If EXPLICIT need length of surrounding tag */
321e1051a39Sopenharmony_ci        if (flags & ASN1_TFLG_EXPTAG)
322e1051a39Sopenharmony_ci            ret = ASN1_object_size(ndef, sklen, ttag);
323e1051a39Sopenharmony_ci        else
324e1051a39Sopenharmony_ci            ret = sklen;
325e1051a39Sopenharmony_ci
326e1051a39Sopenharmony_ci        if (!out || ret == -1)
327e1051a39Sopenharmony_ci            return ret;
328e1051a39Sopenharmony_ci
329e1051a39Sopenharmony_ci        /* Now encode this lot... */
330e1051a39Sopenharmony_ci        /* EXPLICIT tag */
331e1051a39Sopenharmony_ci        if (flags & ASN1_TFLG_EXPTAG)
332e1051a39Sopenharmony_ci            ASN1_put_object(out, ndef, sklen, ttag, tclass);
333e1051a39Sopenharmony_ci        /* SET or SEQUENCE and IMPLICIT tag */
334e1051a39Sopenharmony_ci        ASN1_put_object(out, ndef, skcontlen, sktag, skaclass);
335e1051a39Sopenharmony_ci        /* And the stuff itself */
336e1051a39Sopenharmony_ci        asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item),
337e1051a39Sopenharmony_ci                         isset, iclass);
338e1051a39Sopenharmony_ci        if (ndef == 2) {
339e1051a39Sopenharmony_ci            ASN1_put_eoc(out);
340e1051a39Sopenharmony_ci            if (flags & ASN1_TFLG_EXPTAG)
341e1051a39Sopenharmony_ci                ASN1_put_eoc(out);
342e1051a39Sopenharmony_ci        }
343e1051a39Sopenharmony_ci
344e1051a39Sopenharmony_ci        return ret;
345e1051a39Sopenharmony_ci    }
346e1051a39Sopenharmony_ci
347e1051a39Sopenharmony_ci    if (flags & ASN1_TFLG_EXPTAG) {
348e1051a39Sopenharmony_ci        /* EXPLICIT tagging */
349e1051a39Sopenharmony_ci        /* Find length of tagged item */
350e1051a39Sopenharmony_ci        i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, iclass);
351e1051a39Sopenharmony_ci        if (i == 0) {
352e1051a39Sopenharmony_ci            if ((tt->flags & ASN1_TFLG_OPTIONAL) == 0) {
353e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT);
354e1051a39Sopenharmony_ci                return -1;
355e1051a39Sopenharmony_ci            }
356e1051a39Sopenharmony_ci            return 0;
357e1051a39Sopenharmony_ci        }
358e1051a39Sopenharmony_ci        /* Find length of EXPLICIT tag */
359e1051a39Sopenharmony_ci        ret = ASN1_object_size(ndef, i, ttag);
360e1051a39Sopenharmony_ci        if (out && ret != -1) {
361e1051a39Sopenharmony_ci            /* Output tag and item */
362e1051a39Sopenharmony_ci            ASN1_put_object(out, ndef, i, ttag, tclass);
363e1051a39Sopenharmony_ci            ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, iclass);
364e1051a39Sopenharmony_ci            if (ndef == 2)
365e1051a39Sopenharmony_ci                ASN1_put_eoc(out);
366e1051a39Sopenharmony_ci        }
367e1051a39Sopenharmony_ci        return ret;
368e1051a39Sopenharmony_ci    }
369e1051a39Sopenharmony_ci
370e1051a39Sopenharmony_ci    /* Either normal or IMPLICIT tagging: combine class and flags */
371e1051a39Sopenharmony_ci    len = ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item),
372e1051a39Sopenharmony_ci                              ttag, tclass | iclass);
373e1051a39Sopenharmony_ci    if (len == 0 && (tt->flags & ASN1_TFLG_OPTIONAL) == 0) {
374e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT);
375e1051a39Sopenharmony_ci        return -1;
376e1051a39Sopenharmony_ci    }
377e1051a39Sopenharmony_ci    return len;
378e1051a39Sopenharmony_ci}
379e1051a39Sopenharmony_ci
380e1051a39Sopenharmony_ci/* Temporary structure used to hold DER encoding of items for SET OF */
381e1051a39Sopenharmony_ci
382e1051a39Sopenharmony_citypedef struct {
383e1051a39Sopenharmony_ci    unsigned char *data;
384e1051a39Sopenharmony_ci    int length;
385e1051a39Sopenharmony_ci    const ASN1_VALUE *field;
386e1051a39Sopenharmony_ci} DER_ENC;
387e1051a39Sopenharmony_ci
388e1051a39Sopenharmony_cistatic int der_cmp(const void *a, const void *b)
389e1051a39Sopenharmony_ci{
390e1051a39Sopenharmony_ci    const DER_ENC *d1 = a, *d2 = b;
391e1051a39Sopenharmony_ci    int cmplen, i;
392e1051a39Sopenharmony_ci    cmplen = (d1->length < d2->length) ? d1->length : d2->length;
393e1051a39Sopenharmony_ci    i = memcmp(d1->data, d2->data, cmplen);
394e1051a39Sopenharmony_ci    if (i)
395e1051a39Sopenharmony_ci        return i;
396e1051a39Sopenharmony_ci    return d1->length - d2->length;
397e1051a39Sopenharmony_ci}
398e1051a39Sopenharmony_ci
399e1051a39Sopenharmony_ci/* Output the content octets of SET OF or SEQUENCE OF */
400e1051a39Sopenharmony_ci
401e1051a39Sopenharmony_cistatic int asn1_set_seq_out(STACK_OF(const_ASN1_VALUE) *sk,
402e1051a39Sopenharmony_ci                            unsigned char **out,
403e1051a39Sopenharmony_ci                            int skcontlen, const ASN1_ITEM *item,
404e1051a39Sopenharmony_ci                            int do_sort, int iclass)
405e1051a39Sopenharmony_ci{
406e1051a39Sopenharmony_ci    int i, ret = 0;
407e1051a39Sopenharmony_ci    const ASN1_VALUE *skitem;
408e1051a39Sopenharmony_ci    unsigned char *tmpdat = NULL, *p = NULL;
409e1051a39Sopenharmony_ci    DER_ENC *derlst = NULL, *tder;
410e1051a39Sopenharmony_ci
411e1051a39Sopenharmony_ci    if (do_sort) {
412e1051a39Sopenharmony_ci        /* Don't need to sort less than 2 items */
413e1051a39Sopenharmony_ci        if (sk_const_ASN1_VALUE_num(sk) < 2)
414e1051a39Sopenharmony_ci            do_sort = 0;
415e1051a39Sopenharmony_ci        else {
416e1051a39Sopenharmony_ci            derlst = OPENSSL_malloc(sk_const_ASN1_VALUE_num(sk)
417e1051a39Sopenharmony_ci                                    * sizeof(*derlst));
418e1051a39Sopenharmony_ci            if (derlst == NULL) {
419e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
420e1051a39Sopenharmony_ci                return 0;
421e1051a39Sopenharmony_ci            }
422e1051a39Sopenharmony_ci            tmpdat = OPENSSL_malloc(skcontlen);
423e1051a39Sopenharmony_ci            if (tmpdat == NULL) {
424e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
425e1051a39Sopenharmony_ci                goto err;
426e1051a39Sopenharmony_ci            }
427e1051a39Sopenharmony_ci        }
428e1051a39Sopenharmony_ci    }
429e1051a39Sopenharmony_ci    /* If not sorting just output each item */
430e1051a39Sopenharmony_ci    if (!do_sort) {
431e1051a39Sopenharmony_ci        for (i = 0; i < sk_const_ASN1_VALUE_num(sk); i++) {
432e1051a39Sopenharmony_ci            skitem = sk_const_ASN1_VALUE_value(sk, i);
433e1051a39Sopenharmony_ci            ASN1_item_ex_i2d(&skitem, out, item, -1, iclass);
434e1051a39Sopenharmony_ci        }
435e1051a39Sopenharmony_ci        return 1;
436e1051a39Sopenharmony_ci    }
437e1051a39Sopenharmony_ci    p = tmpdat;
438e1051a39Sopenharmony_ci
439e1051a39Sopenharmony_ci    /* Doing sort: build up a list of each member's DER encoding */
440e1051a39Sopenharmony_ci    for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) {
441e1051a39Sopenharmony_ci        skitem = sk_const_ASN1_VALUE_value(sk, i);
442e1051a39Sopenharmony_ci        tder->data = p;
443e1051a39Sopenharmony_ci        tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass);
444e1051a39Sopenharmony_ci        tder->field = skitem;
445e1051a39Sopenharmony_ci    }
446e1051a39Sopenharmony_ci
447e1051a39Sopenharmony_ci    /* Now sort them */
448e1051a39Sopenharmony_ci    qsort(derlst, sk_const_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
449e1051a39Sopenharmony_ci    /* Output sorted DER encoding */
450e1051a39Sopenharmony_ci    p = *out;
451e1051a39Sopenharmony_ci    for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++) {
452e1051a39Sopenharmony_ci        memcpy(p, tder->data, tder->length);
453e1051a39Sopenharmony_ci        p += tder->length;
454e1051a39Sopenharmony_ci    }
455e1051a39Sopenharmony_ci    *out = p;
456e1051a39Sopenharmony_ci    /* If do_sort is 2 then reorder the STACK */
457e1051a39Sopenharmony_ci    if (do_sort == 2) {
458e1051a39Sopenharmony_ci        for (i = 0, tder = derlst; i < sk_const_ASN1_VALUE_num(sk); i++, tder++)
459e1051a39Sopenharmony_ci            (void)sk_const_ASN1_VALUE_set(sk, i, tder->field);
460e1051a39Sopenharmony_ci    }
461e1051a39Sopenharmony_ci    ret = 1;
462e1051a39Sopenharmony_cierr:
463e1051a39Sopenharmony_ci    OPENSSL_free(derlst);
464e1051a39Sopenharmony_ci    OPENSSL_free(tmpdat);
465e1051a39Sopenharmony_ci    return ret;
466e1051a39Sopenharmony_ci}
467e1051a39Sopenharmony_ci
468e1051a39Sopenharmony_cistatic int asn1_i2d_ex_primitive(const ASN1_VALUE **pval, unsigned char **out,
469e1051a39Sopenharmony_ci                                 const ASN1_ITEM *it, int tag, int aclass)
470e1051a39Sopenharmony_ci{
471e1051a39Sopenharmony_ci    int len;
472e1051a39Sopenharmony_ci    int utype;
473e1051a39Sopenharmony_ci    int usetag;
474e1051a39Sopenharmony_ci    int ndef = 0;
475e1051a39Sopenharmony_ci
476e1051a39Sopenharmony_ci    utype = it->utype;
477e1051a39Sopenharmony_ci
478e1051a39Sopenharmony_ci    /*
479e1051a39Sopenharmony_ci     * Get length of content octets and maybe find out the underlying type.
480e1051a39Sopenharmony_ci     */
481e1051a39Sopenharmony_ci
482e1051a39Sopenharmony_ci    len = asn1_ex_i2c(pval, NULL, &utype, it);
483e1051a39Sopenharmony_ci
484e1051a39Sopenharmony_ci    /*
485e1051a39Sopenharmony_ci     * If SEQUENCE, SET or OTHER then header is included in pseudo content
486e1051a39Sopenharmony_ci     * octets so don't include tag+length. We need to check here because the
487e1051a39Sopenharmony_ci     * call to asn1_ex_i2c() could change utype.
488e1051a39Sopenharmony_ci     */
489e1051a39Sopenharmony_ci    if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
490e1051a39Sopenharmony_ci        (utype == V_ASN1_OTHER))
491e1051a39Sopenharmony_ci        usetag = 0;
492e1051a39Sopenharmony_ci    else
493e1051a39Sopenharmony_ci        usetag = 1;
494e1051a39Sopenharmony_ci
495e1051a39Sopenharmony_ci    /* -1 means omit type */
496e1051a39Sopenharmony_ci
497e1051a39Sopenharmony_ci    if (len == -1)
498e1051a39Sopenharmony_ci        return 0;
499e1051a39Sopenharmony_ci
500e1051a39Sopenharmony_ci    /* -2 return is special meaning use ndef */
501e1051a39Sopenharmony_ci    if (len == -2) {
502e1051a39Sopenharmony_ci        ndef = 2;
503e1051a39Sopenharmony_ci        len = 0;
504e1051a39Sopenharmony_ci    }
505e1051a39Sopenharmony_ci
506e1051a39Sopenharmony_ci    /* If not implicitly tagged get tag from underlying type */
507e1051a39Sopenharmony_ci    if (tag == -1)
508e1051a39Sopenharmony_ci        tag = utype;
509e1051a39Sopenharmony_ci
510e1051a39Sopenharmony_ci    /* Output tag+length followed by content octets */
511e1051a39Sopenharmony_ci    if (out) {
512e1051a39Sopenharmony_ci        if (usetag)
513e1051a39Sopenharmony_ci            ASN1_put_object(out, ndef, len, tag, aclass);
514e1051a39Sopenharmony_ci        asn1_ex_i2c(pval, *out, &utype, it);
515e1051a39Sopenharmony_ci        if (ndef)
516e1051a39Sopenharmony_ci            ASN1_put_eoc(out);
517e1051a39Sopenharmony_ci        else
518e1051a39Sopenharmony_ci            *out += len;
519e1051a39Sopenharmony_ci    }
520e1051a39Sopenharmony_ci
521e1051a39Sopenharmony_ci    if (usetag)
522e1051a39Sopenharmony_ci        return ASN1_object_size(ndef, len, tag);
523e1051a39Sopenharmony_ci    return len;
524e1051a39Sopenharmony_ci}
525e1051a39Sopenharmony_ci
526e1051a39Sopenharmony_ci/* Produce content octets from a structure */
527e1051a39Sopenharmony_ci
528e1051a39Sopenharmony_cistatic int asn1_ex_i2c(const ASN1_VALUE **pval, unsigned char *cout, int *putype,
529e1051a39Sopenharmony_ci                       const ASN1_ITEM *it)
530e1051a39Sopenharmony_ci{
531e1051a39Sopenharmony_ci    ASN1_BOOLEAN *tbool = NULL;
532e1051a39Sopenharmony_ci    ASN1_STRING *strtmp;
533e1051a39Sopenharmony_ci    ASN1_OBJECT *otmp;
534e1051a39Sopenharmony_ci    int utype;
535e1051a39Sopenharmony_ci    const unsigned char *cont;
536e1051a39Sopenharmony_ci    unsigned char c;
537e1051a39Sopenharmony_ci    int len;
538e1051a39Sopenharmony_ci    const ASN1_PRIMITIVE_FUNCS *pf;
539e1051a39Sopenharmony_ci    pf = it->funcs;
540e1051a39Sopenharmony_ci    if (pf && pf->prim_i2c)
541e1051a39Sopenharmony_ci        return pf->prim_i2c(pval, cout, putype, it);
542e1051a39Sopenharmony_ci
543e1051a39Sopenharmony_ci    /* Should type be omitted? */
544e1051a39Sopenharmony_ci    if ((it->itype != ASN1_ITYPE_PRIMITIVE)
545e1051a39Sopenharmony_ci        || (it->utype != V_ASN1_BOOLEAN)) {
546e1051a39Sopenharmony_ci        if (*pval == NULL)
547e1051a39Sopenharmony_ci            return -1;
548e1051a39Sopenharmony_ci    }
549e1051a39Sopenharmony_ci
550e1051a39Sopenharmony_ci    if (it->itype == ASN1_ITYPE_MSTRING) {
551e1051a39Sopenharmony_ci        /* If MSTRING type set the underlying type */
552e1051a39Sopenharmony_ci        strtmp = (ASN1_STRING *)*pval;
553e1051a39Sopenharmony_ci        utype = strtmp->type;
554e1051a39Sopenharmony_ci        *putype = utype;
555e1051a39Sopenharmony_ci    } else if (it->utype == V_ASN1_ANY) {
556e1051a39Sopenharmony_ci        /* If ANY set type and pointer to value */
557e1051a39Sopenharmony_ci        ASN1_TYPE *typ;
558e1051a39Sopenharmony_ci        typ = (ASN1_TYPE *)*pval;
559e1051a39Sopenharmony_ci        utype = typ->type;
560e1051a39Sopenharmony_ci        *putype = utype;
561e1051a39Sopenharmony_ci        pval = (const ASN1_VALUE **)&typ->value.asn1_value; /* actually is const */
562e1051a39Sopenharmony_ci    } else
563e1051a39Sopenharmony_ci        utype = *putype;
564e1051a39Sopenharmony_ci
565e1051a39Sopenharmony_ci    switch (utype) {
566e1051a39Sopenharmony_ci    case V_ASN1_OBJECT:
567e1051a39Sopenharmony_ci        otmp = (ASN1_OBJECT *)*pval;
568e1051a39Sopenharmony_ci        cont = otmp->data;
569e1051a39Sopenharmony_ci        len = otmp->length;
570e1051a39Sopenharmony_ci        if (cont == NULL || len == 0)
571e1051a39Sopenharmony_ci            return -1;
572e1051a39Sopenharmony_ci        break;
573e1051a39Sopenharmony_ci
574e1051a39Sopenharmony_ci    case V_ASN1_NULL:
575e1051a39Sopenharmony_ci        cont = NULL;
576e1051a39Sopenharmony_ci        len = 0;
577e1051a39Sopenharmony_ci        break;
578e1051a39Sopenharmony_ci
579e1051a39Sopenharmony_ci    case V_ASN1_BOOLEAN:
580e1051a39Sopenharmony_ci        tbool = (ASN1_BOOLEAN *)pval;
581e1051a39Sopenharmony_ci        if (*tbool == -1)
582e1051a39Sopenharmony_ci            return -1;
583e1051a39Sopenharmony_ci        if (it->utype != V_ASN1_ANY) {
584e1051a39Sopenharmony_ci            /*
585e1051a39Sopenharmony_ci             * Default handling if value == size field then omit
586e1051a39Sopenharmony_ci             */
587e1051a39Sopenharmony_ci            if (*tbool && (it->size > 0))
588e1051a39Sopenharmony_ci                return -1;
589e1051a39Sopenharmony_ci            if (!*tbool && !it->size)
590e1051a39Sopenharmony_ci                return -1;
591e1051a39Sopenharmony_ci        }
592e1051a39Sopenharmony_ci        c = (unsigned char)*tbool;
593e1051a39Sopenharmony_ci        cont = &c;
594e1051a39Sopenharmony_ci        len = 1;
595e1051a39Sopenharmony_ci        break;
596e1051a39Sopenharmony_ci
597e1051a39Sopenharmony_ci    case V_ASN1_BIT_STRING:
598e1051a39Sopenharmony_ci        return ossl_i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval,
599e1051a39Sopenharmony_ci                                        cout ? &cout : NULL);
600e1051a39Sopenharmony_ci
601e1051a39Sopenharmony_ci    case V_ASN1_INTEGER:
602e1051a39Sopenharmony_ci    case V_ASN1_ENUMERATED:
603e1051a39Sopenharmony_ci        /*
604e1051a39Sopenharmony_ci         * These are all have the same content format as ASN1_INTEGER
605e1051a39Sopenharmony_ci         */
606e1051a39Sopenharmony_ci        return ossl_i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL);
607e1051a39Sopenharmony_ci
608e1051a39Sopenharmony_ci    case V_ASN1_OCTET_STRING:
609e1051a39Sopenharmony_ci    case V_ASN1_NUMERICSTRING:
610e1051a39Sopenharmony_ci    case V_ASN1_PRINTABLESTRING:
611e1051a39Sopenharmony_ci    case V_ASN1_T61STRING:
612e1051a39Sopenharmony_ci    case V_ASN1_VIDEOTEXSTRING:
613e1051a39Sopenharmony_ci    case V_ASN1_IA5STRING:
614e1051a39Sopenharmony_ci    case V_ASN1_UTCTIME:
615e1051a39Sopenharmony_ci    case V_ASN1_GENERALIZEDTIME:
616e1051a39Sopenharmony_ci    case V_ASN1_GRAPHICSTRING:
617e1051a39Sopenharmony_ci    case V_ASN1_VISIBLESTRING:
618e1051a39Sopenharmony_ci    case V_ASN1_GENERALSTRING:
619e1051a39Sopenharmony_ci    case V_ASN1_UNIVERSALSTRING:
620e1051a39Sopenharmony_ci    case V_ASN1_BMPSTRING:
621e1051a39Sopenharmony_ci    case V_ASN1_UTF8STRING:
622e1051a39Sopenharmony_ci    case V_ASN1_SEQUENCE:
623e1051a39Sopenharmony_ci    case V_ASN1_SET:
624e1051a39Sopenharmony_ci    default:
625e1051a39Sopenharmony_ci        /* All based on ASN1_STRING and handled the same */
626e1051a39Sopenharmony_ci        strtmp = (ASN1_STRING *)*pval;
627e1051a39Sopenharmony_ci        /* Special handling for NDEF */
628e1051a39Sopenharmony_ci        if ((it->size == ASN1_TFLG_NDEF)
629e1051a39Sopenharmony_ci            && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) {
630e1051a39Sopenharmony_ci            if (cout) {
631e1051a39Sopenharmony_ci                strtmp->data = cout;
632e1051a39Sopenharmony_ci                strtmp->length = 0;
633e1051a39Sopenharmony_ci            }
634e1051a39Sopenharmony_ci            /* Special return code */
635e1051a39Sopenharmony_ci            return -2;
636e1051a39Sopenharmony_ci        }
637e1051a39Sopenharmony_ci        cont = strtmp->data;
638e1051a39Sopenharmony_ci        len = strtmp->length;
639e1051a39Sopenharmony_ci
640e1051a39Sopenharmony_ci        break;
641e1051a39Sopenharmony_ci
642e1051a39Sopenharmony_ci    }
643e1051a39Sopenharmony_ci    if (cout && len)
644e1051a39Sopenharmony_ci        memcpy(cout, cont, len);
645e1051a39Sopenharmony_ci    return len;
646e1051a39Sopenharmony_ci}
647