Home | History | Annotate | Line # | Download | only in hcrypto
dh.c revision 1.1.1.2
      1 /*	$NetBSD: dh.c,v 1.1.1.2 2014/04/24 12:45:30 pettai Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006 - 2007 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * 3. Neither the name of the Institute nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #ifdef HAVE_CONFIG_H
     37 #include <config.h>
     38 #endif
     39 
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <krb5/krb5-types.h>
     43 #include <krb5/rfc2459_asn1.h>
     44 
     45 #include <dh.h>
     46 
     47 #include <krb5/roken.h>
     48 
     49 /**
     50  * @page page_dh DH - Diffie-Hellman key exchange
     51  *
     52  * Diffie-Hellman key exchange is a protocol that allows two parties
     53  * to establish a shared secret key.
     54  *
     55  * Include and example how to use DH_new() and friends here.
     56  *
     57  * See the library functions here: @ref hcrypto_dh
     58  */
     59 
     60 /**
     61  * Create a new DH object using DH_new_method(NULL), see DH_new_method().
     62  *
     63  * @return a newly allocated DH object.
     64  *
     65  * @ingroup hcrypto_dh
     66  */
     67 
     68 DH *
     69 DH_new(void)
     70 {
     71     return DH_new_method(NULL);
     72 }
     73 
     74 /**
     75  * Create a new DH object from the given engine, if the NULL is used,
     76  * the default engine is used. Free the DH object with DH_free().
     77  *
     78  * @param engine The engine to use to allocate the DH object.
     79  *
     80  * @return a newly allocated DH object.
     81  *
     82  * @ingroup hcrypto_dh
     83  */
     84 
     85 DH *
     86 DH_new_method(ENGINE *engine)
     87 {
     88     DH *dh;
     89 
     90     dh = calloc(1, sizeof(*dh));
     91     if (dh == NULL)
     92 	return NULL;
     93 
     94     dh->references = 1;
     95 
     96     if (engine) {
     97 	ENGINE_up_ref(engine);
     98 	dh->engine = engine;
     99     } else {
    100 	dh->engine = ENGINE_get_default_DH();
    101     }
    102 
    103     if (dh->engine) {
    104 	dh->meth = ENGINE_get_DH(dh->engine);
    105 	if (dh->meth == NULL) {
    106 	    ENGINE_finish(engine);
    107 	    free(dh);
    108 	    return 0;
    109 	}
    110     }
    111 
    112     if (dh->meth == NULL)
    113 	dh->meth = DH_get_default_method();
    114 
    115     (*dh->meth->init)(dh);
    116 
    117     return dh;
    118 }
    119 
    120 /**
    121  * Free a DH object and release related resources, like ENGINE, that
    122  * the object was using.
    123  *
    124  * @param dh object to be freed.
    125  *
    126  * @ingroup hcrypto_dh
    127  */
    128 
    129 void
    130 DH_free(DH *dh)
    131 {
    132     if (dh->references <= 0)
    133 	abort();
    134 
    135     if (--dh->references > 0)
    136 	return;
    137 
    138     (*dh->meth->finish)(dh);
    139 
    140     if (dh->engine)
    141 	ENGINE_finish(dh->engine);
    142 
    143 #define free_if(f) if (f) { BN_free(f); }
    144     free_if(dh->p);
    145     free_if(dh->g);
    146     free_if(dh->pub_key);
    147     free_if(dh->priv_key);
    148     free_if(dh->q);
    149     free_if(dh->j);
    150     free_if(dh->counter);
    151 #undef free_if
    152 
    153     memset(dh, 0, sizeof(*dh));
    154     free(dh);
    155 }
    156 
    157 /**
    158  * Add a reference to the DH object. The object should be free with
    159  * DH_free() to drop the reference.
    160  *
    161  * @param dh the object to increase the reference count too.
    162  *
    163  * @return the updated reference count, can't safely be used except
    164  * for debug printing.
    165  *
    166  * @ingroup hcrypto_dh
    167  */
    168 
    169 int
    170 DH_up_ref(DH *dh)
    171 {
    172     return ++dh->references;
    173 }
    174 
    175 /**
    176  * The maximum output size of the DH_compute_key() function.
    177  *
    178  * @param dh The DH object to get the size from.
    179  *
    180  * @return the maximum size in bytes of the out data.
    181  *
    182  * @ingroup hcrypto_dh
    183  */
    184 
    185 int
    186 DH_size(const DH *dh)
    187 {
    188     return BN_num_bytes(dh->p);
    189 }
    190 
    191 /**
    192  * Set the data index idx in the DH object to data.
    193  *
    194  * @param dh DH object.
    195  * @param idx index to set the data for.
    196  * @param data data to store for the index idx.
    197  *
    198  * @return 1 on success.
    199  *
    200  * @ingroup hcrypto_dh
    201  */
    202 
    203 int
    204 DH_set_ex_data(DH *dh, int idx, void *data)
    205 {
    206     dh->ex_data.sk = data;
    207     return 1;
    208 }
    209 
    210 /**
    211  * Get the data for index idx in the DH object.
    212  *
    213  * @param dh DH object.
    214  * @param idx index to get the data for.
    215  *
    216  * @return the object store in index idx
    217  *
    218  * @ingroup hcrypto_dh
    219  */
    220 
    221 void *
    222 DH_get_ex_data(DH *dh, int idx)
    223 {
    224     return dh->ex_data.sk;
    225 }
    226 
    227 /**
    228  * Generate DH parameters for the DH object give parameters.
    229  *
    230  * @param dh The DH object to generate parameters for.
    231  * @param prime_len length of the prime
    232  * @param generator generator, g
    233  * @param cb Callback parameters to show progress, can be NULL.
    234  *
    235  * @return the maximum size in bytes of the out data.
    236  *
    237  * @ingroup hcrypto_dh
    238  */
    239 
    240 int
    241 DH_generate_parameters_ex(DH *dh, int prime_len, int generator, BN_GENCB *cb)
    242 {
    243     if (dh->meth->generate_params)
    244 	return dh->meth->generate_params(dh, prime_len, generator, cb);
    245     return 0;
    246 }
    247 
    248 /**
    249  * Check that the public key is sane.
    250  *
    251  * @param dh the local peer DH parameters.
    252  * @param pub_key the remote peer public key parameters.
    253  * @param codes return that the failures of the pub_key are.
    254  *
    255  * @return 1 on success, 0 on failure and *codes is set the the
    256  * combined fail check for the public key
    257  *
    258  * @ingroup hcrypto_dh
    259  */
    260 
    261 int
    262 DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes)
    263 {
    264     BIGNUM *bn = NULL, *sum = NULL;
    265     int ret = 0;
    266 
    267     *codes = 0;
    268 
    269     /**
    270      * Checks that the function performs are:
    271      * - pub_key is not negative
    272      */
    273 
    274     if (BN_is_negative(pub_key))
    275 	goto out;
    276 
    277     /**
    278      * - pub_key > 1    and    pub_key < p - 1,
    279      *    to avoid small subgroups attack.
    280      */
    281 
    282     bn = BN_new();
    283     if (bn == NULL)
    284 	goto out;
    285 
    286     if (!BN_set_word(bn, 1))
    287 	goto out;
    288 
    289     if (BN_cmp(bn, pub_key) >= 0)
    290 	*codes |= DH_CHECK_PUBKEY_TOO_SMALL;
    291 
    292     sum = BN_new();
    293     if (sum == NULL)
    294 	goto out;
    295 
    296     BN_uadd(sum, pub_key, bn);
    297 
    298     if (BN_cmp(sum, dh->p) >= 0)
    299 	*codes |= DH_CHECK_PUBKEY_TOO_LARGE;
    300 
    301     /**
    302      * - if g == 2, pub_key have more then one bit set,
    303      *   if bits set is 1, log_2(pub_key) is trival
    304      */
    305 
    306     if (!BN_set_word(bn, 2))
    307 	goto out;
    308 
    309     if (BN_cmp(bn, dh->g) == 0) {
    310 	unsigned i, n = BN_num_bits(pub_key);
    311 	unsigned bits = 0;
    312 
    313 	for (i = 0; i <= n; i++)
    314 	    if (BN_is_bit_set(pub_key, i))
    315 		bits++;
    316 
    317 	if (bits < 2) {
    318 	    *codes |= DH_CHECK_PUBKEY_TOO_SMALL;
    319 	    goto out;
    320 	}
    321     }
    322 
    323     ret = 1;
    324 out:
    325     if (bn)
    326 	BN_free(bn);
    327     if (sum)
    328 	BN_free(sum);
    329 
    330     return ret;
    331 }
    332 
    333 /**
    334  * Generate a new DH private-public key pair. The dh parameter must be
    335  * allocted first with DH_new(). dh->p and dp->g must be set.
    336  *
    337  * @param dh dh parameter.
    338  *
    339  * @return 1 on success.
    340  *
    341  * @ingroup hcrypto_dh
    342  */
    343 
    344 int
    345 DH_generate_key(DH *dh)
    346 {
    347     return dh->meth->generate_key(dh);
    348 }
    349 
    350 /**
    351  * Complute the shared secret key.
    352  *
    353  * @param shared_key the resulting shared key, need to be at least
    354  * DH_size() large.
    355  * @param peer_pub_key the peer's public key.
    356  * @param dh the dh key pair.
    357  *
    358  * @return 1 on success.
    359  *
    360  * @ingroup hcrypto_dh
    361  */
    362 
    363 int
    364 DH_compute_key(unsigned char *shared_key,
    365 	       const BIGNUM *peer_pub_key, DH *dh)
    366 {
    367     int codes;
    368 
    369     /**
    370      * Checks that the pubkey passed in is valid using
    371      * DH_check_pubkey().
    372      */
    373 
    374     if (!DH_check_pubkey(dh, peer_pub_key, &codes) || codes != 0)
    375 	return -1;
    376 
    377     return dh->meth->compute_key(shared_key, peer_pub_key, dh);
    378 }
    379 
    380 /**
    381  * Set a new method for the DH keypair.
    382  *
    383  * @param dh dh parameter.
    384  * @param method the new method for the DH parameter.
    385  *
    386  * @return 1 on success.
    387  *
    388  * @ingroup hcrypto_dh
    389  */
    390 
    391 int
    392 DH_set_method(DH *dh, const DH_METHOD *method)
    393 {
    394     (*dh->meth->finish)(dh);
    395     if (dh->engine) {
    396 	ENGINE_finish(dh->engine);
    397 	dh->engine = NULL;
    398     }
    399     dh->meth = method;
    400     (*dh->meth->init)(dh);
    401     return 1;
    402 }
    403 
    404 /*
    405  *
    406  */
    407 
    408 static int
    409 dh_null_generate_key(DH *dh)
    410 {
    411     return 0;
    412 }
    413 
    414 static int
    415 dh_null_compute_key(unsigned char *shared,const BIGNUM *pub, DH *dh)
    416 {
    417     return 0;
    418 }
    419 
    420 static int
    421 dh_null_init(DH *dh)
    422 {
    423     return 1;
    424 }
    425 
    426 static int
    427 dh_null_finish(DH *dh)
    428 {
    429     return 1;
    430 }
    431 
    432 static int
    433 dh_null_generate_params(DH *dh, int prime_num, int len, BN_GENCB *cb)
    434 {
    435     return 0;
    436 }
    437 
    438 static const DH_METHOD dh_null_method = {
    439     "hcrypto null DH",
    440     dh_null_generate_key,
    441     dh_null_compute_key,
    442     NULL,
    443     dh_null_init,
    444     dh_null_finish,
    445     0,
    446     NULL,
    447     dh_null_generate_params
    448 };
    449 
    450 extern const DH_METHOD _hc_dh_ltm_method;
    451 static const DH_METHOD *dh_default_method = &_hc_dh_ltm_method;
    452 
    453 /**
    454  * Return the dummy DH implementation.
    455  *
    456  * @return pointer to a DH_METHOD.
    457  *
    458  * @ingroup hcrypto_dh
    459  */
    460 
    461 const DH_METHOD *
    462 DH_null_method(void)
    463 {
    464     return &dh_null_method;
    465 }
    466 
    467 /**
    468  * Set the default DH implementation.
    469  *
    470  * @param meth pointer to a DH_METHOD.
    471  *
    472  * @ingroup hcrypto_dh
    473  */
    474 
    475 void
    476 DH_set_default_method(const DH_METHOD *meth)
    477 {
    478     dh_default_method = meth;
    479 }
    480 
    481 /**
    482  * Return the default DH implementation.
    483  *
    484  * @return pointer to a DH_METHOD.
    485  *
    486  * @ingroup hcrypto_dh
    487  */
    488 
    489 const DH_METHOD *
    490 DH_get_default_method(void)
    491 {
    492     return dh_default_method;
    493 }
    494 
    495 /*
    496  *
    497  */
    498 
    499 static int
    500 bn2heim_int(BIGNUM *bn, heim_integer *integer)
    501 {
    502     integer->length = BN_num_bytes(bn);
    503     integer->data = malloc(integer->length);
    504     if (integer->data == NULL) {
    505 	integer->length = 0;
    506 	return ENOMEM;
    507     }
    508     BN_bn2bin(bn, integer->data);
    509     integer->negative = BN_is_negative(bn);
    510     return 0;
    511 }
    512 
    513 /**
    514  *
    515  */
    516 
    517 int
    518 i2d_DHparams(DH *dh, unsigned char **pp)
    519 {
    520     DHParameter data;
    521     size_t size;
    522     int ret;
    523 
    524     memset(&data, 0, sizeof(data));
    525 
    526     if (bn2heim_int(dh->p, &data.prime) ||
    527 	bn2heim_int(dh->g, &data.base))
    528     {
    529 	free_DHParameter(&data);
    530 	return -1;
    531     }
    532 
    533     if (pp == NULL) {
    534 	size = length_DHParameter(&data);
    535 	free_DHParameter(&data);
    536     } else {
    537 	void *p;
    538 	size_t len;
    539 
    540 	ASN1_MALLOC_ENCODE(DHParameter, p, len, &data, &size, ret);
    541 	free_DHParameter(&data);
    542 	if (ret)
    543 	    return -1;
    544 	if (len != size) {
    545 	    abort();
    546             return -1;
    547         }
    548 
    549 	memcpy(*pp, p, size);
    550 	free(p);
    551 
    552 	*pp += size;
    553     }
    554 
    555     return size;
    556 }
    557