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