Annotation of embedaddon/strongswan/src/libcharon/plugins/coupling/coupling_validator.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2011 Martin Willi
        !             3:  * Copyright (C) 2011 revosec AG
        !             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 "coupling_validator.h"
        !            17: 
        !            18: #include <errno.h>
        !            19: #include <time.h>
        !            20: 
        !            21: #include <daemon.h>
        !            22: #include <threading/mutex.h>
        !            23: 
        !            24: /* buffer size for hex-encoded hash */
        !            25: #define MAX_HASH_SIZE (HASH_SIZE_SHA512 * 2 + 1)
        !            26: 
        !            27: typedef struct private_coupling_validator_t private_coupling_validator_t;
        !            28: 
        !            29: /**
        !            30:  * Private data of an coupling_validator_t object.
        !            31:  */
        !            32: struct private_coupling_validator_t {
        !            33: 
        !            34:        /**
        !            35:         * Public coupling_validator_t interface.
        !            36:         */
        !            37:        coupling_validator_t public;
        !            38: 
        !            39:        /**
        !            40:         * Mutex
        !            41:         */
        !            42:        mutex_t *mutex;
        !            43: 
        !            44:        /**
        !            45:         * File with device couplings
        !            46:         */
        !            47:        FILE *f;
        !            48: 
        !            49:        /**
        !            50:         * Hasher to create hashes
        !            51:         */
        !            52:        hasher_t *hasher;
        !            53: 
        !            54:        /**
        !            55:         * maximum number of couplings
        !            56:         */
        !            57:        int max_couplings;
        !            58: };
        !            59: 
        !            60: /**
        !            61:  * Get hash of a certificate
        !            62:  */
        !            63: static bool get_cert_hash(private_coupling_validator_t *this,
        !            64:                                                  certificate_t *cert, char *hex)
        !            65: {
        !            66:        char buf[MAX_HASH_SIZE];
        !            67:        chunk_t encoding;
        !            68: 
        !            69:        if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding))
        !            70:        {
        !            71:                return FALSE;
        !            72:        }
        !            73:        if (!this->hasher->get_hash(this->hasher, encoding, buf))
        !            74:        {
        !            75:                free(encoding.ptr);
        !            76:                return FALSE;
        !            77:        }
        !            78:        free(encoding.ptr);
        !            79:        chunk_to_hex(chunk_create(buf, this->hasher->get_hash_size(this->hasher)),
        !            80:                                 hex, FALSE);
        !            81:        return TRUE;
        !            82: }
        !            83: 
        !            84: /**
        !            85:  * Check if we have an entry for a given hash
        !            86:  */
        !            87: static bool has_entry(private_coupling_validator_t *this, char *hash)
        !            88: {
        !            89:        char line[256];
        !            90:        int hash_len;
        !            91: 
        !            92:        hash_len = strlen(hash);
        !            93:        rewind(this->f);
        !            94: 
        !            95:        while (fgets(line, sizeof(line), this->f))
        !            96:        {
        !            97:                if (strlen(line) >= hash_len &&
        !            98:                        strncaseeq(line, hash, hash_len))
        !            99:                {
        !           100:                        return TRUE;
        !           101:                }
        !           102:        }
        !           103:        return FALSE;
        !           104: }
        !           105: 
        !           106: /**
        !           107:  * Get the number of coupling entries we currently have
        !           108:  */
        !           109: static int get_number_of_entries(private_coupling_validator_t *this)
        !           110: {
        !           111:        char line[256];
        !           112:        int count = 0;
        !           113: 
        !           114:        rewind(this->f);
        !           115: 
        !           116:        while (fgets(line, sizeof(line), this->f))
        !           117:        {
        !           118:                /* valid entries start with hex encoded hash */
        !           119:                if (strchr("1234567890abcdefABCDEF", line[0]))
        !           120:                {
        !           121:                        count++;
        !           122:                }
        !           123:        }
        !           124:        return count;
        !           125: }
        !           126: 
        !           127: /**
        !           128:  * Add a new entry to the file
        !           129:  */
        !           130: static bool add_entry(private_coupling_validator_t *this, char *hash,
        !           131:                                          identification_t *id)
        !           132: {
        !           133:        return fseek(this->f, 0, SEEK_END) == 0 &&
        !           134:                   fprintf(this->f, "%s %u '%Y'\n", hash, time(NULL), id) > 0;
        !           135: }
        !           136: 
        !           137: METHOD(cert_validator_t, validate, bool,
        !           138:        private_coupling_validator_t *this,
        !           139:        certificate_t *subject, certificate_t *issuer,
        !           140:        bool online, u_int pathlen, bool anchor, auth_cfg_t *auth)
        !           141: {
        !           142:        bool valid = FALSE;
        !           143:        char hash[MAX_HASH_SIZE];
        !           144: 
        !           145:        if (pathlen != 0)
        !           146:        {
        !           147:                return TRUE;
        !           148:        }
        !           149:        if (get_cert_hash(this, subject, hash))
        !           150:        {
        !           151:                this->mutex->lock(this->mutex);
        !           152:                if (has_entry(this, hash))
        !           153:                {
        !           154:                        DBG1(DBG_CFG, "coupled certificate '%Y' found, accepted",
        !           155:                                 subject->get_subject(subject));
        !           156:                        valid = TRUE;
        !           157:                }
        !           158:                else if (get_number_of_entries(this) < this->max_couplings)
        !           159:                {
        !           160:                        if (add_entry(this, hash, subject->get_subject(subject)))
        !           161:                        {
        !           162:                                DBG1(DBG_CFG, "coupled new certificate '%Y'",
        !           163:                                         subject->get_subject(subject));
        !           164:                                valid = TRUE;
        !           165:                        }
        !           166:                        else
        !           167:                        {
        !           168:                                DBG1(DBG_CFG, "coupling new certificate '%Y' failed",
        !           169:                                         subject->get_subject(subject));
        !           170:                                lib->credmgr->call_hook(lib->credmgr,
        !           171:                                                                                CRED_HOOK_POLICY_VIOLATION, subject);
        !           172:                        }
        !           173:                }
        !           174:                else
        !           175:                {
        !           176:                        DBG1(DBG_CFG, "coupling new certificate '%Y' failed, limit of %d "
        !           177:                                 "couplings reached", subject->get_subject(subject),
        !           178:                                 this->max_couplings);
        !           179:                        lib->credmgr->call_hook(lib->credmgr, CRED_HOOK_POLICY_VIOLATION,
        !           180:                                                                        subject);
        !           181:                }
        !           182:                this->mutex->unlock(this->mutex);
        !           183:        }
        !           184:        return valid;
        !           185: }
        !           186: 
        !           187: METHOD(coupling_validator_t, destroy, void,
        !           188:        private_coupling_validator_t *this)
        !           189: {
        !           190:        if (this->f)
        !           191:        {
        !           192:                fclose(this->f);
        !           193:        }
        !           194:        DESTROY_IF(this->hasher);
        !           195:        this->mutex->destroy(this->mutex);
        !           196:        free(this);
        !           197: }
        !           198: 
        !           199: /**
        !           200:  * See header
        !           201:  */
        !           202: coupling_validator_t *coupling_validator_create()
        !           203: {
        !           204:        private_coupling_validator_t *this;
        !           205:        hash_algorithm_t alg;
        !           206:        char *path, *hash;
        !           207: 
        !           208:        INIT(this,
        !           209:                .public = {
        !           210:                        .validator = {
        !           211:                                .validate = _validate,
        !           212:                        },
        !           213:                        .destroy = _destroy,
        !           214:                },
        !           215:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           216:                .max_couplings = lib->settings->get_int(lib->settings,
        !           217:                                                                                                "%s.plugins.coupling.max", 1,
        !           218:                                                                                                lib->ns),
        !           219:        );
        !           220: 
        !           221:        hash = lib->settings->get_str(lib->settings,
        !           222:                                                                  "%s.plugins.coupling.hash", "sha1", lib->ns);
        !           223:        if (!enum_from_name(hash_algorithm_short_names, hash, &alg))
        !           224:        {
        !           225:                DBG1(DBG_CFG, "unknown coupling hash algorithm: %s", hash);
        !           226:                destroy(this);
        !           227:                return NULL;
        !           228:        }
        !           229:        this->hasher = lib->crypto->create_hasher(lib->crypto, alg);
        !           230:        if (!this->hasher)
        !           231:        {
        !           232:                DBG1(DBG_CFG, "unsupported coupling hash algorithm: %s", hash);
        !           233:                destroy(this);
        !           234:                return NULL;
        !           235:        }
        !           236: 
        !           237:        path = lib->settings->get_str(lib->settings,
        !           238:                                                                  "%s.plugins.coupling.file", NULL, lib->ns);
        !           239:        if (!path)
        !           240:        {
        !           241:                DBG1(DBG_CFG, "coupling file path unspecified");
        !           242:                destroy(this);
        !           243:                return NULL;
        !           244:        }
        !           245:        this->f = fopen(path, "a+");
        !           246:        if (!this->f)
        !           247:        {
        !           248:                DBG1(DBG_CFG, "opening coupling file '%s' failed: %s",
        !           249:                         path, strerror(errno));
        !           250:                destroy(this);
        !           251:                return NULL;
        !           252:        }
        !           253:        setlinebuf(this->f);
        !           254:        return &this->public;
        !           255: }

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