LCOV - code coverage report
Current view: top level - src/plugins/crypto - testmod_crypto.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 148 149 99.3 %
Date: 2022-05-21 16:19:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief test suite for the crypto plugin
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : #include "crypto.h"
      10             : #include "gpg.h"
      11             : #include "helper.h"
      12             : #include <kdb.h>
      13             : #include <kdbinternal.h>
      14             : #include <stdio.h>
      15             : #include <stdlib.h>
      16             : #include <string.h>
      17             : #include <tests_internal.h>
      18             : #include <tests_plugin.h>
      19             : 
      20             : #include "common_gpg_tests.c"
      21             : #include "gpgagent_teardown.h"
      22             : #include "test_key.h"
      23             : 
      24             : #define PLUGIN_NAME "crypto"
      25             : #define TEST_KEY_ID "DDEBEF9EE2DC931701338212DAF635B17F230E8D"
      26             : 
      27             : static KeySet * newPluginConfiguration (void);
      28             : 
      29             : typedef int (*checkConfPtr) (Key *, KeySet *);
      30             : 
      31             : static const char strVal[] = "abcde";
      32             : static const char strValLong[] = "Oh loooooooooooooooooooong Johnson";
      33             : static const char strFullBlockSingle[] = "abcdefghijklmno";
      34             : static const char strFullBlockDouble[] = "I am root!!!!!!!!!!!!!!!!!!!!!?";
      35             : static const kdb_octet_t binVal[] = { 0x01, 0x02, 0x03, 0x04 };
      36             : 
      37             : static inline ssize_t MIN (ssize_t a, ssize_t b)
      38             : {
      39          36 :         return (a < b) ? a : b;
      40             : }
      41             : 
      42          16 : static int isMarkedForEncryption (const Key * k)
      43             : {
      44          16 :         const Key * metaEncrypt = keyGetMeta (k, ELEKTRA_CRYPTO_META_ENCRYPT);
      45          16 :         if (metaEncrypt && strcmp (keyString (metaEncrypt), "1") == 0)
      46             :         {
      47          12 :                 return 1;
      48             :         }
      49             :         return 0;
      50             : }
      51             : 
      52             : /**
      53             :  * @brief create a new KeySet holding sample data for encryption and decryption.
      54             :  */
      55           4 : static KeySet * newTestdataKeySet (void)
      56             : {
      57           4 :         Key * kUnchanged1 = keyNew ("user:/crypto/test/nochange", KEY_END);
      58           4 :         Key * kUnchanged2 = keyNew ("user:/crypto/test/nochange2", KEY_END);
      59           4 :         Key * kNull = keyNew ("user:/crypto/test/mynull", KEY_END);
      60           4 :         Key * kString = keyNew ("user:/crypto/test/mystring", KEY_END);
      61           4 :         Key * kStringLong = keyNew ("user:/crypto/test/myextralongstring", KEY_END);
      62           4 :         Key * kStringFullBlockSingle = keyNew ("user:/crypto/test/myfullblocksingle", KEY_END);
      63           4 :         Key * kStringFullBlockDouble = keyNew ("user:/crypto/test/myfullblockdouble", KEY_END);
      64           4 :         Key * kBin = keyNew ("user:/crypto/test/mybin", KEY_END);
      65             : 
      66           4 :         keySetString (kUnchanged1, strVal);
      67             : 
      68           4 :         keySetString (kUnchanged2, strVal);
      69           4 :         keySetMeta (kUnchanged2, ELEKTRA_CRYPTO_META_ENCRYPT, "0");
      70             : 
      71           4 :         keySetBinary (kNull, 0, 0);
      72           4 :         keySetMeta (kNull, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      73             : 
      74           4 :         keySetString (kString, strVal);
      75           4 :         keySetMeta (kString, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      76             : 
      77           4 :         keySetString (kStringLong, strValLong);
      78           4 :         keySetMeta (kStringLong, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      79             : 
      80           4 :         keySetString (kStringFullBlockSingle, strFullBlockSingle);
      81           4 :         keySetMeta (kStringFullBlockSingle, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      82             : 
      83           4 :         keySetString (kStringFullBlockDouble, strFullBlockDouble);
      84           4 :         keySetMeta (kStringFullBlockDouble, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      85             : 
      86           4 :         keySetBinary (kBin, binVal, sizeof (binVal));
      87           4 :         keySetMeta (kBin, ELEKTRA_CRYPTO_META_ENCRYPT, "1");
      88             : 
      89           4 :         return ksNew (8, kUnchanged1, kUnchanged2, kNull, kString, kStringLong, kStringFullBlockSingle, kStringFullBlockDouble, kBin,
      90             :                       KS_END);
      91             : }
      92             : 
      93           2 : static inline void setPluginShutdown (KeySet * config)
      94             : {
      95           2 :         ksAppendKey (config, keyNew (ELEKTRA_CRYPTO_PARAM_SHUTDOWN, KEY_VALUE, "1", KEY_END));
      96           2 : }
      97             : 
      98           8 : static KeySet * newPluginConfiguration (void)
      99             : {
     100           8 :         return ksNew (2, keyNew (ELEKTRA_RECIPIENT_KEY, KEY_VALUE, TEST_KEY_ID, KEY_END),
     101             :                       keyNew (ELEKTRA_CRYPTO_PARAM_GPG_UNIT_TEST, KEY_VALUE, "1", KEY_END), KS_END);
     102             : }
     103             : 
     104           2 : static void test_init (const char * pluginName)
     105             : {
     106           2 :         Plugin * plugin = NULL;
     107           2 :         Key * parentKey = keyNew ("system:/", KEY_END);
     108           2 :         KeySet * modules = ksNew (0, KS_END);
     109           2 :         KeySet * configKs = newPluginConfiguration ();
     110           2 :         elektraModulesInit (modules, 0);
     111             : 
     112           2 :         plugin = elektraPluginOpen (pluginName, modules, configKs, 0);
     113           2 :         succeed_if (plugin != 0, "failed to open the plugin");
     114           2 :         if (plugin)
     115             :         {
     116           2 :                 succeed_if (!strcmp (plugin->name, pluginName), "got wrong name");
     117             : 
     118           2 :                 KeySet * config = elektraPluginGetConfig (plugin);
     119           2 :                 succeed_if (config != 0, "there should be a config");
     120             : 
     121           2 :                 succeed_if (plugin->kdbOpen != 0, "no open pointer");
     122           2 :                 succeed_if (plugin->kdbClose != 0, "no close pointer");
     123           2 :                 succeed_if (plugin->kdbGet != 0, "no get pointer");
     124           2 :                 succeed_if (plugin->kdbSet != 0, "no set pointer");
     125             : 
     126             :                 // try re-opening the plugin
     127           2 :                 succeed_if (plugin->kdbClose (plugin, parentKey) == 1, "kdb close failed");
     128           2 :                 succeed_if (plugin->kdbOpen (plugin, parentKey) == 1, "re-opening the plugin failed");
     129           2 :                 succeed_if (plugin->kdbClose (plugin, parentKey) == 1, "kdb close failed");
     130             : 
     131           2 :                 elektraPluginClose (plugin, 0);
     132             :         }
     133             : 
     134           2 :         elektraModulesClose (modules, 0);
     135           2 :         ksDel (modules);
     136           2 :         keyDel (parentKey);
     137           2 : }
     138             : 
     139           2 : static void test_incomplete_config (const char * pluginName)
     140             : {
     141           2 :         Plugin * plugin = NULL;
     142           2 :         Key * parentKey = keyNew ("system:/", KEY_END);
     143           2 :         KeySet * modules = ksNew (0, KS_END);
     144           2 :         KeySet * configKs = ksNew (0, KS_END);
     145           2 :         elektraModulesInit (modules, 0);
     146             : 
     147           2 :         plugin = elektraPluginOpen (pluginName, modules, configKs, 0);
     148           2 :         succeed_if (plugin != 0, "failed to open the plugin");
     149           2 :         if (plugin)
     150             :         {
     151           2 :                 KeySet * data = newTestdataKeySet ();
     152           2 :                 succeed_if (plugin->kdbSet (plugin, data, parentKey) == -1, "kdb set succeeded with incomplete configuration");
     153           2 :                 ksDel (data);
     154           2 :                 elektraPluginClose (plugin, 0);
     155             :         }
     156             : 
     157           2 :         elektraModulesClose (modules, 0);
     158           2 :         ksDel (modules);
     159           2 :         keyDel (parentKey);
     160           2 : }
     161             : 
     162           2 : static void test_crypto_operations (const char * pluginName)
     163             : {
     164           2 :         union
     165             :         {
     166             :                 checkConfPtr f;
     167             :                 void * v;
     168             :         } conversation;
     169             : 
     170           2 :         Plugin * plugin = NULL;
     171           2 :         Key * parentKey = keyNew ("system:/", KEY_END);
     172           2 :         KeySet * modules = ksNew (0, KS_END);
     173           2 :         KeySet * config = newPluginConfiguration ();
     174             : 
     175           2 :         setPluginShutdown (config);
     176             : 
     177           2 :         elektraModulesInit (modules, 0);
     178             : 
     179           2 :         plugin = elektraPluginOpen (pluginName, modules, config, 0);
     180           2 :         if (plugin)
     181             :         {
     182           2 :                 Key * k;
     183           2 :                 KeySet * data = newTestdataKeySet ();
     184           2 :                 KeySet * original = ksDup (data);
     185             : 
     186             :                 // read and check the contract
     187           2 :                 KeySet * contract = ksNew (0, KS_END);
     188           2 :                 Key * contractParent = keyNew ("system:/elektra/modules/" PLUGIN_NAME, KEY_END);
     189           2 :                 succeed_if (plugin->kdbGet (plugin, contract, contractParent) == 1, "kdb get for contract failed");
     190             : 
     191             :                 // run checkconf to generate the master password
     192           2 :                 Key * function = ksLookupByName (contract, "system:/elektra/modules/" PLUGIN_NAME "/exports/checkconf", 0);
     193           2 :                 succeed_if (function, "no symbol exported for the checkconf function");
     194           2 :                 if (function)
     195             :                 {
     196           2 :                         succeed_if (keyGetBinary (function, &conversation.v, sizeof (conversation)) == sizeof (conversation),
     197           2 :                                     "type mismatch in function pointer to checkconf");
     198           2 :                         succeed_if (conversation.f, "exported NULL pointer as checkconf function");
     199             : 
     200           2 :                         if (conversation.f)
     201             :                         {
     202           2 :                                 KeySet * pluginConfig = elektraPluginGetConfig (plugin);
     203           2 :                                 succeed_if (conversation.f (parentKey, pluginConfig) != -1, "checkconf call failed");
     204             :                         }
     205             :                 }
     206             : 
     207           2 :                 keyDel (contractParent);
     208           2 :                 ksDel (contract);
     209             : 
     210             :                 // test encryption with kdb set
     211           2 :                 succeed_if (plugin->kdbSet (plugin, data, parentKey) == 1, "kdb set failed");
     212             : 
     213             :                 // verify key set
     214           2 :                 ksRewind (data);
     215          20 :                 while ((k = ksNext (data)) != 0)
     216             :                 {
     217          16 :                         if (isMarkedForEncryption (k))
     218             :                         {
     219          12 :                                 succeed_if (keyIsBinary (k), "Key value is not binary although it should have been encrypted");
     220          12 :                                 succeed_if (keyGetValueSize (k) > 0, "NULL Key must have encrypted metadata and can not have length 0");
     221          12 :                                 succeed_if (memcmp (keyValue (k), binVal, MIN (keyGetValueSize (k), (ssize_t) sizeof (binVal))),
     222          12 :                                             "encryption failed");
     223          12 :                                 succeed_if (memcmp (keyValue (k), strVal, MIN (keyGetValueSize (k), (ssize_t) sizeof (strVal))),
     224          12 :                                             "encryption failed");
     225          12 :                                 succeed_if (memcmp (keyValue (k), strValLong, MIN (keyGetValueSize (k), (ssize_t) sizeof (strValLong))),
     226             :                                             "encryption failed");
     227             :                         }
     228             :                         else
     229             :                         {
     230          22 :                                 succeed_if (!strcmp (keyString (k), strVal), "Key value changed without being marked for encryption");
     231             :                         }
     232             :                 }
     233             : 
     234             :                 // test decryption with kdb get
     235           2 :                 succeed_if (plugin->kdbGet (plugin, data, parentKey) == 1, "kdb get failed");
     236          20 :                 compare_keyset (data, original);
     237             : 
     238           2 :                 ksDel (original);
     239           2 :                 ksDel (data);
     240           2 :                 elektraPluginClose (plugin, 0);
     241             :         }
     242             : 
     243           2 :         elektraModulesClose (modules, 0);
     244           2 :         ksDel (modules);
     245           2 :         keyDel (parentKey);
     246           2 : }
     247             : 
     248           2 : static void test_gpg (void)
     249             : {
     250             :         // Plugin configuration
     251           2 :         KeySet * conf = newPluginConfiguration ();
     252           2 :         Key * errorKey = keyNew ("/", KEY_END);
     253             : 
     254             :         // install the gpg key
     255           2 :         char * argv[] = { "", "-a", "--import", NULL };
     256           2 :         const size_t argc = 4;
     257           2 :         Key * msg = keyNew ("/", KEY_END);
     258           2 :         keySetBinary (msg, test_key_asc, test_key_asc_len);
     259             : 
     260           2 :         succeed_if (ELEKTRA_PLUGIN_FUNCTION (gpgCall) (conf, errorKey, msg, argv, argc) == 1, "failed to install the GPG test key");
     261             : 
     262           2 :         keyDel (msg);
     263           2 :         keyDel (errorKey);
     264           2 :         ksDel (conf);
     265           2 : }
     266             : 
     267           2 : int main (int argc, char ** argv)
     268             : {
     269           2 :         printf ("CRYPTO       TESTS\n");
     270           2 :         printf ("==================\n\n");
     271             : 
     272           2 :         init (argc, argv);
     273             : 
     274           2 :         if (gpg_available (newPluginConfiguration ()))
     275             :         {
     276           2 :                 test_gpg ();
     277           2 :                 test_init (PLUGIN_NAME);
     278           2 :                 test_incomplete_config (PLUGIN_NAME);
     279           2 :                 test_crypto_operations (PLUGIN_NAME);
     280           2 :                 test_teardown ();
     281             :         }
     282             :         else
     283             :         {
     284           0 :                 printf ("The test was disabled because gpg could not be found on the system.\n");
     285             :         }
     286             : 
     287           6 :         print_result (PLUGIN_NAME);
     288           2 :         return nbError;
     289             : }

Generated by: LCOV version 1.13