Added SILC Server library.
[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 - 2005 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. */
95     if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
96       if (tag != type ||
97           opts & SILC_ASN1_IMPLICIT ||
98           opts & SILC_ASN1_EXPLICIT)
99         ber_class = SILC_BER_CLASS_CONTEXT;
100     }
101
102 #ifdef SILC_DEBUG
103     SILC_LOG_DEBUG(
104       ("%04d: %sEncode %s [%d] %s %s %s %s", depth, sp[0] ? sp : "",
105        silc_asn1_tag_name(type), tag,
106        ber_class == SILC_BER_CLASS_UNIVERSAL   ? "univ" :
107        ber_class == SILC_BER_CLASS_APPLICATION ? "appl" :
108        ber_class == SILC_BER_CLASS_CONTEXT     ? "cont" : "priv",
109        (type != SILC_ASN1_TAG_SEQUENCE && type != SILC_ASN1_TAG_SET) ?
110        opts & SILC_ASN1_EXPLICIT ? "constr" :
111        type == SILC_ASN1_TAG_ANY &&
112        !(opts & SILC_ASN1_EXPLICIT) ? "constr" : "primit" : "constr",
113        indef ? opts & SILC_ASN1_EXPLICIT ? "defin" : "indef" : "defin",
114        opts & SILC_ASN1_IMPLICIT ? "implicit" :
115        opts & SILC_ASN1_EXPLICIT ? "explicit" : ""));
116 #endif /* SILC_DEBUG */
117
118     /* If tagging is explicit we add constructed type before the underlaying
119        types.  The underlaying types are encoded recursively with this
120        encoder. */
121     if (opts & SILC_ASN1_EXPLICIT) {
122       memset(&buf, 0, sizeof(buf));
123
124       primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
125                    type != SILC_ASN1_TAG_SET);
126       opts &= ~SILC_ASN1_EXPLICIT;
127
128       silc_stack_push(stack2, &frame);
129       ret = silc_asn1_encoder(asn1, stack2, stack1, type, type,
130                               SILC_BER_CLASS_UNIVERSAL, opts,
131                               &buf, depth + 1, primitive);
132       silc_stack_pop(stack2);
133
134       if (!ret) {
135         SILC_LOG_DEBUG(("Error encoding explicit tag"));
136         goto fail;
137       }
138
139       /* Encode the explicit tag */
140       len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE);
141       dest = silc_buffer_srealloc_size(stack1, dest,
142                                        silc_buffer_truelen(dest) + len);
143       ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
144                             tag, buf.data, silc_buffer_len(&buf), FALSE);
145       if (!ret)
146         goto fail;
147       if (primitive) {
148         primitive = FALSE;
149         goto cont;
150       }
151       goto ok;
152     }
153
154     /* Encode by the type */
155     switch (type) {
156
157     case SILC_ASN1_TAG_ANY:
158       {
159         /* ANY is another ASN.1 node which is added to this tree */
160         SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
161         if (!node)
162           break;
163
164         /* Encode ASN.1 node into the tree. */
165         if (opts & SILC_ASN1_IMPLICIT || type != tag) {
166           /* We are tagging implicitly so we need to change the identifier
167              of the underlaying type.  Only constructed type is allowed with
168              ANY when tagging implicitly. */
169           const unsigned char *d;
170           SilcUInt32 d_len;
171           SilcBerEncoding enc;
172
173           /* Get the underlaying data */
174           ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
175                                 NULL, NULL);
176           if (!ret) {
177             SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
178             goto fail;
179           }
180           assert(enc == SILC_BER_ENC_CONSTRUCTED);
181
182           /* Now encode with implicit tagging */
183           len = silc_ber_encoded_len(tag, d_len, FALSE);
184           dest = silc_buffer_srealloc_size(stack1, dest,
185                                            silc_buffer_truelen(dest) + len);
186           ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
187                                 tag, d, d_len, FALSE);
188           if (!ret)
189             goto fail;
190         } else {
191           /* Copy the data directly into the tree. */
192           len = silc_buffer_len(node);
193           dest = silc_buffer_srealloc_size(stack1, dest,
194                                            silc_buffer_truelen(dest) + len);
195           silc_buffer_put(dest, node->data, len);
196         }
197         break;
198       }
199
200     case SILC_ASN1_TAG_SEQUENCE:
201     case SILC_ASN1_TAG_SET:
202       {
203         /* SEQUENCE/SET is a sequence of types. Sequences are opened and
204            encoded recursively by calling this same encoder. */
205         memset(&buf, 0, sizeof(buf));
206
207         /* Get type, tag and options for the first argument in recursion */
208         SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
209
210         silc_stack_push(stack2, &frame);
211         ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
212                                 ropts, &buf, depth + 1, FALSE);
213         silc_stack_pop(stack2);
214         if (!ret) {
215           SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
216           goto fail;
217         }
218
219         /* Encode the sequence */
220         len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
221         dest = silc_buffer_srealloc_size(stack1, dest,
222                                          silc_buffer_truelen(dest) + len);
223         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
224                               tag, buf.data, silc_buffer_len(&buf), indef);
225         if (!ret)
226           goto fail;
227         break;
228       }
229
230     case SILC_ASN1_TAG_INTEGER:
231     case SILC_ASN1_TAG_ENUM:
232       {
233         /* Integer */
234         SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
235         if (!mpint)
236           break;
237
238         memset(&buf, 0, sizeof(buf));
239         if (silc_mp_cmp_ui(mpint, 0) < 0) {
240           /* XXX TODO, negative integer.  Take 2s complement, then store
241              bytes in 1s complement */
242         } else {
243           /* Positive */
244           len = (silc_mp_sizeinbase(mpint, 2) + 7) / 8;
245           len += len & 7 ? 1: 0;
246           silc_stack_push(stack2, &frame);
247           silc_buffer_srealloc_size(stack2, &buf,
248                                     silc_buffer_truelen(&buf) + len);
249           silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
250         }
251
252         /* Encode the integer */
253         len = silc_ber_encoded_len(tag, len, indef);
254         dest = silc_buffer_srealloc_size(stack1, dest,
255                                          silc_buffer_truelen(dest) + len);
256         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
257                               tag, buf.data, silc_buffer_len(&buf), FALSE);
258         silc_stack_pop(stack2);
259         if (!ret)
260           goto fail;
261         break;
262       }
263
264     case SILC_ASN1_TAG_OID:
265       {
266         /* Object identifier */
267         char *cp, *oidstr = va_arg(asn1->ap, char *);
268         SilcUInt32 words[24], oid, mask;
269         int i, c = -1;
270         if (!oidstr)
271           break;
272
273         /* Get OID words from the string */
274         cp = strchr(oidstr, '.');
275         while (cp) {
276           c = sscanf(oidstr, "%lu", (unsigned long *)&oid);
277           if (c < 1) {
278             SILC_LOG_DEBUG(("Malformed OID string"));
279             goto fail;
280           }
281           if (c + 1 > sizeof(words) / sizeof(words[0]))
282             goto fail;
283           words[c++] = oid;
284           oidstr = cp + 1;
285           cp = strchr(oidstr, '.');
286         }
287         if (c < 2) {
288           SILC_LOG_DEBUG(("Malfromed OID string"));
289           goto fail;
290         }
291
292         /* Get OID data length */
293         for (i = 2, len = 1; i < c; i++) {
294           if (words[i]) {
295             for (oid = words[i]; oid; oid >>= 7)
296               len++;
297             continue;
298           }
299           len++;
300         }
301
302         /* Encode the OID */
303         memset(&buf, 0, sizeof(buf));
304         silc_stack_push(stack2, &frame);
305         silc_buffer_srealloc_size(stack2, &buf,
306                                   silc_buffer_truelen(&buf) + len);
307         buf.data[0] = words[0] * 40 + words[1];
308         for (i = 2, len = 1; i < c; i++) {
309           oid = words[i];
310           if (oid) {
311             c = len;
312             mask = 0;
313             while (oid) {
314               buf.data[len++] = (oid & 0x7f) | mask;
315               oid >>= 7;
316               mask |= 0x80;
317             }
318             mask = len - 1;
319             while (c < mask) {
320               oid = buf.data[c];
321               buf.data[c] = buf.data[mask];
322               buf.data[mask] = oid;
323               c++;
324               mask--;
325             }
326
327             continue;
328           }
329           buf.data[len++] = 0x00;
330         }
331
332         len = silc_ber_encoded_len(tag, len, indef);
333         dest = silc_buffer_srealloc_size(stack1, dest,
334                                          silc_buffer_truelen(dest) + len);
335         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
336                               tag, buf.data, silc_buffer_len(&buf), FALSE);
337         silc_stack_pop(stack2);
338         if (!ret)
339           goto fail;
340         break;
341       }
342
343     case SILC_ASN1_TAG_BOOLEAN:
344       {
345         /* Encodes boolean (TRUE/FALSE) value */
346         unsigned char val[1];
347         val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
348
349         assert(indef == FALSE);
350         len = silc_ber_encoded_len(tag, 1, FALSE);
351         dest = silc_buffer_srealloc_size(stack1, dest,
352                                          silc_buffer_truelen(dest) + len);
353         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
354                               tag, val, 1, FALSE);
355         if (!ret)
356           goto fail;
357         break;
358       }
359
360     case SILC_ASN1_TAG_BIT_STRING:
361       {
362         /* Encode the data as is, with the bit padding. d_len is in bits. */
363         unsigned char *d = va_arg(asn1->ap, unsigned char *);
364         SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
365         unsigned char pad[1];
366         if (!d)
367           break;
368
369         pad[0] = (8 - (d_len & 7)) & 7;
370         d_len = ((d_len + 7) / 8) + 1;
371
372         memset(&buf, 0, sizeof(buf));
373         silc_stack_push(stack2, &frame);
374         silc_buffer_srealloc_size(stack2, &buf,
375                                   silc_buffer_truelen(&buf) + d_len);
376         silc_buffer_put(&buf, pad, 1);
377         silc_buffer_pull(&buf, 1);
378         silc_buffer_put(&buf, d, d_len - 1);
379         silc_buffer_push(&buf, 1);
380
381         len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
382         dest = silc_buffer_srealloc_size(stack1, dest,
383                                          silc_buffer_truelen(dest) + len);
384         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
385                               tag, buf.data, silc_buffer_len(&buf), indef);
386         silc_stack_pop(stack2);
387         if (!ret)
388           goto fail;
389         break;
390       }
391
392     case SILC_ASN1_TAG_NULL:
393       {
394         /* Encode empty BER block */
395         assert(indef == FALSE);
396         len = silc_ber_encoded_len(tag, 0, FALSE);
397         dest = silc_buffer_srealloc_size(stack1, dest,
398                                          silc_buffer_truelen(dest) + len);
399         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
400                               tag, NULL, 0, FALSE);
401         if (!ret)
402           goto fail;
403         break;
404       }
405
406     case SILC_ASN1_TAG_UTC_TIME:
407       {
408         /* Universal encoded time string */
409         SilcTime timeval = va_arg(asn1->ap, SilcTime);
410         char timestr[32];
411         if (!timeval)
412           break;
413
414         if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
415           SILC_LOG_DEBUG(("Could not encode universal time string"));
416           goto fail;
417         }
418
419         len = silc_ber_encoded_len(tag, strlen(timestr), indef);
420         dest = silc_buffer_srealloc_size(stack1, dest,
421                                          silc_buffer_truelen(dest) + len);
422         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
423                               tag, timestr, strlen(timestr), indef);
424         if (!ret)
425           goto fail;
426         break;
427       }
428
429     case SILC_ASN1_TAG_GENERALIZED_TIME:
430       {
431         /* Generalized encoded time string */
432         SilcTime timeval = va_arg(asn1->ap, SilcTime);
433         char timestr[32];
434         if (!timeval)
435           break;
436
437         if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
438           SILC_LOG_DEBUG(("Could not encode generalized time string"));
439           goto fail;
440         }
441
442         len = silc_ber_encoded_len(tag, strlen(timestr), indef);
443         dest = silc_buffer_srealloc_size(stack1, dest,
444                                          silc_buffer_truelen(dest) + len);
445         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
446                               tag, timestr, strlen(timestr), indef);
447         if (!ret)
448           goto fail;
449         break;
450       }
451
452     case SILC_ASN1_TAG_UTF8_STRING:
453       {
454         /* UTF-8 string */
455         unsigned char *d = va_arg(asn1->ap, unsigned char *);
456         SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
457         if (!d)
458           break;
459
460         /* By default all strings that get here should already be UTF-8 */
461         if (!silc_utf8_valid(d, d_len)) {
462           SILC_LOG_DEBUG(("Malformed UTF-8 string"));
463           goto fail;
464         }
465
466         len = silc_ber_encoded_len(tag, d_len, indef);
467         dest = silc_buffer_srealloc_size(stack1, dest,
468                                          silc_buffer_truelen(dest) + len);
469         ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
470                               tag, d, d_len, indef);
471         if (!ret)
472           goto fail;
473         break;
474       }
475
476     case SILC_ASN1_TAG_OCTET_STRING:
477       {
478         /* Octet string.  We put it in as 8-bit ASCII */
479         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
480         break;
481       }
482
483     case SILC_ASN1_TAG_NUMERIC_STRING:
484       {
485         /* Numerical (digit) string */
486         SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
487         break;
488       }
489
490     case SILC_ASN1_TAG_PRINTABLE_STRING:
491       {
492         /* Printable string */
493         SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
494         break;
495       }
496
497     case SILC_ASN1_TAG_TELETEX_STRING:
498       {
499         /* Teletex (T61) string */
500         SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
501         break;
502       }
503
504     case SILC_ASN1_TAG_IA5_STRING:
505       {
506         /* US ASCII string */
507         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
508         break;
509       }
510
511     case SILC_ASN1_TAG_VISIBLE_STRING:
512       {
513         /* Visible string */
514         SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
515         break;
516       }
517
518     case SILC_ASN1_TAG_UNIVERSAL_STRING:
519       {
520         /* Universal (UCS-4) string */
521         SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
522         break;
523       }
524
525     case SILC_ASN1_TAG_UNRESTRICTED_STRING:
526     case SILC_ASN1_TAG_GENERAL_STRING:
527       {
528         /* Handle now unrestricted and general as 8-bit ascii, which
529            probably isn't correct. */
530         SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
531         break;
532       }
533
534     case SILC_ASN1_TAG_BMP_STRING:
535       {
536         /* BMP (UCS-2) string */
537         SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
538         break;
539       }
540
541     case SILC_ASN1_TAG_ODE:
542     case SILC_ASN1_TAG_ETI:
543     case SILC_ASN1_TAG_REAL:
544     case SILC_ASN1_TAG_EMBEDDED:
545     case SILC_ASN1_TAG_ROI:
546     case SILC_ASN1_TAG_VIDEOTEX_STRING:
547     case SILC_ASN1_TAG_GRAPHIC_STRING:
548       {
549         SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
550         ret = FALSE;
551         goto fail;
552         break;
553       }
554
555     default:
556       SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
557       ret = FALSE;
558       goto fail;
559       break;
560     }
561
562   cont:
563     if (len)
564       silc_buffer_pull(dest, len);
565     if (primitive) {
566       ret = TRUE;
567       goto ok;
568     }
569
570     /* Get next type, tag and options */
571     SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
572     if (type == SILC_ASN1_END) {
573       ret = TRUE;
574       goto ok;
575     }
576   }
577
578  fail:
579   SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
580
581  ok:
582   if (ptr)
583     len = dest->data - ptr;
584   else
585     len = dest->data - dest->head;
586   silc_buffer_push(dest, len);
587
588   return ret;
589 }
590
591 SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
592 {
593   SilcAsn1Tag type, tag;
594   SilcAsn1Options opts;
595   SilcBerClass ber_class;
596   SilcStackFrame frame1, frame2;
597   SilcStack stack1 = NULL;
598   SilcBool ret;
599
600   if (!asn1)
601     return FALSE;
602
603   va_start(asn1->ap, dest);
604
605   /* Get the first arguments and call the encoder. */
606   SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
607   if (!type) {
608     va_end(asn1->ap);
609     asn1->ap = NULL;
610     return FALSE;
611   }
612
613   /* Handle internal options for encoder. */
614   if (type == SILC_ASN1_TAG_OPTS) {
615     SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
616
617     if (o & SILC_ASN1_ALLOC) {
618       /* User wants to alloate everything.  Set the stack to NULL so
619          that stack aware calls revert to normal allocation routines. */
620       stack1 = asn1->stack1;
621       asn1->stack1 = NULL;
622     }
623
624     if (o & SILC_ASN1_ACCUMUL) {
625       /* If accumul flag is not set yet, then push the stack. */
626       if (!asn1->accumul) {
627         silc_stack_push(asn1->stack1, NULL);
628         asn1->accumul = 1;
629       }
630     }
631
632     /* Take again the arguments */
633     SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
634   } else {
635     /* No flags set, all flags will be reset. */
636
637     /* If accumul flag is set now pop the stack so that all accumulated
638        memory becomes free again. */
639     if (asn1->accumul) {
640       silc_stack_pop(asn1->stack1);
641       asn1->accumul = 0;
642     }
643   }
644
645   /* Push the stack for normal allocation from stack. */
646   if (!asn1->accumul)
647     silc_stack_push(asn1->stack1, &frame1);
648
649   /* Start encoding */
650   silc_stack_push(asn1->stack2, &frame2);
651   ret = silc_asn1_encoder(asn1, asn1->stack1, asn1->stack2,
652                           type, tag, ber_class, opts, dest, 0, FALSE);
653   silc_stack_pop(asn1->stack2);
654
655   /* Pop the stack to free normal allocations from stack. */
656   if (!asn1->accumul)
657     silc_stack_pop(asn1->stack1);
658
659   /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
660   if (stack1 && !asn1->stack1)
661     asn1->stack1 = stack1;
662
663   va_end(asn1->ap);
664   asn1->ap = NULL;
665
666   return ret;
667 }