root/source4/heimdal/lib/hcrypto/dh.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. DH_new
  2. DH_new_method
  3. DH_free
  4. DH_up_ref
  5. DH_size
  6. DH_set_ex_data
  7. DH_get_ex_data
  8. DH_generate_parameters_ex
  9. DH_check_pubkey
  10. DH_generate_key
  11. DH_compute_key
  12. DH_set_method
  13. dh_null_generate_key
  14. dh_null_compute_key
  15. dh_null_init
  16. dh_null_finish
  17. dh_null_generate_params
  18. DH_null_method
  19. DH_set_default_method
  20. DH_get_default_method

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

/* [<][>][^][v][top][bottom][index][help] */