Annotation of embedaddon/strongswan/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c, revision 1.1.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>