LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hcrypto - dh.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 64 154 41.6 %
Date: 2024-01-11 09:59:51 Functions: 8 22 36.4 %

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

Generated by: LCOV version 1.14