Annotation of embedaddon/strongswan/src/libstrongswan/asn1/asn1.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006 Martin Will
        !             3:  * Copyright (C) 2000-2016 Andreas Steffen
        !             4:  *
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: #include <stdio.h>
        !            19: #include <string.h>
        !            20: #include <time.h>
        !            21: 
        !            22: #include <utils/debug.h>
        !            23: 
        !            24: #include "oid.h"
        !            25: #include "asn1.h"
        !            26: #include "asn1_parser.h"
        !            27: 
        !            28: /**
        !            29:  * Commonly used ASN1 values.
        !            30:  */
        !            31: const chunk_t ASN1_INTEGER_0 = chunk_from_chars(0x02, 0x01, 0x00);
        !            32: const chunk_t ASN1_INTEGER_1 = chunk_from_chars(0x02, 0x01, 0x01);
        !            33: const chunk_t ASN1_INTEGER_2 = chunk_from_chars(0x02, 0x01, 0x02);
        !            34: 
        !            35: /*
        !            36:  * Described in header
        !            37:  */
        !            38: chunk_t asn1_algorithmIdentifier_params(int oid, chunk_t params)
        !            39: {
        !            40:        return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(oid), params);
        !            41: }
        !            42: 
        !            43: /*
        !            44:  * Described in header
        !            45:  */
        !            46: chunk_t asn1_algorithmIdentifier(int oid)
        !            47: {
        !            48:        chunk_t parameters;
        !            49: 
        !            50:        /* some algorithmIdentifiers have a NULL parameters field and some do not */
        !            51:        switch (oid)
        !            52:        {
        !            53:                case OID_ECDSA_WITH_SHA1:
        !            54:                case OID_ECDSA_WITH_SHA224:
        !            55:                case OID_ECDSA_WITH_SHA256:
        !            56:                case OID_ECDSA_WITH_SHA384:
        !            57:                case OID_ECDSA_WITH_SHA512:
        !            58:                case OID_ED25519:
        !            59:                case OID_ED448:
        !            60:                        parameters = chunk_empty;
        !            61:                        break;
        !            62:                default:
        !            63:                        parameters = asn1_simple_object(ASN1_NULL, chunk_empty);
        !            64:                        break;
        !            65:        }
        !            66:        return asn1_algorithmIdentifier_params(oid, parameters);
        !            67: }
        !            68: 
        !            69: /*
        !            70:  * Defined in header.
        !            71:  */
        !            72: int asn1_known_oid(chunk_t object)
        !            73: {
        !            74:        int oid = 0;
        !            75: 
        !            76:        while (object.len)
        !            77:        {
        !            78:                if (oid_names[oid].octet == *object.ptr)
        !            79:                {
        !            80:                        if (--object.len == 0 || oid_names[oid].down == 0)
        !            81:                        {
        !            82:                                return oid;               /* found terminal symbol */
        !            83:                        }
        !            84:                        else
        !            85:                        {
        !            86:                                object.ptr++; oid++; /* advance to next hex octet */
        !            87:                        }
        !            88:                }
        !            89:                else
        !            90:                {
        !            91:                        if (oid_names[oid].next)
        !            92:                        {
        !            93:                                oid = oid_names[oid].next;
        !            94:                        }
        !            95:                        else
        !            96:                        {
        !            97:                                return OID_UNKNOWN;
        !            98:                        }
        !            99:                }
        !           100:        }
        !           101:        return OID_UNKNOWN;
        !           102: }
        !           103: 
        !           104: /*
        !           105:  * Defined in header.
        !           106:  */
        !           107: chunk_t asn1_build_known_oid(int n)
        !           108: {
        !           109:        chunk_t oid;
        !           110:        int i;
        !           111: 
        !           112:        if (n < 0 || n >= OID_MAX)
        !           113:        {
        !           114:                return chunk_empty;
        !           115:        }
        !           116: 
        !           117:        i = oid_names[n].level + 1;
        !           118:        oid = chunk_alloc(2 + i);
        !           119:        oid.ptr[0] = ASN1_OID;
        !           120:        oid.ptr[1] = i;
        !           121: 
        !           122:        do
        !           123:        {
        !           124:                if (oid_names[n].level >= i)
        !           125:                {
        !           126:                        n--;
        !           127:                        continue;
        !           128:                }
        !           129:                oid.ptr[--i + 2] = oid_names[n--].octet;
        !           130:        }
        !           131:        while (i > 0);
        !           132: 
        !           133:        return oid;
        !           134: }
        !           135: 
        !           136: /**
        !           137:  * Returns the number of bytes required to encode the given OID node
        !           138:  */
        !           139: static int bytes_required(u_int val)
        !           140: {
        !           141:        int shift, required = 1;
        !           142: 
        !           143:        /* sufficient to handle 32 bit node numbers */
        !           144:        for (shift = 28; shift; shift -= 7)
        !           145:        {
        !           146:                if (val >> shift)
        !           147:                {       /* do not encode leading zeroes */
        !           148:                        required++;
        !           149:                }
        !           150:        }
        !           151:        return required;
        !           152: }
        !           153: 
        !           154: /*
        !           155:  * Defined in header.
        !           156:  */
        !           157: chunk_t asn1_oid_from_string(char *str)
        !           158: {
        !           159:        enumerator_t *enumerator;
        !           160:        size_t buf_len = 64;
        !           161:        u_char buf[buf_len];
        !           162:        char *end;
        !           163:        int i = 0, pos = 0, req, shift;
        !           164:        u_int val, first = 0;
        !           165: 
        !           166:        enumerator = enumerator_create_token(str, ".", "");
        !           167:        while (enumerator->enumerate(enumerator, &str))
        !           168:        {
        !           169:                val = strtoul(str, &end, 10);
        !           170:                req = bytes_required(val);
        !           171:                if (end == str || pos + req > buf_len)
        !           172:                {
        !           173:                        pos = 0;
        !           174:                        break;
        !           175:                }
        !           176:                switch (i++)
        !           177:                {
        !           178:                        case 0:
        !           179:                                first = val;
        !           180:                                break;
        !           181:                        case 1:
        !           182:                                buf[pos++] = first * 40 + val;
        !           183:                                break;
        !           184:                        default:
        !           185:                                for (shift = (req - 1) * 7; shift; shift -= 7)
        !           186:                                {
        !           187:                                        buf[pos++] = 0x80 | ((val >> shift) & 0x7F);
        !           188:                                }
        !           189:                                buf[pos++] = val & 0x7F;
        !           190:                }
        !           191:        }
        !           192:        enumerator->destroy(enumerator);
        !           193: 
        !           194:        return chunk_clone(chunk_create(buf, pos));
        !           195: }
        !           196: 
        !           197: /*
        !           198:  * Defined in header.
        !           199:  */
        !           200: char *asn1_oid_to_string(chunk_t oid)
        !           201: {
        !           202:        size_t len = 64;
        !           203:        char buf[len], *pos = buf;
        !           204:        int written;
        !           205:        u_int val;
        !           206: 
        !           207:        if (!oid.len)
        !           208:        {
        !           209:                return NULL;
        !           210:        }
        !           211:        val = oid.ptr[0] / 40;
        !           212:        written = snprintf(buf, len, "%u.%u", val, oid.ptr[0] - val * 40);
        !           213:        oid = chunk_skip(oid, 1);
        !           214:        if (written < 0 || written >= len)
        !           215:        {
        !           216:                return NULL;
        !           217:        }
        !           218:        pos += written;
        !           219:        len -= written;
        !           220:        val = 0;
        !           221: 
        !           222:        while (oid.len)
        !           223:        {
        !           224:                val = (val << 7) + (u_int)(oid.ptr[0] & 0x7f);
        !           225: 
        !           226:                if (oid.ptr[0] < 128)
        !           227:                {
        !           228:                        written = snprintf(pos, len, ".%u", val);
        !           229:                        if (written < 0 || written >= len)
        !           230:                        {
        !           231:                                return NULL;
        !           232:                        }
        !           233:                        pos += written;
        !           234:                        len -= written;
        !           235:                        val = 0;
        !           236:                }
        !           237:                oid = chunk_skip(oid, 1);
        !           238:        }
        !           239:        return (val == 0) ? strdup(buf) : NULL;
        !           240: }
        !           241: 
        !           242: /*
        !           243:  * Defined in header.
        !           244:  */
        !           245: size_t asn1_length(chunk_t *blob)
        !           246: {
        !           247:        u_char n;
        !           248:        size_t len;
        !           249: 
        !           250:        if (blob->len < 2)
        !           251:        {
        !           252:                DBG2(DBG_ASN, "insufficient number of octets to parse ASN.1 length");
        !           253:                return ASN1_INVALID_LENGTH;
        !           254:        }
        !           255: 
        !           256:        /* read length field, skip tag and length */
        !           257:        n = blob->ptr[1];
        !           258:        blob->ptr += 2;
        !           259:        blob->len -= 2;
        !           260: 
        !           261:        if ((n & 0x80) == 0)
        !           262:        {       /* single length octet */
        !           263:                if (n > blob->len)
        !           264:                {
        !           265:                        DBG2(DBG_ASN, "length is larger than remaining blob size");
        !           266:                        return ASN1_INVALID_LENGTH;
        !           267:                }
        !           268:                return n;
        !           269:        }
        !           270: 
        !           271:        /* composite length, determine number of length octets */
        !           272:        n &= 0x7f;
        !           273: 
        !           274:        if (n == 0 || n > blob->len)
        !           275:        {
        !           276:                DBG2(DBG_ASN, "number of length octets invalid");
        !           277:                return ASN1_INVALID_LENGTH;
        !           278:        }
        !           279: 
        !           280:        if (n > sizeof(len))
        !           281:        {
        !           282:                DBG2(DBG_ASN, "number of length octets is larger than limit of"
        !           283:                         " %d octets", (int)sizeof(len));
        !           284:                return ASN1_INVALID_LENGTH;
        !           285:        }
        !           286: 
        !           287:        len = 0;
        !           288: 
        !           289:        while (n-- > 0)
        !           290:        {
        !           291:                len = 256*len + *blob->ptr++;
        !           292:                blob->len--;
        !           293:        }
        !           294:        if (len > blob->len)
        !           295:        {
        !           296:                DBG2(DBG_ASN, "length is larger than remaining blob size");
        !           297:                return ASN1_INVALID_LENGTH;
        !           298:        }
        !           299:        return len;
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * See header.
        !           304:  */
        !           305: int asn1_unwrap(chunk_t *blob, chunk_t *inner)
        !           306: {
        !           307:        chunk_t res;
        !           308:        u_char len;
        !           309:        int type;
        !           310: 
        !           311:        if (blob->len < 2)
        !           312:        {
        !           313:                return ASN1_INVALID;
        !           314:        }
        !           315:        type = blob->ptr[0];
        !           316:        len = blob->ptr[1];
        !           317:        *blob = chunk_skip(*blob, 2);
        !           318: 
        !           319:        if ((len & 0x80) == 0)
        !           320:        {       /* single length octet */
        !           321:                res.len = len;
        !           322:        }
        !           323:        else
        !           324:        {       /* composite length, determine number of length octets */
        !           325:                len &= 0x7f;
        !           326:                if (len == 0 || len > blob->len || len > sizeof(res.len))
        !           327:                {
        !           328:                        return ASN1_INVALID;
        !           329:                }
        !           330:                res.len = 0;
        !           331:                while (len-- > 0)
        !           332:                {
        !           333:                        res.len = 256 * res.len + blob->ptr[0];
        !           334:                        *blob = chunk_skip(*blob, 1);
        !           335:                }
        !           336:        }
        !           337:        if (res.len > blob->len)
        !           338:        {
        !           339:                return ASN1_INVALID;
        !           340:        }
        !           341:        res.ptr = blob->ptr;
        !           342:        *blob = chunk_skip(*blob, res.len);
        !           343:        /* updating inner not before we are finished allows a caller to pass
        !           344:         * blob = inner */
        !           345:        *inner = res;
        !           346:        return type;
        !           347: }
        !           348: 
        !           349: static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
        !           350: static const int tm_leap_1970 = 477;
        !           351: 
        !           352: /**
        !           353:  * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calendar time
        !           354:  */
        !           355: time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
        !           356: {
        !           357:        int tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec;
        !           358:        int tm_leap_4, tm_leap_100, tm_leap_400, tm_leap;
        !           359:        int tz_hour, tz_min, tz_offset;
        !           360:        time_t tm_days, tm_secs;
        !           361:        char buf[BUF_LEN], *eot = NULL;
        !           362: 
        !           363:        snprintf(buf, sizeof(buf), "%.*s", (int)utctime->len, utctime->ptr);
        !           364: 
        !           365:        if ((eot = strchr(buf, 'Z')) != NULL)
        !           366:        {
        !           367:                tz_offset = 0; /* Zulu time with a zero time zone offset */
        !           368:        }
        !           369:        else if ((eot = strchr(buf, '+')) != NULL)
        !           370:        {
        !           371:                if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
        !           372:                {
        !           373:                        return 0; /* error in positive timezone offset format */
        !           374:                }
        !           375:                tz_offset = 3600*tz_hour + 60*tz_min;  /* positive time zone offset */
        !           376:        }
        !           377:        else if ((eot = strchr(buf, '-')) != NULL)
        !           378:        {
        !           379:                if (sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min) != 2)
        !           380:                {
        !           381:                        return 0; /* error in negative timezone offset format */
        !           382:                }
        !           383:                tz_offset = -3600*tz_hour - 60*tz_min;  /* negative time zone offset */
        !           384:        }
        !           385:        else
        !           386:        {
        !           387:                return 0; /* error in time format */
        !           388:        }
        !           389: 
        !           390:        /* parse ASN.1 time string */
        !           391:        {
        !           392:                const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
        !           393:                                                                                                         "%4d%2d%2d%2d%2d";
        !           394: 
        !           395:                if (sscanf(buf, format, &tm_year, &tm_mon, &tm_day,
        !           396:                                                                &tm_hour, &tm_min) != 5)
        !           397:                {
        !           398:                        return 0; /* error in [yy]yymmddhhmm time format */
        !           399:                }
        !           400:        }
        !           401: 
        !           402:        /* is there a seconds field? */
        !           403:        if ((eot - buf) == ((type == ASN1_UTCTIME)?12:14))
        !           404:        {
        !           405:                if (sscanf(eot-2, "%2d", &tm_sec) != 1)
        !           406:                {
        !           407:                        return 0; /* error in ss seconds field format */
        !           408:                }
        !           409:        }
        !           410:        else
        !           411:        {
        !           412:                tm_sec = 0;
        !           413:        }
        !           414: 
        !           415:        /* representation of two-digit years */
        !           416:        if (type == ASN1_UTCTIME)
        !           417:        {
        !           418:                tm_year += (tm_year < 50) ? 2000 : 1900;
        !           419:        }
        !           420: 
        !           421:        /* prevent obvious 32 bit integer overflows */
        !           422:        if (sizeof(time_t) == 4 && (tm_year > 2038 || tm_year < 1901))
        !           423:        {
        !           424:                return TIME_32_BIT_SIGNED_MAX;
        !           425:        }
        !           426: 
        !           427:        /* representation of months as 0..11*/
        !           428:        if (tm_mon < 1 || tm_mon > 12)
        !           429:        {
        !           430:                return 0;
        !           431:        }
        !           432:        tm_mon--;
        !           433: 
        !           434:        /* representation of days as 0..30 */
        !           435:        if (tm_day < 1 || tm_day > 31)
        !           436:        {       /* we don't actually validate the day in relation to tm_year/tm_mon */
        !           437:                return 0;
        !           438:        }
        !           439:        tm_day--;
        !           440: 
        !           441:        if (tm_hour < 0 || tm_hour > 23 ||
        !           442:                tm_min < 0 || tm_min > 59 ||
        !           443:                tm_sec < 0 || tm_sec > 60 /* allow leap seconds */)
        !           444:        {
        !           445:                return 0;
        !           446:        }
        !           447: 
        !           448:        /* number of leap years between last year and 1970? */
        !           449:        tm_leap_4 = (tm_year - 1) / 4;
        !           450:        tm_leap_100 = tm_leap_4 / 25;
        !           451:        tm_leap_400 = tm_leap_100 / 4;
        !           452:        tm_leap = tm_leap_4 - tm_leap_100 + tm_leap_400 - tm_leap_1970;
        !           453: 
        !           454:        /* if date later then February, is the current year a leap year? */
        !           455:        if (tm_mon > 1 && (tm_year % 4 == 0) &&
        !           456:                (tm_year % 100 != 0 || tm_year % 400 == 0))
        !           457:        {
        !           458:                tm_leap++;
        !           459:        }
        !           460:        tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap;
        !           461:        tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec - tz_offset;
        !           462: 
        !           463:        if (sizeof(time_t) == 4)
        !           464:        {       /* has a 32 bit signed integer overflow occurred? */
        !           465:                if (tm_year > 1970 && tm_secs < 0)
        !           466:                {       /* depending on the time zone, the first days in 1970 may result in
        !           467:                         * a negative value, but dates after 1970 never will */
        !           468:                        return TIME_32_BIT_SIGNED_MAX;
        !           469:                }
        !           470:                if (tm_year < 1969 && tm_secs > 0)
        !           471:                {       /* similarly, tm_secs is not positive for dates before 1970, except
        !           472:                         * for the last days in 1969, depending on the time zone */
        !           473:                        return TIME_32_BIT_SIGNED_MAX;
        !           474:                }
        !           475:        }
        !           476:        return tm_secs;
        !           477: }
        !           478: 
        !           479: /**
        !           480:  *  Convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
        !           481:  */
        !           482: chunk_t asn1_from_time(const time_t *time, asn1_t type)
        !           483: {
        !           484:        int offset;
        !           485:        const char *format;
        !           486:        char buf[BUF_LEN];
        !           487:        chunk_t formatted_time;
        !           488:        struct tm t = {};
        !           489: 
        !           490:        gmtime_r(time, &t);
        !           491:        /* RFC 5280 says that dates through the year 2049 MUST be encoded as UTCTIME
        !           492:         * and dates in 2050 or later MUST be encoded as GENERALIZEDTIME. We only
        !           493:         * enforce the latter to avoid overflows but allow callers to force the
        !           494:         * encoding to GENERALIZEDTIME */
        !           495:        type = (t.tm_year >= 150) ? ASN1_GENERALIZEDTIME : type;
        !           496:        if (type == ASN1_GENERALIZEDTIME)
        !           497:        {
        !           498:                format = "%04d%02d%02d%02d%02d%02dZ";
        !           499:                offset = 1900;
        !           500:        }
        !           501:        else /* ASN1_UTCTIME */
        !           502:        {
        !           503:                format = "%02d%02d%02d%02d%02d%02dZ";
        !           504:                offset = (t.tm_year < 100) ? 0 : -100;
        !           505:        }
        !           506:        snprintf(buf, BUF_LEN, format, t.tm_year + offset,
        !           507:                         t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
        !           508:        formatted_time.ptr = buf;
        !           509:        formatted_time.len = strlen(buf);
        !           510:        return asn1_simple_object(type, formatted_time);
        !           511: }
        !           512: 
        !           513: /*
        !           514:  * Defined in header.
        !           515:  */
        !           516: void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
        !           517: {
        !           518:        int oid;
        !           519: 
        !           520:        switch (type)
        !           521:        {
        !           522:                case ASN1_OID:
        !           523:                        oid = asn1_known_oid(object);
        !           524:                        if (oid == OID_UNKNOWN)
        !           525:                        {
        !           526:                                char *oid_str = asn1_oid_to_string(object);
        !           527: 
        !           528:                                if (!oid_str)
        !           529:                                {
        !           530:                                        break;
        !           531:                                }
        !           532:                                DBG2(DBG_ASN, "  %s", oid_str);
        !           533:                                free(oid_str);
        !           534:                        }
        !           535:                        else
        !           536:                        {
        !           537:                                DBG2(DBG_ASN, "  '%s'", oid_names[oid].name);
        !           538:                        }
        !           539:                        return;
        !           540:                case ASN1_UTF8STRING:
        !           541:                case ASN1_IA5STRING:
        !           542:                case ASN1_PRINTABLESTRING:
        !           543:                case ASN1_T61STRING:
        !           544:                case ASN1_VISIBLESTRING:
        !           545:                        DBG2(DBG_ASN, "  '%.*s'", (int)object.len, object.ptr);
        !           546:                        return;
        !           547:                case ASN1_UTCTIME:
        !           548:                case ASN1_GENERALIZEDTIME:
        !           549:                        {
        !           550:                                time_t time = asn1_to_time(&object, type);
        !           551: 
        !           552:                                DBG2(DBG_ASN, "  '%T'", &time, TRUE);
        !           553:                        }
        !           554:                        return;
        !           555:                default:
        !           556:                        break;
        !           557:        }
        !           558:        if (private)
        !           559:        {
        !           560:                DBG4(DBG_ASN, "%B", &object);
        !           561:        }
        !           562:        else
        !           563:        {
        !           564:                DBG3(DBG_ASN, "%B", &object);
        !           565:        }
        !           566: }
        !           567: 
        !           568: /**
        !           569:  * parse an ASN.1 simple type
        !           570:  */
        !           571: bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
        !           572: {
        !           573:        size_t len;
        !           574: 
        !           575:        /* an ASN.1 object must possess at least a tag and length field */
        !           576:        if (object->len < 2)
        !           577:        {
        !           578:                DBG2(DBG_ASN, "L%d - %s:  ASN.1 object smaller than 2 octets", level,
        !           579:                         name);
        !           580:                return FALSE;
        !           581:        }
        !           582: 
        !           583:        if (*object->ptr != type)
        !           584:        {
        !           585:                DBG2(DBG_ASN, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
        !           586:                         level, name, type, *object->ptr);
        !           587:                return FALSE;
        !           588:        }
        !           589: 
        !           590:        len = asn1_length(object);
        !           591: 
        !           592:        if (len == ASN1_INVALID_LENGTH)
        !           593:        {
        !           594:                DBG2(DBG_ASN, "L%d - %s:  length of ASN.1 object invalid or too large",
        !           595:                         level, name);
        !           596:                return FALSE;
        !           597:        }
        !           598: 
        !           599:        DBG2(DBG_ASN, "L%d - %s:", level, name);
        !           600:        asn1_debug_simple_object(*object, type, FALSE);
        !           601:        return TRUE;
        !           602: }
        !           603: 
        !           604: /*
        !           605:  * Described in header
        !           606:  */
        !           607: uint64_t asn1_parse_integer_uint64(chunk_t blob)
        !           608: {
        !           609:        uint64_t val = 0;
        !           610:        int i;
        !           611: 
        !           612:        for (i = 0; i < blob.len; i++)
        !           613:        {       /* if it is longer than 8 bytes, we just use the 8 LSBs */
        !           614:                val <<= 8;
        !           615:                val |= (uint64_t)blob.ptr[i];
        !           616:        }
        !           617:        return val;
        !           618: }
        !           619: 
        !           620: /*
        !           621:  * Described in header
        !           622:  */
        !           623: chunk_t asn1_integer_from_uint64(uint64_t val)
        !           624: {
        !           625:        u_char buf[sizeof(val)];
        !           626:        chunk_t enc = chunk_empty;
        !           627: 
        !           628:        if (val < 0x100)
        !           629:        {
        !           630:                buf[0] = (u_char)val;
        !           631:                return chunk_clone(chunk_create(buf, 1));
        !           632:        }
        !           633:        for (enc.ptr = buf + sizeof(val); val; enc.len++, val >>= 8)
        !           634:        {       /* fill the buffer from the end */
        !           635:                *(--enc.ptr) = val & 0xff;
        !           636:        }
        !           637:        return chunk_clone(enc);
        !           638: }
        !           639: 
        !           640: /**
        !           641:  * ASN.1 definition of an algorithmIdentifier
        !           642:  */
        !           643: static const asn1Object_t algorithmIdentifierObjects[] = {
        !           644:        { 0, "algorithmIdentifier",     ASN1_SEQUENCE,          ASN1_NONE                       }, /* 0 */
        !           645:        { 1,   "algorithm",                     ASN1_OID,                       ASN1_BODY                       }, /* 1 */
        !           646:        { 1,   "parameters",            ASN1_OID,                       ASN1_RAW|ASN1_OPT       }, /* 2 */
        !           647:        { 1,   "end opt",                       ASN1_EOC,                       ASN1_END                        }, /* 3 */
        !           648:        { 1,   "parameters",            ASN1_SEQUENCE,          ASN1_RAW|ASN1_OPT       }, /* 4 */
        !           649:        { 1,   "end opt",                       ASN1_EOC,                       ASN1_END                        }, /* 5 */
        !           650:        { 1,   "parameters",            ASN1_OCTET_STRING,      ASN1_RAW|ASN1_OPT       }, /* 6 */
        !           651:        { 1,   "end opt",                       ASN1_EOC,                       ASN1_END                        }, /* 7 */
        !           652:        { 0, "exit",                            ASN1_EOC,                       ASN1_EXIT                       }
        !           653: };
        !           654: #define ALGORITHM_ID_ALG                               1
        !           655: #define ALGORITHM_ID_PARAMETERS_OID            2
        !           656: #define ALGORITHM_ID_PARAMETERS_SEQ            4
        !           657: #define ALGORITHM_ID_PARAMETERS_OCT            6
        !           658: 
        !           659: /*
        !           660:  * Defined in header
        !           661:  */
        !           662: int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
        !           663: {
        !           664:        asn1_parser_t *parser;
        !           665:        chunk_t object;
        !           666:        int objectID;
        !           667:        int alg = OID_UNKNOWN;
        !           668: 
        !           669:        parser = asn1_parser_create(algorithmIdentifierObjects, blob);
        !           670:        parser->set_top_level(parser, level0);
        !           671: 
        !           672:        while (parser->iterate(parser, &objectID, &object))
        !           673:        {
        !           674:                switch (objectID)
        !           675:                {
        !           676:                        case ALGORITHM_ID_ALG:
        !           677:                                alg = asn1_known_oid(object);
        !           678:                                break;
        !           679:                        case ALGORITHM_ID_PARAMETERS_OID:
        !           680:                        case ALGORITHM_ID_PARAMETERS_SEQ:
        !           681:                        case ALGORITHM_ID_PARAMETERS_OCT:
        !           682:                                if (parameters != NULL)
        !           683:                                {
        !           684:                                        *parameters = object;
        !           685:                                }
        !           686:                                break;
        !           687:                        default:
        !           688:                                break;
        !           689:                }
        !           690:        }
        !           691:        parser->destroy(parser);
        !           692:        return alg;
        !           693: }
        !           694: 
        !           695: /*
        !           696:  *  tests if a blob contains a valid ASN.1 set or sequence
        !           697:  */
        !           698: bool is_asn1(chunk_t blob)
        !           699: {
        !           700:        u_int len;
        !           701:        u_char tag;
        !           702: 
        !           703:        if (!blob.len || !blob.ptr)
        !           704:        {
        !           705:                return FALSE;
        !           706:        }
        !           707: 
        !           708:        tag = *blob.ptr;
        !           709:        if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING)
        !           710:        {
        !           711:                DBG2(DBG_ASN, "  file content is not binary ASN.1");
        !           712:                return FALSE;
        !           713:        }
        !           714: 
        !           715:        len = asn1_length(&blob);
        !           716: 
        !           717:        if (len == ASN1_INVALID_LENGTH)
        !           718:        {
        !           719:                return FALSE;
        !           720:        }
        !           721: 
        !           722:        /* exact match */
        !           723:        if (len == blob.len)
        !           724:        {
        !           725:                return TRUE;
        !           726:        }
        !           727: 
        !           728:        /* some websites append a surplus newline character to the blob */
        !           729:        if (len + 1 == blob.len && *(blob.ptr + len) == '\n')
        !           730:        {
        !           731:                return TRUE;
        !           732:        }
        !           733: 
        !           734:        DBG2(DBG_ASN, "  file size does not match ASN.1 coded length");
        !           735:        return FALSE;
        !           736: }
        !           737: 
        !           738: /*
        !           739:  * Defined in header.
        !           740:  */
        !           741: bool asn1_is_printablestring(chunk_t str)
        !           742: {
        !           743:        const char printablestring_charset[] =
        !           744:                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
        !           745:        u_int i;
        !           746: 
        !           747:        for (i = 0; i < str.len; i++)
        !           748:        {
        !           749:                if (strchr(printablestring_charset, str.ptr[i]) == NULL)
        !           750:                {
        !           751:                        return FALSE;
        !           752:                }
        !           753:        }
        !           754:        return TRUE;
        !           755: }
        !           756: 
        !           757: /**
        !           758:  * codes ASN.1 lengths up to a size of 16'777'215 bytes
        !           759:  */
        !           760: static void asn1_code_length(size_t length, chunk_t *code)
        !           761: {
        !           762:        if (length < 128)
        !           763:        {
        !           764:                code->ptr[0] = length;
        !           765:                code->len = 1;
        !           766:        }
        !           767:        else if (length < 256)
        !           768:        {
        !           769:                code->ptr[0] = 0x81;
        !           770:                code->ptr[1] = (u_char) length;
        !           771:                code->len = 2;
        !           772:        }
        !           773:        else if (length < 65536)
        !           774:        {
        !           775:                code->ptr[0] = 0x82;
        !           776:                code->ptr[1] = length >> 8;
        !           777:                code->ptr[2] = length & 0x00ff;
        !           778:                code->len = 3;
        !           779:        }
        !           780:        else
        !           781:        {
        !           782:                code->ptr[0] = 0x83;
        !           783:                code->ptr[1] = length >> 16;
        !           784:                code->ptr[2] = (length >> 8) & 0x00ff;
        !           785:                code->ptr[3] = length & 0x0000ff;
        !           786:                code->len = 4;
        !           787:        }
        !           788: }
        !           789: 
        !           790: /**
        !           791:  * build an empty asn.1 object with tag and length fields already filled in
        !           792:  */
        !           793: u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen)
        !           794: {
        !           795:        u_char length_buf[4];
        !           796:        chunk_t length = { length_buf, 0 };
        !           797:        u_char *pos;
        !           798: 
        !           799:        /* code the asn.1 length field */
        !           800:        asn1_code_length(datalen, &length);
        !           801: 
        !           802:        /* allocate memory for the asn.1 TLV object */
        !           803:        object->len = 1 + length.len + datalen;
        !           804:        object->ptr = malloc(object->len);
        !           805: 
        !           806:        /* set position pointer at the start of the object */
        !           807:        pos = object->ptr;
        !           808: 
        !           809:        /* copy the asn.1 tag field and advance the pointer */
        !           810:        *pos++ = type;
        !           811: 
        !           812:        /* copy the asn.1 length field and advance the pointer */
        !           813:        memcpy(pos, length.ptr, length.len);
        !           814:        pos += length.len;
        !           815: 
        !           816:        return pos;
        !           817: }
        !           818: 
        !           819: /**
        !           820:  * Build a simple ASN.1 object
        !           821:  */
        !           822: chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
        !           823: {
        !           824:        chunk_t object;
        !           825: 
        !           826:        u_char *pos = asn1_build_object(&object, tag, content.len);
        !           827:        memcpy(pos, content.ptr, content.len);
        !           828: 
        !           829:        return object;
        !           830: }
        !           831: 
        !           832: /**
        !           833:  * Build an ASN.1 BIT_STRING object
        !           834:  */
        !           835: chunk_t asn1_bitstring(const char *mode, chunk_t content)
        !           836: {
        !           837:        chunk_t object;
        !           838:        u_char *pos = asn1_build_object(&object, ASN1_BIT_STRING, 1 + content.len);
        !           839: 
        !           840:        *pos++ = 0x00;
        !           841:        memcpy(pos, content.ptr, content.len);
        !           842:        if (*mode == 'm')
        !           843:        {
        !           844:                free(content.ptr);
        !           845:        }
        !           846:        return object;
        !           847: }
        !           848: 
        !           849: /**
        !           850:  * Build an ASN.1 INTEGER object
        !           851:  */
        !           852: chunk_t asn1_integer(const char *mode, chunk_t content)
        !           853: {
        !           854:        chunk_t zero = chunk_from_chars(0x00), object;
        !           855:        size_t len;
        !           856:        u_char *pos;
        !           857:        bool move;
        !           858: 
        !           859:        if (content.len == 0)
        !           860:        {       /* make sure 0 is encoded properly */
        !           861:                content = zero;
        !           862:                move = FALSE;
        !           863:        }
        !           864:        else
        !           865:        {
        !           866:                move = (*mode == 'm');
        !           867:        }
        !           868: 
        !           869:        /* ASN.1 integers must be positive numbers in two's complement */
        !           870:        len = content.len + ((*content.ptr & 0x80) ? 1 : 0);
        !           871:        pos = asn1_build_object(&object, ASN1_INTEGER, len);
        !           872:        if (len > content.len)
        !           873:        {
        !           874:                *pos++ = 0x00;
        !           875:        }
        !           876:        memcpy(pos, content.ptr, content.len);
        !           877: 
        !           878:        if (move)
        !           879:        {
        !           880:                free(content.ptr);
        !           881:        }
        !           882:        return object;
        !           883: }
        !           884: 
        !           885: /**
        !           886:  * Build an ASN.1 object from a variable number of individual chunks.
        !           887:  * Depending on the mode, chunks either are moved ('m') or copied ('c').
        !           888:  */
        !           889: chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
        !           890: {
        !           891:        chunk_t construct;
        !           892:        va_list chunks;
        !           893:        u_char *pos;
        !           894:        int i;
        !           895:        int count = strlen(mode);
        !           896: 
        !           897:        /* sum up lengths of individual chunks */
        !           898:        va_start(chunks, mode);
        !           899:        construct.len = 0;
        !           900:        for (i = 0; i < count; i++)
        !           901:        {
        !           902:                chunk_t ch = va_arg(chunks, chunk_t);
        !           903:                construct.len += ch.len;
        !           904:        }
        !           905:        va_end(chunks);
        !           906: 
        !           907:        /* allocate needed memory for construct */
        !           908:        pos = asn1_build_object(&construct, type, construct.len);
        !           909: 
        !           910:        /* copy or move the chunks */
        !           911:        va_start(chunks, mode);
        !           912:        for (i = 0; i < count; i++)
        !           913:        {
        !           914:                chunk_t ch = va_arg(chunks, chunk_t);
        !           915: 
        !           916:                memcpy(pos, ch.ptr, ch.len);
        !           917:                pos += ch.len;
        !           918: 
        !           919:                switch (*mode++)
        !           920:                {
        !           921:                        case 's':
        !           922:                                chunk_clear(&ch);
        !           923:                                break;
        !           924:                        case 'm':
        !           925:                                free(ch.ptr);
        !           926:                                break;
        !           927:                        default:
        !           928:                                break;
        !           929:                }
        !           930:        }
        !           931:        va_end(chunks);
        !           932: 
        !           933:        return construct;
        !           934: }
        !           935: 
        !           936: /**
        !           937:  * ASN.1 definition of time
        !           938:  */
        !           939: static const asn1Object_t timeObjects[] = {
        !           940:        { 0, "utcTime",                 ASN1_UTCTIME,                   ASN1_OPT|ASN1_BODY      }, /* 0 */
        !           941:        { 0, "end opt",                 ASN1_EOC,                               ASN1_END                        }, /* 1 */
        !           942:        { 0, "generalizeTime",  ASN1_GENERALIZEDTIME,   ASN1_OPT|ASN1_BODY      }, /* 2 */
        !           943:        { 0, "end opt",                 ASN1_EOC,                               ASN1_END                        }, /* 3 */
        !           944:        { 0, "exit",                    ASN1_EOC,                               ASN1_EXIT                       }
        !           945: };
        !           946: #ifdef TIME_UTC
        !           947: /* used by C11 timespec_get(), <time.h> */
        !           948: # undef TIME_UTC
        !           949: #endif
        !           950: #define TIME_UTC                       0
        !           951: #define TIME_GENERALIZED       2
        !           952: 
        !           953: /**
        !           954:  * extracts and converts a UTCTIME or GENERALIZEDTIME object
        !           955:  */
        !           956: time_t asn1_parse_time(chunk_t blob, int level0)
        !           957: {
        !           958:        asn1_parser_t *parser;
        !           959:        chunk_t object;
        !           960:        int objectID;
        !           961:        time_t utc_time = 0;
        !           962: 
        !           963:        parser= asn1_parser_create(timeObjects, blob);
        !           964:        parser->set_top_level(parser, level0);
        !           965: 
        !           966:        while (parser->iterate(parser, &objectID, &object))
        !           967:        {
        !           968:                if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)
        !           969:                {
        !           970:                        utc_time = asn1_to_time(&object, (objectID == TIME_UTC)
        !           971:                                                                        ? ASN1_UTCTIME : ASN1_GENERALIZEDTIME);
        !           972:                }
        !           973:        }
        !           974:        parser->destroy(parser);
        !           975:        return utc_time;
        !           976: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>