f6d33e177672de624ccb450b78bc6d7e34700a06
[openssl.git] / crypto / asn1 / tasn_enc.c
1 /* tasn_enc.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59
60 #include <stddef.h>
61 #include <openssl/asn1.h>
62 #include <openssl/asn1t.h>
63 #include <openssl/objects.h>
64
65 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
66 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *seq, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int isset);
67
68 /* Encode an ASN1 item, this is compatible with the
69  * standard 'i2d' function. 'out' points to 
70  * a buffer to output the data to, in future we will
71  * have more advanced versions that can output data
72  * a piece at a time and this will simply be a special
73  * case.
74  *
75  * The new i2d has one additional feature. If the output
76  * buffer is NULL (i.e. *out == NULL) then a buffer is
77  * allocated and populated with the encoding.
78  */
79
80
81 int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it)
82 {
83         if(out && !*out) {
84                 unsigned char *p, *buf;
85                 int len;
86                 len = ASN1_item_ex_i2d(&val, NULL, it, -1, 0);
87                 if(len <= 0) return len;
88                 buf = OPENSSL_malloc(len);
89                 if(!buf) return -1;
90                 p = buf;
91                 ASN1_item_ex_i2d(&val, &p, it, -1, 0);
92                 *out = buf;
93                 return len;
94         }
95                 
96         return ASN1_item_ex_i2d(&val, out, it, -1, 0);
97 }
98
99 /* Encode an item, taking care of IMPLICIT tagging (if any).
100  * This function performs the normal item handling: it can be
101  * used in external types.
102  */
103
104 int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass)
105 {
106         const ASN1_TEMPLATE *tt = NULL;
107         unsigned char *p = NULL;
108         int i, seqcontlen, seqlen;
109         ASN1_STRING *strtmp;
110         const ASN1_COMPAT_FUNCS *cf;
111         const ASN1_EXTERN_FUNCS *ef;
112         const ASN1_AUX *aux = it->funcs;
113         ASN1_aux_cb *asn1_cb;
114         if((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) return 0;
115         if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb;
116         else asn1_cb = 0;
117
118         switch(it->itype) {
119
120                 case ASN1_ITYPE_PRIMITIVE:
121                 if(it->templates)
122                         return ASN1_template_i2d(pval, out, it->templates);
123                 return asn1_i2d_ex_primitive(pval, out, it, tag, aclass);
124                 break;
125
126                 case ASN1_ITYPE_MSTRING:
127                 strtmp = (ASN1_STRING *)*pval;
128                 return asn1_i2d_ex_primitive(pval, out, it, -1, 0);
129
130                 case ASN1_ITYPE_CHOICE:
131                 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it))
132                                 return 0;
133                 i = asn1_get_choice_selector(pval, it);
134                 if((i >= 0) && (i < it->tcount)) {
135                         ASN1_VALUE **pchval;
136                         const ASN1_TEMPLATE *chtt;
137                         chtt = it->templates + i;
138                         pchval = asn1_get_field_ptr(pval, chtt);
139                         return ASN1_template_i2d(pchval, out, chtt);
140                 } 
141                 /* Fixme: error condition if selector out of range */
142                 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it))
143                                 return 0;
144                 break;
145
146                 case ASN1_ITYPE_EXTERN:
147                 /* If new style i2d it does all the work */
148                 ef = it->funcs;
149                 return ef->asn1_ex_i2d(pval, out, it, tag, aclass);
150
151                 case ASN1_ITYPE_COMPAT:
152                 /* old style hackery... */
153                 cf = it->funcs;
154                 if(out) p = *out;
155                 i = cf->asn1_i2d(*pval, out);
156                 /* Fixup for IMPLICIT tag: note this messes up for tags > 30,
157                  * but so did the old code. Tags > 30 are very rare anyway.
158                  */
159                 if(out && (tag != -1))
160                         *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED);
161                 return i;
162                 
163                 case ASN1_ITYPE_SEQUENCE:
164                 i = asn1_enc_restore(&seqcontlen, out, pval, it);
165                 /* An error occurred */
166                 if(i < 0) return 0;
167                 /* We have a valid cached encoding... */
168                 if(i > 0) return seqcontlen;
169                 /* Otherwise carry on */
170                 seqcontlen = 0;
171                 /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */
172                 if(tag == -1) {
173                         tag = V_ASN1_SEQUENCE;
174                         aclass = V_ASN1_UNIVERSAL;
175                 }
176                 if(asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it))
177                                 return 0;
178                 /* First work out sequence content length */
179                 for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
180                         const ASN1_TEMPLATE *seqtt;
181                         ASN1_VALUE **pseqval;
182                         seqtt = asn1_do_adb(pval, tt, 1);
183                         if(!seqtt) return 0;
184                         pseqval = asn1_get_field_ptr(pval, seqtt);
185                         /* FIXME: check for errors in enhanced version */
186                         /* FIXME: special handling of indefinite length encoding */
187                         seqcontlen += ASN1_template_i2d(pseqval, NULL, seqtt);
188                 }
189                 seqlen = ASN1_object_size(1, seqcontlen, tag);
190                 if(!out) return seqlen;
191                 /* Output SEQUENCE header */
192                 ASN1_put_object(out, 1, seqcontlen, tag, aclass);
193                 for(i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
194                         const ASN1_TEMPLATE *seqtt;
195                         ASN1_VALUE **pseqval;
196                         seqtt = asn1_do_adb(pval, tt, 1);
197                         if(!seqtt) return 0;
198                         pseqval = asn1_get_field_ptr(pval, seqtt);
199                         /* FIXME: check for errors in enhanced version */
200                         ASN1_template_i2d(pseqval, out, seqtt);
201                 }
202                 if(asn1_cb  && !asn1_cb(ASN1_OP_I2D_POST, pval, it))
203                                 return 0;
204                 return seqlen;
205
206                 default:
207                 return 0;
208         }
209         return 0;
210 }
211
212 int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt)
213 {
214         int i, ret, flags, aclass;
215         flags = tt->flags;
216         aclass = flags & ASN1_TFLG_TAG_CLASS;
217         if(flags & ASN1_TFLG_SK_MASK) {
218                 /* SET OF, SEQUENCE OF */
219                 STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
220                 int isset, sktag, skaclass;
221                 int skcontlen, sklen;
222                 ASN1_VALUE *skitem;
223                 if(!*pval) return 0;
224                 isset = flags & ASN1_TFLG_SET_OF;
225                 /* First work out inner tag value */
226                 if(flags & ASN1_TFLG_IMPTAG) {
227                         sktag = tt->tag;
228                         skaclass = aclass;
229                 } else {
230                         skaclass = V_ASN1_UNIVERSAL;
231                         if(isset) sktag = V_ASN1_SET;
232                         else sktag = V_ASN1_SEQUENCE;
233                 }
234                 /* Now work out length of items */
235                 skcontlen = 0;
236                 for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
237                         skitem = sk_ASN1_VALUE_value(sk, i);
238                         skcontlen += ASN1_item_ex_i2d(&skitem, NULL, tt->item, -1, 0);
239                 }
240                 sklen = ASN1_object_size(1, skcontlen, sktag);
241                 /* If EXPLICIT need length of surrounding tag */
242                 if(flags & ASN1_TFLG_EXPTAG)
243                         ret = ASN1_object_size(1, sklen, tt->tag);
244                 else ret = sklen;
245
246                 if(!out) return ret;
247
248                 /* Now encode this lot... */
249                 /* EXPLICIT tag */
250                 if(flags & ASN1_TFLG_EXPTAG)
251                         ASN1_put_object(out, 1, sklen, tt->tag, aclass);
252                 /* SET or SEQUENCE and IMPLICIT tag */
253                 ASN1_put_object(out, 1, skcontlen, sktag, skaclass);
254                 /* And finally the stuff itself */
255                 asn1_set_seq_out(sk, out, skcontlen, tt->item, isset);
256
257                 return ret;
258         }
259                         
260         if(flags & ASN1_TFLG_EXPTAG) {
261                 /* EXPLICIT tagging */
262                 /* Find length of tagged item */
263                 i = ASN1_item_ex_i2d(pval, NULL, tt->item, -1, 0);
264                 if(!i) return 0;
265                 /* Find length of EXPLICIT tag */
266                 ret = ASN1_object_size(1, i, tt->tag);
267                 if(out) {
268                         /* Output tag and item */
269                         ASN1_put_object(out, 1, i, tt->tag, aclass);
270                         ASN1_item_ex_i2d(pval, out, tt->item, -1, 0);
271                 }
272                 return ret;
273         }
274         if(flags & ASN1_TFLG_IMPTAG) {
275                 /* IMPLICIT tagging */
276                 return ASN1_item_ex_i2d(pval, out, tt->item, tt->tag, aclass);
277         }
278         /* Nothing special: treat as normal */
279         return ASN1_item_ex_i2d(pval, out, tt->item, -1, 0);
280 }
281
282 /* Temporary structure used to hold DER encoding of items for SET OF */
283
284 typedef struct {
285         unsigned char *data;
286         int length;
287 } DER_ENC;
288
289 static int der_cmp(const void *a, const void *b)
290 {
291         const DER_ENC *d1 = a, *d2 = b;
292         int cmplen, i;
293         cmplen = (d1->length < d2->length) ? d1->length : d2->length;
294         i = memcmp(d1->data, d2->data, cmplen);
295         if(i) return i;
296         return d1->length - d2->length;
297 }
298
299 /* Output the content octets of SET OF or SEQUENCE OF */
300
301 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, int skcontlen, const ASN1_ITEM *item, int do_sort)
302 {
303         int i;
304         ASN1_VALUE *skitem;
305         unsigned char *tmpdat, *p;
306         DER_ENC *derlst, *tder;
307         if(do_sort) {
308                 /* Don't need to sort less than 2 items */
309                 if(sk_ASN1_VALUE_num(sk) < 2) do_sort = 0;
310                 else {
311                         derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) * sizeof(*derlst));
312                         tmpdat = OPENSSL_malloc(skcontlen);
313                         if(!derlst || !tmpdat) return 0;
314                 }
315         }
316         /* If not sorting just output each item */
317         if(!do_sort) {
318                 for(i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
319                         skitem = sk_ASN1_VALUE_value(sk, i);
320                         ASN1_item_i2d(skitem, out, item);
321                 }
322                 return 1;
323         }
324         p = tmpdat;
325         /* Doing sort: build up a list of each member's DER encoding */
326         for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
327                 skitem = sk_ASN1_VALUE_value(sk, i);
328                 tder->data = p;
329                 tder->length = ASN1_item_i2d(skitem, &p, item);
330         }
331         /* Now sort them */
332         qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp);
333         /* Output sorted DER encoding */        
334         p = *out;
335         for(i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) {
336                 memcpy(p, tder->data, tder->length);
337                 p += tder->length;
338         }
339         *out = p;
340         OPENSSL_free(derlst);
341         OPENSSL_free(tmpdat);
342         return 1;
343 }
344
345 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass)
346 {
347         int len;
348         int utype;
349         int usetag;
350
351         utype = it->utype;
352
353         /* Get length of content octets and maybe find
354          * out the underlying type.
355          */
356
357         len = asn1_ex_i2c(pval, NULL, &utype, it);
358
359         /* If SEQUENCE, SET or OTHER then header is
360          * included in pseudo content octets so don't
361          * include tag+length. We need to check here
362          * because the call to asn1_ex_i2c() could change
363          * utype.
364          */
365         if((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) ||
366            (utype == V_ASN1_OTHER))
367                 usetag = 0;
368         else usetag = 1;
369
370         /* -1 means omit type */
371
372         if(len == -1) return 0;
373
374         /* If not implicitly tagged get tag from underlying type */
375         if(tag == -1) tag = utype;
376
377         /* Output tag+length followed by content octets */
378         if(out) {
379                 if(usetag) ASN1_put_object(out, 0, len, tag, aclass);
380                 asn1_ex_i2c(pval, *out, &utype, it);
381                 *out += len;
382         }
383
384         if(usetag) return ASN1_object_size(0, len, tag);
385         return len;
386 }
387
388 /* Produce content octets from a structure */
389
390 int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, const ASN1_ITEM *it)
391 {
392         ASN1_BOOLEAN *tbool = NULL;
393         ASN1_STRING *strtmp;
394         ASN1_OBJECT *otmp;
395         int utype;
396         unsigned char *cont, c;
397         int len;
398         const ASN1_PRIMITIVE_FUNCS *pf;
399         pf = it->funcs;
400         if(pf && pf->prim_i2c) return pf->prim_i2c(pval, cout, putype, it);
401
402         /* Should type be omitted? */
403         if((it->itype != ASN1_ITYPE_PRIMITIVE) || (it->utype != V_ASN1_BOOLEAN)) {
404                 if(!*pval) return -1;
405         }
406
407         if(it->itype == ASN1_ITYPE_MSTRING) {
408                 /* If MSTRING type set the underlying type */
409                 strtmp = (ASN1_STRING *)*pval;
410                 utype = strtmp->type;
411                 *putype = utype;
412         } else if(it->utype == V_ASN1_ANY) {
413                 /* If ANY set type and pointer to value */
414                 ASN1_TYPE *typ;
415                 typ = (ASN1_TYPE *)*pval;
416                 utype = typ->type;
417                 *putype = utype;
418                 pval = (ASN1_VALUE **)&typ->value.ptr;
419         } else utype = *putype;
420
421         switch(utype) {
422                 case V_ASN1_OBJECT:
423                 otmp = (ASN1_OBJECT *)*pval;
424                 cont = otmp->data;
425                 len = otmp->length;
426                 break;
427
428                 case V_ASN1_NULL:
429                 cont = NULL;
430                 len = 0;
431                 break;
432
433                 case V_ASN1_BOOLEAN:
434                 tbool = (ASN1_BOOLEAN *)pval;
435                 if(*tbool == -1) return -1;
436                 /* Default handling if value == size field then omit */
437                 if(*tbool && (it->size > 0)) return -1;
438                 if(!*tbool && !it->size) return -1;
439                 c = (unsigned char)*tbool;
440                 cont = &c;
441                 len = 1;
442                 break;
443
444                 case V_ASN1_BIT_STRING:
445                 return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, cout ? &cout : NULL);
446                 break;
447
448                 case V_ASN1_INTEGER:
449                 case V_ASN1_NEG_INTEGER:
450                 case V_ASN1_ENUMERATED:
451                 case V_ASN1_NEG_ENUMERATED:
452                 /* These are all have the same content format
453                  * as ASN1_INTEGER
454                  */
455                 return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL);
456                 break;
457
458                 case V_ASN1_OCTET_STRING:
459                 case V_ASN1_NUMERICSTRING:
460                 case V_ASN1_PRINTABLESTRING:
461                 case V_ASN1_T61STRING:
462                 case V_ASN1_VIDEOTEXSTRING:
463                 case V_ASN1_IA5STRING:
464                 case V_ASN1_UTCTIME:
465                 case V_ASN1_GENERALIZEDTIME:
466                 case V_ASN1_GRAPHICSTRING:
467                 case V_ASN1_VISIBLESTRING:
468                 case V_ASN1_GENERALSTRING:
469                 case V_ASN1_UNIVERSALSTRING:
470                 case V_ASN1_BMPSTRING:
471                 case V_ASN1_UTF8STRING:
472                 case V_ASN1_SEQUENCE:
473                 case V_ASN1_SET:
474                 default:
475                 /* All based on ASN1_STRING and handled the same */
476                 strtmp = (ASN1_STRING *)*pval;
477                 cont = strtmp->data;
478                 len = strtmp->length;
479
480                 break;
481
482         }
483         if(cout && len) memcpy(cout, cont, len);
484         return len;
485 }