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