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 : }
|