Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: tests/qmanifest/root/.gnupg/, tests/qmanifest/, /, man/, man/include/, ...
Date: Fri, 24 May 2019 11:58:58
Message-Id: 1558699106.f1d02fbf01683c42ddb0cdfbfe7815c5ff37e035.grobian@gentoo
1 commit: f1d02fbf01683c42ddb0cdfbfe7815c5ff37e035
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Fri May 24 11:58:26 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Fri May 24 11:58:26 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=f1d02fbf
7
8 qmanifest: allow GPG-signing top-level Manifest
9
10 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
11
12 man/include/qmanifest-01-generation.include | 17 ++
13 man/include/qmanifest.optdesc.yaml | 8 +
14 man/qmanifest.1 | 30 ++-
15 qmanifest.c | 214 ++++++++++++++++-----
16 tests/qmanifest/dotest | 16 +-
17 tests/qmanifest/manifest04.good | 3 +-
18 tests/qmanifest/manifest07.good | 11 +-
19 .../1F0A2C7F1E80A6EEEA3B9C30068FB3349702B3A7.key | Bin 0 -> 1171 bytes
20 .../E37F9F3C8E4A940C625EC65B7070255F4AAA55F9.key | Bin 0 -> 1155 bytes
21 tests/qmanifest/root/.gnupg/pubring.kbx | Bin 0 -> 1435 bytes
22 tests/qmanifest/root/.gnupg/random_seed | Bin 0 -> 600 bytes
23 tests/qmanifest/root/.gnupg/trustdb.gpg | Bin 0 -> 1280 bytes
24 12 files changed, 233 insertions(+), 66 deletions(-)
25
26 diff --git a/man/include/qmanifest-01-generation.include b/man/include/qmanifest-01-generation.include
27 new file mode 100644
28 index 0000000..5a24a02
29 --- /dev/null
30 +++ b/man/include/qmanifest-01-generation.include
31 @@ -0,0 +1,17 @@
32 +.SH "GENERATING A SIGNED TREE"
33 +.PP
34 +By default, \fBqmanifest\fR will not try to sign the top-level Manifest
35 +when it generating thick Manifests. A tree as such isn't completely
36 +valid (as it misses the final signature), but still correct. To sign
37 +the top-level Manifest, the \fB-s\fR flag needs to be used to provide
38 +the GPG keyid to sign with. The passphrase is requested by \fBgpg\fR(1)
39 +itself, unless the \fB-p\fR flag is given, in which case \fBqmanifest\fR
40 +attempts to read the passphrase from \fIstdin\fR and then pass that
41 +passphrase onto \fBgpg\fR. This is useful for scenarios in which the
42 +signing of a tree is scripted.
43 +.PP
44 +To generate a tree signed by GPG keyid \fI0x123567ABC\fR using
45 +passphrase \fImypasswd\fR, one could use:
46 +.nf\fI
47 + $ echo mypasswd | qmanifest -g -s 0x123567ABC -p /path/to/tree
48 +.fi
49
50 diff --git a/man/include/qmanifest.optdesc.yaml b/man/include/qmanifest.optdesc.yaml
51 new file mode 100644
52 index 0000000..8bf1ce7
53 --- /dev/null
54 +++ b/man/include/qmanifest.optdesc.yaml
55 @@ -0,0 +1,8 @@
56 +signas: |
57 + Sign generated Manifest using GPG key. This key must exist in your
58 + keyring and be valid for signing.
59 +passphrase: |
60 + Ask for GPG key password (instead of relying on gpg-agent). While
61 + this option is not very useful compared to gpg's ways of gathering a
62 + password, it is mainly intended for automated setups where the
63 + password is piped in using \fIstdin\fR.
64
65 diff --git a/man/qmanifest.1 b/man/qmanifest.1
66 index e223122..15027f6 100644
67 --- a/man/qmanifest.1
68 +++ b/man/qmanifest.1
69 @@ -38,7 +38,17 @@ with the desired maximum amount of threads in use by \fIqmanifest\fR.
70 .SH OPTIONS
71 .TP
72 \fB\-g\fR, \fB\-\-generate\fR
73 -Generate thick Manifests and sign.
74 +Generate thick Manifests.
75 +.TP
76 +\fB\-s\fR \fI<arg>\fR, \fB\-\-signas\fR \fI<arg>\fR
77 +Sign generated Manifest using GPG key. This key must exist in your
78 +keyring and be valid for signing.
79 +.TP
80 +\fB\-p\fR, \fB\-\-passphrase\fR
81 +Ask for GPG key password (instead of relying on gpg-agent). While
82 +this option is not very useful compared to gpg's ways of gathering a
83 +password, it is mainly intended for automated setups where the
84 +password is piped in using \fIstdin\fR.
85 .TP
86 \fB\-d\fR, \fB\-\-dir\fR
87 Treat arguments as directories.
88 @@ -63,7 +73,23 @@ Print this help and exit.
89 .TP
90 \fB\-V\fR, \fB\-\-version\fR
91 Print version and exit.
92 -
93 +.SH "GENERATING A SIGNED TREE"
94 +.PP
95 +By default, \fBqmanifest\fR will not try to sign the top-level Manifest
96 +when it generating thick Manifests. A tree as such isn't completely
97 +valid (as it misses the final signature), but still correct. To sign
98 +the top-level Manifest, the \fB-s\fR flag needs to be used to provide
99 +the GPG keyid to sign with. The passphrase is requested by \fBgpg\fR(1)
100 +itself, unless the \fB-p\fR flag is given, in which case \fBqmanifest\fR
101 +attempts to read the passphrase from \fIstdin\fR and then pass that
102 +passphrase onto \fBgpg\fR. This is useful for scenarios in which the
103 +signing of a tree is scripted.
104 +.PP
105 +To generate a tree signed by GPG keyid \fI0x123567ABC\fR using
106 +passphrase \fImypasswd\fR, one could use:
107 +.nf\fI
108 + $ echo mypasswd | qmanifest -g -s 0x123567ABC -p /path/to/tree
109 +.fi
110 .SH "REPORTING BUGS"
111 Please report bugs via http://bugs.gentoo.org/
112 .br
113
114 diff --git a/qmanifest.c b/qmanifest.c
115 index 88352fa..ed203a6 100644
116 --- a/qmanifest.c
117 +++ b/qmanifest.c
118 @@ -39,15 +39,19 @@
119 #include "eat_file.h"
120 #include "hash.h"
121
122 -#define QMANIFEST_FLAGS "gdo" COMMON_FLAGS
123 +#define QMANIFEST_FLAGS "gs:pdo" COMMON_FLAGS
124 static struct option const qmanifest_long_opts[] = {
125 {"generate", no_argument, NULL, 'g'},
126 + {"signas", a_argument, NULL, 's'},
127 + {"passphrase", no_argument, NULL, 'p'},
128 {"dir", no_argument, NULL, 'd'},
129 {"overlay", no_argument, NULL, 'o'},
130 COMMON_LONG_OPTS
131 };
132 static const char * const qmanifest_opts_help[] = {
133 - "Generate thick Manifests and sign",
134 + "Generate thick Manifests",
135 + "Sign generated Manifest using GPG key",
136 + "Ask for GPG key password (instead of relying on gpg-agent)",
137 "Treat arguments as directories",
138 "Treat arguments as overlay names",
139 COMMON_OPTS_HELP
140 @@ -55,6 +59,8 @@ static const char * const qmanifest_opts_help[] = {
141 #define qmanifest_usage(ret) usage(ret, QMANIFEST_FLAGS, qmanifest_long_opts, qmanifest_opts_help, NULL, lookup_applet_idx("qmanifest"))
142
143 static int hashes = HASH_DEFAULT;
144 +static char *gpg_sign_key = NULL;
145 +static bool gpg_get_password = false;
146
147 /* linked list structure to hold verification complaints */
148 typedef struct verify_msg {
149 @@ -688,37 +694,124 @@ generate_dir(const char *dir, enum type_manifest mtype)
150 }
151 }
152
153 +static gpgme_error_t
154 +gpgme_pw_cb(void *opaque, const char *uid_hint, const char *pw_info,
155 + int last_was_bad, int fd)
156 +{
157 + char *pass = (char *)opaque;
158 + size_t passlen = strlen(pass);
159 + ssize_t ret;
160 +
161 + (void)uid_hint;
162 + (void)pw_info;
163 + (void)last_was_bad;
164 +
165 + do {
166 + ret = write(fd, pass, passlen);
167 + if (ret > 0) {
168 + pass += ret;
169 + passlen -= ret;
170 + }
171 + } while (passlen > 0 && ret > 0);
172 +
173 + return passlen == 0 ? GPG_ERR_NO_ERROR : gpgme_error_from_errno(errno);
174 +}
175 +
176 static const char *
177 -process_dir_gen(const char *dir)
178 +process_dir_gen(void)
179 {
180 char path[_Q_PATH_MAX];
181 int newhashes;
182 - int curdirfd;
183 + struct termios termio;
184 + char *gpg_pass;
185
186 - snprintf(path, sizeof(path), "%s%s/metadata/layout.conf", portroot, dir);
187 - if ((newhashes = parse_layout_conf(path)) != 0) {
188 + if ((newhashes = parse_layout_conf("metadata/layout.conf")) != 0) {
189 hashes = newhashes;
190 } else {
191 return "generation must be done on a full tree";
192 }
193
194 - if ((curdirfd = open(".", O_RDONLY)) < 0) {
195 - fprintf(stderr, "cannot open current directory?!? %s\n",
196 - strerror(errno));
197 - }
198 - snprintf(path, sizeof(path), "%s%s", portroot, dir);
199 - if (chdir(path) != 0) {
200 - fprintf(stderr, "cannot chdir() to %s: %s\n", dir, strerror(errno));
201 - return "not a directory";
202 - }
203 -
204 if (generate_dir(".\0", GLOBAL_MANIFEST) == NULL)
205 return "generation failed";
206
207 - /* return to where we were before we called this function */
208 - if (fchdir(curdirfd) != 0 && verbose > 1)
209 - warn("could not move back to original directory");
210 - close(curdirfd);
211 + if (gpg_sign_key != NULL) {
212 + gpgme_ctx_t gctx;
213 + gpgme_error_t gerr;
214 + gpgme_key_t gkey;
215 + gpgme_data_t manifest;
216 + gpgme_data_t out;
217 + FILE *f;
218 + size_t dlen;
219 +
220 + gerr = gpgme_new(&gctx);
221 + if (gerr != GPG_ERR_NO_ERROR)
222 + return "GPG setup failed";
223 +
224 + gerr = gpgme_get_key(gctx, gpg_sign_key, &gkey, 0);
225 + if (gerr != GPG_ERR_NO_ERROR)
226 + return "failed to get GPG key";
227 + gerr = gpgme_signers_add(gctx, gkey);
228 + if (gerr != GPG_ERR_NO_ERROR)
229 + return "failed to add GPG key to sign list, is it a suitable key?";
230 +
231 + gpg_pass = NULL;
232 + if (gpg_get_password) {
233 + if (isatty(fileno(stdin))) {
234 + /* disable terminal echo; the printing of what you type */
235 + tcgetattr(fileno(stdin), &termio);
236 + termio.c_lflag &= ~ECHO;
237 + tcsetattr(fileno(stdin), TCSANOW, &termio);
238 +
239 + printf("Password for GPG-key %s: ", gpg_sign_key);
240 + }
241 +
242 + gpg_pass = fgets(path, sizeof(path), stdin);
243 +
244 + if (isatty(fileno(stdin))) {
245 + printf("\n");
246 + /* restore echoing, for what it's worth */
247 + termio.c_lflag |= ECHO;
248 + tcsetattr(fileno(stdin), TCSANOW, &termio);
249 + }
250 +
251 + if (gpg_pass == NULL || *gpg_pass == '\0')
252 + warn("no GPG password given, gpg might ask for it again");
253 + /* continue for the case where gpg-agent holds the pass */
254 + else {
255 + gpgme_set_pinentry_mode(gctx, GPGME_PINENTRY_MODE_LOOPBACK);
256 + gpgme_set_passphrase_cb(gctx, gpgme_pw_cb, gpg_pass);
257 + }
258 + }
259 +
260 + if ((f = fopen(str_manifest, "r+")) == NULL)
261 + return "could not open top-level Manifest file";
262 +
263 + /* finally, sign the Manifest */
264 + if (gpgme_data_new_from_stream(&manifest, f) != GPG_ERR_NO_ERROR)
265 + return "failed to create GPG data from Manifest";
266 +
267 + if (gpgme_data_new(&out) != GPG_ERR_NO_ERROR)
268 + return "failed to create GPG output buffer";
269 +
270 + gerr = gpgme_op_sign(gctx, manifest, out, GPGME_SIG_MODE_CLEAR);
271 + if (gerr != GPG_ERR_NO_ERROR) {
272 + warn("%s: %s", gpgme_strsource(gerr), gpgme_strerror(gerr));
273 + return "failed to GPG sign Manifest";
274 + }
275 +
276 + /* write back signed Manifest */
277 + rewind(f);
278 + gpgme_data_seek(out, 0, SEEK_SET);
279 + do {
280 + dlen = gpgme_data_read(out, path, sizeof(path));
281 + fwrite(path, dlen, 1, f);
282 + } while (dlen == sizeof(path));
283 + fclose(f);
284 +
285 + gpgme_data_release(out);
286 + gpgme_data_release(manifest);
287 + gpgme_release(gctx);
288 + }
289
290 return NULL;
291 }
292 @@ -854,13 +947,19 @@ verify_gpg_sig(const char *path, verify_msg **msgs)
293 "used to verify the signature has been revoked");
294 break;
295 case GPG_ERR_BAD_SIGNATURE:
296 + free(ret);
297 + ret = NULL;
298 printf("the signature is invalid\n");
299 break;
300 case GPG_ERR_NO_PUBKEY:
301 + free(ret);
302 + ret = NULL;
303 printf("the signature could not be verified due to a "
304 "missing key\n");
305 break;
306 default:
307 + free(ret);
308 + ret = NULL;
309 printf("there was some other error which prevented the "
310 "signature verification\n");
311 break;
312 @@ -1414,7 +1513,7 @@ format_line(const char *pfx, const char *msg, int twidth)
313 }
314
315 static const char *
316 -process_dir_vrfy(const char *dir)
317 +process_dir_vrfy(void)
318 {
319 char buf[8192];
320 int newhashes;
321 @@ -1422,7 +1521,6 @@ process_dir_vrfy(const char *dir)
322 struct timeval startt;
323 struct timeval finisht;
324 double etime;
325 - int curdirfd;
326 char *timestamp;
327 verify_msg topmsg;
328 verify_msg *walk = &topmsg;
329 @@ -1436,35 +1534,25 @@ process_dir_vrfy(const char *dir)
330
331 gettimeofday(&startt, NULL);
332
333 - snprintf(buf, sizeof(buf), "%s%s/metadata/layout.conf", portroot, dir);
334 + snprintf(buf, sizeof(buf), "metadata/layout.conf");
335 if ((newhashes = parse_layout_conf(buf)) != 0) {
336 hashes = newhashes;
337 } else {
338 return "verification must be done on a full tree";
339 }
340
341 - if ((curdirfd = open(".", O_RDONLY)) < 0) {
342 - fprintf(stderr, "cannot open current directory?!? %s\n",
343 - strerror(errno));
344 - }
345 - snprintf(buf, sizeof(buf), "%s%s", portroot, dir);
346 - if (chdir(buf) != 0) {
347 - fprintf(stderr, "cannot chdir() to %s: %s\n", dir, strerror(errno));
348 - return "not a directory";
349 - }
350 -
351 if ((gs = verify_gpg_sig(str_manifest, &walk)) == NULL) {
352 ret = "gpg signature invalid";
353 } else {
354 fprintf(stdout,
355 "%s%s%s signature made %s by\n"
356 - "%s\n"
357 + " %s%s%s\n"
358 "primary key fingerprint %s\n"
359 "%4s subkey fingerprint %s\n",
360 gs->isgood ? GREEN : RED,
361 gs->isgood ? "good": "BAD",
362 NORM, gs->timestamp,
363 - gs->signer,
364 + DKBLUE, gs->signer, NORM,
365 gs->pkfingerprint,
366 gs->algo, gs->fingerprint);
367 if (!gs->isgood)
368 @@ -1575,11 +1663,6 @@ process_dir_vrfy(const char *dir)
369
370 gettimeofday(&finisht, NULL);
371
372 - /* return to where we were before we called this function */
373 - if (fchdir(curdirfd) != 0 && verbose > 1)
374 - warn("could not move back to original directory");
375 - close(curdirfd);
376 -
377 etime = ((double)((finisht.tv_sec - startt.tv_sec) * 1000000 +
378 finisht.tv_usec) - (double)startt.tv_usec) / 1000000.0;
379 printf("checked %zd Manifests, %zd files, %zd failures in %.02fs\n",
380 @@ -1591,15 +1674,17 @@ int
381 qmanifest_main(int argc, char **argv)
382 {
383 char *prog;
384 - const char *(*runfunc)(const char *);
385 + const char *(*runfunc)(void);
386 int ret;
387 const char *rsn;
388 bool isdir = false;
389 bool isoverlay = false;
390 char *overlay;
391 char path[_Q_PATH_MAX];
392 + char path2[_Q_PATH_MAX];
393 size_t n;
394 int i;
395 + int curdirfd;
396
397 if ((prog = strrchr(argv[0], '/')) == NULL) {
398 prog = argv[0];
399 @@ -1620,6 +1705,8 @@ qmanifest_main(int argc, char **argv)
400 switch (ret) {
401 COMMON_GETOPTS_CASES(qmanifest)
402 case 'g': runfunc = process_dir_gen; break;
403 + case 's': gpg_sign_key = optarg; break;
404 + case 'p': gpg_get_password = true; break;
405 case 'd': isdir = true; break;
406 case 'o': isoverlay = true; break;
407 }
408 @@ -1653,6 +1740,9 @@ qmanifest_main(int argc, char **argv)
409 }
410 }
411
412 + if ((curdirfd = open(".", O_RDONLY)) < 0)
413 + warn("cannot open current directory?!? %s\n", strerror(errno));
414 +
415 ret = EXIT_SUCCESS;
416 argc -= optind;
417 argv += optind;
418 @@ -1679,20 +1769,27 @@ qmanifest_main(int argc, char **argv)
419 if (isdir || (!isoverlay && overlay == NULL)) /* !isdir && !isoverlay */
420 overlay = argv[i];
421
422 - if (runfunc == process_dir_vrfy)
423 - printf("verifying %s%s%s...\n", BOLD, overlay, NORM);
424 -
425 if (*overlay != '/') {
426 if (portroot[1] == '\0') {
427 /* resolve the path */
428 + (void)fchdir(curdirfd);
429 (void)realpath(overlay, path);
430 } else {
431 snprintf(path, sizeof(path), "./%s", overlay);
432 }
433 - overlay = path;
434 }
435
436 - rsn = runfunc(overlay);
437 + snprintf(path2, sizeof(path2), "%s%s", portroot, path);
438 + if (chdir(path2) != 0) {
439 + warn("cannot change directory to %s: %s", overlay, strerror(errno));
440 + ret |= 1;
441 + continue;
442 + }
443 +
444 + if (runfunc == process_dir_vrfy)
445 + printf("verifying %s%s%s...\n", BOLD, overlay, NORM);
446 +
447 + rsn = runfunc();
448 if (rsn != NULL) {
449 printf("%s%s%s\n", RED, rsn, NORM);
450 ret |= 2;
451 @@ -1700,15 +1797,28 @@ qmanifest_main(int argc, char **argv)
452 }
453
454 if (i == 0) {
455 - if (runfunc == process_dir_vrfy)
456 - printf("verifying %s%s%s...\n", BOLD, main_overlay, NORM);
457 - rsn = runfunc(main_overlay);
458 - if (rsn != NULL) {
459 - printf("%s%s%s\n", RED, rsn, NORM);
460 - ret |= 2;
461 + snprintf(path, sizeof(path), "%s%s", portroot, main_overlay);
462 + if (chdir(path) != 0) {
463 + warn("cannot change directory to %s: %s",
464 + main_overlay, strerror(errno));
465 + ret |= 1;
466 + } else {
467 + if (runfunc == process_dir_vrfy)
468 + printf("verifying %s%s%s...\n", BOLD, main_overlay, NORM);
469 +
470 + rsn = runfunc();
471 + if (rsn != NULL) {
472 + printf("%s%s%s\n", RED, rsn, NORM);
473 + ret |= 2;
474 + }
475 }
476 }
477
478 + /* return to where we were before we called this function */
479 + if (fchdir(curdirfd) != 0 && verbose > 1)
480 + warn("could not move back to original directory");
481 + close(curdirfd);
482 +
483 return ret;
484 }
485
486
487 diff --git a/tests/qmanifest/dotest b/tests/qmanifest/dotest
488 index 636a723..fb2aa22 100755
489 --- a/tests/qmanifest/dotest
490 +++ b/tests/qmanifest/dotest
491 @@ -36,7 +36,7 @@ test 02 2 "qmanifest not_a_tree"
492 test 03 2 "qmanifest notatree"
493
494 # dir test
495 -test 04 2 "qmanifest -d not_a_tree"
496 +test 04 1 "qmanifest -d not_a_tree"
497
498 # overlay test
499 test 05 1 "qmanifest -o notatree"
500 @@ -44,11 +44,19 @@ test 05 1 "qmanifest -o notatree"
501 # generate a valid tree
502 rm -Rf testtree
503 cp -r "${ROOT}/simpletree" testtree || echo try it anyway
504 +# make it a fully valid tree
505 +export HOME=${ROOT} # for gnupg home
506 +rm testtree/my-cat/mypackage/unrecorded-file
507 unset ROOT PORTAGE_CONFIGROOT
508 -test 06 0 "qmanifest -g testtree"
509 +SIGNAS=0x3D695C8C0F87966B62DC5AFCDCFABA8E07F52261
510 +KEYPASS=qmanifest
511 +test 06 0 "echo ${KEYPASS} | qmanifest -g -s ${SIGNAS} -p testtree"
512
513 -# validate the just generated tree (doesn't do GPG signing hence fails)
514 -test 07 0 "qmanifest testtree | sed '/Manifest timestamp/d'"
515 +# validate the just generated tree
516 +test 07 0 "qmanifest testtree | sed -e '/Manifest timestamp/d' -e 's/made .* UTC by/made by/'"
517 +
518 +# shut down agents and whatnot
519 +gpgconf --kill all
520
521 cleantmpdir
522
523
524 diff --git a/tests/qmanifest/manifest04.good b/tests/qmanifest/manifest04.good
525 index 17c6a1f..4831674 100644
526 --- a/tests/qmanifest/manifest04.good
527 +++ b/tests/qmanifest/manifest04.good
528 @@ -1,2 +1 @@
529 -verifying not_a_tree...
530 -verification must be done on a full tree
531 +manifest: cannot change directory to not_a_tree: No such file or directory
532
533 diff --git a/tests/qmanifest/manifest07.good b/tests/qmanifest/manifest07.good
534 index 67176c5..6347806 100644
535 --- a/tests/qmanifest/manifest07.good
536 +++ b/tests/qmanifest/manifest07.good
537 @@ -1,7 +1,6 @@
538 verifying testtree...
539 -Manifest:
540 -- failed to verify signature
541 -my-cat/mypackage/Manifest:
542 -- file not listed: unrecorded-file
543 -checked 5 Manifests, 9 files, 1 failures
544 -manifest verification failed
545 +good signature made by
546 + Qmanifest Test Key
547 +primary key fingerprint 3D69 5C8C 0F87 966B 62DC 5AFC DCFA BA8E 07F5 2261
548 + RSA subkey fingerprint 3D69 5C8C 0F87 966B 62DC 5AFC DCFA BA8E 07F5 2261
549 +checked 5 Manifests, 9 files, 0 failures
550
551 diff --git a/tests/qmanifest/root/.gnupg/private-keys-v1.d/1F0A2C7F1E80A6EEEA3B9C30068FB3349702B3A7.key b/tests/qmanifest/root/.gnupg/private-keys-v1.d/1F0A2C7F1E80A6EEEA3B9C30068FB3349702B3A7.key
552 new file mode 100644
553 index 0000000..b4ed767
554 Binary files /dev/null and b/tests/qmanifest/root/.gnupg/private-keys-v1.d/1F0A2C7F1E80A6EEEA3B9C30068FB3349702B3A7.key differ
555
556 diff --git a/tests/qmanifest/root/.gnupg/private-keys-v1.d/E37F9F3C8E4A940C625EC65B7070255F4AAA55F9.key b/tests/qmanifest/root/.gnupg/private-keys-v1.d/E37F9F3C8E4A940C625EC65B7070255F4AAA55F9.key
557 new file mode 100644
558 index 0000000..4b07401
559 Binary files /dev/null and b/tests/qmanifest/root/.gnupg/private-keys-v1.d/E37F9F3C8E4A940C625EC65B7070255F4AAA55F9.key differ
560
561 diff --git a/tests/qmanifest/root/.gnupg/pubring.kbx b/tests/qmanifest/root/.gnupg/pubring.kbx
562 new file mode 100644
563 index 0000000..848dc93
564 Binary files /dev/null and b/tests/qmanifest/root/.gnupg/pubring.kbx differ
565
566 diff --git a/tests/qmanifest/root/.gnupg/random_seed b/tests/qmanifest/root/.gnupg/random_seed
567 new file mode 100644
568 index 0000000..d32d054
569 Binary files /dev/null and b/tests/qmanifest/root/.gnupg/random_seed differ
570
571 diff --git a/tests/qmanifest/root/.gnupg/trustdb.gpg b/tests/qmanifest/root/.gnupg/trustdb.gpg
572 new file mode 100644
573 index 0000000..78308c6
574 Binary files /dev/null and b/tests/qmanifest/root/.gnupg/trustdb.gpg differ