LCOV - code coverage report
Current view: top level - pkcs11/gkm - gkm-dh-mechanism.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 82.8 % 134 111
Test Date: 2024-04-08 13:24:42 Functions: 80.0 % 5 4

            Line data    Source code
       1              : /*
       2              :  * gnome-keyring
       3              :  *
       4              :  * Copyright (C) 2008 Stefan Walter
       5              :  *
       6              :  * This program is free software; you can redistribute it and/or modify
       7              :  * it under the terms of the GNU Lesser General Public License as
       8              :  * published by the Free Software Foundation; either version 2.1 of
       9              :  * the License, or (at your option) any later version.
      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
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this program; if not, see
      18              :  * <http://www.gnu.org/licenses/>.
      19              :  */
      20              : 
      21              : #include "config.h"
      22              : 
      23              : #include "gkm-attributes.h"
      24              : #include "gkm-crypto.h"
      25              : #include "gkm-dh-mechanism.h"
      26              : #include "gkm-dh-private-key.h"
      27              : #include "gkm-session.h"
      28              : #include "gkm-transaction.h"
      29              : 
      30              : #include "egg/egg-dh.h"
      31              : #include "egg/egg-libgcrypt.h"
      32              : #include "egg/egg-secure-memory.h"
      33              : 
      34            1 : EGG_SECURE_DECLARE (dh_mechanism);
      35              : 
      36              : static GkmObject*
      37            2 : create_dh_object (GkmSession *session, GkmTransaction *transaction, CK_OBJECT_CLASS klass,
      38              :                   CK_ATTRIBUTE_PTR value, CK_ATTRIBUTE_PTR prime, CK_ATTRIBUTE_PTR base,
      39              :                   CK_ATTRIBUTE_PTR id, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
      40              : {
      41            2 :         CK_KEY_TYPE type = CKK_DH;
      42              :         CK_ATTRIBUTE attr;
      43              :         GkmObject *object;
      44              :         GArray *array;
      45              : 
      46            2 :         array = g_array_new (FALSE, TRUE, sizeof (CK_ATTRIBUTE));
      47              : 
      48              :         /* Setup the value */
      49            2 :         g_array_append_val (array, *value);
      50              : 
      51              :         /* Add in the DH params */
      52            2 :         g_array_append_val (array, *prime);
      53            2 :         g_array_append_val (array, *base);
      54              : 
      55              :         /* Setup the class */
      56            2 :         attr.type = CKA_CLASS;
      57            2 :         attr.pValue = &klass;
      58            2 :         attr.ulValueLen = sizeof (klass);
      59            2 :         g_array_append_val (array, attr);
      60              : 
      61              :         /* Setup the key type */
      62            2 :         attr.type = CKA_KEY_TYPE;
      63            2 :         attr.pValue = &type;
      64            2 :         attr.ulValueLen = sizeof (type);
      65            2 :         g_array_append_val (array, attr);
      66              : 
      67              :         /* All the other values */
      68            2 :         g_array_append_vals (array, attrs, n_attrs);
      69              : 
      70              :         /* Add in the identifier last */
      71            2 :         g_array_append_val (array, *id);
      72              : 
      73              :         /* Create the public key object */
      74            2 :         object = gkm_session_create_object_for_attributes (session, transaction,
      75            2 :                                                            (CK_ATTRIBUTE_PTR)array->data, array->len);
      76              : 
      77            2 :         g_array_free (array, TRUE);
      78            2 :         return object;
      79              : }
      80              : 
      81              : CK_RV
      82            1 : gkm_dh_mechanism_generate (GkmSession *session, CK_ATTRIBUTE_PTR pub_atts,
      83              :                            CK_ULONG n_pub_atts, CK_ATTRIBUTE_PTR priv_atts,
      84              :                            CK_ULONG n_priv_atts, GkmObject **pub_key,
      85              :                            GkmObject **priv_key)
      86              : {
      87            1 :         gcry_mpi_t prime = NULL;
      88            1 :         gcry_mpi_t base = NULL;
      89            1 :         gcry_mpi_t pub = NULL;
      90            1 :         gcry_mpi_t priv = NULL;
      91              :         gcry_error_t gcry;
      92              :         CK_ATTRIBUTE value, id;
      93              :         CK_ATTRIBUTE_PTR aprime;
      94              :         CK_ATTRIBUTE_PTR abase;
      95              :         GkmTransaction *transaction;
      96              :         gboolean ret;
      97              :         gsize length;
      98              :         gulong bits;
      99              :         CK_RV rv;
     100              : 
     101            1 :         g_return_val_if_fail (GKM_IS_SESSION (session), CKR_GENERAL_ERROR);
     102            1 :         g_return_val_if_fail (pub_key, CKR_GENERAL_ERROR);
     103            1 :         g_return_val_if_fail (priv_key, CKR_GENERAL_ERROR);
     104              : 
     105            1 :         *priv_key = NULL;
     106            1 :         *pub_key = NULL;
     107              : 
     108            1 :         aprime = gkm_attributes_find (pub_atts, n_pub_atts, CKA_PRIME);
     109            1 :         abase = gkm_attributes_find (pub_atts, n_pub_atts, CKA_BASE);
     110            1 :         if (!aprime || !abase)
     111            0 :                 return CKR_TEMPLATE_INCOMPLETE;
     112              : 
     113            1 :         rv = gkm_attribute_get_mpi (aprime, &prime);
     114            1 :         if (rv != CKR_OK)
     115            0 :                 return rv;
     116              : 
     117            1 :         rv = gkm_attribute_get_mpi (abase, &base);
     118            1 :         if (rv != CKR_OK) {
     119            0 :                 gcry_mpi_release (prime);
     120            0 :                 return rv;
     121              :         }
     122              : 
     123            1 :         if (!gkm_attributes_find_ulong (priv_atts, n_priv_atts, CKA_VALUE_BITS, &bits))
     124            1 :                 bits = gcry_mpi_get_nbits (prime);
     125            1 :         gkm_attributes_consume (priv_atts, n_priv_atts, CKA_VALUE_BITS, G_MAXULONG);
     126              : 
     127              :         /* The private key must be less than or equal to prime */
     128            1 :         if (bits > gcry_mpi_get_nbits (prime)) {
     129            0 :                 gcry_mpi_release (prime);
     130            0 :                 gcry_mpi_release (base);
     131            0 :                 return CKR_TEMPLATE_INCONSISTENT;
     132              :         }
     133              : 
     134            1 :         ret = egg_dh_gen_pair (prime, base, bits, &pub, &priv);
     135              : 
     136            1 :         gcry_mpi_release (prime);
     137            1 :         gcry_mpi_release (base);
     138              : 
     139            1 :         if (ret == FALSE)
     140            0 :                 return CKR_FUNCTION_FAILED;
     141              : 
     142              :         /* Write the public key out to raw data */
     143            1 :         value.type = CKA_VALUE;
     144            1 :         gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &length, pub);
     145            1 :         g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
     146            1 :         value.pValue = g_malloc (length);
     147            1 :         gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value.pValue, length, &length, pub);
     148            1 :         g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
     149            1 :         value.ulValueLen = length;
     150              : 
     151              :         /* Create an identifier */
     152            1 :         id.type = CKA_ID;
     153            1 :         if (value.ulValueLen < 16) {
     154            0 :                 id.ulValueLen = value.ulValueLen;
     155            0 :                 id.pValue = g_memdup (value.pValue, value.ulValueLen);
     156              :         } else {
     157            1 :                 id.ulValueLen = 16;
     158            1 :                 id.pValue = g_memdup ((guchar*)value.pValue + (value.ulValueLen - 16), id.ulValueLen);
     159              :         }
     160              : 
     161            1 :         transaction = gkm_transaction_new ();
     162              : 
     163            1 :         *pub_key = create_dh_object (session, transaction, CKO_PUBLIC_KEY, &value,
     164              :                                     aprime, abase, &id, pub_atts, n_pub_atts);
     165            1 :         g_free (value.pValue);
     166              : 
     167            1 :         if (!gkm_transaction_get_failed (transaction)) {
     168              : 
     169              :                 /* Write the private key out to raw data */
     170            1 :                 value.type = CKA_VALUE;
     171            1 :                 gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &length, priv);
     172            1 :                 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
     173            1 :                 value.pValue = egg_secure_alloc (length);
     174            1 :                 gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value.pValue, length, &length, priv);
     175            1 :                 g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
     176            1 :                 value.ulValueLen = length;
     177              : 
     178            1 :                 *priv_key = create_dh_object (session, transaction, CKO_PRIVATE_KEY, &value,
     179              :                                               aprime, abase, &id, priv_atts, n_priv_atts);
     180            1 :                 egg_secure_clear (value.pValue, value.ulValueLen);
     181            1 :                 egg_secure_free (value.pValue);
     182              :         }
     183              : 
     184            1 :         g_free (id.pValue);
     185              : 
     186            1 :         gkm_transaction_complete (transaction);
     187            1 :         if (gkm_transaction_get_failed (transaction)) {
     188            0 :                 if (*pub_key)
     189            0 :                         g_object_unref (*pub_key);
     190            0 :                 if (*priv_key)
     191            0 :                         g_object_unref (*priv_key);
     192            0 :                 *priv_key = *pub_key = NULL;
     193              :         }
     194              : 
     195            1 :         rv = gkm_transaction_get_result (transaction);
     196            1 :         g_object_unref (transaction);
     197              : 
     198            1 :         gkm_attributes_consume (pub_atts, n_pub_atts, CKA_PRIME, CKA_BASE, G_MAXULONG);
     199              : 
     200            1 :         return rv;
     201              : }
     202              : 
     203              : CK_RV
     204            1 : gkm_dh_mechanism_derive (GkmSession *session, CK_MECHANISM_PTR mech, GkmObject *base,
     205              :                          CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GkmObject **derived)
     206              : {
     207            1 :         gcry_mpi_t peer = NULL;
     208              :         gcry_mpi_t prime;
     209              :         gcry_mpi_t priv;
     210              :         gcry_error_t gcry;
     211              :         CK_ATTRIBUTE attr;
     212              :         GArray *array;
     213            1 :         gsize n_actual = 0;
     214            1 :         CK_ULONG n_value = 0;
     215              :         guchar *value;
     216              :         GkmTransaction *transaction;
     217              :         CK_KEY_TYPE type;
     218              : 
     219            1 :         g_return_val_if_fail (GKM_IS_DH_PRIVATE_KEY (base), CKR_GENERAL_ERROR);
     220              : 
     221            1 :         if (mech->ulParameterLen && mech->pParameter) {
     222            1 :                 gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, mech->pParameter,
     223              :                                       mech->ulParameterLen, NULL);
     224            1 :                 if (gcry != 0)
     225            0 :                         peer = NULL;
     226              :         }
     227              : 
     228            1 :         if (peer == NULL)
     229            0 :                 return CKR_MECHANISM_PARAM_INVALID;
     230              : 
     231            1 :         prime = gkm_dh_key_get_prime (GKM_DH_KEY (base));
     232            1 :         priv = gkm_dh_private_key_get_value (GKM_DH_PRIVATE_KEY (base));
     233              : 
     234              :         /* What length should we truncate to? */
     235            1 :         if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_VALUE_LEN, &n_value)) {
     236            1 :                 if (gkm_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type))
     237            1 :                         n_value = gkm_crypto_secret_key_length (type);
     238              :         }
     239              : 
     240              :         /* Default to full length of the DH prime */
     241            1 :         if (n_value == 0)
     242            1 :                 n_value = (gcry_mpi_get_nbits (prime) + 7) / 8;
     243              : 
     244            1 :         value = egg_dh_gen_secret (peer, priv, prime, &n_actual);
     245            1 :         gcry_mpi_release (peer);
     246              : 
     247            1 :         if (value == NULL)
     248            0 :                 return CKR_FUNCTION_FAILED;
     249              : 
     250              :         /* Now setup the attributes with our new value */
     251            1 :         array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
     252              : 
     253              :         /* Prepend the value */
     254            1 :         attr.type = CKA_VALUE;
     255            1 :         attr.ulValueLen = n_value;
     256              : 
     257              :         /* Is it too long, move to the front and truncate */
     258            1 :         if (n_actual > n_value) {
     259            0 :                 attr.pValue = value + (n_actual - n_value);
     260              : 
     261              :         /* If it's too short, expand with zeros */
     262            1 :         } else if (n_actual < n_value) {
     263            0 :                 value = egg_secure_realloc (value, n_value);
     264            0 :                 memmove (value + (n_value - n_actual), value, n_actual);
     265            0 :                 memset (value, 0, (n_value - n_actual));
     266            0 :                 attr.pValue = value;
     267              : 
     268              :         /* It's just right */
     269              :         } else {
     270            1 :                 attr.pValue = value;
     271              :         }
     272              : 
     273            1 :         g_array_append_val (array, attr);
     274              : 
     275              :         /* Add the remainder of the attributes */
     276            1 :         g_array_append_vals (array, attrs, n_attrs);
     277              : 
     278            1 :         transaction = gkm_transaction_new ();
     279              : 
     280              :         /* Now create an object with these attributes */
     281            2 :         *derived = gkm_session_create_object_for_attributes (session, transaction,
     282            1 :                                                              (CK_ATTRIBUTE_PTR)array->data, array->len);
     283              : 
     284            1 :         egg_secure_free (value);
     285            1 :         g_array_free (array, TRUE);
     286              : 
     287            1 :         return gkm_transaction_complete_and_unref (transaction);
     288              : }
        

Generated by: LCOV version 2.0-1