5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2003 - 2006 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 /************************** ASN.1 Encoder routines **************************/
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); \
33 s_len = silc_utf8_decoded_len(d, d_len, (enc)); \
35 SILC_LOG_DEBUG(("Malformed %d string value", (enc))); \
38 silc_stack_push(asn1->stack2, &frame); \
39 s = silc_smalloc_ua(stack2, s_len + 1); \
41 silc_utf8_decode(d, d_len, (enc), s, s_len); \
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); \
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. */
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,
65 unsigned char *ptr = dest->data;
66 SilcAsn1Tag rtype, rtag;
67 SilcAsn1Options ropts;
70 SilcBool ret = FALSE, indef;
75 char sp[SILC_ASN1_RECURSION_DEPTH + 1];
76 memset(sp, 0, sizeof(sp));
78 memset(sp, 32, depth);
79 #endif /* SILC_DEBUG */
81 if (depth >= SILC_ASN1_RECURSION_DEPTH) {
82 SILC_LOG_DEBUG(("Maximum recursion depth reached"));
87 /* These options cannot be used in encoding */
88 opts &= ~SILC_ASN1_OPTIONAL;
90 /* Get length encoding */
91 indef = (opts & SILC_ASN1_INDEFINITE ? TRUE : FALSE);
93 /* By default UNIVERSAL is implied unless the following conditions
94 are met when CONTEXT will apply. For SILC_ASN1_TAG_ANY_PRIMITIVE
95 the class is changed only if flags dictate it. */
96 if (ber_class == SILC_BER_CLASS_UNIVERSAL) {
97 if (type == SILC_ASN1_TAG_ANY_PRIMITIVE) {
98 if (opts & SILC_ASN1_IMPLICIT ||
99 opts & SILC_ASN1_EXPLICIT)
100 ber_class = SILC_BER_CLASS_CONTEXT;
103 opts & SILC_ASN1_IMPLICIT ||
104 opts & SILC_ASN1_EXPLICIT)
105 ber_class = SILC_BER_CLASS_CONTEXT;
111 ("%04d: %sEncode %s [%d] %s %s %s %s", depth, sp[0] ? sp : "",
112 silc_asn1_tag_name(type), tag,
113 ber_class == SILC_BER_CLASS_UNIVERSAL ? "univ" :
114 ber_class == SILC_BER_CLASS_APPLICATION ? "appl" :
115 ber_class == SILC_BER_CLASS_CONTEXT ? "cont" : "priv",
116 (type != SILC_ASN1_TAG_SEQUENCE && type != SILC_ASN1_TAG_SET) ?
117 opts & SILC_ASN1_EXPLICIT ? "constr" :
118 type == SILC_ASN1_TAG_ANY &&
119 !(opts & SILC_ASN1_EXPLICIT) ? "constr" : "primit" : "constr",
120 indef ? opts & SILC_ASN1_EXPLICIT ? "defin" : "indef" : "defin",
121 opts & SILC_ASN1_IMPLICIT ? "implicit" :
122 opts & SILC_ASN1_EXPLICIT ? "explicit" : ""));
123 #endif /* SILC_DEBUG */
125 /* If tagging is explicit we add constructed type before the underlaying
126 types. The underlaying types are encoded recursively with this
128 if (opts & SILC_ASN1_EXPLICIT) {
129 memset(&buf, 0, sizeof(buf));
131 primitive = (type != SILC_ASN1_TAG_SEQUENCE &&
132 type != SILC_ASN1_TAG_SET);
133 opts &= ~SILC_ASN1_EXPLICIT;
135 silc_stack_push(stack2, &frame);
136 ret = silc_asn1_encoder(asn1, stack2, stack1, type, type,
137 SILC_BER_CLASS_UNIVERSAL, opts,
138 &buf, depth + 1, primitive);
139 silc_stack_pop(stack2);
142 SILC_LOG_DEBUG(("Error encoding explicit tag"));
146 /* Encode the explicit tag */
147 len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), FALSE);
148 dest = silc_buffer_srealloc_size(stack1, dest,
149 silc_buffer_truelen(dest) + len);
150 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
151 tag, buf.data, silc_buffer_len(&buf), FALSE);
161 /* Encode by the type */
164 case SILC_ASN1_TAG_ANY:
166 /* ANY is another ASN.1 node which is added to this tree */
167 SilcBuffer node = va_arg(asn1->ap, SilcBuffer);
171 /* Encode ASN.1 node into the tree. */
172 if (opts & SILC_ASN1_IMPLICIT || type != tag) {
173 /* We are tagging implicitly so we need to change the identifier
174 of the underlaying type. Only constructed type is allowed with
175 ANY when tagging implicitly. */
176 const unsigned char *d;
180 /* Get the underlaying data */
181 ret = silc_ber_decode(node, NULL, &enc, NULL, &d, &d_len,
184 SILC_LOG_DEBUG(("Error decoding underlaying node for ANY"));
187 assert(enc == SILC_BER_ENC_CONSTRUCTED);
189 /* Now encode with implicit tagging */
190 len = silc_ber_encoded_len(tag, d_len, FALSE);
191 dest = silc_buffer_srealloc_size(stack1, dest,
192 silc_buffer_truelen(dest) + len);
193 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
194 tag, d, d_len, FALSE);
198 /* Copy the data directly into the tree. */
199 len = silc_buffer_len(node);
200 dest = silc_buffer_srealloc_size(stack1, dest,
201 silc_buffer_truelen(dest) + len);
204 silc_buffer_put(dest, node->data, len);
209 case SILC_ASN1_TAG_ANY_PRIMITIVE:
211 /* ANY_PRIMITIVE is any primitive in encoded format. */
212 SilcBuffer prim = va_arg(asn1->ap, SilcBuffer);
216 /* Encode the primitive data */
217 len = silc_ber_encoded_len(tag, silc_buffer_len(prim), FALSE);
218 dest = silc_buffer_srealloc_size(stack1, dest,
219 silc_buffer_truelen(dest) + len);
220 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
221 tag, prim->data, silc_buffer_len(prim), FALSE);
227 case SILC_ASN1_TAG_SEQUENCE:
228 case SILC_ASN1_TAG_SET:
230 /* SEQUENCE/SET is a sequence of types. Sequences are opened and
231 encoded recursively by calling this same encoder. */
232 memset(&buf, 0, sizeof(buf));
234 /* Get type, tag and options for the first argument in recursion */
235 SILC_ASN1_ARGS(asn1, rtype, rtag, rclass, ropts);
237 silc_stack_push(stack2, &frame);
238 ret = silc_asn1_encoder(asn1, stack2, stack1, rtype, rtag, rclass,
239 ropts, &buf, depth + 1, FALSE);
240 silc_stack_pop(stack2);
242 SILC_LOG_DEBUG(("Error traversing a SEQUENCE/SET"));
246 /* Encode the sequence */
247 len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
248 dest = silc_buffer_srealloc_size(stack1, dest,
249 silc_buffer_truelen(dest) + len);
250 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_CONSTRUCTED,
251 tag, buf.data, silc_buffer_len(&buf), indef);
257 case SILC_ASN1_TAG_INTEGER:
258 case SILC_ASN1_TAG_ENUM:
261 SilcMPInt *mpint = va_arg(asn1->ap, SilcMPInt *);
265 memset(&buf, 0, sizeof(buf));
266 if (silc_mp_cmp_ui(mpint, 0) < 0) {
267 /* XXX TODO, negative integer. Take 2s complement, then store
268 bytes in 1s complement */
271 len = silc_mp_sizeinbase(mpint, 2);
273 len = ((len + 7) / 8) + 1;
276 silc_stack_push(stack2, &frame);
277 silc_buffer_srealloc_size(stack2, &buf,
278 silc_buffer_truelen(&buf) + len);
280 silc_mp_mp2bin_noalloc(mpint, buf.data, silc_buffer_len(&buf));
283 /* Encode the integer */
284 len = silc_ber_encoded_len(tag, len, indef);
285 dest = silc_buffer_srealloc_size(stack1, dest,
286 silc_buffer_truelen(dest) + len);
287 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
288 tag, buf.data, silc_buffer_len(&buf), FALSE);
289 silc_stack_pop(stack2);
295 case SILC_ASN1_TAG_SHORT_INTEGER:
298 SilcUInt32 sint = va_arg(asn1->ap, SilcUInt32);
301 if (tag == SILC_ASN1_TAG_SHORT_INTEGER)
302 tag = SILC_ASN1_TAG_INTEGER;
304 memset(&buf, 0, sizeof(buf));
306 silc_stack_push(stack2, &frame);
307 silc_mp_sinit(stack2, &z);
308 silc_mp_set_ui(&z, sint);
310 len = silc_mp_sizeinbase(&z, 2);
312 len = ((len + 7) / 8) + 1;
315 silc_buffer_srealloc_size(stack2, &buf,
316 silc_buffer_truelen(&buf) + len);
318 silc_mp_mp2bin_noalloc(&z, buf.data, silc_buffer_len(&buf));
321 /* Encode the integer */
322 len = silc_ber_encoded_len(tag, len, indef);
323 dest = silc_buffer_srealloc_size(stack1, dest,
324 silc_buffer_truelen(dest) + len);
325 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
326 tag, buf.data, silc_buffer_len(&buf), FALSE);
327 silc_stack_pop(stack2);
334 case SILC_ASN1_TAG_OID:
336 /* Object identifier */
337 char *cp, *oidstr = va_arg(asn1->ap, char *);
338 SilcUInt32 words[24], oid, mask;
343 /* Get OID words from the string */
344 cp = strchr(oidstr, '.');
346 if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
347 SILC_LOG_DEBUG(("Malformed OID string"));
350 if (c + 1 > sizeof(words) / sizeof(words[0]))
354 cp = strchr(oidstr, '.');
357 if (sscanf(oidstr, "%lu", (unsigned long *)&oid) != 1) {
358 SILC_LOG_DEBUG(("Malformed OID string"));
361 if (c + 1 > sizeof(words) / sizeof(words[0]))
368 SILC_LOG_DEBUG(("Malfromed OID string"));
372 /* Get OID data length */
373 for (i = 2, len = 1; i < c; i++) {
375 for (oid = words[i]; oid; oid >>= 7)
383 memset(&buf, 0, sizeof(buf));
384 silc_stack_push(stack2, &frame);
385 silc_buffer_srealloc_size(stack2, &buf,
386 silc_buffer_truelen(&buf) + len);
387 buf.data[0] = words[0] * 40 + words[1];
388 for (i = 2, len = 1; i < c; i++) {
394 buf.data[len++] = (oid & 0x7f) | mask;
401 buf.data[k] = buf.data[mask];
402 buf.data[mask] = oid;
409 buf.data[len++] = 0x00;
412 len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
413 dest = silc_buffer_srealloc_size(stack1, dest,
414 silc_buffer_truelen(dest) + len);
415 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
416 tag, buf.data, silc_buffer_len(&buf), FALSE);
417 silc_stack_pop(stack2);
423 case SILC_ASN1_TAG_BOOLEAN:
425 /* Encodes boolean (TRUE/FALSE) value */
426 unsigned char val[1];
427 val[0] = (va_arg(asn1->ap, SilcUInt32) ? 0xff : 0x00);
429 assert(indef == FALSE);
430 len = silc_ber_encoded_len(tag, 1, FALSE);
431 dest = silc_buffer_srealloc_size(stack1, dest,
432 silc_buffer_truelen(dest) + len);
433 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
440 case SILC_ASN1_TAG_BIT_STRING:
442 /* Encode the data as is, with the bit padding. d_len is in bits. */
443 unsigned char *d = va_arg(asn1->ap, unsigned char *);
444 SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
445 unsigned char pad[1];
449 pad[0] = (8 - (d_len & 7)) & 7;
450 d_len = ((d_len + 7) / 8) + 1;
452 memset(&buf, 0, sizeof(buf));
453 silc_stack_push(stack2, &frame);
454 silc_buffer_srealloc_size(stack2, &buf,
455 silc_buffer_truelen(&buf) + d_len);
456 silc_buffer_put(&buf, pad, 1);
457 silc_buffer_pull(&buf, 1);
458 silc_buffer_put(&buf, d, d_len - 1);
459 silc_buffer_push(&buf, 1);
461 len = silc_ber_encoded_len(tag, silc_buffer_len(&buf), indef);
462 dest = silc_buffer_srealloc_size(stack1, dest,
463 silc_buffer_truelen(dest) + len);
464 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
465 tag, buf.data, silc_buffer_len(&buf), indef);
466 silc_stack_pop(stack2);
472 case SILC_ASN1_TAG_NULL:
474 /* Encode empty BER block */
475 assert(indef == FALSE);
476 len = silc_ber_encoded_len(tag, 0, FALSE);
477 dest = silc_buffer_srealloc_size(stack1, dest,
478 silc_buffer_truelen(dest) + len);
479 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
480 tag, NULL, 0, FALSE);
486 case SILC_ASN1_TAG_UTC_TIME:
488 /* Universal encoded time string */
489 SilcTime timeval = va_arg(asn1->ap, SilcTime);
494 if (!silc_time_universal_string(timeval, timestr, sizeof(timestr))) {
495 SILC_LOG_DEBUG(("Could not encode universal time string"));
499 len = silc_ber_encoded_len(tag, strlen(timestr), indef);
500 dest = silc_buffer_srealloc_size(stack1, dest,
501 silc_buffer_truelen(dest) + len);
502 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
503 tag, timestr, strlen(timestr), indef);
509 case SILC_ASN1_TAG_GENERALIZED_TIME:
511 /* Generalized encoded time string */
512 SilcTime timeval = va_arg(asn1->ap, SilcTime);
517 if (!silc_time_generalized_string(timeval, timestr, sizeof(timestr))) {
518 SILC_LOG_DEBUG(("Could not encode generalized time string"));
522 len = silc_ber_encoded_len(tag, strlen(timestr), indef);
523 dest = silc_buffer_srealloc_size(stack1, dest,
524 silc_buffer_truelen(dest) + len);
525 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
526 tag, timestr, strlen(timestr), indef);
532 case SILC_ASN1_TAG_UTF8_STRING:
535 unsigned char *d = va_arg(asn1->ap, unsigned char *);
536 SilcUInt32 d_len = va_arg(asn1->ap, SilcUInt32);
540 /* By default all strings that get here should already be UTF-8 */
541 if (!silc_utf8_valid(d, d_len)) {
542 SILC_LOG_DEBUG(("Malformed UTF-8 string"));
546 len = silc_ber_encoded_len(tag, d_len, indef);
547 dest = silc_buffer_srealloc_size(stack1, dest,
548 silc_buffer_truelen(dest) + len);
549 ret = silc_ber_encode(dest, ber_class, SILC_BER_ENC_PRIMITIVE,
550 tag, d, d_len, indef);
556 case SILC_ASN1_TAG_OCTET_STRING:
558 /* Octet string. We put it in as 8-bit ASCII */
559 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
563 case SILC_ASN1_TAG_NUMERIC_STRING:
565 /* Numerical (digit) string */
566 SILC_ASN1_ENCODE_STRING(SILC_STRING_NUMERICAL);
570 case SILC_ASN1_TAG_PRINTABLE_STRING:
572 /* Printable string */
573 SILC_ASN1_ENCODE_STRING(SILC_STRING_PRINTABLE);
577 case SILC_ASN1_TAG_TELETEX_STRING:
579 /* Teletex (T61) string */
580 SILC_ASN1_ENCODE_STRING(SILC_STRING_TELETEX);
584 case SILC_ASN1_TAG_IA5_STRING:
586 /* US ASCII string */
587 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
591 case SILC_ASN1_TAG_VISIBLE_STRING:
594 SILC_ASN1_ENCODE_STRING(SILC_STRING_VISIBLE);
598 case SILC_ASN1_TAG_UNIVERSAL_STRING:
600 /* Universal (UCS-4) string */
601 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
605 case SILC_ASN1_TAG_UNRESTRICTED_STRING:
606 case SILC_ASN1_TAG_GENERAL_STRING:
608 /* Handle now unrestricted and general as 8-bit ascii, which
609 probably isn't correct. */
610 SILC_ASN1_ENCODE_STRING(SILC_STRING_ASCII);
614 case SILC_ASN1_TAG_BMP_STRING:
616 /* BMP (UCS-2) string */
617 SILC_ASN1_ENCODE_STRING(SILC_STRING_UNIVERSAL);
621 case SILC_ASN1_TAG_ODE:
622 case SILC_ASN1_TAG_ETI:
623 case SILC_ASN1_TAG_REAL:
624 case SILC_ASN1_TAG_EMBEDDED:
625 case SILC_ASN1_TAG_ROI:
626 case SILC_ASN1_TAG_VIDEOTEX_STRING:
627 case SILC_ASN1_TAG_GRAPHIC_STRING:
629 SILC_NOT_IMPLEMENTED("Unsupported ASN.1 tag");
636 SILC_LOG_DEBUG(("Invalid ASN.1 tag `%d'. Cannot encode ASN.1.", type));
644 silc_buffer_pull(dest, len);
650 /* Get next type, tag and options */
651 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
652 if (type == SILC_ASN1_END) {
659 SILC_LOG_DEBUG(("Error encoding type %d (depth %d)", type, depth));
663 len = dest->data - ptr;
665 len = dest->data - dest->head;
666 silc_buffer_push(dest, len);
671 SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...)
673 SilcAsn1Tag type, tag;
674 SilcAsn1Options opts;
675 SilcBerClass ber_class;
676 SilcStackFrame frame1, frame2;
677 SilcStack stack1 = NULL;
683 va_start(asn1->ap, dest);
685 /* Get the first arguments and call the encoder. */
686 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
692 /* Handle internal options for encoder. */
693 if (type == SILC_ASN1_TAG_OPTS) {
694 SilcUInt32 o = va_arg(asn1->ap, SilcUInt32);
696 if (o & SILC_ASN1_ALLOC) {
697 /* User wants to alloate everything. Set the stack to NULL so
698 that stack aware calls revert to normal allocation routines. */
699 stack1 = asn1->stack1;
703 if (o & SILC_ASN1_ACCUMUL) {
704 /* If accumul flag is not set yet, then push the stack. */
705 if (!asn1->accumul) {
706 silc_stack_push(asn1->stack1, NULL);
711 /* Take again the arguments */
712 SILC_ASN1_ARGS(asn1, type, tag, ber_class, opts);
714 /* No flags set, all flags will be reset. */
716 /* If accumul flag is set now pop the stack so that all accumulated
717 memory becomes free again. */
719 silc_stack_pop(asn1->stack1);
724 /* Push the stack for normal allocation from stack. */
726 silc_stack_push(asn1->stack1, &frame1);
729 silc_stack_push(asn1->stack2, &frame2);
730 ret = silc_asn1_encoder(asn1, asn1->stack1, asn1->stack2,
731 type, tag, ber_class, opts, dest, 0, FALSE);
732 silc_stack_pop(asn1->stack2);
734 /* Pop the stack to free normal allocations from stack. */
736 silc_stack_pop(asn1->stack1);
738 /* If SILC_ASN1_ALLOC flag was set, restore the stack. */
739 if (stack1 && !asn1->stack1)
740 asn1->stack1 = stack1;