1 /*
2 * Copyright (c) 2018-2019 [Ribose Inc](https://www.ribose.com).
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "rnp_tests.h"
28 #include "support.h"
29 #include "time-utils.h"
30
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #else
34 #ifndef WIFEXITED
35 #define WIFEXITED(stat) (((*((int *) &(stat))) & 0xC0000000) == 0)
36 #endif
37
38 #ifndef WEXITSTATUS
39 #define WEXITSTATUS(stat) (*((int *) &(stat)))
40 #endif
41 #endif
42
43 #ifdef _WIN32
44 #include <windows.h>
45 #include "str-utils.h"
46 #endif
47
48 int rnp_main(int argc, char **argv);
49 int rnpkeys_main(int argc, char **argv);
50
51 static int
call_rnp(const char * cmd,...)52 call_rnp(const char *cmd, ...)
53 {
54 int argc = 0;
55 int res;
56 char ** argv = (char **) calloc(32, sizeof(char *));
57 va_list args;
58
59 va_start(args, cmd);
60 while (cmd) {
61 argv[argc++] = (char *) cmd;
62 cmd = va_arg(args, char *);
63 }
64 va_end(args);
65 /* reset state of getopt_long used in rnp */
66 optind = 1;
67
68 if (!strcmp(argv[0], "rnp")) {
69 res = rnp_main(argc, argv);
70 } else if (!strcmp(argv[0], "rnpkeys")) {
71 res = rnpkeys_main(argc, argv);
72 } else {
73 res = -1;
74 }
75 free(argv);
76
77 return res;
78 }
79
80 #define KEYS "data/keyrings"
81 #define GENKEYS "data/keyrings_genkey_tmp"
82 #define MKEYS "data/test_stream_key_merge/"
83 #define FILES "data/test_cli"
84 #define G10KEYS "data/test_stream_key_load/g10"
85
TEST_F(rnp_tests,test_cli_rnp_keyfile)86 TEST_F(rnp_tests, test_cli_rnp_keyfile)
87 {
88 int ret;
89
90 /* sign with keyfile, using default key */
91 ret = call_rnp("rnp",
92 "--keyfile",
93 MKEYS "key-sec.asc",
94 "--password",
95 "password",
96 "-s",
97 FILES "/hello.txt",
98 NULL);
99 assert_int_equal(ret, 0);
100 assert_true(rnp_file_exists(FILES "/hello.txt.pgp"));
101 /* verify signed file */
102 ret =
103 call_rnp("rnp", "--keyfile", MKEYS "key-pub.asc", "-v", FILES "/hello.txt.pgp", NULL);
104 assert_int_equal(ret, 0);
105 assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
106
107 /* sign with keyfile, using user id */
108 ret = call_rnp("rnp",
109 "-f",
110 MKEYS "key-sec.asc",
111 "-u",
112 "key-merge-uid-2",
113 "--password",
114 "password",
115 "--armor",
116 "-s",
117 FILES "/hello.txt",
118 NULL);
119 assert_int_equal(ret, 0);
120 assert_true(rnp_file_exists(FILES "/hello.txt.asc"));
121 /* verify signed file */
122 ret = call_rnp("rnp", "-f", MKEYS "key-pub.asc", "-v", FILES "/hello.txt.asc", NULL);
123 assert_int_equal(ret, 0);
124 /* verify with key without self-signature - should fail */
125 ret =
126 call_rnp("rnp", "-f", MKEYS "key-pub-just-key.pgp", "-v", FILES "/hello.txt.asc", NULL);
127 assert_int_not_equal(ret, 0);
128 assert_int_equal(rnp_unlink(FILES "/hello.txt.asc"), 0);
129
130 /* encrypt with keyfile, using default key */
131 ret = call_rnp("rnp", "--keyfile", MKEYS "key-pub.asc", "-e", FILES "/hello.txt", NULL);
132 assert_int_equal(ret, 0);
133 assert_true(rnp_file_exists(FILES "/hello.txt.pgp"));
134 /* decrypt it with raw seckey, without userids and sigs */
135 ret = call_rnp("rnp",
136 "--keyfile",
137 MKEYS "key-sec-no-uid-no-sigs.pgp",
138 "--password",
139 "password",
140 "-d",
141 FILES "/hello.txt.pgp",
142 NULL);
143 assert_int_equal(ret, 0);
144 assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
145
146 /* try to encrypt with keyfile, using the signing subkey */
147 ret = call_rnp("rnp",
148 "--keyfile",
149 MKEYS "key-pub.asc",
150 "-r",
151 "16CD16F267CCDD4F",
152 "--armor",
153 "-e",
154 FILES "/hello.txt",
155 NULL);
156 assert_int_not_equal(ret, 0);
157 assert_false(rnp_file_exists(FILES "/hello.txt.asc"));
158 /* now encrypt with keyfile, using the encrypting subkey */
159 ret = call_rnp("rnp",
160 "--keyfile",
161 MKEYS "key-pub.asc",
162 "-r",
163 "AF1114A47F5F5B28",
164 "--armor",
165 "-e",
166 FILES "/hello.txt",
167 NULL);
168 assert_int_equal(ret, 0);
169 assert_true(rnp_file_exists(FILES "/hello.txt.asc"));
170 /* fail to decrypt it with pubkey */
171 ret = call_rnp("rnp",
172 "--keyfile",
173 MKEYS "key-pub-subkey-1.pgp",
174 "--password",
175 "password",
176 "-d",
177 FILES "/hello.txt.asc",
178 NULL);
179 assert_int_not_equal(ret, 0);
180 /* decrypt correctly with seckey + subkeys */
181 ret = call_rnp("rnp",
182 "--keyfile",
183 MKEYS "key-sec.pgp",
184 "--password",
185 "password",
186 "-d",
187 FILES "/hello.txt.asc",
188 NULL);
189 assert_int_equal(ret, 0);
190 assert_int_equal(rnp_unlink(FILES "/hello.txt.asc"), 0);
191 }
192
193 static bool
test_cli_g10_key_sign(const char * userid)194 test_cli_g10_key_sign(const char *userid)
195 {
196 int ret;
197
198 /* create signature */
199 ret = call_rnp("rnp",
200 "--homedir",
201 G10KEYS,
202 "--password",
203 "password",
204 "-u",
205 userid,
206 "-s",
207 FILES "/hello.txt",
208 NULL);
209 if (ret) {
210 return false;
211 }
212
213 /* verify back */
214 ret = call_rnp("rnp", "--homedir", G10KEYS, "-v", FILES "/hello.txt.pgp", NULL);
215 if (ret) {
216 return false;
217 }
218 rnp_unlink(FILES "/hello.txt.pgp");
219 return true;
220 }
221
222 static bool
test_cli_g10_key_encrypt(const char * userid)223 test_cli_g10_key_encrypt(const char *userid)
224 {
225 int ret;
226
227 /* encrypt */
228 ret = call_rnp("rnp", "--homedir", G10KEYS, "-r", userid, "-e", FILES "/hello.txt", NULL);
229 if (ret) {
230 return false;
231 }
232
233 /* decrypt it back */
234 ret = call_rnp("rnp",
235 "--homedir",
236 G10KEYS,
237 "--password",
238 "password",
239 "-d",
240 FILES "/hello.txt.pgp",
241 NULL);
242 if (ret) {
243 return false;
244 }
245 rnp_unlink(FILES "/hello.txt.pgp");
246 return true;
247 }
248
TEST_F(rnp_tests,test_cli_g10_operations)249 TEST_F(rnp_tests, test_cli_g10_operations)
250 {
251 int ret;
252
253 /* sign with default g10 key */
254 ret = call_rnp(
255 "rnp", "--homedir", G10KEYS, "--password", "password", "-s", FILES "/hello.txt", NULL);
256 assert_int_equal(ret, 0);
257
258 /* verify back */
259 ret = call_rnp("rnp", "--homedir", G10KEYS, "-v", FILES "/hello.txt.pgp", NULL);
260 assert_int_equal(ret, 0);
261 assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
262
263 /* encrypt with default g10 key */
264 ret = call_rnp("rnp", "--homedir", G10KEYS, "-e", FILES "/hello.txt", NULL);
265 assert_int_equal(ret, 0);
266
267 /* decrypt it back */
268 ret = call_rnp("rnp",
269 "--homedir",
270 G10KEYS,
271 "--password",
272 "password",
273 "-d",
274 FILES "/hello.txt.pgp",
275 NULL);
276 assert_int_equal(ret, 0);
277 assert_int_equal(rnp_unlink(FILES "/hello.txt.pgp"), 0);
278
279 /* check dsa/eg key */
280 assert_true(test_cli_g10_key_sign("c8a10a7d78273e10")); // signing key
281 assert_true(test_cli_g10_key_encrypt("c8a10a7d78273e10")); // will find subkey
282 assert_false(test_cli_g10_key_sign("02a5715c3537717e")); // fail - encrypting subkey
283 assert_true(test_cli_g10_key_encrypt("02a5715c3537717e")); // success
284
285 /* check rsa/rsa key, key is SC while subkey is E */
286 assert_true(test_cli_g10_key_sign("2fb9179118898e8b"));
287 assert_true(test_cli_g10_key_encrypt("2fb9179118898e8b"));
288 assert_false(test_cli_g10_key_sign("6e2f73008f8b8d6e"));
289 assert_true(test_cli_g10_key_encrypt("6e2f73008f8b8d6e"));
290
291 /* check ed25519 key */
292 assert_true(test_cli_g10_key_sign("cc786278981b0728"));
293 assert_false(test_cli_g10_key_encrypt("cc786278981b0728"));
294
295 /* check ed25519/x25519 key */
296 assert_true(test_cli_g10_key_sign("941822a0fc1b30a5"));
297 assert_true(test_cli_g10_key_encrypt("941822a0fc1b30a5"));
298 assert_false(test_cli_g10_key_sign("c711187e594376af"));
299 assert_true(test_cli_g10_key_encrypt("c711187e594376af"));
300
301 /* check p256 key */
302 assert_true(test_cli_g10_key_sign("23674f21b2441527"));
303 assert_true(test_cli_g10_key_encrypt("23674f21b2441527"));
304 assert_false(test_cli_g10_key_sign("37e285e9e9851491"));
305 assert_true(test_cli_g10_key_encrypt("37e285e9e9851491"));
306
307 /* check p384 key */
308 assert_true(test_cli_g10_key_sign("242a3aa5ea85f44a"));
309 assert_true(test_cli_g10_key_encrypt("242a3aa5ea85f44a"));
310 assert_false(test_cli_g10_key_sign("e210e3d554a4fad9"));
311 assert_true(test_cli_g10_key_encrypt("e210e3d554a4fad9"));
312
313 /* check p521 key */
314 assert_true(test_cli_g10_key_sign("2092ca8324263b6a"));
315 assert_true(test_cli_g10_key_encrypt("2092ca8324263b6a"));
316 assert_false(test_cli_g10_key_sign("9853df2f6d297442"));
317 assert_true(test_cli_g10_key_encrypt("9853df2f6d297442"));
318
319 /* check bp256 key */
320 assert_true(test_cli_g10_key_sign("d0c8a3daf9e0634a"));
321 assert_true(test_cli_g10_key_encrypt("d0c8a3daf9e0634a"));
322 assert_false(test_cli_g10_key_sign("2edabb94d3055f76"));
323 assert_true(test_cli_g10_key_encrypt("2edabb94d3055f76"));
324
325 /* check bp384 key */
326 assert_true(test_cli_g10_key_sign("6cf2dce85599ada2"));
327 assert_true(test_cli_g10_key_encrypt("6cf2dce85599ada2"));
328 assert_false(test_cli_g10_key_sign("cff1bb6f16d28191"));
329 assert_true(test_cli_g10_key_encrypt("cff1bb6f16d28191"));
330
331 /* check bp512 key */
332 assert_true(test_cli_g10_key_sign("aa5c58d14f7b8f48"));
333 assert_true(test_cli_g10_key_encrypt("aa5c58d14f7b8f48"));
334 assert_false(test_cli_g10_key_sign("20cdaa1482ba79ce"));
335 assert_true(test_cli_g10_key_encrypt("20cdaa1482ba79ce"));
336
337 /* check secp256k1 key */
338 assert_true(test_cli_g10_key_sign("3ea5bb6f9692c1a0"));
339 assert_true(test_cli_g10_key_encrypt("3ea5bb6f9692c1a0"));
340 assert_false(test_cli_g10_key_sign("7635401f90d3e533"));
341 assert_true(test_cli_g10_key_encrypt("7635401f90d3e533"));
342 }
343
TEST_F(rnp_tests,test_cli_rnpkeys_unicode)344 TEST_F(rnp_tests, test_cli_rnpkeys_unicode)
345 {
346 #ifdef _WIN32
347 std::string uid_acp = "\x80@a.com";
348 std::wstring uid2_wide =
349 L"\x03C9\x0410@b.com"; // some Greek and Cyrillic for CreateProcessW test
350 char *rnpkeys_path = rnp_compose_path(original_dir(), "../rnpkeys/rnpkeys.exe", NULL);
351 std::string homedir_s = std::string(m_dir) + "/unicode";
352 rnp_mkdir(homedir_s.c_str());
353 std::string path_s = rnpkeys_path;
354 std::string cmdline_s = path_s + " --numbits 2048 --homedir " + homedir_s +
355 " --password password --userid " + uid_acp + " --generate-key";
356 UINT acp = GetACP();
357 STARTUPINFOA si;
358 ZeroMemory(&si, sizeof si);
359 PROCESS_INFORMATION pi;
360 ZeroMemory(&pi, sizeof pi);
361 BOOL res = CreateProcessA(NULL, // (LPSTR) path_s.c_str(), // Module name
362 (LPSTR) cmdline_s.c_str(), // Command line
363 NULL, // Process handle not inheritable
364 NULL, // Thread handle not inheritable
365 FALSE, // Handle inheritance
366 0, // Creation flags
367 NULL, // Use parent's environment block
368 NULL, // Use parent's starting directory
369 &si, // Pointer to STARTUPINFO structure
370 &pi); // Pointer to PROCESS_INFORMATION structure
371 assert_true(res);
372 assert_true(WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0);
373 CloseHandle(pi.hProcess);
374 CloseHandle(pi.hThread);
375
376 std::wstring homedir_ws = wstr_from_utf8(homedir_s);
377 std::wstring path_ws = wstr_from_utf8(path_s);
378 std::wstring cmdline_ws = path_ws + L" --numbits 2048 --homedir " + homedir_ws +
379 L" --password password --userid " + uid2_wide +
380 L" --generate-key";
381 STARTUPINFOW siw;
382 ZeroMemory(&siw, sizeof siw);
383 ZeroMemory(&pi, sizeof pi);
384 res = CreateProcessW(NULL,
385 (LPWSTR) cmdline_ws.c_str(), // Command line
386 NULL, // Process handle not inheritable
387 NULL, // Thread handle not inheritable
388 FALSE, // Handle inheritance
389 0, // Creation flags
390 NULL, // Use parent's environment block
391 NULL, // Use parent's starting directory
392 &siw, // Pointer to STARTUPINFO structure
393 &pi); // Pointer to PROCESS_INFORMATION structure
394 assert_true(res);
395 assert_true(WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0);
396 CloseHandle(pi.hProcess);
397 CloseHandle(pi.hThread);
398 // Load the keyring and check what was actually written
399 rnp_ffi_t ffi;
400 assert_rnp_success(rnp_ffi_create(&ffi, "GPG", "GPG"));
401 rnp_input_t input = NULL;
402 assert_rnp_success(rnp_input_from_path(&input, "unicode/pubring.gpg"));
403 assert_rnp_success(rnp_load_keys(ffi, "GPG", input, RNP_LOAD_SAVE_PUBLIC_KEYS));
404 rnp_input_destroy(input);
405
406 // convert from ACP to wide char via Windows native mechanism
407 int convertResult = MultiByteToWideChar(acp, 0, uid_acp.c_str(), uid_acp.size(), NULL, 0);
408 assert_true(convertResult > 0);
409 std::wstring uid_wide;
410 uid_wide.resize(convertResult);
411 convertResult = MultiByteToWideChar(
412 acp, 0, uid_acp.c_str(), uid_acp.size(), &uid_wide[0], (int) uid_wide.size());
413 assert_true(convertResult > 0);
414
415 // we expect to find UID in UTF-8
416 std::string uid_utf8 = wstr_to_utf8(uid_wide);
417 rnp_key_handle_t key = NULL;
418 assert_rnp_success(rnp_locate_key(ffi, "userid", uid_utf8.c_str(), &key));
419 assert_non_null(key);
420
421 size_t uids = 0;
422 assert_rnp_success(rnp_key_get_uid_count(key, &uids));
423 assert_int_equal(uids, 1);
424
425 rnp_uid_handle_t uid = NULL;
426 assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
427 assert_non_null(uid);
428
429 size_t size = 0;
430 char * data = NULL;
431 assert_rnp_success(rnp_uid_get_data(uid, (void **) &data, &size));
432 std::string uid_read(data, data + size);
433 assert_int_equal(0, uid_read.compare(uid_utf8));
434 rnp_buffer_destroy(data);
435 rnp_uid_handle_destroy(uid);
436 rnp_key_handle_destroy(key);
437
438 uid_utf8 = wstr_to_utf8(uid2_wide);
439 key = NULL;
440 assert_rnp_success(rnp_locate_key(ffi, "userid", uid_utf8.c_str(), &key));
441 assert_non_null(key);
442
443 uids = 0;
444 assert_rnp_success(rnp_key_get_uid_count(key, &uids));
445 assert_int_equal(uids, 1);
446
447 uid = NULL;
448 assert_rnp_success(rnp_key_get_uid_handle_at(key, 0, &uid));
449 assert_non_null(uid);
450
451 size = 0;
452 data = NULL;
453 assert_rnp_success(rnp_uid_get_data(uid, (void **) &data, &size));
454 std::string uid2_read(data, data + size);
455 assert_int_equal(0, uid2_read.compare(uid_utf8));
456 rnp_buffer_destroy(data);
457 rnp_uid_handle_destroy(uid);
458 rnp_key_handle_destroy(key);
459 rnp_ffi_destroy(ffi);
460 #endif
461 }
462
TEST_F(rnp_tests,test_cli_rnp)463 TEST_F(rnp_tests, test_cli_rnp)
464 {
465 int ret;
466 assert_int_equal(0, call_rnp("rnp", "--version", NULL));
467
468 /* sign with default key */
469 ret = call_rnp("rnp",
470 "--homedir",
471 KEYS "/1",
472 "--password",
473 "password",
474 "--sign",
475 FILES "/hello.txt",
476 NULL);
477 assert_int_equal(ret, 0);
478
479 /* encrypt with default key */
480 ret = call_rnp(
481 "rnp", "--homedir", KEYS "/1", "--encrypt", FILES "/hello.txt", "--overwrite", NULL);
482 assert_int_equal(ret, 0);
483
484 /* sign and verify back with g10 key */
485 ret = call_rnp("rnp",
486 "--homedir",
487 KEYS "/3",
488 "-u",
489 "4BE147BB22DF1E60",
490 "--password",
491 "password",
492 "--sign",
493 FILES "/hello.txt",
494 "--overwrite",
495 NULL);
496 assert_int_equal(ret, 0);
497 ret = call_rnp("rnp", "--homedir", KEYS "/3", "--verify", FILES "/hello.txt.pgp", NULL);
498 assert_int_equal(ret, 0);
499
500 /* encrypt and decrypt back with g10 key */
501 ret = call_rnp("rnp",
502 "--homedir",
503 KEYS "/3",
504 "-r",
505 "4BE147BB22DF1E60",
506 "--encrypt",
507 FILES "/hello.txt",
508 "--overwrite",
509 NULL);
510 assert_int_equal(ret, 0);
511 ret = call_rnp("rnp",
512 "--homedir",
513 KEYS "/3",
514 "--password",
515 "password",
516 "--decrypt",
517 FILES "/hello.txt.pgp",
518 NULL);
519 assert_int_equal(ret, 0);
520 }
521
TEST_F(rnp_tests,test_cli_examples)522 TEST_F(rnp_tests, test_cli_examples)
523 {
524 char *examples_path = rnp_compose_path(original_dir(), "../examples", NULL);
525 char *example_path = NULL;
526 /* key generation example */
527 example_path = rnp_compose_path(examples_path, "generate", NULL);
528 assert_non_null(example_path);
529 assert_int_equal(system(example_path), 0);
530 free(example_path);
531
532 /* encryption sample */
533 example_path = rnp_compose_path(examples_path, "encrypt", NULL);
534 assert_non_null(example_path);
535 assert_int_equal(system(example_path), 0);
536 free(example_path);
537
538 /* decryption sample */
539 example_path = rnp_compose_path(examples_path, "decrypt", NULL);
540 assert_non_null(example_path);
541 assert_int_equal(system(example_path), 0);
542 free(example_path);
543
544 /* signing sample */
545 example_path = rnp_compose_path(examples_path, "sign", NULL);
546 assert_non_null(example_path);
547 assert_int_equal(system(example_path), 0);
548 free(example_path);
549
550 /* verification sample */
551 example_path = rnp_compose_path(examples_path, "verify", NULL);
552 assert_non_null(example_path);
553 assert_int_equal(system(example_path), 0);
554 free(example_path);
555
556 free(examples_path);
557 }
558
TEST_F(rnp_tests,test_cli_rnpkeys)559 TEST_F(rnp_tests, test_cli_rnpkeys)
560 {
561 int ret;
562 assert_int_equal(0, call_rnp("rnpkeys", "--version", NULL));
563
564 /* test keys listing */
565 ret = call_rnp("rnpkeys", "--homedir", KEYS "/1", "--list-keys", NULL);
566 assert_int_equal(ret, 0);
567
568 ret = call_rnp("rnpkeys", "--homedir", KEYS "/1", "--list-keys", "--with-sigs", NULL);
569 assert_int_equal(ret, 0);
570
571 ret = call_rnp("rnpkeys", "--homedir", KEYS "/2", "--list-keys", NULL);
572 assert_int_equal(ret, 0);
573
574 ret = call_rnp("rnpkeys", "--homedir", KEYS "/2", "--list-keys", "--with-sigs", NULL);
575 assert_int_equal(ret, 0);
576
577 ret = call_rnp("rnpkeys", "--homedir", KEYS "/3", "--list-keys", NULL);
578 assert_int_equal(ret, 0);
579
580 ret = call_rnp("rnpkeys", "--homedir", KEYS "/3", "--list-keys", "--with-sigs", NULL);
581 assert_int_equal(ret, 0);
582
583 ret = call_rnp("rnpkeys", "--homedir", KEYS "/5", "--list-keys", NULL);
584 assert_int_equal(ret, 0);
585
586 ret = call_rnp("rnpkeys", "--homedir", KEYS "/5", "--list-keys", "--with-sigs", NULL);
587 assert_int_equal(ret, 0);
588
589 ret = call_rnp("rnpkeys", "--homedir", G10KEYS, "--list-keys", NULL);
590 assert_int_equal(ret, 0);
591
592 ret = call_rnp("rnpkeys", "--homedir", G10KEYS, "--list-keys", "--with-sigs", NULL);
593 assert_int_equal(ret, 0);
594
595 /* test single key listing command */
596 ret = call_rnp("rnpkeys", "--homedir", KEYS "/1", "--list-keys", "2fcadf05ffa501bb", NULL);
597 assert_int_equal(ret, 0);
598
599 ret = call_rnp("rnpkeys", "--homedir", KEYS "/1", "--list-keys", "00000000", NULL);
600 assert_int_not_equal(ret, 0);
601
602 ret = call_rnp("rnpkeys", "--homedir", KEYS "/1", "--list-keys", "zzzzzzzz", NULL);
603 assert_int_not_equal(ret, 0);
604 }
605
606 // check both primary key and subkey for the given userid
607 static int
key_expiration_check(rnp_key_store_t * keystore,const char * userid,uint32_t expectedExpiration)608 key_expiration_check(rnp_key_store_t *keystore,
609 const char * userid,
610 uint32_t expectedExpiration)
611 {
612 int res = -1; // not found
613 for (auto &key : keystore->keys) {
614 pgp_key_t *pk;
615 if (key.is_primary()) {
616 pk = &key;
617 } else {
618 assert_true(key.has_primary_fp());
619 pk = rnp_key_store_get_key_by_fpr(keystore, key.primary_fp());
620 }
621 assert_int_equal(pk->uid_count(), 1);
622 auto uid = pk->get_uid(0).str;
623 if (uid != userid) {
624 continue;
625 }
626 auto expiration = key.expiration();
627 if (uid == "expiration_absolute@rnp" || uid == "expiration_beyond2038_absolute@rnp") {
628 auto diff = expectedExpiration < expiration ? expiration - expectedExpiration :
629 expectedExpiration - expiration;
630 // allow 10 minutes diff
631 if (diff < 600) {
632 res = 1;
633 } else {
634 return 0;
635 }
636 } else {
637 if (expectedExpiration == expiration) {
638 res = 1;
639 } else {
640 RNP_LOG(
641 "key_expiration_check error: userid=%s expectedExpiration=%u expiration=%u",
642 userid,
643 expectedExpiration,
644 expiration);
645 return 0;
646 }
647 }
648 }
649 return res;
650 }
651
652 static int
key_generate(const char * homedir,const char * userid,const char * expiration)653 key_generate(const char *homedir, const char *userid, const char *expiration)
654 {
655 int ret = call_rnp("rnpkeys",
656 "--password",
657 "1234",
658 "--homedir",
659 homedir,
660 "--generate-key",
661 "--expiration",
662 expiration,
663 "--userid",
664 userid,
665 "--numbits",
666 "1024",
667 NULL);
668 return ret;
669 }
670
TEST_F(rnp_tests,test_cli_rnpkeys_genkey)671 TEST_F(rnp_tests, test_cli_rnpkeys_genkey)
672 {
673 assert_false(RNP_MKDIR(GENKEYS, S_IRWXU));
674 time_t basetime = time(NULL);
675 time_t rawtime = basetime + 604800;
676 time_t y2k38time = INT32_MAX;
677 uint32_t expected_diff_beyond2038_absolute;
678 if (rnp_y2k38_warning(y2k38time)) {
679 // we're on the system that doesn't support dates beyond y2k38
680 auto diff_to_y2k38 = y2k38time - basetime;
681 expected_diff_beyond2038_absolute = diff_to_y2k38;
682 } else {
683 time_t now = time(NULL);
684 struct tm tm2100 = *localtime(&now);
685 tm2100.tm_hour = 0;
686 tm2100.tm_min = 0;
687 tm2100.tm_sec = 0;
688 tm2100.tm_mday = 1;
689 tm2100.tm_mon = 0;
690 tm2100.tm_year = 200;
691 expected_diff_beyond2038_absolute = mktime(&tm2100) - basetime;
692 }
693 struct tm *timeinfo = localtime(&rawtime);
694 // clear hours, minutes and seconds
695 timeinfo->tm_hour = 0;
696 timeinfo->tm_min = 0;
697 timeinfo->tm_sec = 0;
698 rawtime = mktime(timeinfo);
699 auto exp =
700 fmt("%d-%02d-%02d", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday);
701
702 // these should fail and not go to the keystore
703 assert_int_not_equal(key_generate(GENKEYS, "expiration_negative@rnp", "-1"), 0);
704 assert_int_not_equal(key_generate(GENKEYS, "expiration_unrecognized_1@rnp", "1z"), 0);
705 assert_int_not_equal(key_generate(GENKEYS, "expiration_unrecognized_2@rnp", "now"), 0);
706 assert_int_not_equal(key_generate(GENKEYS, "expiration_unrecognized_3@rnp", "00000-01-01"),
707 0);
708 assert_int_not_equal(
709 key_generate(GENKEYS, "expiration_integer_overflow@rnp", "1234567890123456789"), 0);
710 assert_int_not_equal(key_generate(GENKEYS, "expiration_32bit_overflow@rnp", "4294967296"),
711 0);
712 assert_int_not_equal(key_generate(GENKEYS, "expiration_overflow_day@rnp", "2037-02-29"),
713 0);
714 assert_int_not_equal(key_generate(GENKEYS, "expiration_overflow_month@rnp", "2037-13-01"),
715 0);
716 if (!rnp_y2k38_warning(y2k38time)) {
717 assert_int_not_equal(
718 key_generate(GENKEYS, "expiration_overflow_year@rnp", "2337-01-01"), 0);
719 }
720 assert_int_not_equal(key_generate(GENKEYS, "expiration_underflow_day@rnp", "2037-02-00"),
721 0);
722 assert_int_not_equal(key_generate(GENKEYS, "expiration_underflow_month@rnp", "2037-00-01"),
723 0);
724 assert_int_not_equal(key_generate(GENKEYS, "expiration_underflow_year@rnp", "1800-01-01"),
725 0);
726 assert_int_not_equal(key_generate(GENKEYS, "expiration_overflow@rnp", "200y"), 0);
727 assert_int_not_equal(key_generate(GENKEYS, "expiration_past@rnp", "2021-01-01"), 0);
728
729 // these should pass and go to the keystore -- 15 primary keys and 15 subkeys
730 assert_int_equal(key_generate(GENKEYS, "expiration_beyond2038_relative@rnp", "20y"), 0);
731 assert_int_equal(key_generate(GENKEYS, "expiration_beyond2038_absolute@rnp", "2100-01-01"),
732 0);
733 assert_int_equal(key_generate(GENKEYS, "expiration_absolute@rnp", exp.c_str()), 0);
734 assert_int_equal(key_generate(GENKEYS, "expiration_max_32bit@rnp", "4294967295"), 0);
735 assert_int_equal(key_generate(GENKEYS, "expiration_max_32bit_h@rnp", "1193046h"), 0);
736 assert_int_equal(key_generate(GENKEYS, "expiration_1sec@rnp", "1"), 0);
737 assert_int_equal(key_generate(GENKEYS, "expiration_1hour@rnp", "1h"), 0);
738 assert_int_equal(key_generate(GENKEYS, "expiration_1day@rnp", "1d"), 0);
739 assert_int_equal(key_generate(GENKEYS, "expiration_1week@rnp", "1w"), 0);
740 assert_int_equal(key_generate(GENKEYS, "expiration_1month@rnp", "1m"), 0);
741 assert_int_equal(key_generate(GENKEYS, "expiration_1year@rnp", "1y"), 0);
742 assert_int_equal(key_generate(GENKEYS, "expiration_2sec@rnp", "2"), 0);
743 assert_int_equal(key_generate(GENKEYS, "expiration_2hours@rnp", "2h"), 0);
744 assert_int_equal(key_generate(GENKEYS, "expiration_2days@rnp", "2d"), 0);
745 assert_int_equal(key_generate(GENKEYS, "expiration_2weeks@rnp", "2w"), 0);
746 assert_int_equal(key_generate(GENKEYS, "expiration_2months@rnp", "2m"), 0);
747 assert_int_equal(key_generate(GENKEYS, "expiration_2years@rnp", "2y"), 0);
748
749 auto keystore = new rnp_key_store_t(PGP_KEY_STORE_GPG, "");
750 pgp_source_t src = {};
751 assert_rnp_success(init_file_src(&src, GENKEYS "/pubring.gpg"));
752 assert_true(rnp_key_store_load_from_src(keystore, &src, NULL));
753 assert_int_equal(rnp_key_store_get_key_count(keystore), 34);
754 src_close(&src);
755 assert_int_equal(key_expiration_check(keystore, "expiration_max_32bit@rnp", 4294967295),
756 1);
757 assert_int_equal(key_expiration_check(keystore, "expiration_max_32bit_h@rnp", 4294965600),
758 1);
759 assert_int_equal(key_expiration_check(keystore, "expiration_1sec@rnp", 1), 1);
760 assert_int_equal(key_expiration_check(keystore, "expiration_1hour@rnp", 3600), 1);
761 assert_int_equal(key_expiration_check(keystore, "expiration_1day@rnp", 86400), 1);
762 assert_int_equal(key_expiration_check(keystore, "expiration_1week@rnp", 604800), 1);
763 assert_int_equal(key_expiration_check(keystore, "expiration_1month@rnp", 2678400), 1);
764 assert_int_equal(key_expiration_check(keystore, "expiration_1year@rnp", 31536000), 1);
765 assert_int_equal(key_expiration_check(keystore, "expiration_2sec@rnp", 2), 1);
766 assert_int_equal(key_expiration_check(keystore, "expiration_2hours@rnp", 7200), 1);
767 assert_int_equal(key_expiration_check(keystore, "expiration_2days@rnp", 172800), 1);
768 assert_int_equal(key_expiration_check(keystore, "expiration_2weeks@rnp", 1209600), 1);
769 assert_int_equal(key_expiration_check(keystore, "expiration_2months@rnp", 5356800), 1);
770 assert_int_equal(key_expiration_check(keystore, "expiration_2years@rnp", 63072000), 1);
771 assert_int_equal(
772 key_expiration_check(keystore, "expiration_absolute@rnp", rawtime - basetime), 1);
773 assert_int_equal(key_expiration_check(keystore,
774 "expiration_beyond2038_absolute@rnp",
775 expected_diff_beyond2038_absolute),
776 1);
777 assert_int_equal(
778 key_expiration_check(keystore, "expiration_beyond2038_relative@rnp", 630720000), 1);
779
780 delete keystore;
781 delete_recursively(GENKEYS);
782 }
783
TEST_F(rnp_tests,test_cli_dump)784 TEST_F(rnp_tests, test_cli_dump)
785 {
786 char *dump_path = rnp_compose_path(original_dir(), "../examples/dump", NULL);
787 char cmd[512] = {0};
788 int chnum;
789 int status;
790 /* call dump's help */
791 chnum = snprintf(cmd, sizeof(cmd), "%s -h", dump_path);
792 assert_true(chnum < (int) sizeof(cmd));
793 status = system(cmd);
794 assert_true(WIFEXITED(status));
795 assert_int_equal(WEXITSTATUS(status), 1);
796 /* run dump on some data */
797 chnum = snprintf(cmd, sizeof(cmd), "%s \"%s\"", dump_path, KEYS "/1/pubring.gpg");
798 assert_true(chnum < (int) sizeof(cmd));
799 status = system(cmd);
800 assert_true(WIFEXITED(status));
801 assert_int_equal(WEXITSTATUS(status), 0);
802 /* run dump on some data with json output */
803 chnum = snprintf(cmd, sizeof(cmd), "%s -j \"%s\"", dump_path, KEYS "/1/pubring.gpg");
804 assert_true(chnum < (int) sizeof(cmd));
805 status = system(cmd);
806 assert_true(WIFEXITED(status));
807 assert_int_equal(WEXITSTATUS(status), 0);
808 /* run dump on directory - must fail but not crash */
809 chnum = snprintf(cmd, sizeof(cmd), "%s \"%s\"", dump_path, KEYS "/1/");
810 assert_true(chnum < (int) sizeof(cmd));
811 status = system(cmd);
812 assert_true(WIFEXITED(status));
813 assert_int_not_equal(WEXITSTATUS(status), 0);
814
815 free(dump_path);
816 }
817
TEST_F(rnp_tests,test_cli_logname)818 TEST_F(rnp_tests, test_cli_logname)
819 {
820 char * logname = getenv("LOGNAME");
821 char * user = getenv("USER");
822 std::string testname(user ? user : "user");
823 testname.append("-test-user");
824
825 setenv("LOGNAME", testname.c_str(), 1);
826 assert_string_equal(getenv_logname(), testname.c_str());
827 if (user) {
828 unsetenv("LOGNAME");
829 assert_string_equal(getenv_logname(), user);
830 }
831
832 if (logname) {
833 setenv("LOGNAME", logname, 1);
834 } else {
835 unsetenv("LOGNAME");
836 }
837 }
838