Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008 Tobias Brunner
        !             3:  * Copyright (C) 2006-2009 Martin Willi
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "ike_cert_pre.h"
        !            18: 
        !            19: #include <daemon.h>
        !            20: #include <sa/ike_sa.h>
        !            21: #include <encoding/payloads/cert_payload.h>
        !            22: #include <encoding/payloads/certreq_payload.h>
        !            23: #include <credentials/certificates/x509.h>
        !            24: 
        !            25: 
        !            26: typedef struct private_ike_cert_pre_t private_ike_cert_pre_t;
        !            27: 
        !            28: /**
        !            29:  * Private members of a ike_cert_pre_t task.
        !            30:  */
        !            31: struct private_ike_cert_pre_t {
        !            32: 
        !            33:        /**
        !            34:         * Public methods and task_t interface.
        !            35:         */
        !            36:        ike_cert_pre_t public;
        !            37: 
        !            38:        /**
        !            39:         * Assigned IKE_SA.
        !            40:         */
        !            41:        ike_sa_t *ike_sa;
        !            42: 
        !            43:        /**
        !            44:         * Are we the initiator?
        !            45:         */
        !            46:        bool initiator;
        !            47: 
        !            48:        /**
        !            49:         * Do we accept HTTP certificate lookup requests
        !            50:         */
        !            51:        bool do_http_lookup;
        !            52: 
        !            53:        /**
        !            54:         * whether this is the final authentication round
        !            55:         */
        !            56:        bool final;
        !            57: };
        !            58: 
        !            59: /**
        !            60:  * Process a single certificate request payload
        !            61:  */
        !            62: static void process_certreq(private_ike_cert_pre_t *this,
        !            63:                                                        certreq_payload_t *certreq, auth_cfg_t *auth)
        !            64: {
        !            65:        enumerator_t *enumerator;
        !            66:        u_int unknown = 0;
        !            67:        chunk_t keyid;
        !            68: 
        !            69:        this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
        !            70: 
        !            71:        if (certreq->get_cert_type(certreq) != CERT_X509)
        !            72:        {
        !            73:                DBG1(DBG_IKE, "cert payload %N not supported - ignored",
        !            74:                         certificate_type_names, certreq->get_cert_type(certreq));
        !            75:                return;
        !            76:        }
        !            77: 
        !            78:        enumerator = certreq->create_keyid_enumerator(certreq);
        !            79:        while (enumerator->enumerate(enumerator, &keyid))
        !            80:        {
        !            81:                identification_t *id;
        !            82:                certificate_t *cert;
        !            83: 
        !            84:                id = identification_create_from_encoding(ID_KEY_ID, keyid);
        !            85:                cert = lib->credmgr->get_cert(lib->credmgr,
        !            86:                                                                          CERT_X509, KEY_ANY, id, TRUE);
        !            87:                if (cert)
        !            88:                {
        !            89:                        DBG1(DBG_IKE, "received cert request for \"%Y\"",
        !            90:                                 cert->get_subject(cert));
        !            91:                        auth->add(auth, AUTH_RULE_CA_CERT, cert);
        !            92:                }
        !            93:                else
        !            94:                {
        !            95:                        DBG2(DBG_IKE, "received cert request for unknown ca with keyid %Y",
        !            96:                                 id);
        !            97:                        unknown++;
        !            98:                }
        !            99:                id->destroy(id);
        !           100:        }
        !           101:        enumerator->destroy(enumerator);
        !           102:        if (unknown)
        !           103:        {
        !           104:                DBG1(DBG_IKE, "received %u cert requests for an unknown ca",
        !           105:                         unknown);
        !           106:        }
        !           107: }
        !           108: 
        !           109: /**
        !           110:  * Process a single notify payload
        !           111:  */
        !           112: static void process_notify(private_ike_cert_pre_t *this,
        !           113:                                                   notify_payload_t *notify)
        !           114: {
        !           115:        switch (notify->get_notify_type(notify))
        !           116:        {
        !           117:                case HTTP_CERT_LOOKUP_SUPPORTED:
        !           118:                        this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL);
        !           119:                        break;
        !           120:                default:
        !           121:                        break;
        !           122:        }
        !           123: }
        !           124: 
        !           125: /**
        !           126:  * read certificate requests
        !           127:  */
        !           128: static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
        !           129: {
        !           130:        enumerator_t *enumerator;
        !           131:        payload_t *payload;
        !           132:        auth_cfg_t *auth;
        !           133: 
        !           134:        auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
        !           135: 
        !           136:        enumerator = message->create_payload_enumerator(message);
        !           137:        while (enumerator->enumerate(enumerator, &payload))
        !           138:        {
        !           139:                switch (payload->get_type(payload))
        !           140:                {
        !           141:                        case PLV2_CERTREQ:
        !           142:                                process_certreq(this, (certreq_payload_t*)payload, auth);
        !           143:                                break;
        !           144:                        case PLV2_NOTIFY:
        !           145:                                process_notify(this, (notify_payload_t*)payload);
        !           146:                                break;
        !           147:                        default:
        !           148:                                /* ignore other payloads here, these are handled elsewhere */
        !           149:                                break;
        !           150:                }
        !           151:        }
        !           152:        enumerator->destroy(enumerator);
        !           153: }
        !           154: 
        !           155: /**
        !           156:  * tries to extract a certificate from the cert payload or the credential
        !           157:  * manager (based on the hash of a "Hash and URL" encoded cert).
        !           158:  * Note: the returned certificate (if any) has to be destroyed
        !           159:  */
        !           160: static certificate_t *try_get_cert(cert_payload_t *cert_payload)
        !           161: {
        !           162:        certificate_t *cert = NULL;
        !           163: 
        !           164:        switch (cert_payload->get_cert_encoding(cert_payload))
        !           165:        {
        !           166:                case ENC_X509_SIGNATURE:
        !           167:                {
        !           168:                        cert = cert_payload->get_cert(cert_payload);
        !           169:                        break;
        !           170:                }
        !           171:                case ENC_X509_HASH_AND_URL:
        !           172:                {
        !           173:                        identification_t *id;
        !           174:                        chunk_t hash = cert_payload->get_hash(cert_payload);
        !           175:                        if (!hash.ptr)
        !           176:                        {
        !           177:                                /* invalid "Hash and URL" data (logged elsewhere) */
        !           178:                                break;
        !           179:                        }
        !           180:                        id = identification_create_from_encoding(ID_KEY_ID, hash);
        !           181:                        cert = lib->credmgr->get_cert(lib->credmgr,
        !           182:                                                                                  CERT_X509, KEY_ANY, id, FALSE);
        !           183:                        id->destroy(id);
        !           184:                        break;
        !           185:                }
        !           186:                default:
        !           187:                {
        !           188:                        break;
        !           189:                }
        !           190:        }
        !           191:        return cert;
        !           192: }
        !           193: 
        !           194: /**
        !           195:  * Process a X509 certificate payload
        !           196:  */
        !           197: static void process_x509(cert_payload_t *payload, auth_cfg_t *auth,
        !           198:                                                 cert_encoding_t encoding, bool *first)
        !           199: {
        !           200:        certificate_t *cert;
        !           201:        char *url;
        !           202: 
        !           203:        cert = try_get_cert(payload);
        !           204:        if (cert)
        !           205:        {
        !           206:                if (*first)
        !           207:                {       /* the first is an end entity certificate */
        !           208:                        DBG1(DBG_IKE, "received end entity cert \"%Y\"",
        !           209:                                 cert->get_subject(cert));
        !           210:                        auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert);
        !           211:                        *first = FALSE;
        !           212:                }
        !           213:                else
        !           214:                {
        !           215:                        DBG1(DBG_IKE, "received issuer cert \"%Y\"",
        !           216:                                 cert->get_subject(cert));
        !           217:                        auth->add(auth, AUTH_HELPER_IM_CERT, cert);
        !           218:                }
        !           219:        }
        !           220:        else if (encoding == ENC_X509_HASH_AND_URL)
        !           221:        {
        !           222:                /* we fetch the certificate not yet, but only if
        !           223:                 * it is really needed during authentication */
        !           224:                url = payload->get_url(payload);
        !           225:                if (!url)
        !           226:                {
        !           227:                        DBG1(DBG_IKE, "received invalid hash-and-url "
        !           228:                                 "encoded cert, ignore");
        !           229:                        return;
        !           230:                }
        !           231:                url = strdup(url);
        !           232:                if (*first)
        !           233:                {       /* first URL is for an end entity certificate */
        !           234:                        DBG1(DBG_IKE, "received hash-and-url for end entity cert \"%s\"",
        !           235:                                 url);
        !           236:                        auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url);
        !           237:                        *first = FALSE;
        !           238:                }
        !           239:                else
        !           240:                {
        !           241:                        DBG1(DBG_IKE, "received hash-and-url for issuer cert \"%s\"", url);
        !           242:                        auth->add(auth, AUTH_HELPER_IM_HASH_URL, url);
        !           243:                }
        !           244:        }
        !           245: }
        !           246: 
        !           247: /**
        !           248:  * Process a CRL certificate payload
        !           249:  */
        !           250: static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
        !           251: {
        !           252:        certificate_t *cert;
        !           253: 
        !           254:        cert = payload->get_cert(payload);
        !           255:        if (cert)
        !           256:        {
        !           257:                DBG1(DBG_IKE, "received CRL \"%Y\"", cert->get_subject(cert));
        !           258:                auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
        !           259:        }
        !           260: }
        !           261: 
        !           262: /**
        !           263:  * Process an attribute certificate payload
        !           264:  */
        !           265: static void process_ac(cert_payload_t *payload, auth_cfg_t *auth)
        !           266: {
        !           267:        certificate_t *cert;
        !           268: 
        !           269:        cert = payload->get_cert(payload);
        !           270:        if (cert)
        !           271:        {
        !           272:                if (cert->get_issuer(cert))
        !           273:                {
        !           274:                        DBG1(DBG_IKE, "received attribute certificate issued by \"%Y\"",
        !           275:                                 cert->get_issuer(cert));
        !           276:                }
        !           277:                else if (cert->get_subject(cert))
        !           278:                {
        !           279:                        DBG1(DBG_IKE, "received attribute certificate for \"%Y\"",
        !           280:                                 cert->get_subject(cert));
        !           281:                }
        !           282:                auth->add(auth, AUTH_HELPER_AC_CERT, cert);
        !           283:        }
        !           284: }
        !           285: 
        !           286: /**
        !           287:  * Process certificate payloads
        !           288:  */
        !           289: static void process_certs(private_ike_cert_pre_t *this, message_t *message)
        !           290: {
        !           291:        enumerator_t *enumerator;
        !           292:        payload_t *payload;
        !           293:        auth_cfg_t *auth;
        !           294:        bool first = TRUE;
        !           295: 
        !           296:        auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE);
        !           297: 
        !           298:        enumerator = message->create_payload_enumerator(message);
        !           299:        while (enumerator->enumerate(enumerator, &payload))
        !           300:        {
        !           301:                if (payload->get_type(payload) == PLV2_CERTIFICATE)
        !           302:                {
        !           303:                        cert_payload_t *cert_payload;
        !           304:                        cert_encoding_t encoding;
        !           305: 
        !           306:                        cert_payload = (cert_payload_t*)payload;
        !           307:                        encoding = cert_payload->get_cert_encoding(cert_payload);
        !           308: 
        !           309:                        switch (encoding)
        !           310:                        {
        !           311:                                case ENC_X509_HASH_AND_URL:
        !           312:                                        if (!this->do_http_lookup)
        !           313:                                        {
        !           314:                                                DBG1(DBG_IKE, "received hash-and-url encoded cert, but "
        !           315:                                                         "we don't accept them, ignore");
        !           316:                                                break;
        !           317:                                        }
        !           318:                                        /* FALL */
        !           319:                                case ENC_X509_SIGNATURE:
        !           320:                                        process_x509(cert_payload, auth, encoding, &first);
        !           321:                                        break;
        !           322:                                case ENC_CRL:
        !           323:                                        process_crl(cert_payload, auth);
        !           324:                                        break;
        !           325:                                case ENC_X509_ATTRIBUTE:
        !           326:                                        process_ac(cert_payload, auth);
        !           327:                                        break;
        !           328:                                case ENC_PKCS7_WRAPPED_X509:
        !           329:                                case ENC_PGP:
        !           330:                                case ENC_DNS_SIGNED_KEY:
        !           331:                                case ENC_KERBEROS_TOKEN:
        !           332:                                case ENC_ARL:
        !           333:                                case ENC_SPKI:
        !           334:                                case ENC_RAW_RSA_KEY:
        !           335:                                case ENC_X509_HASH_AND_URL_BUNDLE:
        !           336:                                case ENC_OCSP_CONTENT:
        !           337:                                default:
        !           338:                                        DBG1(DBG_ENC, "certificate encoding %N not supported",
        !           339:                                                 cert_encoding_names, encoding);
        !           340:                        }
        !           341:                }
        !           342:        }
        !           343:        enumerator->destroy(enumerator);
        !           344: }
        !           345: 
        !           346: /**
        !           347:  * add the keyid of a certificate to the certificate request payload
        !           348:  */
        !           349: static void add_certreq(certreq_payload_t **req, certificate_t *cert)
        !           350: {
        !           351:        switch (cert->get_type(cert))
        !           352:        {
        !           353:                case CERT_X509:
        !           354:                {
        !           355:                        public_key_t *public;
        !           356:                        chunk_t keyid;
        !           357:                        x509_t *x509 = (x509_t*)cert;
        !           358: 
        !           359:                        if (!(x509->get_flags(x509) & X509_CA))
        !           360:                        {       /* no CA cert, skip */
        !           361:                                break;
        !           362:                        }
        !           363:                        public = cert->get_public_key(cert);
        !           364:                        if (!public)
        !           365:                        {
        !           366:                                break;
        !           367:                        }
        !           368:                        if (*req == NULL)
        !           369:                        {
        !           370:                                *req = certreq_payload_create_type(CERT_X509);
        !           371:                        }
        !           372:                        if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
        !           373:                        {
        !           374:                                (*req)->add_keyid(*req, keyid);
        !           375:                                DBG1(DBG_IKE, "sending cert request for \"%Y\"",
        !           376:                                         cert->get_subject(cert));
        !           377:                        }
        !           378:                        public->destroy(public);
        !           379:                        break;
        !           380:                }
        !           381:                default:
        !           382:                        break;
        !           383:        }
        !           384: }
        !           385: 
        !           386: /**
        !           387:  * add a auth_cfg's CA certificates to the certificate request
        !           388:  */
        !           389: static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
        !           390: {
        !           391:        enumerator_t *enumerator;
        !           392:        auth_rule_t type;
        !           393:        void *value;
        !           394: 
        !           395:        enumerator = auth->create_enumerator(auth);
        !           396:        while (enumerator->enumerate(enumerator, &type, &value))
        !           397:        {
        !           398:                switch (type)
        !           399:                {
        !           400:                        case AUTH_RULE_CA_CERT:
        !           401:                                add_certreq(req, (certificate_t*)value);
        !           402:                                break;
        !           403:                        default:
        !           404:                                break;
        !           405:                }
        !           406:        }
        !           407:        enumerator->destroy(enumerator);
        !           408: }
        !           409: 
        !           410: /**
        !           411:  * build certificate requests
        !           412:  */
        !           413: static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
        !           414: {
        !           415:        enumerator_t *enumerator;
        !           416:        ike_cfg_t *ike_cfg;
        !           417:        peer_cfg_t *peer_cfg;
        !           418:        certificate_t *cert;
        !           419:        auth_cfg_t *auth;
        !           420:        certreq_payload_t *req = NULL;
        !           421: 
        !           422:        ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
        !           423:        if (!ike_cfg->send_certreq(ike_cfg))
        !           424:        {
        !           425:                return;
        !           426:        }
        !           427: 
        !           428:        /* check if we require a specific CA for that peer */
        !           429:        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
        !           430:        if (peer_cfg)
        !           431:        {
        !           432:                enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
        !           433:                while (enumerator->enumerate(enumerator, &auth))
        !           434:                {
        !           435:                        add_certreqs(&req, auth);
        !           436:                }
        !           437:                enumerator->destroy(enumerator);
        !           438:        }
        !           439: 
        !           440:        if (!req)
        !           441:        {
        !           442:                /* otherwise add all trusted CA certificates */
        !           443:                enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
        !           444:                                                                                                CERT_ANY, KEY_ANY, NULL, TRUE);
        !           445:                while (enumerator->enumerate(enumerator, &cert))
        !           446:                {
        !           447:                        add_certreq(&req, cert);
        !           448:                }
        !           449:                enumerator->destroy(enumerator);
        !           450:        }
        !           451: 
        !           452:        if (req)
        !           453:        {
        !           454:                message->add_payload(message, (payload_t*)req);
        !           455: 
        !           456:                if (lib->settings->get_bool(lib->settings,
        !           457:                                                                        "%s.hash_and_url", FALSE, lib->ns))
        !           458:                {
        !           459:                        message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
        !           460:                                                                chunk_empty);
        !           461:                        this->do_http_lookup = TRUE;
        !           462:                }
        !           463:        }
        !           464: }
        !           465: 
        !           466: /**
        !           467:  * Check if this is the final authentication round
        !           468:  */
        !           469: static bool final_auth(message_t *message)
        !           470: {
        !           471:        /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */
        !           472:        if (message->get_payload(message, PLV2_AUTH) == NULL)
        !           473:        {
        !           474:                return FALSE;
        !           475:        }
        !           476:        if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS))
        !           477:        {
        !           478:                return FALSE;
        !           479:        }
        !           480:        return TRUE;
        !           481: }
        !           482: 
        !           483: METHOD(task_t, build_i, status_t,
        !           484:        private_ike_cert_pre_t *this, message_t *message)
        !           485: {
        !           486:        if (message->get_message_id(message) == 1)
        !           487:        {       /* initiator sends CERTREQs in first IKE_AUTH */
        !           488:                build_certreqs(this, message);
        !           489:        }
        !           490:        return NEED_MORE;
        !           491: }
        !           492: 
        !           493: METHOD(task_t, process_r, status_t,
        !           494:        private_ike_cert_pre_t *this, message_t *message)
        !           495: {
        !           496:        if (message->get_exchange_type(message) != IKE_SA_INIT)
        !           497:        {       /* handle certreqs/certs in any IKE_AUTH, just in case */
        !           498:                process_certreqs(this, message);
        !           499:                process_certs(this, message);
        !           500:        }
        !           501:        this->final = final_auth(message);
        !           502:        return NEED_MORE;
        !           503: }
        !           504: 
        !           505: METHOD(task_t, build_r, status_t,
        !           506:        private_ike_cert_pre_t *this, message_t *message)
        !           507: {
        !           508:        if (message->get_exchange_type(message) == IKE_SA_INIT)
        !           509:        {
        !           510:                build_certreqs(this, message);
        !           511:        }
        !           512:        if (this->final)
        !           513:        {
        !           514:                return SUCCESS;
        !           515:        }
        !           516:        return NEED_MORE;
        !           517: }
        !           518: 
        !           519: METHOD(task_t, process_i, status_t,
        !           520:        private_ike_cert_pre_t *this, message_t *message)
        !           521: {
        !           522:        if (message->get_exchange_type(message) == IKE_SA_INIT)
        !           523:        {
        !           524:                process_certreqs(this, message);
        !           525:        }
        !           526:        process_certs(this, message);
        !           527: 
        !           528:        if (final_auth(message))
        !           529:        {
        !           530:                return SUCCESS;
        !           531:        }
        !           532:        return NEED_MORE;
        !           533: }
        !           534: 
        !           535: METHOD(task_t, get_type, task_type_t,
        !           536:        private_ike_cert_pre_t *this)
        !           537: {
        !           538:        return TASK_IKE_CERT_PRE;
        !           539: }
        !           540: 
        !           541: METHOD(task_t, migrate, void,
        !           542:        private_ike_cert_pre_t *this, ike_sa_t *ike_sa)
        !           543: {
        !           544:        this->ike_sa = ike_sa;
        !           545: }
        !           546: 
        !           547: METHOD(task_t, destroy, void,
        !           548:        private_ike_cert_pre_t *this)
        !           549: {
        !           550:        free(this);
        !           551: }
        !           552: 
        !           553: /*
        !           554:  * Described in header.
        !           555:  */
        !           556: ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
        !           557: {
        !           558:        private_ike_cert_pre_t *this;
        !           559: 
        !           560:        INIT(this,
        !           561:                .public = {
        !           562:                        .task = {
        !           563:                                .get_type = _get_type,
        !           564:                                .migrate = _migrate,
        !           565:                                .destroy = _destroy,
        !           566:                        },
        !           567:                },
        !           568:                .ike_sa = ike_sa,
        !           569:                .initiator = initiator,
        !           570:        );
        !           571: 
        !           572:        if (initiator)
        !           573:        {
        !           574:                this->public.task.build = _build_i;
        !           575:                this->public.task.process = _process_i;
        !           576:        }
        !           577:        else
        !           578:        {
        !           579:                this->public.task.build = _build_r;
        !           580:                this->public.task.process = _process_r;
        !           581:        }
        !           582: 
        !           583:        return &this->public;
        !           584: }

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