Annotation of embedaddon/strongswan/src/libsimaka/simaka_message.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2009 Martin Willi
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "simaka_message.h"
                     17: 
                     18: #include "simaka_manager.h"
                     19: 
                     20: #include <utils/debug.h>
                     21: #include <collections/linked_list.h>
                     22: 
                     23: typedef struct private_simaka_message_t private_simaka_message_t;
                     24: typedef struct hdr_t hdr_t;
                     25: typedef struct attr_hdr_t attr_hdr_t;
                     26: typedef struct attr_t attr_t;
                     27: 
                     28: /**
                     29:  * packed EAP-SIM/AKA header struct
                     30:  */
                     31: struct hdr_t {
                     32:        /** EAP code (REQUEST/RESPONSE) */
                     33:        uint8_t code;
                     34:        /** unique message identifier */
                     35:        uint8_t identifier;
                     36:        /** length of whole message */
                     37:        uint16_t length;
                     38:        /** EAP type => EAP_SIM/EAP_AKA */
                     39:        uint8_t type;
                     40:        /** SIM subtype */
                     41:        uint8_t subtype;
                     42:        /** reserved bytes */
                     43:        uint16_t reserved;
                     44: } __attribute__((__packed__));
                     45: 
                     46: /**
                     47:  * packed EAP-SIM/AKA attribute header struct
                     48:  */
                     49: struct attr_hdr_t {
                     50:        /** attribute type */
                     51:        uint8_t type;
                     52:        /** attribute length */
                     53:        uint8_t length;
                     54: } __attribute__((__packed__));
                     55: 
                     56: /**
                     57:  * SIM/AKA attribute, parsed
                     58:  */
                     59: struct attr_t {
                     60:        /** type of attribute */
                     61:        simaka_attribute_t type;
                     62:        /** length of data */
                     63:        size_t len;
                     64:        /** start of data, variable length */
                     65:        char data[];
                     66: };
                     67: 
                     68: ENUM_BEGIN(simaka_subtype_names, AKA_CHALLENGE, AKA_IDENTITY,
                     69:        "AKA_CHALLENGE",
                     70:        "AKA_AUTHENTICATION_REJECT",
                     71:        "AKA_3",
                     72:        "AKA_SYNCHRONIZATION_FAILURE",
                     73:        "AKA_IDENTITY");
                     74: ENUM_NEXT(simaka_subtype_names, SIM_START, AKA_CLIENT_ERROR, AKA_IDENTITY,
                     75:        "SIM_START",
                     76:        "SIM_CHALLENGE",
                     77:        "SIM/AKA_NOTIFICATION",
                     78:        "SIM/AKA_REAUTHENTICATION",
                     79:        "SIM/AKA_CLIENT_ERROR");
                     80: ENUM_END(simaka_subtype_names, AKA_CLIENT_ERROR);
                     81: 
                     82: 
                     83: ENUM_BEGIN(simaka_attribute_names, AT_RAND, AT_CLIENT_ERROR_CODE,
                     84:        "AT_RAND",
                     85:        "AT_AUTN",
                     86:        "AT_RES",
                     87:        "AT_AUTS",
                     88:        "AT_5",
                     89:        "AT_PADDING",
                     90:        "AT_NONCE_MT",
                     91:        "AT_8",
                     92:        "AT_9",
                     93:        "AT_PERMANENT_ID_REQ",
                     94:        "AT_MAC",
                     95:        "AT_NOTIFICATION",
                     96:        "AT_ANY_ID_REQ",
                     97:        "AT_IDENTITY",
                     98:        "AT_VERSION_LIST",
                     99:        "AT_SELECTED_VERSION",
                    100:        "AT_FULLAUTH_ID_REQ",
                    101:        "AT_18",
                    102:        "AT_COUNTER",
                    103:        "AT_COUNTER_TOO_SMALL",
                    104:        "AT_NONCE_S",
                    105:        "AT_CLIENT_ERROR_CODE");
                    106: ENUM_NEXT(simaka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
                    107:        "AT_IV",
                    108:        "AT_ENCR_DATA",
                    109:        "AT_131",
                    110:        "AT_NEXT_PSEUDONYM",
                    111:        "AT_NEXT_REAUTH_ID",
                    112:        "AT_CHECKCODE",
                    113:        "AT_RESULT_IND");
                    114: ENUM_END(simaka_attribute_names, AT_RESULT_IND);
                    115: 
                    116: 
                    117: ENUM_BEGIN(simaka_notification_names, SIM_GENERAL_FAILURE_AA, SIM_GENERAL_FAILURE_AA,
                    118:        "General failure after authentication");
                    119: ENUM_NEXT(simaka_notification_names, SIM_TEMP_DENIED, SIM_TEMP_DENIED, SIM_GENERAL_FAILURE_AA,
                    120:        "User has been temporarily denied access");
                    121: ENUM_NEXT(simaka_notification_names, SIM_NOT_SUBSCRIBED, SIM_NOT_SUBSCRIBED, SIM_TEMP_DENIED,
                    122:        "User has not subscribed to the requested service");
                    123: ENUM_NEXT(simaka_notification_names, SIM_GENERAL_FAILURE, SIM_GENERAL_FAILURE, SIM_NOT_SUBSCRIBED,
                    124:        "General failure");
                    125: ENUM_NEXT(simaka_notification_names, SIM_SUCCESS, SIM_SUCCESS, SIM_GENERAL_FAILURE,
                    126:        "User has been successfully authenticated");
                    127: ENUM_END(simaka_notification_names, SIM_SUCCESS);
                    128: 
                    129: 
                    130: ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH,
                    131:        "unable to process packet",
                    132:        "unsupported version",
                    133:        "insufficient number of challenges",
                    134:        "RANDs are not fresh",
                    135: );
                    136: 
                    137: /**
                    138:  * Check if an EAP-SIM/AKA attribute is skippable
                    139:  */
                    140: bool simaka_attribute_skippable(simaka_attribute_t attribute)
                    141: {
                    142:        bool skippable = !((int)attribute >= 0 && attribute <= 127);
                    143: 
                    144:        DBG1(DBG_LIB, "%sskippable EAP-SIM/AKA attribute %N",
                    145:                 skippable ? "ignoring " : "found non-",
                    146:                 simaka_attribute_names, attribute);
                    147:        return skippable;
                    148: }
                    149: 
                    150: /**
                    151:  * Private data of an simaka_message_t object.
                    152:  */
                    153: struct private_simaka_message_t {
                    154: 
                    155:        /**
                    156:         * Public simaka_message_t interface.
                    157:         */
                    158:        simaka_message_t public;
                    159: 
                    160:        /**
                    161:         * EAP message, starting with EAP header
                    162:         */
                    163:        hdr_t *hdr;
                    164: 
                    165:        /**
                    166:         * List of parsed attributes, attr_t
                    167:         */
                    168:        linked_list_t *attributes;
                    169: 
                    170:        /**
                    171:         * Currently parsing AT_ENCR_DATA wrapped attributes?
                    172:         */
                    173:        bool encrypted;
                    174: 
                    175:        /**
                    176:         * crypto helper
                    177:         */
                    178:        simaka_crypto_t *crypto;
                    179: 
                    180:        /**
                    181:         * Phase a NOTIFICATION is sent within
                    182:         */
                    183:        bool p_bit;
                    184: 
                    185:        /**
                    186:         * MAC value, pointing into message
                    187:         */
                    188:        chunk_t mac;
                    189: 
                    190:        /**
                    191:         * ENCR_DATA value, pointing into message
                    192:         */
                    193:        chunk_t encr;
                    194: 
                    195:        /**
                    196:         * IV value, pointing into message
                    197:         */
                    198:        chunk_t iv;
                    199: };
                    200: 
                    201: METHOD(simaka_message_t, is_request, bool,
                    202:        private_simaka_message_t *this)
                    203: {
                    204:        return this->hdr->code == EAP_REQUEST;
                    205: }
                    206: 
                    207: METHOD(simaka_message_t, get_identifier, uint8_t,
                    208:        private_simaka_message_t *this)
                    209: {
                    210:        return this->hdr->identifier;
                    211: }
                    212: 
                    213: METHOD(simaka_message_t, get_subtype, simaka_subtype_t,
                    214:        private_simaka_message_t *this)
                    215: {
                    216:        return this->hdr->subtype;
                    217: }
                    218: 
                    219: METHOD(simaka_message_t, get_type, eap_type_t,
                    220:        private_simaka_message_t *this)
                    221: {
                    222:        return this->hdr->type;
                    223: }
                    224: 
                    225: CALLBACK(attr_enum_filter, bool,
                    226:        void *null, enumerator_t *orig, va_list args)
                    227: {
                    228:        attr_t *attr;
                    229:        simaka_attribute_t *type;
                    230:        chunk_t *data;
                    231: 
                    232:        VA_ARGS_VGET(args, type, data);
                    233: 
                    234:        if (orig->enumerate(orig, &attr))
                    235:        {
                    236:                *type = attr->type;
                    237:                *data = chunk_create(attr->data, attr->len);
                    238:                return TRUE;
                    239:        }
                    240:        return FALSE;
                    241: }
                    242: 
                    243: METHOD(simaka_message_t, create_attribute_enumerator, enumerator_t*,
                    244:        private_simaka_message_t *this)
                    245: {
                    246:        return enumerator_create_filter(
                    247:                                                this->attributes->create_enumerator(this->attributes),
                    248:                                                attr_enum_filter, NULL, NULL);
                    249: }
                    250: 
                    251: METHOD(simaka_message_t, add_attribute, void,
                    252:        private_simaka_message_t *this, simaka_attribute_t type, chunk_t data)
                    253: {
                    254:        attr_t *attr;
                    255: 
                    256:        attr = malloc(sizeof(attr_t) + data.len);
                    257:        attr->len = data.len;
                    258:        attr->type = type;
                    259:        memcpy(attr->data, data.ptr, data.len);
                    260: 
                    261:        this->attributes->insert_last(this->attributes, attr);
                    262: }
                    263: 
                    264: /**
                    265:  * Error handling for unencrypted attributes
                    266:  */
                    267: static bool not_encrypted(simaka_attribute_t type)
                    268: {
                    269:        DBG1(DBG_LIB, "received unencrypted %N", simaka_attribute_names, type);
                    270:        return FALSE;
                    271: }
                    272: 
                    273: /**
                    274:  * Error handling for invalid length
                    275:  */
                    276: static bool invalid_length(simaka_attribute_t type)
                    277: {
                    278:        DBG1(DBG_LIB, "invalid length of %N", simaka_attribute_names, type);
                    279:        return FALSE;
                    280: }
                    281: 
                    282: /**
                    283:  * Call SIM/AKA message hooks
                    284:  */
                    285: static void call_hook(private_simaka_message_t *this,
                    286:                                          bool inbound, bool decrypted)
                    287: {
                    288:        simaka_manager_t *mgr;
                    289: 
                    290:        switch (this->hdr->type)
                    291:        {
                    292:                case EAP_SIM:
                    293:                        mgr = lib->get(lib, "sim-manager");
                    294:                        break;
                    295:                case EAP_AKA:
                    296:                        mgr = lib->get(lib, "aka-manager");
                    297:                        break;
                    298:                default:
                    299:                        return;
                    300:        }
                    301:        mgr->message_hook(mgr, &this->public, inbound, decrypted);
                    302: }
                    303: 
                    304: /**
                    305:  * Parse attributes from a chunk of data
                    306:  */
                    307: static bool parse_attributes(private_simaka_message_t *this, chunk_t in)
                    308: {
                    309:        while (in.len)
                    310:        {
                    311:                attr_hdr_t *hdr;
                    312:                chunk_t data;
                    313: 
                    314:                if (in.len < sizeof(attr_hdr_t))
                    315:                {
                    316:                        DBG1(DBG_LIB, "found short %N attribute header",
                    317:                                 eap_type_names, this->hdr->type);
                    318:                        return FALSE;
                    319:                }
                    320:                hdr = (attr_hdr_t*)in.ptr;
                    321: 
                    322:                switch (hdr->type)
                    323:                {
                    324:                        /* attributes without data */
                    325:                        case AT_COUNTER_TOO_SMALL:
                    326:                                if (!this->encrypted)
                    327:                                {
                    328:                                        return not_encrypted(hdr->type);
                    329:                                }
                    330:                                /* FALL */
                    331:                        case AT_ANY_ID_REQ:
                    332:                        case AT_PERMANENT_ID_REQ:
                    333:                        case AT_FULLAUTH_ID_REQ:
                    334:                        {
                    335:                                if (hdr->length != 1 || in.len < 4)
                    336:                                {
                    337:                                        return invalid_length(hdr->type);
                    338:                                }
                    339:                                data = chunk_empty;
                    340:                                in = chunk_skip(in, 4);
                    341:                                break;
                    342:                        }
                    343:                        /* attributes with two bytes data */
                    344:                        case AT_COUNTER:
                    345:                                if (!this->encrypted)
                    346:                                {
                    347:                                        return not_encrypted(hdr->type);
                    348:                                }
                    349:                                /* FALL */
                    350:                        case AT_CLIENT_ERROR_CODE:
                    351:                        case AT_SELECTED_VERSION:
                    352:                        case AT_NOTIFICATION:
                    353:                        {
                    354:                                if (hdr->length != 1 || in.len < 4)
                    355:                                {
                    356:                                        return invalid_length(hdr->type);
                    357:                                }
                    358:                                data = chunk_create(in.ptr + 2, 2);
                    359:                                in = chunk_skip(in, 4);
                    360:                                break;
                    361:                        }
                    362:                        /* attributes with an additional actual-length in bits or bytes */
                    363:                        case AT_NEXT_PSEUDONYM:
                    364:                        case AT_NEXT_REAUTH_ID:
                    365:                                if (!this->encrypted)
                    366:                                {
                    367:                                        return not_encrypted(hdr->type);
                    368:                                }
                    369:                                /* FALL */
                    370:                        case AT_RES:
                    371:                        case AT_IDENTITY:
                    372:                        case AT_VERSION_LIST:
                    373:                        {
                    374:                                uint16_t len;
                    375: 
                    376:                                if (hdr->length < 1 || in.len < 4)
                    377:                                {
                    378:                                        return invalid_length(hdr->type);
                    379:                                }
                    380:                                memcpy(&len, in.ptr + 2, 2);
                    381:                                len = ntohs(len);
                    382:                                if (hdr->type == AT_RES)
                    383:                                {       /* AT_RES uses length encoding in bits */
                    384:                                        len /= 8;
                    385:                                }
                    386:                                if (len > hdr->length * 4 || len > in.len)
                    387:                                {
                    388:                                        return invalid_length(hdr->type);
                    389:                                }
                    390:                                data = chunk_create(in.ptr + 4, len);
                    391:                                in = chunk_skip(in, hdr->length * 4);
                    392:                                break;
                    393:                        }
                    394:                        /* attributes with two reserved bytes, 16 bytes length */
                    395:                        case AT_NONCE_S:
                    396:                                if (!this->encrypted)
                    397:                                {
                    398:                                        return not_encrypted(hdr->type);
                    399:                                }
                    400:                                /* FALL */
                    401:                        case AT_AUTN:
                    402:                        case AT_NONCE_MT:
                    403:                        case AT_IV:
                    404:                        case AT_MAC:
                    405:                        {
                    406:                                if (hdr->length != 5 || in.len < 20)
                    407:                                {
                    408:                                        return invalid_length(hdr->type);
                    409:                                }
                    410:                                data = chunk_create(in.ptr + 4, 16);
                    411:                                in = chunk_skip(in, 20);
                    412:                                break;
                    413:                        }
                    414:                        /* attributes with two reserved bytes, variable length */
                    415:                        case AT_ENCR_DATA:
                    416:                        case AT_RAND:
                    417:                        {
                    418:                                if (hdr->length * 4 > in.len || in.len < 4)
                    419:                                {
                    420:                                        return invalid_length(hdr->type);
                    421:                                }
                    422:                                data = chunk_create(in.ptr + 4, hdr->length * 4 - 4);
                    423:                                in = chunk_skip(in, hdr->length * 4);
                    424:                                break;
                    425:                        }
                    426:                        /* attributes with no reserved bytes, 14 bytes length */
                    427:                        case AT_AUTS:
                    428:                        {
                    429:                                if (hdr->length != 4 || in.len < 16)
                    430:                                {
                    431:                                        return invalid_length(hdr->type);
                    432:                                }
                    433:                                data = chunk_create(in.ptr + 2, 14);
                    434:                                in = chunk_skip(in, 16);
                    435:                                break;
                    436:                        }
                    437:                        /* other attributes (with 4n + 2 length) */
                    438:                        case AT_PADDING:
                    439:                        default:
                    440:                        {
                    441:                                if (hdr->length * 4 > in.len || in.len < 4)
                    442:                                {
                    443:                                        return invalid_length(hdr->type);
                    444:                                }
                    445:                                data = chunk_create(in.ptr + 2, hdr->length * 4 - 2);
                    446:                                in = chunk_skip(in, hdr->length * 4);
                    447:                                break;
                    448:                        }
                    449:                }
                    450: 
                    451:                /* handle special attributes */
                    452:                switch (hdr->type)
                    453:                {
                    454:                        case AT_MAC:
                    455:                                this->mac = data;
                    456:                                break;
                    457:                        case AT_IV:
                    458:                                this->iv = data;
                    459:                                break;
                    460:                        case AT_ENCR_DATA:
                    461:                                this->encr = data;
                    462:                                break;
                    463:                        case AT_PADDING:
                    464:                                break;
                    465:                        case AT_NOTIFICATION:
                    466:                                if (this->p_bit)
                    467:                                {       /* remember P bit for MAC verification */
                    468:                                        this->p_bit = !!(data.ptr[0] & 0x40);
                    469:                                }
                    470:                                else if (!this->encrypted)
                    471:                                {
                    472:                                        DBG1(DBG_LIB, "found P-bit 0 notify in unencrypted message");
                    473:                                        return FALSE;
                    474:                                }
                    475:                                /* FALL */
                    476:                        default:
                    477:                                add_attribute(this, hdr->type, data);
                    478:                                break;
                    479:                }
                    480:        }
                    481: 
                    482:        call_hook(this, TRUE, this->encrypted);
                    483: 
                    484:        return TRUE;
                    485: }
                    486: 
                    487: /**
                    488:  * Decrypt a message and parse the decrypted attributes
                    489:  */
                    490: static bool decrypt(private_simaka_message_t *this)
                    491: {
                    492:        bool success;
                    493:        crypter_t *crypter;
                    494:        chunk_t plain;
                    495: 
                    496:        crypter = this->crypto->get_crypter(this->crypto);
                    497:        if (!crypter || !this->iv.len || !this->encr.len || this->encrypted)
                    498:        {
                    499:                return TRUE;
                    500:        }
                    501:        if (this->encr.len % crypter->get_block_size(crypter))
                    502:        {
                    503:                DBG1(DBG_LIB, "%N ENCR_DATA not a multiple of block size",
                    504:                         eap_type_names, this->hdr->type);
                    505:                return FALSE;
                    506:        }
                    507:        if (!crypter->decrypt(crypter, this->encr, this->iv, &plain))
                    508:        {
                    509:                return FALSE;
                    510:        }
                    511: 
                    512:        this->encrypted = TRUE;
                    513:        success = parse_attributes(this, plain);
                    514:        this->encrypted = FALSE;
                    515:        free(plain.ptr);
                    516:        return success;
                    517: }
                    518: 
                    519: METHOD(simaka_message_t, parse, bool,
                    520:        private_simaka_message_t *this)
                    521: {
                    522:        chunk_t in;
                    523: 
                    524:        if (this->attributes->get_count(this->attributes))
                    525:        {       /* Already parsed. Try to decrypt and parse AT_ENCR_DATA. */
                    526:                return decrypt(this);
                    527:        }
                    528: 
                    529:        in = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
                    530:        if (!parse_attributes(this, chunk_skip(in, sizeof(hdr_t))))
                    531:        {
                    532:                return FALSE;
                    533:        }
                    534:        /* try to decrypt if we already have keys */
                    535:        return decrypt(this);
                    536: }
                    537: 
                    538: METHOD(simaka_message_t, verify, bool,
                    539:        private_simaka_message_t *this, chunk_t sigdata)
                    540: {
                    541:        chunk_t data, backup;
                    542:        signer_t *signer;
                    543: 
                    544:        signer = this->crypto->get_signer(this->crypto);
                    545: 
                    546:        switch (this->hdr->subtype)
                    547:        {
                    548:                case SIM_START:
                    549:                case SIM_CLIENT_ERROR:
                    550:                  /* AKA_CLIENT_ERROR: */
                    551:                case AKA_AUTHENTICATION_REJECT:
                    552:                case AKA_SYNCHRONIZATION_FAILURE:
                    553:                case AKA_IDENTITY:
                    554:                        /* skip MAC if available */
                    555:                        return TRUE;
                    556:                case SIM_CHALLENGE:
                    557:                case AKA_CHALLENGE:
                    558:                case SIM_REAUTHENTICATION:
                    559:                  /* AKA_REAUTHENTICATION: */
                    560:                {
                    561:                        if (!this->mac.ptr || !signer)
                    562:                        {       /* require MAC, but not found */
                    563:                                DBG1(DBG_LIB, "%N message requires a MAC, but none found",
                    564:                                         simaka_subtype_names, this->hdr->subtype);
                    565:                                return FALSE;
                    566:                        }
                    567:                        break;
                    568:                }
                    569:                case SIM_NOTIFICATION:
                    570:                  /* AKA_NOTIFICATION: */
                    571:                {
                    572:                        if (this->p_bit)
                    573:                        {       /* MAC not verified if in Phase 1 */
                    574:                                return TRUE;
                    575:                        }
                    576:                        if (!this->mac.ptr || !signer)
                    577:                        {
                    578:                                DBG1(DBG_LIB, "%N message has a phase 0 notify, but "
                    579:                                         "no MAC found", simaka_subtype_names, this->hdr->subtype);
                    580:                                return FALSE;
                    581:                        }
                    582:                        break;
                    583:                }
                    584:                default:
                    585:                        /* unknown message? */
                    586:                        DBG1(DBG_LIB, "signature rule for %N messages missing",
                    587:                                 simaka_subtype_names, this->hdr->subtype);
                    588:                        return FALSE;
                    589:        }
                    590: 
                    591:        /* zero MAC for verification */
                    592:        backup = chunk_clonea(this->mac);
                    593:        memset(this->mac.ptr, 0, this->mac.len);
                    594: 
                    595:        data = chunk_create((char*)this->hdr, ntohs(this->hdr->length));
                    596:        if (sigdata.len)
                    597:        {
                    598:                data = chunk_cata("cc", data, sigdata);
                    599:        }
                    600:        if (!signer->verify_signature(signer, data, backup))
                    601:        {
                    602:                DBG1(DBG_LIB, "%N MAC verification failed",
                    603:                         eap_type_names, this->hdr->type);
                    604:                return FALSE;
                    605:        }
                    606:        return TRUE;
                    607: }
                    608: 
                    609: METHOD(simaka_message_t, generate, bool,
                    610:        private_simaka_message_t *this, chunk_t sigdata, chunk_t *gen)
                    611: {
                    612:        /* buffers large enough for messages we generate */
                    613:        char out_buf[1024], encr_buf[512];
                    614:        enumerator_t *enumerator;
                    615:        chunk_t out, encr, data, *target, mac = chunk_empty;
                    616:        simaka_attribute_t type;
                    617:        attr_hdr_t *hdr;
                    618:        uint16_t len;
                    619:        signer_t *signer;
                    620: 
                    621:        call_hook(this, FALSE, TRUE);
                    622: 
                    623:        out = chunk_create(out_buf, sizeof(out_buf));
                    624:        encr = chunk_create(encr_buf, sizeof(encr_buf));
                    625: 
                    626:        /* copy header */
                    627:        memcpy(out.ptr, this->hdr, sizeof(hdr_t));
                    628:        out = chunk_skip(out, sizeof(hdr_t));
                    629: 
                    630:        /* encode attributes */
                    631:        enumerator = create_attribute_enumerator(this);
                    632:        while (enumerator->enumerate(enumerator, &type, &data))
                    633:        {
                    634:                /* encrypt this attribute? */
                    635:                switch (type)
                    636:                {
                    637:                        case AT_NONCE_S:
                    638:                        case AT_NEXT_PSEUDONYM:
                    639:                        case AT_NEXT_REAUTH_ID:
                    640:                        case AT_COUNTER:
                    641:                        case AT_COUNTER_TOO_SMALL:
                    642:                                target = &encr;
                    643:                                break;
                    644:                        case AT_NOTIFICATION:
                    645:                                /* P bit not set, encrypt */
                    646:                                if (!(data.ptr[0] & 0x40))
                    647:                                {
                    648:                                        target = &encr;
                    649:                                        break;
                    650:                                }
                    651:                                /* FALL */
                    652:                        default:
                    653:                                target = &out;
                    654:                                break;
                    655:                }
                    656: 
                    657:                hdr = (attr_hdr_t*)target->ptr;
                    658:                hdr->type = type;
                    659: 
                    660:                /* encode type specific */
                    661:                switch (type)
                    662:                {
                    663:                        /* attributes without data */
                    664:                        case AT_COUNTER_TOO_SMALL:
                    665:                        case AT_ANY_ID_REQ:
                    666:                        case AT_PERMANENT_ID_REQ:
                    667:                        case AT_FULLAUTH_ID_REQ:
                    668:                        {
                    669:                                hdr->length = 1;
                    670:                                memset(target->ptr + 2, 0, 2);
                    671:                                *target = chunk_skip(*target, 4);
                    672:                                break;
                    673:                        }
                    674:                        /* attributes with two bytes data */
                    675:                        case AT_COUNTER:
                    676:                        case AT_CLIENT_ERROR_CODE:
                    677:                        case AT_SELECTED_VERSION:
                    678:                        case AT_NOTIFICATION:
                    679:                        {
                    680:                                hdr->length = 1;
                    681:                                memcpy(target->ptr + 2, data.ptr, 2);
                    682:                                *target = chunk_skip(*target, 4);
                    683:                                break;
                    684:                        }
                    685:                        /* attributes with an additional actual-length in bits or bytes */
                    686:                        case AT_NEXT_PSEUDONYM:
                    687:                        case AT_NEXT_REAUTH_ID:
                    688:                        case AT_IDENTITY:
                    689:                        case AT_VERSION_LIST:
                    690:                        case AT_RES:
                    691:                        {
                    692:                                uint16_t len, padding;
                    693: 
                    694:                                len = htons(data.len);
                    695:                                if (type == AT_RES)
                    696:                                {       /* AT_RES uses length encoding in bits */
                    697:                                        len *= 8;
                    698:                                }
                    699:                                memcpy(target->ptr + 2, &len, sizeof(len));
                    700:                                memcpy(target->ptr + 4, data.ptr, data.len);
                    701:                                hdr->length = data.len / 4 + 1;
                    702:                                padding = (4 - (data.len % 4)) % 4;
                    703:                                if (padding)
                    704:                                {
                    705:                                        hdr->length++;
                    706:                                        memset(target->ptr + 4 + data.len, 0, padding);
                    707:                                }
                    708:                                *target = chunk_skip(*target, hdr->length * 4);
                    709:                                break;
                    710:                        }
                    711:                        /* attributes with two reserved bytes, 16 bytes length */
                    712:                        case AT_NONCE_S:
                    713:                        case AT_NONCE_MT:
                    714:                        case AT_AUTN:
                    715:                        {
                    716:                                hdr->length = 5;
                    717:                                memset(target->ptr + 2, 0, 2);
                    718:                                memcpy(target->ptr + 4, data.ptr, data.len);
                    719:                                *target = chunk_skip(*target, 20);
                    720:                                break;
                    721:                        }
                    722:                        /* attributes with two reserved bytes, variable length */
                    723:                        case AT_RAND:
                    724:                        {
                    725:                                hdr->length = 1 + data.len / 4;
                    726:                                memset(target->ptr + 2, 0, 2);
                    727:                                memcpy(target->ptr + 4, data.ptr, data.len);
                    728:                                *target = chunk_skip(*target, data.len + 4);
                    729:                                break;
                    730:                        }
                    731:                        /* attributes with no reserved bytes, 14 bytes length */
                    732:                        case AT_AUTS:
                    733:                        {
                    734:                                hdr->length = 4;
                    735:                                memcpy(target->ptr + 2, data.ptr, data.len);
                    736:                                *target = chunk_skip(*target, 16);
                    737:                                break;
                    738:                        }
                    739:                        default:
                    740:                        {
                    741:                                DBG1(DBG_LIB, "no rule to encode %N, skipped",
                    742:                                         simaka_attribute_names, type);
                    743:                                break;
                    744:                        }
                    745:                }
                    746:        }
                    747:        enumerator->destroy(enumerator);
                    748: 
                    749:        /* encrypt attributes, if any */
                    750:        if (encr.len < sizeof(encr_buf))
                    751:        {
                    752:                chunk_t iv;
                    753:                size_t bs, padding;
                    754:                crypter_t *crypter;
                    755:                rng_t *rng;
                    756: 
                    757:                crypter = this->crypto->get_crypter(this->crypto);
                    758:                bs = crypter->get_block_size(crypter);
                    759:                iv.len = crypter->get_iv_size(crypter);
                    760: 
                    761:                /* add AT_PADDING attribute */
                    762:                padding = bs - ((sizeof(encr_buf) - encr.len) % bs);
                    763:                if (padding)
                    764:                {
                    765:                        hdr = (attr_hdr_t*)encr.ptr;
                    766:                        hdr->type = AT_PADDING;
                    767:                        hdr->length = padding / 4;
                    768:                        memset(encr.ptr + 2, 0, padding - 2);
                    769:                        encr = chunk_skip(encr, padding);
                    770:                }
                    771:                encr = chunk_create(encr_buf, sizeof(encr_buf) - encr.len);
                    772: 
                    773:                /* add IV attribute */
                    774:                hdr = (attr_hdr_t*)out.ptr;
                    775:                hdr->type = AT_IV;
                    776:                hdr->length = iv.len / 4 + 1;
                    777:                memset(out.ptr + 2, 0, 2);
                    778:                out = chunk_skip(out, 4);
                    779: 
                    780:                rng = this->crypto->get_rng(this->crypto);
                    781:                if (!rng->get_bytes(rng, iv.len, out.ptr))
                    782:                {
                    783:                        return FALSE;
                    784:                }
                    785: 
                    786:                iv = chunk_clonea(chunk_create(out.ptr, iv.len));
                    787:                out = chunk_skip(out, iv.len);
                    788: 
                    789:                /* inline encryption */
                    790:                if (!crypter->encrypt(crypter, encr, iv, NULL))
                    791:                {
                    792:                        return FALSE;
                    793:                }
                    794: 
                    795:                /* add ENCR_DATA attribute */
                    796:                hdr = (attr_hdr_t*)out.ptr;
                    797:                hdr->type = AT_ENCR_DATA;
                    798:                hdr->length = encr.len / 4 + 1;
                    799:                memset(out.ptr + 2, 0, 2);
                    800:                memcpy(out.ptr + 4, encr.ptr, encr.len);
                    801:                out = chunk_skip(out, encr.len + 4);
                    802:        }
                    803: 
                    804:        /* include MAC ? */
                    805:        signer = this->crypto->get_signer(this->crypto);
                    806:        switch (this->hdr->subtype)
                    807:        {
                    808:                case SIM_CHALLENGE:
                    809:                case AKA_CHALLENGE:
                    810:                case SIM_REAUTHENTICATION:
                    811:                  /* AKA_REAUTHENTICATION: */
                    812:                /* TODO: Notifications without P bit */
                    813:                {
                    814:                        size_t bs;
                    815: 
                    816:                        bs = signer->get_block_size(signer);
                    817:                        hdr = (attr_hdr_t*)out.ptr;
                    818:                        hdr->type = AT_MAC;
                    819:                        hdr->length = bs / 4 + 1;
                    820:                        memset(out.ptr + 2, 0, 2 + bs);
                    821:                        mac = chunk_create(out.ptr + 4, bs);
                    822:                        out = chunk_skip(out, bs + 4);
                    823:                        break;
                    824:                }
                    825:                default:
                    826:                        break;
                    827:        }
                    828: 
                    829:        /* calculate message length */
                    830:        out = chunk_create(out_buf, sizeof(out_buf) - out.len);
                    831:        len = htons(out.len);
                    832:        memcpy(out.ptr + 2, &len, sizeof(len));
                    833: 
                    834:        /* generate MAC */
                    835:        if (mac.len)
                    836:        {
                    837:                data = chunk_cata("cc", out, sigdata);
                    838:                if (!signer->get_signature(signer, data, mac.ptr))
                    839:                {
                    840:                        return FALSE;
                    841:                }
                    842:        }
                    843: 
                    844:        call_hook(this, FALSE, FALSE);
                    845: 
                    846:        *gen = chunk_clone(out);
                    847:        return TRUE;
                    848: }
                    849: 
                    850: METHOD(simaka_message_t, destroy, void,
                    851:        private_simaka_message_t *this)
                    852: {
                    853:        this->attributes->destroy_function(this->attributes, free);
                    854:        free(this->hdr);
                    855:        free(this);
                    856: }
                    857: 
                    858: /**
                    859:  * Generic constructor.
                    860:  */
                    861: static simaka_message_t *simaka_message_create_data(chunk_t data,
                    862:                                                                                                        simaka_crypto_t *crypto)
                    863: {
                    864:        private_simaka_message_t *this;
                    865:        hdr_t *hdr = (hdr_t*)data.ptr;
                    866: 
                    867:        if (data.len < sizeof(hdr_t) || hdr->length != htons(data.len))
                    868:        {
                    869:                DBG1(DBG_LIB, "EAP-SIM/AKA header has invalid length");
                    870:                return NULL;
                    871:        }
                    872:        if (hdr->code != EAP_REQUEST && hdr->code != EAP_RESPONSE)
                    873:        {
                    874:                DBG1(DBG_LIB, "invalid EAP code in EAP-SIM/AKA message",
                    875:                         eap_type_names, hdr->type);
                    876:                return NULL;
                    877:        }
                    878:        if (hdr->type != EAP_SIM && hdr->type != EAP_AKA)
                    879:        {
                    880:                DBG1(DBG_LIB, "invalid EAP type in EAP-SIM/AKA message",
                    881:                         eap_type_names, hdr->type);
                    882:                return NULL;
                    883:        }
                    884: 
                    885:        INIT(this,
                    886:                .public = {
                    887:                        .is_request = _is_request,
                    888:                        .get_identifier = _get_identifier,
                    889:                        .get_type = _get_type,
                    890:                        .get_subtype = _get_subtype,
                    891:                        .create_attribute_enumerator = _create_attribute_enumerator,
                    892:                        .add_attribute = _add_attribute,
                    893:                        .parse = _parse,
                    894:                        .verify = _verify,
                    895:                        .generate = _generate,
                    896:                        .destroy = _destroy,
                    897:                },
                    898:                .attributes = linked_list_create(),
                    899:                .crypto = crypto,
                    900:                .p_bit = TRUE,
                    901:                .hdr = malloc(data.len),
                    902:        );
                    903:        memcpy(this->hdr, hdr, data.len);
                    904: 
                    905:        return &this->public;
                    906: }
                    907: 
                    908: /**
                    909:  * See header.
                    910:  */
                    911: simaka_message_t *simaka_message_create_from_payload(chunk_t data,
                    912:                                                                                                         simaka_crypto_t *crypto)
                    913: {
                    914:        return simaka_message_create_data(data, crypto);
                    915: }
                    916: 
                    917: /**
                    918:  * See header.
                    919:  */
                    920: simaka_message_t *simaka_message_create(bool request, uint8_t identifier,
                    921:                                                                        eap_type_t type, simaka_subtype_t subtype,
                    922:                                                                        simaka_crypto_t *crypto)
                    923: {
                    924:        hdr_t hdr = {
                    925:                .code = request ? EAP_REQUEST : EAP_RESPONSE,
                    926:                .identifier = identifier,
                    927:                .length = htons(sizeof(hdr_t)),
                    928:                .type = type,
                    929:                .subtype = subtype,
                    930:        };
                    931:        return simaka_message_create_data(chunk_create((char*)&hdr, sizeof(hdr)),
                    932:                                                                          crypto);
                    933: }
                    934: 

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