5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2003 - 2007 Pekka Riikonen
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.
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.
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
27 /************************** ASN.1 Encoder routines **************************/
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); \
36 s_len = silc_utf8_decoded_len(d, d_len, (enc)); \
38 SILC_LOG_DEBUG(("Malformed %d string value", (enc))); \
41 silc_stack_push(asn1->stack2, &frame); \
42 s = silc_smalloc(stack2, s_len + 1); \
44 silc_utf8_decode(d, d_len, (enc), s, s_len); \
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); \
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. */
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,
68 unsigned char *ptr = dest->data;
69 SilcAsn1Tag rtype, rtag;
70 SilcAsn1Options ropts;
73 SilcBool ret = FALSE, indef;
78 char sp[SILC_ASN1_RECURSION_DEPTH + 1];
79 memset(sp, 0, sizeof(sp));
81 memset(sp, 32, depth);
82 #endif /* SILC_DEBUG */
84 if (depth >= SILC_ASN1_RECURSION_DEPTH) {
85 SILC_LOG_DEBUG(("Maximum recursion depth reached"));
90 /* These options cannot be used in encoding */
91 opts &= ~SILC_ASN1_OPTIONAL;
93 /* Get length encoding */
94 indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
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;
106 opts & SILC_ASN1_IMPLICIT ||
107 opts & SILC_ASN1_EXPLICIT)
108 ber_class = SILC_BER_CLASS_CONTEXT;
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 */
128 /* If tagging is explicit we add constructed type before the underlaying
129 types. The underlaying types are encoded recursively with this
131 if (opts & SILC_ASN1_EXPLICIT) {
132 memset(&buf, 0, sizeof(buf));
134 primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
135 type != SILC_ASN1_TAG_SET);
136 opts &= ~SILC_ASN1_EXPLICIT;
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);
144 SILC_LOG_DEBUG(("Error encoding explicit tag"));
145 silc_stack_pop(stack2);
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);
166 /* Encode by the type */
169 case SILC_ASN1_TAG_ANY:
171 /* ANY is another ASN.1 node which is added to this tree */
172 SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
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;
185 /* Get the underlaying data */
186 ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
189 SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
192 assert(enc == SILC_BER_ENC_CONSTRUCTED);
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);
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);
209 silc_buffer_put(dest, node->data, len);
214 case SILC_ASN1_TAG_ANY_PRIMITIVE:
216 /* ANY_PRIMITIVE is any primitive in encoded format. */
217 SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
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);
232 case SILC_ASN1_TAG_SEQUENCE:
233 case SILC_ASN1_TAG_SET:
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));
239 /* Get type, tag and options for the first argument in recursion */
240 SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
242 silc_stack_push(stack2, &frame);
243 ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
244 ropts, &buf, depth + 1, FALSE);
246 SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
247 silc_stack_pop(stack2);
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);
264 case SILC_ASN1_TAG_INTEGER:
265 case SILC_ASN1_TAG_ENUM:
268 SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
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 */
278 len = silc_mp_sizeinbase(mpint, 2);
280 len = ((len + 7) / 8) + 1;
283 silc_stack_push(stack2, &frame);
284 silc_buffer_srealloc_size(stack2, &buf,
285 silc_buffer_truelen(&buf) + len);
287 silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
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);
303 case SILC_ASN1_TAG_SHORT_INTEGER:
306 SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
309 if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
310 tag = SILC_ASN1_TAG_INTEGER;
312 memset(&buf, 0, sizeof(buf));
314 silc_stack_push(stack2, &frame);
315 silc_mp_sinit(stack2, &z);
316 silc_mp_set_ui(&z, sint);
318 len = silc_mp_sizeinbase(&z, 2);
320 len = ((len + 7) / 8) + 1;
323 silc_buffer_srealloc_size(stack2, &buf,
324 silc_buffer_truelen(&buf) + len);
326 silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
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);
343 case SILC_ASN1_TAG_OID:
345 /* Object identifier */
346 char *cp, *oidstr = va_arg(asn1->ap, char *);
347 SilcUInt32 words[24], oid, mask;
352 /* Get OID words from the string */
353 cp = strchr(oidstr, '.');
355 if (sscanf(oidstr, "%lu", &oid) != 1) {
356 SILC_LOG_DEBUG(("Malformed OID string"));
359 if (c + 1 > sizeof(words) / sizeof(words[0]))
363 cp = strchr(oidstr, '.');
366 if (sscanf(oidstr, "%lu", &oid) != 1) {
367 SILC_LOG_DEBUG(("Malformed OID string"));
370 if (c + 1 > sizeof(words) / sizeof(words[0]))
377 SILC_LOG_DEBUG(("Malfromed OID string"));
381 /* Get OID data length */
382 for (i = 2, len = 1; i < c; i++) {
384 for (oid = words[i]; oid; oid >>= 7)
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++) {
403 buf.data[len++] = (oid & 0x7f) | mask;
410 buf.data[k] = buf.data[mask];
411 buf.data[mask] = oid;
418 buf.data[len++] = 0x00;
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);
433 case SILC_ASN1_TAG_BOOLEAN:
435 /* Encodes boolean (TRUE/FALSE) value */
436 unsigned char val[1];
437 val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
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,
450 case SILC_ASN1_TAG_BIT_STRING:
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];
459 pad[0] = (8 - (d_len & 7)) & 7;
460 d_len = ((d_len + 7) / 8) + 1;
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);
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);
483 case SILC_ASN1_TAG_NULL:
485 /* Encode empty BER block */
486 SilcBool val = va_arg(asn1->ap, SilcUInt32);
488 assert(indef == FALSE);
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);
504 case SILC_ASN1_TAG_UTC_TIME:
506 /* Universal encoded time string */
507 SilcTime timeval = va_arg(asn1->ap, SilcTime);
512 if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
513 SILC_LOG_DEBUG(("Could not encode universal time string"));
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);
527 case SILC_ASN1_TAG_GENERALIZED_TIME:
529 /* Generalized encoded time string */
530 SilcTime timeval = va_arg(asn1->ap, SilcTime);
535 if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
536 SILC_LOG_DEBUG(("Could not encode generalized time string"));
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);
550 case SILC_ASN1_TAG_UTF8_STRING:
553 unsigned char *d = va_arg(asn1->ap, unsigned char *);
554 SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
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"));
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);
574 case SILC_ASN1_TAG_OCTET_STRING:
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);
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);
590 case SILC_ASN1_TAG_NUMERIC_STRING:
592 /* Numerical (digit) string */
593 SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
597 case SILC_ASN1_TAG_PRINTABLE_STRING:
599 /* Printable string */
600 SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
604 case SILC_ASN1_TAG_TELETEX_STRING:
606 /* Teletex (T61) string */
607 SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
611 case SILC_ASN1_TAG_IA5_STRING:
613 /* US ASCII string */
614 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
618 case SILC_ASN1_TAG_VISIBLE_STRING:
621 SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
625 case SILC_ASN1_TAG_UNIVERSAL_STRING:
627 /* Universal (UCS-4) string */
628 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
632 case SILC_ASN1_TAG_UNRESTRICTED_STRING:
633 case SILC_ASN1_TAG_GENERAL_STRING:
635 /* Handle now unrestricted and general as 8-bit ascii, which
636 probably isn't correct. */
637 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
641 case SILC_ASN1_TAG_BMP_STRING:
643 /* BMP (UCS-2) string */
644 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
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:
656 SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
663 SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
671 silc_buffer_pull(dest, len);
677 /* Get next type, tag and options */
678 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
679 if (type == SILC_ASN1_END) {
686 SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
690 len = dest->data - ptr;
692 len = dest->data - dest->head;
693 silc_buffer_push(dest, len);
698 SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
700 SilcAsn1Tag type, tag;
701 SilcAsn1Options opts;
702 SilcBerClass ber_class;
703 SilcStackFrame frame1, frame2;
704 SilcStack stack1 = NULL, orig;
710 va_start(asn1->ap, dest);
712 orig = asn1->orig_stack;
713 asn1->orig_stack = NULL;
715 /* Get the first arguments and call the encoder. */
716 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
722 /* Handle internal options for encoder. */
723 if (type == SILC_ASN1_TAG_OPTS) {
724 SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
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;
731 asn1->orig_stack = orig;
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);
742 /* Take again the arguments */
743 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
745 /* No flags set, all flags will be reset. */
747 /* If accumul flag is set now pop the stack so that all accumulated
748 memory becomes free again. */
750 silc_stack_pop(asn1->stack1);
755 /* Push the stack for normal allocation from stack. */
757 silc_stack_push(asn1->stack1, &frame1);
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);
765 /* Pop the stack to free normal allocations from stack. */
767 silc_stack_pop(asn1->stack1);
769 /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
770 if (stack1 && !asn1->stack1)
771 asn1->stack1 = stack1;
773 asn1->orig_stack = orig;