LCOV - code coverage report
Current view: top level - egg - egg-symkey.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.1 % 577 514
Test Date: 2024-12-15 20:37:51 Functions: 100.0 % 17 17

            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 "egg-asn1-defs.h"
      24              : #include "egg-asn1x.h"
      25              : #include "egg-secure-memory.h"
      26              : #include "egg-symkey.h"
      27              : 
      28          354 : EGG_SECURE_DECLARE (symkey);
      29              : 
      30              : /* -----------------------------------------------------------------------------
      31              :  * QUARKS
      32              :  */
      33              : 
      34              : static GQuark OID_PBE_MD2_DES_CBC;
      35              : static GQuark OID_PBE_MD5_DES_CBC;
      36              : static GQuark OID_PBE_MD2_RC2_CBC;
      37              : static GQuark OID_PBE_MD5_RC2_CBC;
      38              : static GQuark OID_PBE_SHA1_DES_CBC;
      39              : static GQuark OID_PBE_SHA1_RC2_CBC;
      40              : static GQuark OID_PBES2;
      41              : static GQuark OID_PBKDF2;
      42              : 
      43              : static GQuark OID_DES_CBC;
      44              : static GQuark OID_DES_RC2_CBC;
      45              : static GQuark OID_DES_EDE3_CBC;
      46              : static GQuark OID_DES_RC5_CBC;
      47              : 
      48              : static GQuark OID_PKCS12_PBE_ARCFOUR_SHA1;
      49              : static GQuark OID_PKCS12_PBE_RC4_40_SHA1;
      50              : static GQuark OID_PKCS12_PBE_3DES_SHA1;
      51              : static GQuark OID_PKCS12_PBE_2DES_SHA1;
      52              : static GQuark OID_PKCS12_PBE_RC2_128_SHA1;
      53              : static GQuark OID_PKCS12_PBE_RC2_40_SHA1;
      54              : 
      55              : static GQuark OID_SHA1;
      56              : 
      57              : static void
      58           51 : init_quarks (void)
      59              : {
      60              :         static gsize quarks_inited = 0;
      61              : 
      62           51 :         if (g_once_init_enter (&quarks_inited)) {
      63              : 
      64              :                 #define QUARK(name, value) \
      65              :                         name = g_quark_from_static_string(value)
      66              : 
      67            3 :                 QUARK (OID_PBE_MD2_DES_CBC, "1.2.840.113549.1.5.1");
      68            3 :                 QUARK (OID_PBE_MD5_DES_CBC, "1.2.840.113549.1.5.3");
      69            3 :                 QUARK (OID_PBE_MD2_RC2_CBC, "1.2.840.113549.1.5.4");
      70            3 :                 QUARK (OID_PBE_MD5_RC2_CBC, "1.2.840.113549.1.5.6");
      71            3 :                 QUARK (OID_PBE_SHA1_DES_CBC, "1.2.840.113549.1.5.10");
      72            3 :                 QUARK (OID_PBE_SHA1_RC2_CBC, "1.2.840.113549.1.5.11");
      73              : 
      74            3 :                 QUARK (OID_PBES2, "1.2.840.113549.1.5.13");
      75              : 
      76            3 :                 QUARK (OID_PBKDF2, "1.2.840.113549.1.5.12");
      77              : 
      78            3 :                 QUARK (OID_DES_CBC, "1.3.14.3.2.7");
      79            3 :                 QUARK (OID_DES_RC2_CBC, "1.2.840.113549.3.2");
      80            3 :                 QUARK (OID_DES_EDE3_CBC, "1.2.840.113549.3.7");
      81            3 :                 QUARK (OID_DES_RC5_CBC, "1.2.840.113549.3.9");
      82              : 
      83            3 :                 QUARK (OID_PKCS12_PBE_ARCFOUR_SHA1, "1.2.840.113549.1.12.1.1");
      84            3 :                 QUARK (OID_PKCS12_PBE_RC4_40_SHA1, "1.2.840.113549.1.12.1.2");
      85            3 :                 QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3");
      86            3 :                 QUARK (OID_PKCS12_PBE_2DES_SHA1, "1.2.840.113549.1.12.1.4");
      87            3 :                 QUARK (OID_PKCS12_PBE_RC2_128_SHA1, "1.2.840.113549.1.12.1.5");
      88            3 :                 QUARK (OID_PKCS12_PBE_RC2_40_SHA1, "1.2.840.113549.1.12.1.6");
      89              : 
      90            3 :                 QUARK (OID_SHA1, "1.3.14.3.2.26");
      91              : 
      92              :                 #undef QUARK
      93              : 
      94            3 :                 g_once_init_leave (&quarks_inited, 1);
      95              :         }
      96           51 : }
      97              : 
      98              : /* -----------------------------------------------------------------------------
      99              :  * PASSWORD TO KEY/IV
     100              :  */
     101              : 
     102              : gboolean
     103           91 : egg_symkey_generate_simple (int cipher_algo, int hash_algo,
     104              :                             const gchar *password, gssize n_password,
     105              :                             const guchar *salt, gsize n_salt, int iterations,
     106              :                             guchar **key, guchar **iv)
     107              : {
     108              :         gcry_md_hd_t mdh;
     109              :         gcry_error_t gcry;
     110              :         guchar *digest;
     111              :         guchar *digested;
     112              :         guint n_digest;
     113              :         gint pass, i;
     114              :         gint needed_iv, needed_key;
     115              :         guchar *at_iv, *at_key;
     116              : 
     117           91 :         g_assert (cipher_algo);
     118           91 :         g_assert (hash_algo);
     119              : 
     120           91 :         g_return_val_if_fail (iterations >= 1, FALSE);
     121              : 
     122           91 :         if (!password)
     123            3 :                 n_password = 0;
     124           91 :         if (n_password == -1)
     125            2 :                 n_password = strlen (password);
     126              : 
     127              :         /*
     128              :          * If cipher algo needs more bytes than hash algo has available
     129              :          * then the entire hashing process is done again (with the previous
     130              :          * hash bytes as extra input), and so on until satisfied.
     131              :          */
     132              : 
     133           91 :         needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
     134           91 :         needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
     135              : 
     136           91 :         gcry = gcry_md_open (&mdh, hash_algo, 0);
     137           91 :         if (gcry) {
     138            0 :                 g_warning ("couldn't create '%s' hash context: %s",
     139              :                            gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
     140            0 :                 return FALSE;
     141              :         }
     142              : 
     143           91 :         n_digest = gcry_md_get_algo_dlen (hash_algo);
     144           91 :         g_return_val_if_fail (n_digest > 0, FALSE);
     145              : 
     146           91 :         digest = egg_secure_alloc (n_digest);
     147           91 :         g_return_val_if_fail (digest, FALSE);
     148           91 :         if (key) {
     149           91 :                 *key = egg_secure_alloc (needed_key);
     150           91 :                 g_return_val_if_fail (*key, FALSE);
     151              :         }
     152           91 :         if (iv)
     153           71 :                 *iv = g_new0 (guchar, needed_iv);
     154              : 
     155           91 :         at_key = key ? *key : NULL;
     156           91 :         at_iv = iv ? *iv : NULL;
     157              : 
     158          111 :         for (pass = 0; TRUE; ++pass) {
     159          111 :                 gcry_md_reset (mdh);
     160              : 
     161              :                 /* Hash in the previous buffer on later passes */
     162          111 :                 if (pass > 0)
     163           20 :                         gcry_md_write (mdh, digest, n_digest);
     164              : 
     165          111 :                 if (password)
     166          108 :                         gcry_md_write (mdh, password, n_password);
     167          111 :                 if (salt && n_salt)
     168          111 :                         gcry_md_write (mdh, salt, n_salt);
     169          111 :                 gcry_md_final (mdh);
     170          111 :                 digested = gcry_md_read (mdh, 0);
     171          111 :                 g_return_val_if_fail (digested, FALSE);
     172          111 :                 memcpy (digest, digested, n_digest);
     173              : 
     174       135077 :                 for (i = 1; i < iterations; ++i) {
     175       134966 :                         gcry_md_reset (mdh);
     176       134966 :                         gcry_md_write (mdh, digest, n_digest);
     177       134966 :                         gcry_md_final (mdh);
     178       134966 :                         digested = gcry_md_read (mdh, 0);
     179       134966 :                         g_return_val_if_fail (digested, FALSE);
     180       134966 :                         memcpy (digest, digested, n_digest);
     181              :                 }
     182              : 
     183              :                 /* Copy as much as possible into the destinations */
     184          111 :                 i = 0;
     185         1695 :                 while (needed_key && i < n_digest) {
     186         1584 :                         if (at_key)
     187         1584 :                                 *(at_key++) = digest[i];
     188         1584 :                         needed_key--;
     189         1584 :                         i++;
     190              :                 }
     191         1439 :                 while (needed_iv && i < n_digest) {
     192         1328 :                         if (at_iv)
     193         1136 :                                 *(at_iv++) = digest[i];
     194         1328 :                         needed_iv--;
     195         1328 :                         i++;
     196              :                 }
     197              : 
     198          111 :                 if (needed_key == 0 && needed_iv == 0)
     199           91 :                         break;
     200              :         }
     201              : 
     202           91 :         egg_secure_free (digest);
     203           91 :         gcry_md_close (mdh);
     204              : 
     205           91 :         return TRUE;
     206              : }
     207              : 
     208              : gboolean
     209            6 : egg_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password,
     210              :                          gssize n_password, const guchar *salt, gsize n_salt, int iterations,
     211              :                          guchar **key, guchar **iv)
     212              : {
     213              :         gcry_md_hd_t mdh;
     214              :         gcry_error_t gcry;
     215              :         guchar *digest;
     216              :         guchar *digested;
     217              :         guint i, n_digest;
     218              :         gint needed_iv, needed_key;
     219              : 
     220            6 :         g_assert (cipher_algo);
     221            6 :         g_assert (hash_algo);
     222              : 
     223            6 :         g_return_val_if_fail (iterations >= 1, FALSE);
     224              : 
     225            6 :         if (!password)
     226            0 :                 n_password = 0;
     227            6 :         if (n_password == -1)
     228            1 :                 n_password = strlen (password);
     229              : 
     230              :         /*
     231              :          * We only do one pass here.
     232              :          *
     233              :          * The key ends up as the first needed_key bytes of the hash buffer.
     234              :          * The iv ends up as the last needed_iv bytes of the hash buffer.
     235              :          *
     236              :          * The IV may overlap the key (which is stupid) if the wrong pair of
     237              :          * hash/cipher algorithms are chosen.
     238              :          */
     239              : 
     240            6 :         n_digest = gcry_md_get_algo_dlen (hash_algo);
     241            6 :         g_return_val_if_fail (n_digest > 0, FALSE);
     242              : 
     243            6 :         needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
     244            6 :         needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
     245            6 :         if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) {
     246            0 :                 g_warning ("using PBE symkey generation with %s using an algorithm that needs "
     247              :                            "too many bytes of key and/or IV: %s",
     248              :                            gcry_cipher_algo_name (hash_algo),
     249              :                            gcry_cipher_algo_name (cipher_algo));
     250            0 :                 return FALSE;
     251              :         }
     252              : 
     253            6 :         gcry = gcry_md_open (&mdh, hash_algo, 0);
     254            6 :         if (gcry) {
     255            0 :                 g_warning ("couldn't create '%s' hash context: %s",
     256              :                            gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
     257            0 :                 return FALSE;
     258              :         }
     259              : 
     260            6 :         digest = egg_secure_alloc (n_digest);
     261            6 :         g_return_val_if_fail (digest, FALSE);
     262            6 :         if (key) {
     263            6 :                 *key = egg_secure_alloc (needed_key);
     264            6 :                 g_return_val_if_fail (*key, FALSE);
     265              :         }
     266            6 :         if (iv)
     267            5 :                 *iv = g_new0 (guchar, needed_iv);
     268              : 
     269            6 :         if (password)
     270            6 :                 gcry_md_write (mdh, password, n_password);
     271            6 :         if (salt && n_salt)
     272            6 :                 gcry_md_write (mdh, salt, n_salt);
     273            6 :         gcry_md_final (mdh);
     274            6 :         digested = gcry_md_read (mdh, 0);
     275            6 :         g_return_val_if_fail (digested, FALSE);
     276            6 :         memcpy (digest, digested, n_digest);
     277              : 
     278        10282 :         for (i = 1; i < iterations; ++i)
     279        10276 :                 gcry_md_hash_buffer (hash_algo, digest, digest, n_digest);
     280              : 
     281              :         /* The first x bytes are the key */
     282            6 :         if (key) {
     283            6 :                 g_assert (needed_key <= n_digest);
     284            6 :                 memcpy (*key, digest, needed_key);
     285              :         }
     286              : 
     287              :         /* The last 16 - x bytes are the iv */
     288            6 :         if (iv) {
     289            5 :                 g_assert (needed_iv <= n_digest && n_digest >= 16);
     290            5 :                 memcpy (*iv, digest + (16 - needed_iv), needed_iv);
     291              :         }
     292              : 
     293            6 :         egg_secure_free (digest);
     294            6 :         gcry_md_close (mdh);
     295              : 
     296            6 :         return TRUE;
     297              : }
     298              : 
     299              : static gboolean
     300           30 : generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password,
     301              :                  gssize n_password, const guchar *salt, gsize n_salt,
     302              :                  int iterations, guchar *output, gsize n_output)
     303              : {
     304              :         gcry_mpi_t num_b1, num_ij;
     305              :         guchar *hash, *buf_i, *buf_b;
     306              :         const gchar *end_password;
     307              :         gcry_md_hd_t mdh;
     308              :         const gchar *p2;
     309              :         guchar *p;
     310              :         gsize n_hash, i;
     311              :         gunichar unich;
     312              :         gcry_error_t gcry;
     313              :         gsize length;
     314              : 
     315           30 :         num_b1 = num_ij = NULL;
     316              : 
     317           30 :         n_hash = gcry_md_get_algo_dlen (hash_algo);
     318           30 :         g_return_val_if_fail (n_hash > 0, FALSE);
     319              : 
     320           30 :         if (!utf8_password)
     321            1 :                 n_password = 0;
     322           30 :         if (n_password == -1)
     323            3 :                 end_password = utf8_password + strlen (utf8_password);
     324              :         else
     325           27 :                 end_password = utf8_password + n_password;
     326              : 
     327           30 :         gcry = gcry_md_open (&mdh, hash_algo, 0);
     328           30 :         if (gcry) {
     329            0 :                 g_warning ("couldn't create '%s' hash context: %s",
     330              :                            gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
     331            0 :                 return FALSE;
     332              :         }
     333              : 
     334              :         /* Reqisition me a buffer */
     335           30 :         hash = egg_secure_alloc (n_hash);
     336           30 :         buf_i = egg_secure_alloc (128);
     337           30 :         buf_b = egg_secure_alloc (64);
     338           30 :         g_return_val_if_fail (hash && buf_i && buf_b, FALSE);
     339              : 
     340              :         /* Bring in the salt */
     341           30 :         p = buf_i;
     342           30 :         if (salt) {
     343         1950 :                 for (i = 0; i < 64; ++i)
     344         1920 :                         *(p++) = salt[i % n_salt];
     345              :         } else {
     346            0 :                 memset (p, 0, 64);
     347            0 :                 p += 64;
     348              :         }
     349              : 
     350              :         /* Bring in the password, as 16bits per character BMP string, ie: UCS2 */
     351           30 :         if (utf8_password) {
     352           29 :                 p2 = utf8_password;
     353          957 :                 for (i = 0; i < 64; i += 2) {
     354              : 
     355              :                         /* Get a character from the string */
     356          928 :                         if (p2 < end_password) {
     357          751 :                                 unich = g_utf8_get_char (p2);
     358          751 :                                 p2 = g_utf8_next_char (p2);
     359              : 
     360              :                         /* Get zero null terminator, and loop back to beginning */
     361              :                         } else {
     362          177 :                                 unich = 0;
     363          177 :                                 p2 = utf8_password;
     364              :                         }
     365              : 
     366              :                         /* Encode the bytes received */
     367          928 :                         *(p++) = (unich & 0xFF00) >> 8;
     368          928 :                         *(p++) = (unich & 0xFF);
     369              :                 }
     370              :         } else {
     371            1 :                 memset (p, 0, 64);
     372              :         }
     373              : 
     374              :         /* Hash and bash */
     375              :         for (;;) {
     376           43 :                 gcry_md_reset (mdh);
     377              : 
     378              :                 /* Put in the PKCS#12 type of key */
     379         2795 :                 for (i = 0; i < 64; ++i)
     380         2752 :                         gcry_md_putc (mdh, type);
     381              : 
     382              :                 /* Bring in the password */
     383           43 :                 gcry_md_write (mdh, buf_i, utf8_password ? 128 : 64);
     384              : 
     385              :                 /* First iteration done */
     386           43 :                 memcpy (hash, gcry_md_read (mdh, hash_algo), n_hash);
     387              : 
     388              :                 /* All the other iterations */
     389       106992 :                 for (i = 1; i < iterations; i++)
     390       106949 :                         gcry_md_hash_buffer (hash_algo, hash, hash, n_hash);
     391              : 
     392              :                 /* Take out as much as we need */
     393          502 :                 for (i = 0; i < n_hash && n_output; ++i) {
     394          459 :                         *(output++) = hash[i];
     395          459 :                         --n_output;
     396              :                 }
     397              : 
     398              :                 /* Is that enough generated keying material? */
     399           43 :                 if (!n_output)
     400           30 :                         break;
     401              : 
     402              :                 /* Need more bytes, do some voodoo */
     403          845 :                 for (i = 0; i < 64; ++i)
     404          832 :                         buf_b[i] = hash[i % n_hash];
     405           13 :                 gcry = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, NULL);
     406           13 :                 g_return_val_if_fail (gcry == 0, FALSE);
     407           13 :                 gcry_mpi_add_ui (num_b1, num_b1, 1);
     408           39 :                 for (i = 0; i < 128; i += 64) {
     409           26 :                         gcry = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, NULL);
     410           26 :                         g_return_val_if_fail (gcry == 0, FALSE);
     411           26 :                         gcry_mpi_add (num_ij, num_ij, num_b1);
     412           26 :                         gcry_mpi_clear_highbit (num_ij, 64 * 8);
     413              :                         /* We take special care to right align the number in the buffer */
     414           26 :                         gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &length, num_ij);
     415           26 :                         g_return_val_if_fail (gcry == 0 && length <= 64, FALSE);
     416           26 :                         memset (buf_i + i, 0, 64 - length);
     417           26 :                         gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i + (64 - length), 64, NULL, num_ij);
     418           26 :                         g_return_val_if_fail (gcry == 0, FALSE);
     419           26 :                         gcry_mpi_release (num_ij);
     420              :                 }
     421              :         }
     422              : 
     423           30 :         egg_secure_free (buf_i);
     424           30 :         egg_secure_free (buf_b);
     425           30 :         egg_secure_free (hash);
     426           30 :         gcry_mpi_release (num_b1);
     427           30 :         gcry_md_close (mdh);
     428              : 
     429           30 :         return TRUE;
     430              : }
     431              : 
     432              : gboolean
     433           17 : egg_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password,
     434              :                             gssize n_password, const guchar *salt, gsize n_salt,
     435              :                             int iterations, guchar **key, guchar **iv)
     436              : {
     437              :         gsize n_block, n_key;
     438           17 :         gboolean ret = TRUE;
     439              : 
     440           17 :         g_return_val_if_fail (cipher_algo, FALSE);
     441           17 :         g_return_val_if_fail (hash_algo, FALSE);
     442           17 :         g_return_val_if_fail (iterations > 0, FALSE);
     443              : 
     444           17 :         n_key = gcry_cipher_get_algo_keylen (cipher_algo);
     445           17 :         n_block = gcry_cipher_get_algo_blklen (cipher_algo);
     446              : 
     447           17 :         if (password && !g_utf8_validate (password, n_password, NULL)) {
     448            0 :                 g_warning ("invalid non-UTF8 password");
     449            0 :                 g_return_val_if_reached (FALSE);
     450              :         }
     451              : 
     452           17 :         if (key)
     453           17 :                 *key = NULL;
     454           17 :         if (iv)
     455           12 :                 *iv = NULL;
     456              : 
     457              :         /* Generate us an key */
     458           17 :         if (key) {
     459           17 :                 *key = egg_secure_alloc (n_key);
     460           17 :                 g_return_val_if_fail (*key != NULL, FALSE);
     461           17 :                 ret = generate_pkcs12 (hash_algo, 1, password, n_password, salt, n_salt,
     462              :                                        iterations, *key, n_key);
     463              :         }
     464              : 
     465              :         /* Generate us an iv */
     466           17 :         if (ret && iv) {
     467           12 :                 if (n_block > 1) {
     468           12 :                         *iv = g_malloc (n_block);
     469           12 :                         ret = generate_pkcs12 (hash_algo, 2, password, n_password, salt, n_salt,
     470              :                                                iterations, *iv, n_block);
     471              :                 } else {
     472            0 :                         *iv = NULL;
     473              :                 }
     474              :         }
     475              : 
     476              :         /* Cleanup in case of failure */
     477           17 :         if (!ret) {
     478            0 :                 g_free (iv ? *iv : NULL);
     479            0 :                 egg_secure_free (key ? *key : NULL);
     480              :         }
     481              : 
     482           17 :         return ret;
     483              : }
     484              : 
     485              : gboolean
     486            1 : egg_symkey_generate_pkcs12_mac (int hash_algo,
     487              :                                 const gchar *password,
     488              :                                 gssize n_password,
     489              :                                 const guchar *salt,
     490              :                                 gsize n_salt,
     491              :                                 int iterations,
     492              :                                 guchar **key)
     493              : {
     494              :         gsize n_key;
     495            1 :         gboolean ret = TRUE;
     496              : 
     497            1 :         g_return_val_if_fail (hash_algo, FALSE);
     498            1 :         g_return_val_if_fail (iterations > 0, FALSE);
     499              : 
     500            1 :         n_key = gcry_md_get_algo_dlen (hash_algo);
     501              : 
     502            1 :         if (password && !g_utf8_validate (password, n_password, NULL)) {
     503            0 :                 g_warning ("invalid non-UTF8 password");
     504            0 :                 g_return_val_if_reached (FALSE);
     505              :         }
     506              : 
     507              :         /* Generate us an key */
     508            1 :         if (key) {
     509            1 :                 *key = egg_secure_alloc (n_key);
     510            1 :                 g_return_val_if_fail (*key != NULL, FALSE);
     511            1 :                 ret = generate_pkcs12 (hash_algo, 3, password, n_password, salt, n_salt,
     512              :                                        iterations, *key, n_key);
     513              :         }
     514              : 
     515              :         /* Cleanup in case of failure */
     516            1 :         if (!key)
     517            0 :                 egg_secure_free (key ? *key : NULL);
     518              : 
     519            1 :         return ret;
     520              : }
     521              : 
     522              : static gboolean
     523           13 : generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
     524              :                  const guchar *salt, gsize n_salt, guint iterations,
     525              :                  guchar *output, gsize n_output)
     526              : {
     527              :         gcry_md_hd_t mdh;
     528              :         guint u, l, r, i, k;
     529              :         gcry_error_t gcry;
     530              :         guchar *U, *T, *buf;
     531              :         gsize n_buf, n_hash;
     532              : 
     533           13 :         g_return_val_if_fail (hash_algo > 0, FALSE);
     534           13 :         g_return_val_if_fail (iterations > 0, FALSE);
     535           13 :         g_return_val_if_fail (n_output > 0, FALSE);
     536           13 :         g_return_val_if_fail (n_output < G_MAXUINT32, FALSE);
     537              : 
     538           13 :         n_hash = gcry_md_get_algo_dlen (hash_algo);
     539           13 :         g_return_val_if_fail (n_hash > 0, FALSE);
     540              : 
     541           13 :         gcry = gcry_md_open (&mdh, hash_algo, GCRY_MD_FLAG_HMAC);
     542           13 :         if (gcry != 0) {
     543            0 :                 g_warning ("couldn't create '%s' hash context: %s",
     544              :                            gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
     545            0 :                 return FALSE;
     546              :         }
     547              : 
     548              :         /* Get us a temporary buffers */
     549           13 :         T = egg_secure_alloc (n_hash);
     550           13 :         U = egg_secure_alloc (n_hash);
     551           13 :         n_buf = n_salt + 4;
     552           13 :         buf = egg_secure_alloc (n_buf);
     553           13 :         g_return_val_if_fail (buf && T && U, FALSE);
     554              : 
     555              :         /* n_hash blocks in output, rounding up */
     556           13 :         l = ((n_output - 1) / n_hash) + 1;
     557              : 
     558              :         /* number of bytes in last, rounded up, n_hash block */
     559           13 :         r = n_output - (l - 1) * n_hash;
     560              : 
     561           13 :         memcpy (buf, salt, n_salt);
     562           37 :         for (i = 1; i <= l; i++) {
     563           24 :                 memset (T, 0, n_hash);
     564        43131 :                 for (u = 1; u <= iterations; u++) {
     565        43107 :                         gcry_md_reset (mdh);
     566              : 
     567        43107 :                         gcry = gcry_md_setkey (mdh, password, n_password);
     568        43107 :                         g_return_val_if_fail (gcry == 0, FALSE);
     569              : 
     570              :                         /* For first iteration on each block add 4 extra bytes */
     571        43107 :                         if (u == 1) {
     572           24 :                                 buf[n_salt + 0] = (i & 0xff000000) >> 24;
     573           24 :                                 buf[n_salt + 1] = (i & 0x00ff0000) >> 16;
     574           24 :                                 buf[n_salt + 2] = (i & 0x0000ff00) >> 8;
     575           24 :                                 buf[n_salt + 3] = (i & 0x000000ff) >> 0;
     576              : 
     577           24 :                                 gcry_md_write (mdh, buf, n_buf);
     578              : 
     579              :                         /* Other iterations, any block */
     580              :                         } else {
     581        43083 :                                 gcry_md_write (mdh, U, n_hash);
     582              :                         }
     583              : 
     584        43107 :                         memcpy (U, gcry_md_read (mdh, hash_algo), n_hash);
     585              : 
     586       905247 :                         for (k = 0; k < n_hash; k++)
     587       862140 :                                 T[k] ^= U[k];
     588              :                 }
     589              : 
     590           24 :                 memcpy (output + (i - 1) * n_hash, T, i == l ? r : n_hash);
     591              :         }
     592              : 
     593           13 :         egg_secure_free (T);
     594           13 :         egg_secure_free (U);
     595           13 :         egg_secure_free (buf);
     596           13 :         gcry_md_close (mdh);
     597           13 :         return TRUE;
     598              : }
     599              : 
     600              : gboolean
     601           13 : egg_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo,
     602              :                             const gchar *password, gssize n_password,
     603              :                             const guchar *salt, gsize n_salt, int iterations,
     604              :                             guchar **key, guchar **iv)
     605              : {
     606              :         gsize n_key, n_block;
     607           13 :         gboolean ret = TRUE;
     608              : 
     609           13 :         g_return_val_if_fail (hash_algo, FALSE);
     610           13 :         g_return_val_if_fail (cipher_algo, FALSE);
     611           13 :         g_return_val_if_fail (iterations > 0, FALSE);
     612              : 
     613           13 :         n_key = gcry_cipher_get_algo_keylen (cipher_algo);
     614           13 :         n_block = gcry_cipher_get_algo_blklen (cipher_algo);
     615              : 
     616           13 :         if (key)
     617           13 :                 *key = NULL;
     618           13 :         if (iv)
     619            0 :                 *iv = NULL;
     620              : 
     621           13 :         if (!password)
     622            3 :                 n_password = 0;
     623           13 :         if (n_password == -1)
     624            2 :                 n_password = strlen (password);
     625              : 
     626              :         /* Generate us an key */
     627           13 :         if (key) {
     628           13 :                 *key = egg_secure_alloc (n_key);
     629           13 :                 g_return_val_if_fail (*key != NULL, FALSE);
     630           13 :                 ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt,
     631              :                                        iterations, *key, n_key);
     632              :         }
     633              : 
     634              :         /* Generate us an iv */
     635           13 :         if (ret && iv) {
     636            0 :                 if (n_block > 1) {
     637            0 :                         *iv = g_malloc (n_block);
     638            0 :                         gcry_create_nonce (*iv, n_block);
     639              :                 } else {
     640            0 :                         *iv = NULL;
     641              :                 }
     642              :         }
     643              : 
     644              :         /* Cleanup in case of failure */
     645           13 :         if (!ret) {
     646            0 :                 g_free (iv ? *iv : NULL);
     647            0 :                 egg_secure_free (key ? *key : NULL);
     648              :         }
     649              : 
     650           13 :         return ret;
     651              : }
     652              : 
     653              : /* ----------------------------------------------------------------------------
     654              :  * DER encoded cipher params
     655              :  */
     656              : 
     657              : 
     658              : static gboolean
     659            6 : read_cipher_pkcs5_pbe (int cipher_algo,
     660              :                        int cipher_mode,
     661              :                        int hash_algo,
     662              :                        const gchar *password,
     663              :                        gsize n_password,
     664              :                        GNode *data,
     665              :                        gcry_cipher_hd_t *cih)
     666              : {
     667            6 :         GNode *asn = NULL;
     668              :         gcry_error_t gcry;
     669            6 :         GBytes *salt = NULL;
     670              :         gsize n_block, n_key;
     671              :         gulong iterations;
     672            6 :         guchar *key = NULL;
     673            6 :         guchar *iv = NULL;
     674              :         gboolean ret;
     675              : 
     676            6 :         g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, FALSE);
     677            6 :         g_return_val_if_fail (cih != NULL, FALSE);
     678            6 :         g_return_val_if_fail (data != NULL, FALSE);
     679              : 
     680            6 :         *cih = NULL;
     681            6 :         ret = FALSE;
     682              : 
     683              :         /* Check if we can use this algorithm */
     684           12 :         if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 ||
     685            6 :             gcry_md_test_algo (hash_algo) != 0)
     686            0 :                 goto done;
     687              : 
     688            6 :         asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
     689            6 :         g_return_val_if_fail (asn, FALSE);
     690              : 
     691            6 :         if (!egg_asn1x_get_any_into (data, asn))
     692            1 :                 goto done;
     693              : 
     694            5 :         salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
     695            5 :         g_return_val_if_fail (salt != NULL, FALSE);
     696            5 :         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
     697            0 :                 g_return_val_if_reached (FALSE);
     698              : 
     699            5 :         n_key = gcry_cipher_get_algo_keylen (cipher_algo);
     700            5 :         g_return_val_if_fail (n_key > 0, FALSE);
     701            5 :         n_block = gcry_cipher_get_algo_blklen (cipher_algo);
     702              : 
     703           10 :         if (!egg_symkey_generate_pbe (cipher_algo, hash_algo, password, n_password,
     704            5 :                                       g_bytes_get_data (salt, NULL), g_bytes_get_size (salt),
     705              :                                       iterations, &key, n_block > 1 ? &iv : NULL))
     706            0 :                 goto done;
     707              : 
     708            5 :         gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
     709            5 :         if (gcry != 0) {
     710            0 :                 g_warning ("couldn't create cipher: %s", gcry_strerror (gcry));
     711            0 :                 goto done;
     712              :         }
     713              : 
     714            5 :         if (iv)
     715            5 :                 gcry_cipher_setiv (*cih, iv, n_block);
     716            5 :         gcry_cipher_setkey (*cih, key, n_key);
     717              : 
     718            5 :         ret = TRUE;
     719              : 
     720            6 : done:
     721            6 :         g_free (iv);
     722            6 :         if (salt != NULL)
     723            5 :                 g_bytes_unref (salt);
     724            6 :         egg_secure_free (key);
     725            6 :         egg_asn1x_destroy (asn);
     726              : 
     727            6 :         return ret;
     728              : }
     729              : 
     730              : #if NOT_SUPPORTED
     731              : static gboolean
     732              : setup_pkcs5_rc2_params (GNode *any,
     733              :                         gcry_cipher_hd_t cih)
     734              : {
     735              :         GNode *asn = NULL;
     736              :         gcry_error_t gcry;
     737              :         GBytes *iv = NULL;
     738              :         gulong version;
     739              :         gboolean ret = FALSE;
     740              : 
     741              :         g_assert (any != NULL);
     742              : 
     743              :         asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
     744              :         if (asn == NULL)
     745              :                 goto done;
     746              : 
     747              :         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "rc2ParameterVersion", NULL), &version))
     748              :                 goto done;
     749              : 
     750              :         iv = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "iv", NULL));
     751              :         if (!iv)
     752              :                 goto done;
     753              : 
     754              :         gcry = gcry_cipher_setiv (cih, g_bytes_get_data (iv, NULL), g_bytes_get_size (iv));
     755              :         if (gcry != 0) {
     756              :                 g_message ("couldn't set %lu byte iv on cipher", (gulong)g_bytes_get_size (iv));
     757              :                 goto done;
     758              :         }
     759              : 
     760              :         ret = TRUE;
     761              : 
     762              : done:
     763              :         if (iv != NULL)
     764              :                 g_bytes_unref (iv);
     765              :         egg_asn1x_destroy (asn);
     766              :         return ret;
     767              : }
     768              : #endif
     769              : 
     770              : static gboolean
     771           15 : setup_pkcs5_des_params (GNode *any,
     772              :                         gcry_cipher_hd_t cih)
     773              : {
     774           15 :         GNode *asn = NULL;
     775              :         gcry_error_t gcry;
     776              :         GBytes *iv;
     777              :         gboolean ret;
     778              : 
     779           15 :         g_assert (any != NULL);
     780              : 
     781           15 :         asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params");
     782           15 :         if (!asn)
     783            1 :                 asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-des-CBC-params");
     784           15 :         if (!asn)
     785            1 :                 return FALSE;
     786              : 
     787           14 :         iv = egg_asn1x_get_string_as_bytes (asn);
     788           14 :         egg_asn1x_destroy (asn);
     789              : 
     790           14 :         if (!iv)
     791            0 :                 return FALSE;
     792              : 
     793           14 :         gcry = gcry_cipher_setiv (cih, g_bytes_get_data (iv, NULL), g_bytes_get_size (iv));
     794           14 :         if (gcry != 0) {
     795            0 :                 g_message ("couldn't set %lu byte iv on cipher", (gulong)g_bytes_get_size (iv));
     796            0 :                 ret = FALSE;
     797              :         } else {
     798           14 :                 ret = TRUE;
     799              :         }
     800              : 
     801           14 :         g_bytes_unref (iv);
     802           14 :         return ret;
     803              : }
     804              : 
     805              : static gboolean
     806           13 : setup_pkcs5_pbkdf2_params (const gchar *password,
     807              :                            gsize n_password,
     808              :                            GNode *any,
     809              :                            int cipher_algo,
     810              :                            gcry_cipher_hd_t cih)
     811              : {
     812           13 :         GNode *asn = NULL;
     813              :         gboolean ret;
     814              :         gcry_error_t gcry;
     815           13 :         guchar *key = NULL;
     816           13 :         GBytes *salt = NULL;
     817              :         gsize n_key;
     818              :         gulong iterations;
     819              : 
     820           13 :         g_assert (cipher_algo);
     821           13 :         g_assert (any != NULL);
     822              : 
     823           13 :         ret = FALSE;
     824              : 
     825           13 :         asn = egg_asn1x_get_any_as (any, pkix_asn1_tab, "pkcs-5-PBKDF2-params");
     826           13 :         if (!asn)
     827            1 :                 goto done;
     828              : 
     829           12 :         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
     830            0 :                 g_return_val_if_reached (FALSE);
     831           12 :         salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", "specified", NULL));
     832           12 :         if (!salt)
     833            1 :                 goto done;
     834              : 
     835           22 :         if (!egg_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, n_password,
     836           11 :                                          g_bytes_get_data (salt, NULL), g_bytes_get_size (salt),
     837              :                                          iterations, &key, NULL))
     838            0 :                 goto done;
     839              : 
     840           11 :         n_key = gcry_cipher_get_algo_keylen (cipher_algo);
     841           11 :         g_return_val_if_fail (n_key > 0, FALSE);
     842              : 
     843           11 :         gcry = gcry_cipher_setkey (cih, key, n_key);
     844           11 :         if (gcry != 0) {
     845            0 :                 g_message ("couldn't set %lu byte key on cipher", (gulong)n_key);
     846            0 :                 goto done;
     847              :         }
     848              : 
     849           11 :         ret = TRUE;
     850              : 
     851           13 : done:
     852           13 :         if (salt != NULL)
     853           11 :                 g_bytes_unref (salt);
     854           13 :         egg_secure_free (key);
     855           13 :         egg_asn1x_destroy (asn);
     856           13 :         return ret;
     857              : }
     858              : 
     859              : static gboolean
     860           17 : read_cipher_pkcs5_pbes2 (const gchar *password,
     861              :                          gsize n_password,
     862              :                          GNode *data,
     863              :                          gcry_cipher_hd_t *cih)
     864              : {
     865           17 :         GNode *asn = NULL;
     866              :         gboolean r, ret;
     867              :         GQuark key_deriv_algo, enc_oid;
     868           17 :         GNode *params = NULL;
     869              :         gcry_error_t gcry;
     870              :         int algo, mode;
     871              : 
     872           17 :         g_return_val_if_fail (cih != NULL, FALSE);
     873           17 :         g_return_val_if_fail (data != NULL, FALSE);
     874              : 
     875           17 :         init_quarks ();
     876              : 
     877           17 :         *cih = NULL;
     878           17 :         ret = FALSE;
     879              : 
     880           17 :         asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-5-PBES2-params");
     881           17 :         if (!asn)
     882            1 :                 goto done;
     883              : 
     884           16 :         algo = mode = 0;
     885              : 
     886              :         /* Read in all the encryption type */
     887           16 :         enc_oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionScheme", "algorithm", NULL));
     888           16 :         if (!enc_oid)
     889            0 :                 goto done;
     890           16 :         if (enc_oid == OID_DES_EDE3_CBC)
     891           13 :                 algo = GCRY_CIPHER_3DES;
     892            3 :         else if (enc_oid == OID_DES_CBC)
     893            2 :                 algo = GCRY_CIPHER_DES;
     894            1 :         else if (enc_oid == OID_DES_RC2_CBC)
     895              :                 /* GCRY_CIPHER_RFC2268_128 isn't actually implemented in libgcrypt (yet?) */;
     896            1 :         else if (enc_oid == OID_DES_RC5_CBC)
     897              :                 /* RC5 doesn't exist in libgcrypt */;
     898              : 
     899              :         /* Unsupported? */
     900           16 :         if (algo == 0 || gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
     901            1 :                 goto done;
     902              : 
     903              :         /* Instantiate our cipher */
     904           15 :         gcry = gcry_cipher_open (cih, algo, GCRY_CIPHER_MODE_CBC, 0);
     905           15 :         if (gcry != 0) {
     906            0 :                 g_warning ("couldn't create cipher: %s", gcry_cipher_algo_name (algo)); /* UNREACHABLE: */
     907            0 :                 goto done; /* UNREACHABLE: with normal libgcrypt behavior */
     908              :         }
     909              : 
     910              :         /* Read out the parameters. OPTIONAL, but will always find node */
     911           15 :         params = egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL);
     912           15 :         g_return_val_if_fail (params != NULL, FALSE);
     913              : 
     914           15 :         switch (algo) {
     915           15 :         case GCRY_CIPHER_3DES:
     916              :         case GCRY_CIPHER_DES:
     917           15 :                 r = setup_pkcs5_des_params (params, *cih);
     918           15 :                 break;
     919              : #if 0
     920              :         case GCRY_CIPHER_RFC2268_128:
     921              :                 r = setup_pkcs5_rc2_params (params, *cih);
     922              :                 break;
     923              : #endif
     924            0 :         default:
     925              :                 /* Should have been caught on the oid check above */
     926            0 :                 g_assert_not_reached ();
     927              :                 r = FALSE;
     928              :                 break;
     929              :         };
     930              : 
     931           15 :         if (r != TRUE)
     932            1 :                 goto done;
     933              : 
     934              :         /* Read out the key creation paramaters */
     935           14 :         key_deriv_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "keyDerivationFunc", "algorithm", NULL));
     936           14 :         if (!key_deriv_algo)
     937            0 :                 goto done;
     938           14 :         if (key_deriv_algo != OID_PBKDF2) {
     939            1 :                 g_message ("unsupported key derivation algorithm: %s", g_quark_to_string (key_deriv_algo));
     940            1 :                 goto done;
     941              :         }
     942              : 
     943              :         /* parameters is OPTIONAL, but will always find node */
     944           13 :         params = egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL);
     945           13 :         g_return_val_if_fail (params != NULL, FALSE);
     946              : 
     947           13 :         ret = setup_pkcs5_pbkdf2_params (password, n_password, params, algo, *cih);
     948              : 
     949           17 : done:
     950           17 :         if (ret != TRUE && *cih) {
     951            4 :                 gcry_cipher_close (*cih);
     952            4 :                 *cih = NULL;
     953              :         }
     954              : 
     955           17 :         egg_asn1x_destroy (asn);
     956           17 :         return ret;
     957              : }
     958              : 
     959              : static gboolean
     960            9 : read_cipher_pkcs12_pbe (int cipher_algo,
     961              :                         int cipher_mode,
     962              :                         const gchar *password,
     963              :                         gsize n_password,
     964              :                         GNode *data,
     965              :                         gcry_cipher_hd_t *cih)
     966              : {
     967            9 :         GNode *asn = NULL;
     968              :         gcry_error_t gcry;
     969              :         gboolean ret;
     970            9 :         GBytes *salt = NULL;
     971              :         gsize n_block, n_key;
     972              :         gulong iterations;
     973            9 :         guchar *key = NULL;
     974            9 :         guchar *iv = NULL;
     975              : 
     976            9 :         g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, FALSE);
     977            9 :         g_return_val_if_fail (cih != NULL, FALSE);
     978            9 :         g_return_val_if_fail (data != NULL, FALSE);
     979              : 
     980            9 :         *cih = NULL;
     981            9 :         ret = FALSE;
     982              : 
     983              :         /* Check if we can use this algorithm */
     984            9 :         if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
     985            0 :                 goto done;
     986              : 
     987            9 :         asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-PbeParams");
     988            9 :         if (!asn)
     989            1 :                 goto done;
     990              : 
     991            8 :         salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (asn, "salt", NULL));
     992            8 :         g_return_val_if_fail (salt != NULL, FALSE);
     993            8 :         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
     994            0 :                 g_return_val_if_reached (FALSE);
     995              : 
     996            8 :         n_block = gcry_cipher_get_algo_blklen (cipher_algo);
     997            8 :         n_key = gcry_cipher_get_algo_keylen (cipher_algo);
     998              : 
     999              :         /* Generate IV and key using salt read above */
    1000           16 :         if (!egg_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password, n_password,
    1001            8 :                                          g_bytes_get_data (salt, NULL), g_bytes_get_size (salt),
    1002              :                                          iterations, &key, n_block > 1 ? &iv : NULL))
    1003            0 :                 goto done;
    1004              : 
    1005            8 :         gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
    1006            8 :         if (gcry != 0) {
    1007            0 :                 g_warning ("couldn't create encryption cipher: %s", gcry_strerror (gcry));
    1008            0 :                 goto done;
    1009              :         }
    1010              : 
    1011            8 :         if (iv)
    1012            7 :                 gcry_cipher_setiv (*cih, iv, n_block);
    1013            8 :         gcry_cipher_setkey (*cih, key, n_key);
    1014              : 
    1015            8 :         ret = TRUE;
    1016              : 
    1017            9 : done:
    1018            9 :         if (ret != TRUE && *cih) {
    1019            0 :                 gcry_cipher_close (*cih);
    1020            0 :                 *cih = NULL;
    1021              :         }
    1022              : 
    1023            9 :         if (salt != NULL)
    1024            8 :                 g_bytes_unref (salt);
    1025            9 :         g_free (iv);
    1026            9 :         egg_secure_free (key);
    1027            9 :         egg_asn1x_destroy (asn);
    1028            9 :         return ret;
    1029              : }
    1030              : 
    1031              : static gboolean
    1032            2 : read_mac_pkcs12_pbe (int hash_algo,
    1033              :                      const gchar *password,
    1034              :                      gsize n_password,
    1035              :                      GNode *data,
    1036              :                      gcry_md_hd_t *mdh,
    1037              :                      gsize *digest_len)
    1038              : {
    1039            2 :         GNode *asn = NULL;
    1040              :         gcry_error_t gcry;
    1041              :         gboolean ret;
    1042              :         gsize n_key;
    1043            2 :         GBytes *salt = NULL;
    1044              :         gulong iterations;
    1045            2 :         guchar *key = NULL;
    1046              : 
    1047            2 :         g_return_val_if_fail (hash_algo != 0, FALSE);
    1048            2 :         g_return_val_if_fail (mdh != NULL, FALSE);
    1049            2 :         g_return_val_if_fail (data != NULL, FALSE);
    1050              : 
    1051            2 :         *mdh = NULL;
    1052            2 :         ret = FALSE;
    1053              : 
    1054              :         /* Check if we can use this algorithm */
    1055            2 :         if (gcry_md_algo_info (hash_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
    1056            0 :                 goto done; /* UNREACHABLE: unless libgcrypt changes behavior */
    1057              : 
    1058            2 :         if (egg_asn1x_type (data) == EGG_ASN1X_ANY) {
    1059            2 :                 asn = egg_asn1x_get_any_as (data, pkix_asn1_tab, "pkcs-12-MacData");
    1060            2 :                 if (!asn)
    1061            1 :                         goto done;
    1062            1 :                 data = asn;
    1063              :         }
    1064              : 
    1065            1 :         salt = egg_asn1x_get_string_as_bytes (egg_asn1x_node (data, "macSalt", NULL));
    1066            1 :         if (!salt)
    1067            0 :                 g_return_val_if_reached (FALSE);
    1068            1 :         if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (data, "iterations", NULL), &iterations))
    1069            0 :                 g_return_val_if_reached (FALSE);
    1070              : 
    1071            1 :         n_key = gcry_md_get_algo_dlen (hash_algo);
    1072              : 
    1073              :         /* Generate IV and key using salt read above */
    1074            2 :         if (!egg_symkey_generate_pkcs12_mac (hash_algo, password, n_password,
    1075            1 :                                              g_bytes_get_data (salt, NULL), g_bytes_get_size (salt),
    1076              :                                              iterations, &key))
    1077            0 :                 goto done;
    1078              : 
    1079            1 :         gcry = gcry_md_open (mdh, hash_algo, GCRY_MD_FLAG_HMAC);
    1080            1 :         if (gcry != 0) {
    1081            0 :                 g_warning ("couldn't create mac digest: %s", gcry_strerror (gcry));
    1082            0 :                 goto done;
    1083              :         }
    1084              : 
    1085            1 :         if (digest_len)
    1086            1 :                 *digest_len = n_key;
    1087            1 :         gcry_md_setkey (*mdh, key, n_key);
    1088              : 
    1089            1 :         ret = TRUE;
    1090              : 
    1091            2 : done:
    1092            2 :         if (ret != TRUE && *mdh) {
    1093            0 :                 gcry_md_close (*mdh);
    1094            0 :                 *mdh = NULL;
    1095              :         }
    1096              : 
    1097            2 :         if (salt != NULL)
    1098            1 :                 g_bytes_unref (salt);
    1099            2 :         egg_secure_free (key);
    1100            2 :         egg_asn1x_destroy (asn);
    1101            2 :         return ret;
    1102              : }
    1103              : 
    1104              : gboolean
    1105           32 : egg_symkey_read_cipher (GQuark oid_scheme,
    1106              :                         const gchar *password,
    1107              :                         gsize n_password,
    1108              :                         GNode *data,
    1109              :                         gcry_cipher_hd_t *cih)
    1110              : {
    1111           32 :         gboolean ret = FALSE;
    1112              : 
    1113           32 :         g_return_val_if_fail (oid_scheme != 0, FALSE);
    1114           32 :         g_return_val_if_fail (cih != NULL, FALSE);
    1115           32 :         g_return_val_if_fail (data != NULL, FALSE);
    1116              : 
    1117           32 :         init_quarks ();
    1118              : 
    1119              :         /* PKCS#5 PBE */
    1120           32 :         if (oid_scheme == OID_PBE_MD2_DES_CBC)
    1121            0 :                 ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
    1122              :                                              GCRY_MD_MD2, password, n_password, data, cih);
    1123              : 
    1124           32 :         else if (oid_scheme == OID_PBE_MD2_RC2_CBC)
    1125              :                 /* RC2-64 has no implementation in libgcrypt */;
    1126              : 
    1127           32 :         else if (oid_scheme == OID_PBE_MD5_DES_CBC)
    1128            3 :                 ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
    1129              :                                              GCRY_MD_MD5, password, n_password, data, cih);
    1130           29 :         else if (oid_scheme == OID_PBE_MD5_RC2_CBC)
    1131              :                 /* RC2-64 has no implementation in libgcrypt */;
    1132              : 
    1133           29 :         else if (oid_scheme == OID_PBE_SHA1_DES_CBC)
    1134            3 :                 ret = read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
    1135              :                                              GCRY_MD_SHA1, password, n_password, data, cih);
    1136           26 :         else if (oid_scheme == OID_PBE_SHA1_RC2_CBC)
    1137              :                 /* RC2-64 has no implementation in libgcrypt */;
    1138              : 
    1139              : 
    1140              :         /* PKCS#5 PBES2 */
    1141           26 :         else if (oid_scheme == OID_PBES2)
    1142           17 :                 ret = read_cipher_pkcs5_pbes2 (password, n_password, data, cih);
    1143              : 
    1144              : 
    1145              :         /* PKCS#12 PBE */
    1146            9 :         else if (oid_scheme == OID_PKCS12_PBE_ARCFOUR_SHA1)
    1147            1 :                 ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM,
    1148              :                                               password, n_password, data, cih);
    1149            8 :         else if (oid_scheme == OID_PKCS12_PBE_RC4_40_SHA1)
    1150              :                 /* RC4-40 has no implementation in libgcrypt */;
    1151              : 
    1152            8 :         else if (oid_scheme == OID_PKCS12_PBE_3DES_SHA1)
    1153            7 :                 ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC,
    1154              :                                               password, n_password, data, cih);
    1155            1 :         else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1)
    1156              :                 /* 2DES has no implementation in libgcrypt */;
    1157              : 
    1158            1 :         else if (oid_scheme == OID_PKCS12_PBE_RC2_128_SHA1)
    1159            0 :                 ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC,
    1160              :                                               password, n_password, data, cih);
    1161              : 
    1162            1 :         else if (oid_scheme == OID_PKCS12_PBE_RC2_40_SHA1)
    1163            1 :                 ret = read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC,
    1164              :                                               password, n_password, data, cih);
    1165              : 
    1166           32 :         if (ret == FALSE)
    1167            8 :                 g_message ("unsupported or invalid cipher: %s", g_quark_to_string (oid_scheme));
    1168              : 
    1169           32 :         return ret;
    1170              : }
    1171              : 
    1172              : gboolean
    1173            2 : egg_symkey_read_mac (GQuark oid_scheme,
    1174              :                      const gchar *password,
    1175              :                      gsize n_password,
    1176              :                      GNode *data,
    1177              :                      gcry_md_hd_t *mdh,
    1178              :                      gsize *digest_len)
    1179              : {
    1180            2 :         gboolean ret = FALSE;
    1181              : 
    1182            2 :         g_return_val_if_fail (oid_scheme != 0, FALSE);
    1183            2 :         g_return_val_if_fail (mdh != NULL, FALSE);
    1184            2 :         g_return_val_if_fail (data != NULL, FALSE);
    1185              : 
    1186            2 :         init_quarks ();
    1187              : 
    1188              :         /* PKCS#12 MAC with SHA-1 */
    1189            2 :         if (oid_scheme == OID_SHA1)
    1190            2 :                 ret = read_mac_pkcs12_pbe (GCRY_MD_SHA1, password, n_password,
    1191              :                                            data, mdh, digest_len);
    1192              : 
    1193            2 :         if (ret == FALSE)
    1194            1 :                 g_message ("unsupported or invalid mac: %s", g_quark_to_string (oid_scheme));
    1195              : 
    1196            2 :         return ret;
    1197              : }
        

Generated by: LCOV version 2.0-1