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);
26 /************************** ASN.1 Encoder routines **************************/
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); \
35 s_len = silc_utf8_decoded_len(d, d_len, (enc)); \
37 SILC_LOG_DEBUG(("Malformed %d string value", (enc))); \
40 silc_stack_push(asn1->stack2, &frame); \
41 s = silc_smalloc_ua(stack2, s_len + 1); \
43 silc_utf8_decode(d, d_len, (enc), s, s_len); \
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); \
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. */
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,
67 unsigned char *ptr = dest->data;
68 SilcAsn1Tag rtype, rtag;
69 SilcAsn1Options ropts;
72 SilcBool ret = FALSE, indef;
77 char sp[SILC_ASN1_RECURSION_DEPTH + 1];
78 memset(sp, 0, sizeof(sp));
80 memset(sp, 32, depth);
81 #endif /* SILC_DEBUG */
83 if (depth >= SILC_ASN1_RECURSION_DEPTH) {
84 SILC_LOG_DEBUG(("Maximum recursion depth reached"));
89 /* These options cannot be used in encoding */
90 opts &= ~SILC_ASN1_OPTIONAL;
92 /* Get length encoding */
93 indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
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;
105 opts & SILC_ASN1_IMPLICIT ||
106 opts & SILC_ASN1_EXPLICIT)
107 ber_class = SILC_BER_CLASS_CONTEXT;
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 */
127 /* If tagging is explicit we add constructed type before the underlaying
128 types. The underlaying types are encoded recursively with this
130 if (opts & SILC_ASN1_EXPLICIT) {
131 memset(&buf, 0, sizeof(buf));
133 primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
134 type != SILC_ASN1_TAG_SET);
135 opts &= ~SILC_ASN1_EXPLICIT;
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);
143 SILC_LOG_DEBUG(("Error encoding explicit tag"));
144 silc_stack_pop(stack2);
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);
165 /* Encode by the type */
168 case SILC_ASN1_TAG_ANY:
170 /* ANY is another ASN.1 node which is added to this tree */
171 SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
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;
184 /* Get the underlaying data */
185 ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
188 SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
191 assert(enc == SILC_BER_ENC_CONSTRUCTED);
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);
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);
208 silc_buffer_put(dest, node->data, len);
213 case SILC_ASN1_TAG_ANY_PRIMITIVE:
215 /* ANY_PRIMITIVE is any primitive in encoded format. */
216 SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
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);
231 case SILC_ASN1_TAG_SEQUENCE:
232 case SILC_ASN1_TAG_SET:
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));
238 /* Get type, tag and options for the first argument in recursion */
239 SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
241 silc_stack_push(stack2, &frame);
242 ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
243 ropts, &buf, depth + 1, FALSE);
245 SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
246 silc_stack_pop(stack2);
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);
263 case SILC_ASN1_TAG_INTEGER:
264 case SILC_ASN1_TAG_ENUM:
267 SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
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 */
277 len = silc_mp_sizeinbase(mpint, 2);
279 len = ((len + 7) / 8) + 1;
282 silc_stack_push(stack2, &frame);
283 silc_buffer_srealloc_size(stack2, &buf,
284 silc_buffer_truelen(&buf) + len);
286 silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
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);
302 case SILC_ASN1_TAG_SHORT_INTEGER:
305 SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
308 if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
309 tag = SILC_ASN1_TAG_INTEGER;
311 memset(&buf, 0, sizeof(buf));
313 silc_stack_push(stack2, &frame);
314 silc_mp_sinit(stack2, &z);
315 silc_mp_set_ui(&z, sint);
317 len = silc_mp_sizeinbase(&z, 2);
319 len = ((len + 7) / 8) + 1;
322 silc_buffer_srealloc_size(stack2, &buf,
323 silc_buffer_truelen(&buf) + len);
325 silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
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);
342 case SILC_ASN1_TAG_OID:
344 /* Object identifier */
345 char *cp, *oidstr = va_arg(asn1->ap, char *);
346 SilcUInt32 words[24], oid, mask;
351 /* Get OID words from the string */
352 cp = strchr(oidstr, '.');
354 if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
355 SILC_LOG_DEBUG(("Malformed OID string"));
358 if (c + 1 > sizeof(words) / sizeof(words[0]))
362 cp = strchr(oidstr, '.');
365 if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
366 SILC_LOG_DEBUG(("Malformed OID string"));
369 if (c + 1 > sizeof(words) / sizeof(words[0]))
376 SILC_LOG_DEBUG(("Malfromed OID string"));
380 /* Get OID data length */
381 for (i = 2, len = 1; i < c; i++) {
383 for (oid = words[i]; oid; oid >>= 7)
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++) {
402 buf.data[len++] = (oid & 0x7f) | mask;
409 buf.data[k] = buf.data[mask];
410 buf.data[mask] = oid;
417 buf.data[len++] = 0x00;
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);
432 case SILC_ASN1_TAG_BOOLEAN:
434 /* Encodes boolean (TRUE/FALSE) value */
435 unsigned char val[1];
436 val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
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,
449 case SILC_ASN1_TAG_BIT_STRING:
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];
458 pad[0] = (8 - (d_len & 7)) & 7;
459 d_len = ((d_len + 7) / 8) + 1;
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);
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);
482 case SILC_ASN1_TAG_NULL:
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);
496 case SILC_ASN1_TAG_UTC_TIME:
498 /* Universal encoded time string */
499 SilcTime timeval = va_arg(asn1->ap, SilcTime);
504 if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
505 SILC_LOG_DEBUG(("Could not encode universal time string"));
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);
519 case SILC_ASN1_TAG_GENERALIZED_TIME:
521 /* Generalized encoded time string */
522 SilcTime timeval = va_arg(asn1->ap, SilcTime);
527 if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
528 SILC_LOG_DEBUG(("Could not encode generalized time string"));
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);
542 case SILC_ASN1_TAG_UTF8_STRING:
545 unsigned char *d = va_arg(asn1->ap, unsigned char *);
546 SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
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"));
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);
566 case SILC_ASN1_TAG_OCTET_STRING:
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);
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);
582 case SILC_ASN1_TAG_NUMERIC_STRING:
584 /* Numerical (digit) string */
585 SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
589 case SILC_ASN1_TAG_PRINTABLE_STRING:
591 /* Printable string */
592 SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
596 case SILC_ASN1_TAG_TELETEX_STRING:
598 /* Teletex (T61) string */
599 SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
603 case SILC_ASN1_TAG_IA5_STRING:
605 /* US ASCII string */
606 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
610 case SILC_ASN1_TAG_VISIBLE_STRING:
613 SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
617 case SILC_ASN1_TAG_UNIVERSAL_STRING:
619 /* Universal (UCS-4) string */
620 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
624 case SILC_ASN1_TAG_UNRESTRICTED_STRING:
625 case SILC_ASN1_TAG_GENERAL_STRING:
627 /* Handle now unrestricted and general as 8-bit ascii, which
628 probably isn't correct. */
629 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
633 case SILC_ASN1_TAG_BMP_STRING:
635 /* BMP (UCS-2) string */
636 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
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:
648 SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
655 SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
663 silc_buffer_pull(dest, len);
669 /* Get next type, tag and options */
670 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
671 if (type == SILC_ASN1_END) {
678 SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
682 len = dest->data - ptr;
684 len = dest->data - dest->head;
685 silc_buffer_push(dest, len);
690 SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
692 SilcAsn1Tag type, tag;
693 SilcAsn1Options opts;
694 SilcBerClass ber_class;
695 SilcStackFrame frame1, frame2;
696 SilcStack stack1 = NULL;
702 va_start(asn1->ap, dest);
704 /* Get the first arguments and call the encoder. */
705 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
711 /* Handle internal options for encoder. */
712 if (type == SILC_ASN1_TAG_OPTS) {
713 SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
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;
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);
730 /* Take again the arguments */
731 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
733 /* No flags set, all flags will be reset. */
735 /* If accumul flag is set now pop the stack so that all accumulated
736 memory becomes free again. */
738 silc_stack_pop(asn1->stack1);
743 /* Push the stack for normal allocation from stack. */
745 silc_stack_push(asn1->stack1, &frame1);
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);
753 /* Pop the stack to free normal allocations from stack. */
755 silc_stack_pop(asn1->stack1);
757 /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
758 if (stack1 && !asn1->stack1)
759 asn1->stack1 = stack1;