Added SILC_ASN1_SHORT_INT.
[silc.git] / lib / silcasn1 / silcasn1_encode.c
1 /*
2
3   silcasn1_encode.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2003 - 2006 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21 #include "silcasn1.h"
22 #include "silcber.h"
23
24 /************************** ASN.1 Encoder routines **************************/
25
26 /* Encode string from UTF-8 string to other string encodings.  Encodes
27    diretly to BER blob. */
28 #define SILC_ASN1_ENCODE_STRING(enc)                                    \
29   unsigned char *s, *d = va_arg(asn1->ap, unsigned char *);             \
30   SilcUInt32 s_len, d_len = va_arg(asn1->ap, SilcUInt32);               \
31   if (!d)                                                               \
32     break;                                                              \
33   s_len = silc_utf8_decoded_len(d, d_len, (enc));                       \
34   if (s_len == 0) {                                                     \
35     SILC_LOG_DEBUG(("Malformed %d string value", (enc)));               \
36     goto fail;                                                          \
37   }                                                                     \
38   silc_stack_push(asn1->stack2, &frame);                                \
39   s = silc_smalloc_ua(stack2, s_len + 1);                               \
40   if (s) {                                                              \
41     silc_utf8_decode(d, d_len, (enc), s, s_len);                        \
42     s[s_len] = '\0';                                                    \
43   }                                                                     \
44   len = silc_ber_encoded_len(tag, s_len, indef);                        \
45   dest = silc_buffer_srealloc_size(stack1, dest,                        \
46                                    silc_buffer_truelen(dest) + len);    \
47   ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,        \
48                         tag, s, s_len, indef);                          \
49   silc_stack_pop(asn1->stack2);                                         \
50   if (!ret)                                                             \
51     goto fail;
52
53 /* The internal ASN.1 encoder.  The `type', `tag' and `opts' are the
54    first arguments (either very first or first for recursion) for a type.
55    The `depth' includes the current depth of recursion.  The `primitive'
56    is TRUE if this encoder receives one primitive type as argument.  If
57    it is a constructed type it must be FALSE value. */
58
59 static SilcBool
60 silc_asn1_encoder(SilcAsn1 asn1, SilcStack stack1, SilcStack stack2,
61                   SilcAsn1Tag type, SilcAsn1Tag tag, SilcBerClass ber_class,
62                   SilcAsn1Options opts, SilcBuffer dest, SilcUInt32 depth,
63                   SilcBool primitive)
64 {
65   unsigned char *ptr = dest->data;
66   SilcAsn1Tag rtype, rtag;
67   SilcAsn1Options ropts;
68   SilcBerClass rclass;
69   SilcUInt32 len = 0;
70   SilcBool ret = FALSE, indef;
71   SilcBufferStruct buf;
72   SilcStackFrame frame;
73
74 #ifdef SILC_DEBUG
75   char sp[SILC_ASN1_RECURSION_DEPTH + 1];
76   memset(sp, 0, sizeof(sp));
77   if (depth)
78     memset(sp, 32, depth);
79 #endif /* SILC_DEBUG */
80
81   if (depth >= SILC_ASN1_RECURSION_DEPTH) {
82     SILC_LOG_DEBUG(("Maximum recursion depth reached"));
83     return FALSE;
84   }
85
86   while (1) {
87     /* These options cannot be used in encoding */
88     opts &= ~SILC_ASN1_OPTIONAL;
89
90     /* Get length encoding */
91     indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
92
93     /* By default UNIVERSAL is implied unless the following conditions
94        are met when CONTEXT will apply.  For SILC_ASN1_TAG_ANY_PRIMITIVE
95        the class is changed only if flags dictate it. */
96     if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
97       if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
98         if (opts & SILC_ASN1_IMPLICIT ||
99             opts & SILC_ASN1_EXPLICIT)
100           ber_class = SILC_BER_CLASS_CONTEXT;
101       } else {
102         if (tag != type ||
103             opts & SILC_ASN1_IMPLICIT ||
104             opts & SILC_ASN1_EXPLICIT)
105           ber_class = SILC_BER_CLASS_CONTEXT;
106       }
107     }
108
109 #ifdef SILC_DEBUG
110     SILC_LOG_DEBUG(
111       ("%04d: %sEncode %s [%d] %s %s %s %s", depth, sp[0] ? sp : "",
112        silc_asn1_tag_name(type), tag,
113        ber_class == SILC_BER_CLASS_UNIVERSAL   ? "univ" :
114        ber_class == SILC_BER_CLASS_APPLICATION ? "appl" :
115        ber_class == SILC_BER_CLASS_CONTEXT     ? "cont" : "priv",
116        (type != SILC_ASN1_TAG_SEQUENCE && type != SILC_ASN1_TAG_SET) ?
117        opts & SILC_ASN1_EXPLICIT ? "constr" :
118        type == SILC_ASN1_TAG_ANY &&
119        !(opts & SILC_ASN1_EXPLICIT) ? "constr" : "primit" : "constr",
120        indef ? opts & SILC_ASN1_EXPLICIT ? "defin" : "indef" : "defin",
121        opts & SILC_ASN1_IMPLICIT ? "implicit" :
122        opts & SILC_ASN1_EXPLICIT ? "explicit" : ""));
123 #endif /* SILC_DEBUG */
124
125     /* If tagging is explicit we add constructed type before the underlaying
126        types.  The underlaying types are encoded recursively with this
127        encoder. */
128     if (opts & SILC_ASN1_EXPLICIT) {
129       memset(&buf, 0, sizeof(buf));
130
131       primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
132                    type != SILC_ASN1_TAG_SET);
133       opts &= ~SILC_ASN1_EXPLICIT;
134
135       silc_stack_push(stack2, &frame);
136       ret = silc_asn1_encoder(asn1, stack2, stack1, type, type,
137                               SILC_BER_CLASS_UNIVERSAL, opts,
138                               &buf, depth + 1, primitive);
139       silc_stack_pop(stack2);
140
141       if (!ret) {
142         SILC_LOG_DEBUG(("Error encoding explicit tag"));
143         goto fail;
144       }
145
146       /* Encode the explicit tag */
147       len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE);
148       dest = silc_buffer_srealloc_size(stack1, dest,
149                                        silc_buffer_truelen(dest) + len);
150       ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
151                             tag, buf.data, silc_buffer_len(&buf), FALSE);
152       if (!ret)
153         goto fail;
154       if (primitive) {
155         primitive = FALSE;
156         goto cont;
157       }
158       goto ok;
159     }
160
161     /* Encode by the type */
162     switch (type) {
163
164     case SILC_ASN1_TAG_ANY:
165       {
166         /* ANY is another ASN.1 node which is added to this tree */
167         SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
168         if (!node)
169           break;
170
171         /* Encode ASN.1 node into the tree. */
172         if (opts & SILC_ASN1_IMPLICIT || type != tag) {
173           /* We are tagging implicitly so we need to change the identifier
174              of the underlaying type.  Only constructed type is allowed with
175              ANY when tagging implicitly. */
176           const unsigned char *d;
177           SilcUInt32 d_len;
178           SilcBerEncoding enc;
179
180           /* Get the underlaying data */
181           ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
182                                 NULL, NULL);
183           if (!ret) {
184             SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
185             goto fail;
186           }
187           assert(enc == SILC_BER_ENC_CONSTRUCTED);
188
189           /* Now encode with implicit tagging */
190           len = silc_ber_encoded_len(tag, d_len, FALSE);
191           dest = silc_buffer_srealloc_size(stack1, dest,
192                                            silc_buffer_truelen(dest) + len);
193           ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
194                                 tag, d, d_len, FALSE);
195           if (!ret)
196             goto fail;
197         } else {
198           /* Copy the data directly into the tree. */
199           len = silc_buffer_len(node);
200           dest = silc_buffer_srealloc_size(stack1, dest,
201                                            silc_buffer_truelen(dest) + len);
202           if (!dest)
203             goto fail;
204           silc_buffer_put(dest, node->data, len);
205         }
206         break;
207       }
208
209     case SILC_ASN1_TAG_ANY_PRIMITIVE:
210       {
211         /* ANY_PRIMITIVE is any primitive in encoded format. */
212         SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
213         if (!prim)
214           break;
215
216         /* Encode the primitive data */
217         len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
218         dest = silc_buffer_srealloc_size(stack1, dest,
219                                          silc_buffer_truelen(dest) + len);
220         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
221                               tag, prim->data, silc_buffer_len(prim), FALSE);
222         if (!ret)
223           goto fail;
224         break;
225       }
226
227     case SILC_ASN1_TAG_SEQUENCE:
228     case SILC_ASN1_TAG_SET:
229       {
230         /* SEQUENCE/SET is a sequence of types. Sequences are opened and
231            encoded recursively by calling this same encoder. */
232         memset(&buf, 0, sizeof(buf));
233
234         /* Get type, tag and options for the first argument in recursion */
235         SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
236
237         silc_stack_push(stack2, &frame);
238         ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
239                                 ropts, &buf, depth + 1, FALSE);
240         silc_stack_pop(stack2);
241         if (!ret) {
242           SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
243           goto fail;
244         }
245
246         /* Encode the sequence */
247         len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
248         dest = silc_buffer_srealloc_size(stack1, dest,
249                                          silc_buffer_truelen(dest) + len);
250         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
251                               tag, buf.data, silc_buffer_len(&buf), indef);
252         if (!ret)
253           goto fail;
254         break;
255       }
256
257     case SILC_ASN1_TAG_INTEGER:
258     case SILC_ASN1_TAG_ENUM:
259       {
260         /* Integer */
261         SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
262         if (!mpint)
263           break;
264
265         memset(&buf, 0, sizeof(buf));
266         if (silc_mp_cmp_ui(mpint, 0) < 0) {
267           /* XXX TODO, negative integer.  Take 2s complement, then store
268              bytes in 1s complement */
269         } else {
270           /* Positive */
271           len = silc_mp_sizeinbase(mpint, 2);
272           if (!(len & 7))
273             len = ((len + 7) / 8) + 1;
274           else
275             len = (len + 7) / 8;
276           silc_stack_push(stack2, &frame);
277           silc_buffer_srealloc_size(stack2, &buf,
278                                     silc_buffer_truelen(&buf) + len);
279           buf.data[0] = 0x00;
280           silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
281         }
282
283         /* Encode the integer */
284         len = silc_ber_encoded_len(tag, len, indef);
285         dest = silc_buffer_srealloc_size(stack1, dest,
286                                          silc_buffer_truelen(dest) + len);
287         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
288                               tag, buf.data, silc_buffer_len(&buf), FALSE);
289         silc_stack_pop(stack2);
290         if (!ret)
291           goto fail;
292         break;
293       }
294
295     case SILC_ASN1_TAG_SHORT_INTEGER:
296       {
297         /* Short Integer */
298         SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
299         SilcMPInt z;
300
301         if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
302           tag = SILC_ASN1_TAG_INTEGER;
303
304         memset(&buf, 0, sizeof(buf));
305
306         silc_stack_push(stack2, &frame);
307         silc_mp_sinit(stack2, &z);
308         silc_mp_set_ui(&z, sint);
309
310         len = silc_mp_sizeinbase(&z, 2);
311         if (!(len & 7))
312           len = ((len + 7) / 8) + 1;
313         else
314           len = (len + 7) / 8;
315         silc_buffer_srealloc_size(stack2, &buf,
316                                   silc_buffer_truelen(&buf) + len);
317         buf.data[0] = 0x00;
318         silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
319         silc_mp_uninit(&z);
320
321         /* Encode the integer */
322         len = silc_ber_encoded_len(tag, len, indef);
323         dest = silc_buffer_srealloc_size(stack1, dest,
324                                          silc_buffer_truelen(dest) + len);
325         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
326                               tag, buf.data, silc_buffer_len(&buf), FALSE);
327         silc_stack_pop(stack2);
328         if (!ret)
329           goto fail;
330         break;
331       }
332       break;
333
334     case SILC_ASN1_TAG_OID:
335       {
336         /* Object identifier */
337         char *cp, *oidstr = va_arg(asn1->ap, char *);
338         SilcUInt32 words[24], oid, mask;
339         int i, k, c = 0;
340         if (!oidstr)
341           break;
342
343         /* Get OID words from the string */
344         cp = strchr(oidstr, '.');
345         while (cp) {
346           if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
347             SILC_LOG_DEBUG(("Malformed OID string"));
348             goto fail;
349           }
350           if (c + 1 > sizeof(words) / sizeof(words[0]))
351             goto fail;
352           words[c++] = oid;
353           oidstr = cp + 1;
354           cp = strchr(oidstr, '.');
355
356           if (!cp) {
357             if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
358               SILC_LOG_DEBUG(("Malformed OID string"));
359               goto fail;
360             }
361             if (c + 1 > sizeof(words) / sizeof(words[0]))
362               goto fail;
363             words[c++] = oid;
364             break;
365           }
366         }
367         if (c < 2) {
368           SILC_LOG_DEBUG(("Malfromed OID string"));
369           goto fail;
370         }
371
372         /* Get OID data length */
373         for (i = 2, len = 1; i < c; i++) {
374           if (words[i]) {
375             for (oid = words[i]; oid; oid >>= 7)
376               len++;
377             continue;
378           }
379           len++;
380         }
381
382         /* Encode the OID */
383         memset(&buf, 0, sizeof(buf));
384         silc_stack_push(stack2, &frame);
385         silc_buffer_srealloc_size(stack2, &buf,
386                                   silc_buffer_truelen(&buf) + len);
387         buf.data[0] = words[0] * 40 + words[1];
388         for (i = 2, len = 1; i < c; i++) {
389           oid = words[i];
390           if (oid) {
391             k = len;
392             mask = 0;
393             while (oid) {
394               buf.data[len++] = (oid & 0x7f) | mask;
395               oid >>= 7;
396               mask |= 0x80;
397             }
398             mask = len - 1;
399             while (k < mask) {
400               oid = buf.data[k];
401               buf.data[k] = buf.data[mask];
402               buf.data[mask] = oid;
403               k++;
404               mask--;
405             }
406
407             continue;
408           }
409           buf.data[len++] = 0x00;
410         }
411
412         len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
413         dest = silc_buffer_srealloc_size(stack1, dest,
414                                          silc_buffer_truelen(dest) + len);
415         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
416                               tag, buf.data, silc_buffer_len(&buf), FALSE);
417         silc_stack_pop(stack2);
418         if (!ret)
419           goto fail;
420         break;
421       }
422
423     case SILC_ASN1_TAG_BOOLEAN:
424       {
425         /* Encodes boolean (TRUE/FALSE) value */
426         unsigned char val[1];
427         val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
428
429         assert(indef == FALSE);
430         len = silc_ber_encoded_len(tag, 1, FALSE);
431         dest = silc_buffer_srealloc_size(stack1, dest,
432                                          silc_buffer_truelen(dest) + len);
433         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
434                               tag, val, 1, FALSE);
435         if (!ret)
436           goto fail;
437         break;
438       }
439
440     case SILC_ASN1_TAG_BIT_STRING:
441       {
442         /* Encode the data as is, with the bit padding. d_len is in bits. */
443         unsigned char *d = va_arg(asn1->ap, unsigned char *);
444         SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
445         unsigned char pad[1];
446         if (!d)
447           break;
448
449         pad[0] = (8 - (d_len & 7)) & 7;
450         d_len = ((d_len + 7) / 8) + 1;
451
452         memset(&buf, 0, sizeof(buf));
453         silc_stack_push(stack2, &frame);
454         silc_buffer_srealloc_size(stack2, &buf,
455                                   silc_buffer_truelen(&buf) + d_len);
456         silc_buffer_put(&buf, pad, 1);
457         silc_buffer_pull(&buf, 1);
458         silc_buffer_put(&buf, d, d_len - 1);
459         silc_buffer_push(&buf, 1);
460
461         len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
462         dest = silc_buffer_srealloc_size(stack1, dest,
463                                          silc_buffer_truelen(dest) + len);
464         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
465                               tag, buf.data, silc_buffer_len(&buf), indef);
466         silc_stack_pop(stack2);
467         if (!ret)
468           goto fail;
469         break;
470       }
471
472     case SILC_ASN1_TAG_NULL:
473       {
474         /* Encode empty BER block */
475         assert(indef == FALSE);
476         len = silc_ber_encoded_len(tag, 0, FALSE);
477         dest = silc_buffer_srealloc_size(stack1, dest,
478                                          silc_buffer_truelen(dest) + len);
479         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
480                               tag, NULL, 0, FALSE);
481         if (!ret)
482           goto fail;
483         break;
484       }
485
486     case SILC_ASN1_TAG_UTC_TIME:
487       {
488         /* Universal encoded time string */
489         SilcTime timeval = va_arg(asn1->ap, SilcTime);
490         char timestr[32];
491         if (!timeval)
492           break;
493
494         if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
495           SILC_LOG_DEBUG(("Could not encode universal time string"));
496           goto fail;
497         }
498
499         len = silc_ber_encoded_len(tag, strlen(timestr), indef);
500         dest = silc_buffer_srealloc_size(stack1, dest,
501                                          silc_buffer_truelen(dest) + len);
502         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
503                               tag, timestr, strlen(timestr), indef);
504         if (!ret)
505           goto fail;
506         break;
507       }
508
509     case SILC_ASN1_TAG_GENERALIZED_TIME:
510       {
511         /* Generalized encoded time string */
512         SilcTime timeval = va_arg(asn1->ap, SilcTime);
513         char timestr[32];
514         if (!timeval)
515           break;
516
517         if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
518           SILC_LOG_DEBUG(("Could not encode generalized time string"));
519           goto fail;
520         }
521
522         len = silc_ber_encoded_len(tag, strlen(timestr), indef);
523         dest = silc_buffer_srealloc_size(stack1, dest,
524                                          silc_buffer_truelen(dest) + len);
525         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
526                               tag, timestr, strlen(timestr), indef);
527         if (!ret)
528           goto fail;
529         break;
530       }
531
532     case SILC_ASN1_TAG_UTF8_STRING:
533       {
534         /* UTF-8 string */
535         unsigned char *d = va_arg(asn1->ap, unsigned char *);
536         SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
537         if (!d)
538           break;
539
540         /* By default all strings that get here should already be UTF-8 */
541         if (!silc_utf8_valid(d, d_len)) {
542           SILC_LOG_DEBUG(("Malformed UTF-8 string"));
543           goto fail;
544         }
545
546         len = silc_ber_encoded_len(tag, d_len, indef);
547         dest = silc_buffer_srealloc_size(stack1, dest,
548                                          silc_buffer_truelen(dest) + len);
549         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
550                               tag, d, d_len, indef);
551         if (!ret)
552           goto fail;
553         break;
554       }
555
556     case SILC_ASN1_TAG_OCTET_STRING:
557       {
558         /* Octet string.  We put it in as 8-bit ASCII */
559         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
560         break;
561       }
562
563     case SILC_ASN1_TAG_NUMERIC_STRING:
564       {
565         /* Numerical (digit) string */
566         SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
567         break;
568       }
569
570     case SILC_ASN1_TAG_PRINTABLE_STRING:
571       {
572         /* Printable string */
573         SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
574         break;
575       }
576
577     case SILC_ASN1_TAG_TELETEX_STRING:
578       {
579         /* Teletex (T61) string */
580         SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
581         break;
582       }
583
584     case SILC_ASN1_TAG_IA5_STRING:
585       {
586         /* US ASCII string */
587         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
588         break;
589       }
590
591     case SILC_ASN1_TAG_VISIBLE_STRING:
592       {
593         /* Visible string */
594         SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
595         break;
596       }
597
598     case SILC_ASN1_TAG_UNIVERSAL_STRING:
599       {
600         /* Universal (UCS-4) string */
601         SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
602         break;
603       }
604
605     case SILC_ASN1_TAG_UNRESTRICTED_STRING:
606     case SILC_ASN1_TAG_GENERAL_STRING:
607       {
608         /* Handle now unrestricted and general as 8-bit ascii, which
609            probably isn't correct. */
610         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
611         break;
612       }
613
614     case SILC_ASN1_TAG_BMP_STRING:
615       {
616         /* BMP (UCS-2) string */
617         SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
618         break;
619       }
620
621     case SILC_ASN1_TAG_ODE:
622     case SILC_ASN1_TAG_ETI:
623     case SILC_ASN1_TAG_REAL:
624     case SILC_ASN1_TAG_EMBEDDED:
625     case SILC_ASN1_TAG_ROI:
626     case SILC_ASN1_TAG_VIDEOTEX_STRING:
627     case SILC_ASN1_TAG_GRAPHIC_STRING:
628       {
629         SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
630         ret = FALSE;
631         goto fail;
632         break;
633       }
634
635     default:
636       SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
637       ret = FALSE;
638       goto fail;
639       break;
640     }
641
642   cont:
643     if (len)
644       silc_buffer_pull(dest, len);
645     if (primitive) {
646       ret = TRUE;
647       goto ok;
648     }
649
650     /* Get next type, tag and options */
651     SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
652     if (type == SILC_ASN1_END) {
653       ret = TRUE;
654       goto ok;
655     }
656   }
657
658  fail:
659   SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
660
661  ok:
662   if (ptr)
663     len = dest->data - ptr;
664   else
665     len = dest->data - dest->head;
666   silc_buffer_push(dest, len);
667
668   return ret;
669 }
670
671 SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
672 {
673   SilcAsn1Tag type, tag;
674   SilcAsn1Options opts;
675   SilcBerClass ber_class;
676   SilcStackFrame frame1, frame2;
677   SilcStack stack1 = NULL;
678   SilcBool ret;
679
680   if (!asn1)
681     return FALSE;
682
683   va_start(asn1->ap, dest);
684
685   /* Get the first arguments and call the encoder. */
686   SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
687   if (!type) {
688     va_end(asn1->ap);
689     asn1->ap = NULL;
690     return FALSE;
691   }
692
693   /* Handle internal options for encoder. */
694   if (type == SILC_ASN1_TAG_OPTS) {
695     SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
696
697     if (o & SILC_ASN1_ALLOC) {
698       /* User wants to alloate everything.  Set the stack to NULL so
699          that stack aware calls revert to normal allocation routines. */
700       stack1 = asn1->stack1;
701       asn1->stack1 = NULL;
702     }
703
704     if (o & SILC_ASN1_ACCUMUL) {
705       /* If accumul flag is not set yet, then push the stack. */
706       if (!asn1->accumul) {
707         silc_stack_push(asn1->stack1, NULL);
708         asn1->accumul = 1;
709       }
710     }
711
712     /* Take again the arguments */
713     SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
714   } else {
715     /* No flags set, all flags will be reset. */
716
717     /* If accumul flag is set now pop the stack so that all accumulated
718        memory becomes free again. */
719     if (asn1->accumul) {
720       silc_stack_pop(asn1->stack1);
721       asn1->accumul = 0;
722     }
723   }
724
725   /* Push the stack for normal allocation from stack. */
726   if (!asn1->accumul)
727     silc_stack_push(asn1->stack1, &frame1);
728
729   /* Start encoding */
730   silc_stack_push(asn1->stack2, &frame2);
731   ret = silc_asn1_encoder(asn1, asn1->stack1, asn1->stack2,
732                           type, tag, ber_class, opts, dest, 0, FALSE);
733   silc_stack_pop(asn1->stack2);
734
735   /* Pop the stack to free normal allocations from stack. */
736   if (!asn1->accumul)
737     silc_stack_pop(asn1->stack1);
738
739   /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
740   if (stack1 && !asn1->stack1)
741     asn1->stack1 = stack1;
742
743   va_end(asn1->ap);
744   asn1->ap = NULL;
745
746   return ret;
747 }