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