Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2008-2010 Tobias Brunner
        !             3:  * Copyright (C) 2008 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 <openssl/opensslconf.h>
        !            18: 
        !            19: #ifndef OPENSSL_NO_DH
        !            20: 
        !            21: #include <openssl/bn.h>
        !            22: #include <openssl/dh.h>
        !            23: 
        !            24: #include "openssl_diffie_hellman.h"
        !            25: #include "openssl_util.h"
        !            26: 
        !            27: #include <utils/debug.h>
        !            28: 
        !            29: /* these were added with 1.1.0 when DH was made opaque */
        !            30: #if OPENSSL_VERSION_NUMBER < 0x10100000L
        !            31: OPENSSL_KEY_FALLBACK(DH, key, pub_key, priv_key)
        !            32: OPENSSL_KEY_FALLBACK(DH, pqg, p, q, g)
        !            33: #define DH_set_length(dh, len) ({ (dh)->length = len; 1; })
        !            34: #endif
        !            35: 
        !            36: typedef struct private_openssl_diffie_hellman_t private_openssl_diffie_hellman_t;
        !            37: 
        !            38: /**
        !            39:  * Private data of an openssl_diffie_hellman_t object.
        !            40:  */
        !            41: struct private_openssl_diffie_hellman_t {
        !            42:        /**
        !            43:         * Public openssl_diffie_hellman_t interface.
        !            44:         */
        !            45:        openssl_diffie_hellman_t public;
        !            46: 
        !            47:        /**
        !            48:         * Diffie Hellman group number.
        !            49:         */
        !            50:        diffie_hellman_group_t group;
        !            51: 
        !            52:        /**
        !            53:         * Diffie Hellman object
        !            54:         */
        !            55:        DH *dh;
        !            56: 
        !            57:        /**
        !            58:         * Other public value
        !            59:         */
        !            60:        BIGNUM *pub_key;
        !            61: 
        !            62:        /**
        !            63:         * Shared secret
        !            64:         */
        !            65:        chunk_t shared_secret;
        !            66: 
        !            67:        /**
        !            68:         * True if shared secret is computed
        !            69:         */
        !            70:        bool computed;
        !            71: };
        !            72: 
        !            73: METHOD(diffie_hellman_t, get_my_public_value, bool,
        !            74:        private_openssl_diffie_hellman_t *this, chunk_t *value)
        !            75: {
        !            76:        const BIGNUM *pubkey;
        !            77: 
        !            78:        *value = chunk_alloc(DH_size(this->dh));
        !            79:        memset(value->ptr, 0, value->len);
        !            80:        DH_get0_key(this->dh, &pubkey, NULL);
        !            81:        BN_bn2bin(pubkey, value->ptr + value->len - BN_num_bytes(pubkey));
        !            82:        return TRUE;
        !            83: }
        !            84: 
        !            85: METHOD(diffie_hellman_t, get_shared_secret, bool,
        !            86:        private_openssl_diffie_hellman_t *this, chunk_t *secret)
        !            87: {
        !            88:        if (!this->computed)
        !            89:        {
        !            90:                return FALSE;
        !            91:        }
        !            92:        /* shared secret should requires a len according the DH group */
        !            93:        *secret = chunk_alloc(DH_size(this->dh));
        !            94:        memset(secret->ptr, 0, secret->len);
        !            95:        memcpy(secret->ptr + secret->len - this->shared_secret.len,
        !            96:                   this->shared_secret.ptr, this->shared_secret.len);
        !            97:        return TRUE;
        !            98: }
        !            99: 
        !           100: 
        !           101: METHOD(diffie_hellman_t, set_other_public_value, bool,
        !           102:        private_openssl_diffie_hellman_t *this, chunk_t value)
        !           103: {
        !           104:        int len;
        !           105: 
        !           106:        if (!diffie_hellman_verify_value(this->group, value))
        !           107:        {
        !           108:                return FALSE;
        !           109:        }
        !           110: 
        !           111:        BN_bin2bn(value.ptr, value.len, this->pub_key);
        !           112:        chunk_clear(&this->shared_secret);
        !           113:        this->shared_secret.ptr = malloc(DH_size(this->dh));
        !           114:        memset(this->shared_secret.ptr, 0xFF, this->shared_secret.len);
        !           115:        len = DH_compute_key(this->shared_secret.ptr, this->pub_key, this->dh);
        !           116:        if (len < 0)
        !           117:        {
        !           118:                DBG1(DBG_LIB, "DH shared secret computation failed");
        !           119:                return FALSE;
        !           120:        }
        !           121:        this->shared_secret.len = len;
        !           122:        this->computed = TRUE;
        !           123:        return TRUE;
        !           124: }
        !           125: 
        !           126: METHOD(diffie_hellman_t, set_private_value, bool,
        !           127:        private_openssl_diffie_hellman_t *this, chunk_t value)
        !           128: {
        !           129:        BIGNUM *privkey;
        !           130: 
        !           131:        privkey = BN_bin2bn(value.ptr, value.len, NULL);
        !           132:        if (privkey)
        !           133:        {
        !           134:                if (!DH_set0_key(this->dh, NULL, privkey))
        !           135:                {
        !           136:                        return FALSE;
        !           137:                }
        !           138:                chunk_clear(&this->shared_secret);
        !           139:                this->computed = FALSE;
        !           140:                return DH_generate_key(this->dh);
        !           141:        }
        !           142:        return FALSE;
        !           143: }
        !           144: 
        !           145: METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t,
        !           146:        private_openssl_diffie_hellman_t *this)
        !           147: {
        !           148:        return this->group;
        !           149: }
        !           150: 
        !           151: /**
        !           152:  * Lookup the modulus in modulo table
        !           153:  */
        !           154: static status_t set_modulus(private_openssl_diffie_hellman_t *this)
        !           155: {
        !           156:        BIGNUM *p, *g;
        !           157: 
        !           158:        diffie_hellman_params_t *params = diffie_hellman_get_params(this->group);
        !           159:        if (!params)
        !           160:        {
        !           161:                return NOT_FOUND;
        !           162:        }
        !           163:        p = BN_bin2bn(params->prime.ptr, params->prime.len, NULL);
        !           164:        g = BN_bin2bn(params->generator.ptr, params->generator.len, NULL);
        !           165:        if (!DH_set0_pqg(this->dh, p, NULL, g))
        !           166:        {
        !           167:                return FAILED;
        !           168:        }
        !           169:        if (params->exp_len != params->prime.len)
        !           170:        {
        !           171: #ifdef OPENSSL_IS_BORINGSSL
        !           172:                this->dh->priv_length = params->exp_len * 8;
        !           173: #else
        !           174:                if (!DH_set_length(this->dh, params->exp_len * 8))
        !           175:                {
        !           176:                        return FAILED;
        !           177:                }
        !           178: #endif
        !           179:        }
        !           180:        return SUCCESS;
        !           181: }
        !           182: 
        !           183: METHOD(diffie_hellman_t, destroy, void,
        !           184:        private_openssl_diffie_hellman_t *this)
        !           185: {
        !           186:        BN_clear_free(this->pub_key);
        !           187:        DH_free(this->dh);
        !           188:        chunk_clear(&this->shared_secret);
        !           189:        free(this);
        !           190: }
        !           191: 
        !           192: /*
        !           193:  * Described in header.
        !           194:  */
        !           195: openssl_diffie_hellman_t *openssl_diffie_hellman_create(
        !           196:                                                                                        diffie_hellman_group_t group, ...)
        !           197: {
        !           198:        private_openssl_diffie_hellman_t *this;
        !           199:        const BIGNUM *privkey;
        !           200: 
        !           201:        INIT(this,
        !           202:                .public = {
        !           203:                        .dh = {
        !           204:                                .get_shared_secret = _get_shared_secret,
        !           205:                                .set_other_public_value = _set_other_public_value,
        !           206:                                .get_my_public_value = _get_my_public_value,
        !           207:                                .set_private_value = _set_private_value,
        !           208:                                .get_dh_group = _get_dh_group,
        !           209:                                .destroy = _destroy,
        !           210:                        },
        !           211:                },
        !           212:        );
        !           213: 
        !           214:        this->dh = DH_new();
        !           215:        if (!this->dh)
        !           216:        {
        !           217:                free(this);
        !           218:                return NULL;
        !           219:        }
        !           220: 
        !           221:        this->group = group;
        !           222:        this->computed = FALSE;
        !           223:        this->pub_key = BN_new();
        !           224:        this->shared_secret = chunk_empty;
        !           225: 
        !           226:        if (group == MODP_CUSTOM)
        !           227:        {
        !           228:                chunk_t g, p;
        !           229: 
        !           230:                VA_ARGS_GET(group, g, p);
        !           231:                if (!DH_set0_pqg(this->dh, BN_bin2bn(p.ptr, p.len, NULL), NULL,
        !           232:                                                 BN_bin2bn(g.ptr, g.len, NULL)))
        !           233:                {
        !           234:                        destroy(this);
        !           235:                        return NULL;
        !           236:                }
        !           237:        }
        !           238:        else
        !           239:        {
        !           240:                /* find a modulus according to group */
        !           241:                if (set_modulus(this) != SUCCESS)
        !           242:                {
        !           243:                        destroy(this);
        !           244:                        return NULL;
        !           245:                }
        !           246:        }
        !           247: 
        !           248:        /* generate my public and private values */
        !           249:        if (!DH_generate_key(this->dh))
        !           250:        {
        !           251:                destroy(this);
        !           252:                return NULL;
        !           253:        }
        !           254:        DH_get0_key(this->dh, NULL, &privkey);
        !           255:        DBG2(DBG_LIB, "size of DH secret exponent: %d bits", BN_num_bits(privkey));
        !           256:        return &this->public;
        !           257: }
        !           258: 
        !           259: #endif /* OPENSSL_NO_DH */

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