Annotation of embedaddon/strongswan/src/libcharon/plugins/coupling/coupling_validator.c, revision 1.1.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>