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