root/trunk/src/libopensc/asn1.c

Revision 3504, 38.0 kB (checked in by alonbl, 7 months ago)

SIGSEGV print_tags_recursive - fix

Patch opensc-0.11.4.trunk-r3502-fix-segv_print_tags_asn1.diff (for trunk
trunk revision 3502) is draft.

Example 1 (SIGSEGV):

OpenSC Explorer version 0.11.4-svn
OpenSC [3F00]> cd ff00
OpenSC [3F00/FF00]> asn1 0001
Printing tags for buffer of length 512
[Switching to Thread -1211906368 (LWP 25131)]

By Aktiv Co. Aleksey Samsonov

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * asn1.c: ASN.1 decoding functions (DER)
3 *
4 * Copyright (C) 2001, 2002  Juha YrjölÀ <juha.yrjola@iki.fi>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include "internal.h"
22#include "asn1.h"
23#include <stdio.h>
24#include <string.h>
25#include <ctype.h>
26#include <assert.h>
27#include <stdlib.h>
28
29static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1,
30                       const u8 *in, size_t len, const u8 **newp, size_t *len_left,
31                       int choice, int depth);
32static int asn1_encode(sc_context_t *ctx, const struct sc_asn1_entry *asn1,
33                       u8 **ptr, size_t *size, int depth);
34
35static const char *tag2str(unsigned int tag)
36{
37        static const char *tags[] = {
38                "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING",      /* 0-4 */
39                "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL",      /* 5-9 */
40                "ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>",   /* 10-13 */
41                "<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET",    /* 15-17 */
42                "NUMERICSTRING", "PRINTABLESTRING", "T61STRING",        /* 18-20 */
43                "VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME",    /* 21-24 */
44                "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING",      /* 25-27 */
45                "UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING"     /* 28-30 */
46        };
47
48        if (tag > 30)
49                return "(unknown)";
50        return tags[tag];
51}
52
53int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out,
54                     unsigned int *tag_out, size_t *taglen)
55{
56        const u8 *p = *buf;
57        size_t left = buflen, len;
58        unsigned int cla, tag, i;
59
60        if (left < 2)
61                return SC_ERROR_INVALID_ASN1_OBJECT;
62        *buf = NULL;
63        if (*p == 0xff || *p == 0)
64                /* end of data reached */
65                return SC_SUCCESS;
66        /* parse tag byte(s) */
67        cla = (*p & SC_ASN1_TAG_CLASS) | (*p & SC_ASN1_TAG_CONSTRUCTED);
68        tag = *p & SC_ASN1_TAG_PRIMITIVE;
69        p++;
70        left--;
71        if (tag == SC_ASN1_TAG_PRIMITIVE) {
72                /* high tag number */
73                size_t n = sizeof(int) - 1;
74                /* search the last tag octet */
75                while (left-- != 0 && n != 0) {
76                        tag <<= 8;
77                        tag |= *p;
78                        if ((*p++ & 0x80) == 0)
79                                break;
80                        n--;
81                }
82                if (left == 0 || n == 0)
83                        /* either an invalid tag or it doesn't fit in
84                         * unsigned int */
85                        return SC_ERROR_INVALID_ASN1_OBJECT;
86               
87        }
88        if (left == 0)
89                return SC_ERROR_INVALID_ASN1_OBJECT;
90        /* parse length byte(s) */
91        len = *p & 0x7f;
92        if (*p++ & 0x80) {
93                unsigned int a = 0;
94                if (len > 4 || len > left)
95                        return SC_ERROR_INVALID_ASN1_OBJECT;
96                left -= len;
97                for (i = 0; i < len; i++) {
98                        a <<= 8;
99                        a |= *p;
100                        p++;
101                }
102                len = a;
103        }
104        if (len > left)
105                return SC_ERROR_INVALID_ASN1_OBJECT;
106        *cla_out = cla;
107        *tag_out = tag;
108        *taglen = len;
109        *buf = p;
110        return SC_SUCCESS;
111}
112
113void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg,
114                          int set_present)
115{
116        entry->parm = parm;
117        entry->arg  = arg;
118        if (set_present)
119                entry->flags |= SC_ASN1_PRESENT;
120}
121
122void sc_copy_asn1_entry(const struct sc_asn1_entry *src,
123                        struct sc_asn1_entry *dest)
124{
125        while (src->name != NULL) {
126                *dest = *src;
127                dest++;
128                src++;
129        }
130        dest->name = NULL;
131}
132
133static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen)
134{
135        size_t i;
136
137        for (i = 0; i < buflen; i++)
138                printf("%02X", buf[i]);
139}
140
141static void sc_asn1_print_utf8string(const u8 * buf, size_t buflen)
142{
143        size_t i;
144
145        for (i = 0; i < buflen; i++)
146                printf("%c", buf[i]);
147}
148
149static void sc_asn1_print_integer(const u8 * buf, size_t buflen)
150{
151#ifndef _WIN32
152        long long a = 0;
153#else
154        __int64 a = 0;
155#endif
156        size_t i;
157
158        if (buflen > sizeof(a)) {
159                printf("too long");
160                return;
161        }
162        for (i = 0; i < buflen; i++) {
163                a <<= 8;
164                a |= buf[i];
165        }
166        printf("%lld", a);
167}
168
169static void sc_asn1_print_bit_string(const u8 * buf, size_t buflen)
170{
171#ifndef _WIN32
172        long long a = 0;
173#else
174        __int64 a = 0;
175#endif
176        int r, i;
177
178        if (buflen > sizeof(a) + 1) {
179                printf("too long");
180                return;
181        }
182        r = sc_asn1_decode_bit_string(buf, buflen, &a, sizeof(a));
183        if (r < 0) {
184                printf("decode error");
185                return;
186        }
187        for (i = r - 1; i >= 0; i--) {
188                printf("%c", ((a >> i) & 1) ? '1' : '0');
189        }
190}
191
192static void sc_asn1_print_object_id(const u8 * buf, size_t buflen)
193{
194        int i = 0;
195        struct sc_object_id oid;
196        char sbuf[256];
197
198        if (sc_asn1_decode_object_id(buf, buflen, &oid)) {
199                printf("decode error");
200                return;
201        }
202        sbuf[0] = 0;
203        while (oid.value[i] >= 0) {
204                char tmp[12];
205               
206                if (i)
207                        strcat(sbuf, ".");
208                sprintf(tmp, "%d", oid.value[i]);
209                strcat(sbuf, tmp);
210                i++;
211        }
212        printf("%s", sbuf);
213}
214
215static void print_tags_recursive(const u8 * buf0, const u8 * buf,
216                                 size_t buflen, int depth)
217{
218        int i, r;
219        size_t bytesleft = buflen;
220        const char *classes[4] = {
221                "Univ", "Appl", "Cntx", "Priv"
222        };
223        const u8 *p = buf;
224
225        while (bytesleft >= 2) {
226                unsigned int cla = 0, tag = 0, hlen;
227                const u8 *tagp = p;
228                size_t len;
229
230                r = sc_asn1_read_tag(&tagp, bytesleft, &cla, &tag, &len);
231                if (r != SC_SUCCESS) {
232                        printf("Error in decoding.\n");
233                        return;
234                }
235                hlen = tagp - p;
236                if (cla == 0 && tag == 0) {
237                        printf("Zero tag, finishing\n");
238                        break;
239                }
240                for (i = 0; i < depth; i++) {
241                        putchar(' ');
242                        putchar(' ');
243                }
244                printf("%02X %s: tag 0x%02X, length %3d: ",
245                       cla | tag, classes[cla >> 6], tag & 0x1f, (int) len);
246                if (len + hlen > bytesleft) {
247                        printf(" Illegal length!\n");
248                        return;
249                }
250                p += hlen + len;
251                bytesleft -= hlen + len;
252                if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL)
253                        printf("%s", tag2str(tag));
254
255                if (cla & SC_ASN1_TAG_CONSTRUCTED) {
256                        putchar('\n');
257                        print_tags_recursive(buf0, tagp, len, depth + 1);
258                        continue;
259                }
260                if ((cla & SC_ASN1_TAG_CLASS) == SC_ASN1_TAG_UNIVERSAL) {
261                        printf(" [");
262                        switch (tag) {
263                        case SC_ASN1_TAG_BIT_STRING:
264                                sc_asn1_print_bit_string(tagp, len);
265                                break;
266                        case SC_ASN1_TAG_OCTET_STRING:
267                                sc_asn1_print_octet_string(tagp, len);
268                                break;
269                        case SC_ASN1_TAG_OBJECT:
270                                sc_asn1_print_object_id(tagp, len);
271                                break;
272                        case SC_ASN1_TAG_INTEGER:
273                        case SC_ASN1_TAG_ENUMERATED:
274                                sc_asn1_print_integer(tagp, len);
275                                break;
276                        case SC_ASN1_TAG_T61STRING:
277                        case SC_ASN1_TAG_PRINTABLESTRING:
278                        case SC_ASN1_TAG_UTF8STRING:
279                                sc_asn1_print_utf8string(tagp, len);
280                                break;
281                        }
282                        printf("]");
283                }
284                putchar('\n');
285        }
286        return;
287}
288
289void sc_asn1_print_tags(const u8 * buf, size_t buflen)
290{
291        printf("Printing tags for buffer of length %d\n", (int) buflen);
292        print_tags_recursive(buf, buf, buflen, 0);
293}
294
295const u8 *sc_asn1_find_tag(sc_context_t *ctx, const u8 * buf,
296        size_t buflen, unsigned int tag_in, size_t *taglen_in)
297{
298        size_t left = buflen, taglen;
299        const u8 *p = buf;
300
301        *taglen_in = 0;
302        while (left >= 2) {
303                unsigned int cla, tag, mask = 0xff00;
304
305                buf = p;
306                /* read a tag */
307                if (sc_asn1_read_tag(&p, left, &cla, &tag, &taglen) != SC_SUCCESS)
308                        return NULL;
309                if (left < (size_t)(p - buf)) {
310                        sc_error(ctx, "invalid TLV object\n");
311                        return NULL;
312                }
313                left -= (p - buf);
314                /* we need to shift the class byte to the leftmost
315                 * byte of the tag */
316                while ((tag & mask) != 0) {
317                        cla  <<= 8;
318                        mask <<= 8;
319                }
320                /* compare the read tag with the given tag */
321                if ((tag | cla) == tag_in) {
322                        /* we have a match => return length and value part */
323                        if (taglen > left)
324                                return NULL;
325                        *taglen_in = taglen;
326                        return p;
327                }
328                /* otherwise continue reading tags */
329                if (left < taglen) {
330                        sc_error(ctx, "invalid TLV object\n");
331                        return NULL;
332                }
333                left -= taglen;
334                p += taglen;
335        }
336        return NULL;
337}
338
339const u8 *sc_asn1_skip_tag(sc_context_t *ctx, const u8 ** buf, size_t *buflen,
340                           unsigned int tag_in, size_t *taglen_out)
341{
342        const u8 *p = *buf;
343        size_t len = *buflen, taglen;
344        unsigned int cla, tag;
345
346        if (sc_asn1_read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != SC_SUCCESS)
347                return NULL;
348        switch (cla & 0xC0) {
349        case SC_ASN1_TAG_UNIVERSAL:
350                if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_UNI)
351                        return NULL;
352                break;
353        case SC_ASN1_TAG_APPLICATION:
354                if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_APP)
355                        return NULL;
356                break;
357        case SC_ASN1_TAG_CONTEXT:
358                if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_CTX)
359                        return NULL;
360                break;
361        case SC_ASN1_TAG_PRIVATE:
362                if ((tag_in & SC_ASN1_CLASS_MASK) != SC_ASN1_PRV)
363                        return NULL;
364                break;
365        }
366        if (cla & SC_ASN1_TAG_CONSTRUCTED) {
367                if ((tag_in & SC_ASN1_CONS) == 0)
368                        return NULL;
369        } else
370                if (tag_in & SC_ASN1_CONS)
371                        return NULL;
372        if ((tag_in & SC_ASN1_TAG_MASK) != tag)
373                return NULL;
374        len -= (p - *buf);      /* header size */
375        if (taglen > len) {
376                sc_error(ctx, "too long ASN.1 object (size %d while only %d available)\n",
377                      taglen, len);
378                return NULL;
379        }
380        *buflen -= (p - *buf) + taglen;
381        *buf = p + taglen;      /* point to next tag */
382        *taglen_out = taglen;
383        return p;
384}
385
386const u8 *sc_asn1_verify_tag(sc_context_t *ctx, const u8 * buf, size_t buflen,
387                             unsigned int tag_in, size_t *taglen_out)
388{
389        return sc_asn1_skip_tag(ctx, &buf, &buflen, tag_in, taglen_out);
390}
391
392static int decode_bit_string(const u8 * inbuf, size_t inlen, void *outbuf,
393                             size_t outlen, int invert)
394{
395        const u8 *in = inbuf;
396        u8 *out = (u8 *) outbuf;
397        int zero_bits = *in & 0x07;
398        size_t octets_left = inlen - 1;
399        int i, count = 0;
400
401        memset(outbuf, 0, outlen);
402        in++;
403        if (outlen < octets_left)
404                return SC_ERROR_BUFFER_TOO_SMALL;
405        if (inlen < 1)
406                return SC_ERROR_INVALID_ASN1_OBJECT;
407        while (octets_left) {
408                /* 1st octet of input:  ABCDEFGH, where A is the MSB */
409                /* 1st octet of output: HGFEDCBA, where A is the LSB */
410                /* first bit in bit string is the LSB in first resulting octet */
411                int bits_to_go;
412
413                *out = 0;
414                if (octets_left == 1)
415                        bits_to_go = 8 - zero_bits;
416                else
417                        bits_to_go = 8;
418                if (invert)
419                        for (i = 0; i < bits_to_go; i++) {
420                                *out |= ((*in >> (7 - i)) & 1) << i;
421                        }
422                else {
423                        *out = *in;
424                }
425                out++;
426                in++;
427                octets_left--;
428                count++;
429        }
430        return (count * 8) - zero_bits;
431}
432
433int sc_asn1_decode_bit_string(const u8 * inbuf, size_t inlen,
434                              void *outbuf, size_t outlen)
435{
436        return decode_bit_string(inbuf, inlen, outbuf, outlen, 1);
437}
438
439int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen,
440                                 void *outbuf, size_t outlen)
441{
442        return decode_bit_string(inbuf, inlen, outbuf, outlen, 0);
443}
444
445static int encode_bit_string(const u8 * inbuf, size_t bits_left, u8 **outbuf,
446                             size_t *outlen, int invert)
447{
448        const u8 *in = inbuf;
449        u8 *out;
450        size_t bytes;
451        int skipped = 0;
452       
453        bytes = (bits_left + 7)/8 + 1;
454        *outbuf = out = (u8 *) malloc(bytes);
455        if (out == NULL)
456                return SC_ERROR_OUT_OF_MEMORY;
457        *outlen = bytes;
458        out += 1;
459        while (bits_left) {
460                int i, bits_to_go = 8;
461               
462                *out = 0;
463                if (bits_left < 8) {
464                        bits_to_go = bits_left;
465                        skipped = 8 - bits_left;
466                }
467                if (invert) {
468                        for (i = 0; i < bits_to_go; i++)
469                                *out |= ((*in >> i) & 1) << (7 - i);
470                } else {
471                        *out = *in;
472                        if (bits_left < 8)
473                                return SC_ERROR_NOT_SUPPORTED; /* FIXME */
474                }
475                bits_left -= bits_to_go;
476                out++, in++;
477        }
478        out = *outbuf;
479        out[0] = skipped;
480        return 0;
481}
482
483/*
484 * Bitfields are just bit strings, stored in an unsigned int
485 * (taking endianness into account)
486 */
487static int decode_bit_field(const u8 * inbuf, size_t inlen, void *outbuf, size_t outlen)
488{
489        u8              data[sizeof(unsigned int)];
490        unsigned int    field = 0;
491        int             i, n;
492
493        if (outlen != sizeof(data))
494                return SC_ERROR_BUFFER_TOO_SMALL;
495
496        n = decode_bit_string(inbuf, inlen, data, sizeof(data), 1);
497        if (n < 0)
498                return n;
499
500        for (i = 0; i < n; i += 8) {
501                field |= (data[i/8] << i);
502        }
503        memcpy(outbuf, &field, outlen);
504        return 0;
505}
506
507static int encode_bit_field(const u8 *inbuf, size_t inlen,
508                            u8 **outbuf, size_t *outlen)
509{
510        u8              data[sizeof(unsigned int)];
511        unsigned int    field = 0;
512        size_t          i, bits;
513
514        if (inlen != sizeof(data))
515                return SC_ERROR_BUFFER_TOO_SMALL;
516
517        /* count the bits */
518        memcpy(&field, inbuf, inlen);
519        for (bits = 0; field; bits++)
520                field >>= 1;
521
522        memcpy(&field, inbuf, inlen);
523        for (i = 0; i < bits; i += 8)
524                data[i/8] = field >> i;
525
526        return encode_bit_string(data, bits, outbuf, outlen, 1);
527}
528
529int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out)
530{
531        int    a = 0;
532        size_t i;
533
534        if (inlen > sizeof(int))
535                return SC_ERROR_INVALID_ASN1_OBJECT;
536        if (inbuf[0] & 0x80)
537                a = -1;
538        for (i = 0; i < inlen; i++) {
539                a <<= 8;
540                a |= *inbuf++;
541        }
542        *out = a;
543        return 0;
544}
545
546static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize)
547{
548        int i = sizeof(in) * 8, skip_zero, skip_sign;
549        u8 *p, b;
550
551        if (in < 0)
552        {
553                skip_sign = 1;
554                skip_zero= 0;
555        }
556        else
557        {
558                skip_sign = 0;
559                skip_zero= 1;
560        }
561        *obj = p = (u8 *) malloc(sizeof(in)+1);
562        if (*obj == NULL)
563                return SC_ERROR_OUT_OF_MEMORY;
564        do {
565                i -= 8;
566                b = in >> i;
567                if (skip_sign)
568                {
569                        if (b != 0xff)
570                                skip_sign = 0;
571                        if (b & 0x80)
572                        {
573                                *p = b;
574                                if (0xff == b)
575                                        continue;
576                        }
577                        else
578                        {
579                                p++;
580                                skip_sign = 0;
581                        }
582                }
583                if (b == 0 && skip_zero)
584                        continue;
585                if (skip_zero) {
586                        skip_zero = 0;
587                        /* prepend 0x00 if MSb is 1 and integer positive */
588                        if ((b & 0x80) != 0 && in > 0)
589                                *p++ = 0;
590                }
591                *p++ = b;
592        } while (i > 0);
593        if (skip_sign)
594                p++;
595        *objsize = p - *obj;
596        if (*objsize == 0) {
597                *objsize = 1;
598                (*obj)[0] = 0;
599        }
600        return 0;
601}
602
603int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen,
604                             struct sc_object_id *id)
605{
606        int i, a;
607        const u8 *p = inbuf;
608        int *octet;
609       
610        if (inlen == 0 || inbuf == NULL || id == NULL)
611                return SC_ERROR_INVALID_ARGUMENTS;
612        octet = id->value;
613        for (i = 0; i < SC_MAX_OBJECT_ID_OCTETS; i++)
614                id->value[i] = -1;
615        a = *p;
616        *octet++ = a / 40;
617        *octet++ = a % 40;
618        inlen--;
619       
620        while (inlen) {
621                p++;
622                a = *p & 0x7F;
623                inlen--;
624                while (inlen && *p & 0x80) {
625                        p++;
626                        a <<= 7;
627                        a |= *p & 0x7F;
628                        inlen--;
629                }
630                *octet++ = a;
631                if (octet - id->value >= SC_MAX_OBJECT_ID_OCTETS-1)
632                        return SC_ERROR_INVALID_ASN1_OBJECT;
633        };
634       
635        return 0;
636}
637
638static int sc_asn1_encode_object_id(u8 **buf, size_t *buflen,
639                             const struct sc_object_id *id)
640{
641        u8 temp[SC_MAX_OBJECT_ID_OCTETS*5], *p = temp;
642        size_t  count = 0;
643        int     i;
644        const int *value = (const int *) id->value;
645
646        for (i = 0; value[i] > 0 && i < SC_MAX_OBJECT_ID_OCTETS; i++) {
647                unsigned int k, shift;
648
649                k = value[i];
650                switch (i) {
651                case 0:
652                        if (k > 2)
653                                return SC_ERROR_INVALID_ARGUMENTS;
654                        *p = k * 40;
655                        break;
656                case 1:
657                        if (k > 39)
658                                return SC_ERROR_INVALID_ARGUMENTS;
659                        *p++ += k;
660                        break;
661                default:
662                        shift = 28;
663                        while (shift && (k >> shift) == 0)
664                                shift -= 7;
665                        while (shift) {
666                                *p++ = 0x80 | ((k >> shift) & 0x7f);
667                                shift -= 7;
668                        }
669                        *p++ = k & 0x7F;
670                        break;
671                }
672        }
673        if (i == 1)
674                /* an OID must have at least two components */
675                return SC_ERROR_INVALID_ARGUMENTS;
676        *buflen = count = p - temp;
677        *buf = (u8 *) malloc(count);
678        if (!*buf)
679                return SC_ERROR_OUT_OF_MEMORY;
680        memcpy(*buf, temp, count);
681        return 0;
682}
683
684static int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen,
685                              u8 *out, size_t *outlen)
686{
687        if (inlen+1 > *outlen)
688                return SC_ERROR_BUFFER_TOO_SMALL;
689        *outlen = inlen+1;
690        memcpy(out, inbuf, inlen);
691        out[inlen] = 0;
692        return 0;
693}
694
695int sc_asn1_put_tag(int tag, const u8 * data, size_t datalen, u8 * out, size_t outlen, u8 **ptr)
696{
697        u8 *p = out;
698
699        if (outlen < 2)
700                return SC_ERROR_INVALID_ARGUMENTS;
701        if (datalen > 127)
702                return SC_ERROR_INVALID_ARGUMENTS;
703        *p++ = tag & 0xFF;      /* FIXME: Support longer tags */
704        outlen--;
705        *p++ = datalen;
706        outlen--;
707        if (outlen < datalen)
708                return SC_ERROR_INVALID_ARGUMENTS;
709               
710        memcpy(p, data, datalen);
711        p += datalen;
712        if (ptr != NULL)
713                *ptr = p;
714        return 0;
715}
716
717static int asn1_write_element(sc_context_t *ctx, unsigned int tag,
718        const u8 * data, size_t datalen, u8 ** out, size_t * outlen)
719{
720        u8 t;
721        u8 *buf, *p;
722        int c = 0;
723       
724        t = tag & 0x1F;
725        if (t != (tag & SC_ASN1_TAG_MASK)) {
726                sc_error(ctx, "Long tags not supported\n");
727                return SC_ERROR_INVALID_ARGUMENTS;
728        }
729        switch (tag & SC_ASN1_CLASS_MASK) {
730        case SC_ASN1_UNI:
731                break;
732        case SC_ASN1_APP:
733                t |= SC_ASN1_TAG_APPLICATION;
734                break;
735        case SC_ASN1_CTX:
736                t |= SC_ASN1_TAG_CONTEXT;
737                break;
738        case SC_ASN1_PRV:
739                t |= SC_ASN1_TAG_PRIVATE;
740                break;
741        }
742        if (tag & SC_ASN1_CONS)
743                t |= SC_ASN1_TAG_CONSTRUCTED;
744        if (datalen > 127) {
745                c = 1;
746                while (datalen >> (c << 3))
747                        c++;
748        }
749        *outlen = 2 + c + datalen;
750        buf = (u8 *) malloc(*outlen);
751        if (buf == NULL)
752                SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY);
753        *out = p = buf;
754        *p++ = t;
755        if (c) {
756                *p++ = 0x80 | c;
757                while (c--)
758                        *p++ = (datalen >> (c << 3)) & 0xFF;
759        } else
760                *p++ = datalen & 0x7F;
761        memcpy(p, data, datalen);
762       
763        return 0;
764}
765
766static const struct sc_asn1_entry c_asn1_path[4] = {
767        { "path",   SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, 0, NULL, NULL },
768        { "index",  SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
769        { "length", SC_ASN1_INTEGER, SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, NULL, NULL },
770        { NULL, 0, 0, 0, NULL, NULL }
771};
772
773static int asn1_decode_path(sc_context_t *ctx, const u8 *in, size_t len,
774                            sc_path_t *path, int depth)
775{
776        int idx, count, r;
777        struct sc_asn1_entry asn1_path[4];
778       
779        sc_copy_asn1_entry(c_asn1_path, asn1_path);
780        sc_format_asn1_entry(asn1_path + 0, &path->value, &path->len, 0);
781        sc_format_asn1_entry(asn1_path + 1, &idx, NULL, 0);
782        sc_format_asn1_entry(asn1_path + 2, &count, NULL, 0);
783        path->len = SC_MAX_PATH_SIZE;
784        r = asn1_decode(ctx, asn1_path, in, len, NULL, NULL, 0, depth + 1);
785        if (r)
786                return r;
787        if (path->len == 2)
788                path->type = SC_PATH_TYPE_FILE_ID;
789        else
790                path->type = SC_PATH_TYPE_PATH;
791        if ((asn1_path[1].flags & SC_ASN1_PRESENT)
792         && (asn1_path[2].flags & SC_ASN1_PRESENT)) {
793                path->index = idx;
794                path->count = count;
795        } else {
796                path->index = 0;
797                path->count = -1;
798        }
799        return 0;
800}
801
802static int asn1_encode_path(sc_context_t *ctx, const sc_path_t *path,
803                            u8 **buf, size_t *bufsize, int depth)
804{
805        int r;
806        struct sc_asn1_entry asn1_path[4];
807        sc_path_t tpath = *path;
808
809        sc_copy_asn1_entry(c_asn1_path, asn1_path);
810        sc_format_asn1_entry(asn1_path + 0, (void *) &tpath.value, (void *) &tpath.len, 1);
811        if (path->count > 0) {
812                sc_format_asn1_entry(asn1_path + 1, (void *) &tpath.index, NULL, 1);
813                sc_format_asn1_entry(asn1_path + 2, (void *) &tpath.count, NULL, 1);
814        }
815        r = asn1_encode(ctx, asn1_path, buf, bufsize, depth + 1);
816        return r;       
817}
818
819static const struct sc_asn1_entry c_asn1_se_info[4] = {
820        { "se",     SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, 0, NULL, NULL },
821        { "owner",  SC_ASN1_OBJECT,  SC_ASN1_TAG_OBJECT,  SC_ASN1_OPTIONAL, NULL, NULL },
822        { "aid",    SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
823        { NULL, 0, 0, 0, NULL, NULL }
824};
825
826static int asn1_decode_se_info(sc_context_t *ctx, const u8 *obj, size_t objlen,
827                               sc_pkcs15_sec_env_info_t ***se, size_t *num, int depth)
828{
829        sc_pkcs15_sec_env_info_t **ses;
830
831        const unsigned char *p;
832        size_t plen, idx = 0, size = 8, left = size;
833        int    ret = SC_SUCCESS;
834
835        p = sc_asn1_find_tag(ctx, obj, objlen, 0x30, &plen);
836        if (p == NULL)
837                return SC_ERROR_INVALID_ASN1_OBJECT;
838
839        ses = calloc(size, sizeof(sc_pkcs15_sec_env_info_t *));
840        if (ses == NULL)
841                return SC_ERROR_OUT_OF_MEMORY;
842
843        while (plen != 0) {
844                struct sc_asn1_entry asn1_se_info[4];
845
846                sc_pkcs15_sec_env_info_t *si = calloc(1, sizeof(sc_pkcs15_sec_env_info_t));
847                if (si == NULL) {
848                        ret = SC_ERROR_OUT_OF_MEMORY;
849                        goto err;
850                }
851
852                si->aid_len = sizeof(si->aid);
853                sc_copy_asn1_entry(c_asn1_se_info, asn1_se_info);
854                sc_format_asn1_entry(asn1_se_info + 0, &si->se, NULL, 0);
855                sc_format_asn1_entry(asn1_se_info + 1, &si->owner, NULL, 0);
856                sc_format_asn1_entry(asn1_se_info + 2, &si->aid, &si->aid_len, 0);
857                ret = asn1_decode(ctx, asn1_se_info, p, plen, &p, &plen, 0, depth+1);
858                if (ret != SC_SUCCESS) {
859                        free(si);
860                        ret = SC_ERROR_INVALID_ASN1_OBJECT;
861                        goto err;
862                }
863                if (--left == 0) {
864                        sc_pkcs15_sec_env_info_t **np;
865                        size <<= 1;
866                        np = realloc(ses, sizeof(sc_pkcs15_sec_env_info_t *) * size);
867                        if (np == NULL) {
868                                free(si);
869                                ret = SC_ERROR_OUT_OF_MEMORY;
870                                goto err;
871                        }
872                        ses  = np;
873                        left = size >> 1;
874                }
875                ses[idx++] = si;
876        }
877err:
878        if (ret == SC_SUCCESS) {
879                *se  = ses;
880                *num = idx;
881        } else {
882                size_t i;
883                for (i = 0; i < idx; i++)
884                        free(ses[i]);
885                free(ses);
886        }
887
888        return ret;     
889}
890
891static const struct sc_asn1_entry c_asn1_com_obj_attr[6] = {
892        { "label", SC_ASN1_UTF8STRING, SC_ASN1_TAG_UTF8STRING, SC_ASN1_OPTIONAL, NULL, NULL },
893        { "flags", SC_ASN1_BIT_FIELD, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
894        { "authId", SC_ASN1_PKCS15_ID, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL, NULL, NULL },
895        { "userConsent", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
896        { "accessControlRules", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
897        { NULL, 0, 0, 0, NULL, NULL }
898};
899
900static const struct sc_asn1_entry c_asn1_p15_obj[5] = {
901        { "commonObjectAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
902        { "classAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
903        { "subClassAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
904        { "typeAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL, NULL },
905        { NULL, 0, 0, 0, NULL, NULL }
906};
907
908static int asn1_decode_p15_object(sc_context_t *ctx, const u8 *in,
909                                  size_t len, struct sc_asn1_pkcs15_object *obj,
910                                  int depth)
911{
912        int r;
913        struct sc_pkcs15_object *p15_obj = obj->p15_obj;
914        struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5];
915        size_t flags_len = sizeof(p15_obj->flags);
916        size_t label_len = sizeof(p15_obj->label);
917
918        sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr);
919        sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj);
920        sc_format_asn1_entry(asn1_c_attr + 0, p15_obj->label, &label_len, 0);
921        sc_format_asn1_entry(asn1_c_attr + 1, &p15_obj->flags, &flags_len, 0);
922        sc_format_asn1_entry(asn1_c_attr + 2, &p15_obj->auth_id, NULL, 0);
923        sc_format_asn1_entry(asn1_c_attr + 3, &p15_obj->user_consent, NULL, 0);
924        /* FIXME: encode accessControlRules */
925        sc_format_asn1_entry(asn1_c_attr + 4, NULL, NULL, 0);
926        sc_format_asn1_entry(asn1_p15_obj + 0, asn1_c_attr, NULL, 0);
927        sc_format_asn1_entry(asn1_p15_obj + 1, obj->asn1_class_attr, NULL, 0);
928        sc_format_asn1_entry(asn1_p15_obj + 2, obj->asn1_subclass_attr, NULL, 0);
929        sc_format_asn1_entry(asn1_p15_obj + 3, obj->asn1_type_attr, NULL, 0);
930
931        r = asn1_decode(ctx, asn1_p15_obj, in, len, NULL, NULL, 0, depth + 1);
932        return r;
933}
934
935static int asn1_encode_p15_object(sc_context_t *ctx, const struct sc_asn1_pkcs15_object *obj,
936                                  u8 **buf, size_t *bufsize, int depth)
937{
938        int r;
939        struct sc_pkcs15_object p15_obj = *obj->p15_obj;
940        struct sc_asn1_entry    asn1_c_attr[6], asn1_p15_obj[5];
941        size_t label_len = strlen(p15_obj.label);
942        size_t flags_len;
943
944        sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr);
945        sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj);
946        if (label_len != 0)
947                sc_format_asn1_entry(asn1_c_attr + 0, (void *) p15_obj.label, &label_len, 1);
948        if (p15_obj.flags) {
949                flags_len = sizeof(p15_obj.flags);
950                sc_format_asn1