rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

signature.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 #include <rpmio.h>
8 #include <rpmurl.h>
9 #include <rpmcb.h> /* XXX rpmIsVerbose() */
10 #define _RPMPGP_INTERNAL
11 #include <rpmpgp.h>
12 #include <rpmmacro.h> /* XXX for rpmGetPath() */
13 #include <rpmku.h>
14
15 #include <rpmtag.h>
16 #include "rpmdb.h"
17 #include <pkgio.h> /* XXX expects <rpmts.h> */
18 #include "legacy.h" /* XXX for dodogest() */
19 #include "signature.h"
20
21 #include "debug.h"
22
23 /*@access FD_t@*/ /* XXX ufdio->read arg1 is void ptr */
24 /*@access Header@*/ /* XXX compared with NULL */
25 /*@access DIGEST_CTX@*/ /* XXX compared with NULL */
26 /*@access pgpDig@*/
27 /*@access pgpDigParams@*/
28
29 int rpmTempFile(const char * prefix, const char ** fnptr, void * fdptr)
30 {
31 const char * tpmacro = "%{?_tmppath}%{!?_tmppath:/var/tmp/}";
32 const char * tempfn = NULL;
33 const char * tfn = NULL;
34 static int _initialized = 0;
35 int temput;
36 FD_t fd = NULL;
37 unsigned int ran;
38
39 if (!prefix) prefix = "";
40
41 /* Create the temp directory if it doesn't already exist. */
42 if (!_initialized) {
43 _initialized = 1;
44 tempfn = rpmGenPath(prefix, tpmacro, NULL);
45 if (rpmioMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
46 goto errxit;
47 }
48
49 /* XXX should probably use mkstemp here */
50 ran = (unsigned) time(NULL);
51 srand(ran);
52 ran = rand() % 100000;
53
54 /* maybe this should use link/stat? */
55
56 do {
57 char tfnbuf[64];
58 #ifndef NOTYET
59 sprintf(tfnbuf, "rpm-tmp.%u", ran++);
60 tempfn = _free(tempfn);
61 tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
62 #else
63 strcpy(tfnbuf, "rpm-tmp.XXXXXX");
64 tempfn = _free(tempfn);
65 tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
66 #endif
67
68 temput = urlPath(tempfn, &tfn);
69 if (*tfn == '\0') goto errxit;
70
71 switch (temput) {
72 case URL_IS_DASH:
73 case URL_IS_HKP:
74 goto errxit;
75 /*@notreached@*/ /*@switchbreak@*/ break;
76 case URL_IS_HTTPS:
77 case URL_IS_HTTP:
78 case URL_IS_FTP:
79 default:
80 /*@switchbreak@*/ break;
81 }
82
83 fd = Fopen(tempfn, "w+x.fdio");
84 /* XXX FIXME: errno may not be correct for ufdio */
85 } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
86
87 if (fd == NULL || Ferror(fd)) {
88 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tempfn);
89 goto errxit;
90 }
91
92 switch(temput) {
93 case URL_IS_PATH:
94 case URL_IS_UNKNOWN:
95 { struct stat sb, sb2;
96 if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
97 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
98 goto errxit;
99 }
100
101 if (sb.st_nlink != 1) {
102 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
103 goto errxit;
104 }
105
106 if (fstat(Fileno(fd), &sb2) == 0) {
107 if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
108 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
109 goto errxit;
110 }
111 }
112 } break;
113 default:
114 break;
115 }
116
117 if (fnptr)
118 *fnptr = tempfn;
119 else
120 tempfn = _free(tempfn);
121 if (fdptr)
122 *(FD_t *)fdptr = fd;
123
124 return 0;
125
126 errxit:
127 tempfn = _free(tempfn);
128 if (fnptr)
129 *fnptr = NULL;
130 /*@-usereleased@*/
131 if (fd != NULL) (void) Fclose(fd);
132 /*@=usereleased@*/
133 return 1;
134 }
135
136
146 static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
147 /*@out@*/ rpmuint8_t ** pktp, /*@out@*/ rpmuint32_t * pktlenp,
148 /*@null@*/ const char * passPhrase)
149 /*@globals rpmGlobalMacroContext, h_errno,
150 fileSystem, internalState @*/
151 /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext,
152 fileSystem, internalState @*/
153 {
154 char * sigfile = alloca(strlen(file)+sizeof(".sig"));
155 pid_t pid;
156 int status;
157 int inpipe[2];
158 FILE * fpipe;
159 struct stat st;
160 const char * cmd;
161 char *const *av;
162 pgpDig dig = NULL;
163 pgpDigParams sigp = NULL;
164 const char * pw = NULL;
165 int rc;
166
167 (void) stpcpy( stpcpy(sigfile, file), ".sig");
168
169 addMacro(NULL, "__plaintext_filename", NULL, file, -1);
170 addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
171
172 inpipe[0] = inpipe[1] = 0;
173 if (pipe(inpipe) < 0) {
174 rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
175 return 1;
176 }
177
178 if (!(pid = fork())) {
179 const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
180
181 (void) dup2(inpipe[0], 3);
182 (void) close(inpipe[1]);
183
184 if (gpg_path && *gpg_path != '\0')
185 (void) setenv("GNUPGHOME", gpg_path, 1);
186
187 unsetenv("MALLOC_CHECK_");
188 cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
189 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
190 if (!rc)
191 rc = execve(av[0], av+1, environ);
192
193 rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
194 strerror(errno));
195 _exit(EXIT_FAILURE);
196 }
197
198 delMacro(NULL, "__plaintext_filename");
199 delMacro(NULL, "__signature_filename");
200
201 pw = rpmkuPassPhrase(passPhrase);
202 if (pw == NULL) {
203 rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
204 strerror(errno));
205 return 1;
206 }
207
208 fpipe = fdopen(inpipe[1], "w");
209 (void) close(inpipe[0]);
210 if (fpipe) {
211 fprintf(fpipe, "%s\n", (pw ? pw : ""));
212 (void) fclose(fpipe);
213 }
214
215 if (pw != NULL) {
216 (void) memset((void *)pw, 0, strlen(pw));
217 pw = _free(pw);
218 }
219
220 /*@+longunsignedintegral@*/
221 (void) waitpid(pid, &status, 0);
222 /*@=longunsignedintegral@*/
223 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
224 rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
225 return 1;
226 }
227
228 if (Stat(sigfile, &st)) {
229 /* GPG failed to write signature */
230 if (sigfile) (void) Unlink(sigfile); /* Just in case */
231 rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
232 return 1;
233 }
234
235 *pktlenp = (rpmuint32_t)st.st_size;
236 rpmlog(RPMLOG_DEBUG, D_("GPG sig size: %u\n"), (unsigned)*pktlenp);
237 *pktp = xmalloc(*pktlenp);
238
239 { FD_t fd;
240
241 rc = 0;
242 fd = Fopen(sigfile, "r.ufdio");
243 if (fd != NULL && !Ferror(fd)) {
244 rc = (int) Fread(*pktp, sizeof((*pktp)[0]), *pktlenp, fd);
245 if (sigfile) (void) Unlink(sigfile);
246 (void) Fclose(fd);
247 }
248 if ((rpmuint32_t)rc != *pktlenp) {
249 *pktp = _free(*pktp);
250 rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
251 return 1;
252 }
253 }
254
255 rpmlog(RPMLOG_DEBUG, D_("Got %u bytes of GPG sig\n"), (unsigned)*pktlenp);
256
257 /* Parse the signature, change signature tag as appropriate. */
258 dig = pgpDigNew(0);
259
260 (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
261 sigp = pgpGetSignature(dig);
262
263 /* Identify the type of signature being returned. */
264 switch (*sigTagp) {
265 default:
266 assert(0); /* XXX never happens. */
267 /*@notreached@*/ break;
268 case RPMSIGTAG_SIZE:
269 case RPMSIGTAG_MD5:
270 case RPMSIGTAG_SHA1:
271 break;
272 case RPMSIGTAG_DSA:
273 /* XXX check hash algorithm too? */
274 if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA)
275 *sigTagp = RPMSIGTAG_RSA;
276 break;
277 case RPMSIGTAG_RSA:
278 if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA)
279 *sigTagp = RPMSIGTAG_DSA;
280 break;
281 }
282
283 dig = pgpDigFree(dig, "makeGPGSignature");
284
285 return 0;
286 }
287
296 /*@-mustmod@*/ /* sigh is modified */
297 static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
298 /*@null@*/ const char * passPhrase)
299 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
300 /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/
301 {
302 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
303 Header h = NULL;
304 FD_t fd = NULL;
305 rpmuint8_t * pkt;
306 rpmuint32_t pktlen;
307 const char * fn = NULL;
308 const char * msg;
309 rpmRC rc;
310 int ret = -1; /* assume failure. */
311 int xx;
312
313 switch (sigTag) {
314 default:
315 assert(0); /* XXX never happens. */
316 /*@notreached@*/ break;
317 case RPMSIGTAG_SIZE:
318 case RPMSIGTAG_MD5:
319 case RPMSIGTAG_PGP5: /* XXX legacy */
320 case RPMSIGTAG_PGP:
321 case RPMSIGTAG_GPG:
322 goto exit;
323 /*@notreached@*/ break;
324 case RPMSIGTAG_SHA1:
325 { const char * SHA1 = NULL;
326 fd = Fopen(file, "r.fdio");
327 if (fd == NULL || Ferror(fd))
328 goto exit;
329 { const char item[] = "Header";
330 msg = NULL;
331 rc = rpmpkgRead(item, fd, &h, &msg);
332 if (rc != RPMRC_OK) {
333 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
334 msg = _free(msg);
335 goto exit;
336 }
337 msg = _free(msg);
338 }
339 (void) Fclose(fd); fd = NULL;
340
341 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
342 unsigned char * hmagic = NULL;
343 size_t nmagic = 0;
344 DIGEST_CTX ctx;
345
346 he->tag = RPMTAG_HEADERIMMUTABLE;
347 if (!headerGet(h, he, 0) || he->p.ptr == NULL)
348 {
349 (void)headerFree(h);
350 h = NULL;
351 goto exit;
352 }
353 (void) headerGetMagic(NULL, &hmagic, &nmagic);
354 ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
355 if (hmagic && nmagic > 0)
356 (void) rpmDigestUpdate(ctx, hmagic, nmagic);
357 (void) rpmDigestUpdate(ctx, he->p.ptr, he->c);
358 (void) rpmDigestFinal(ctx, &SHA1, NULL, 1);
359 he->p.ptr = _free(he->p.ptr);
360 }
361 (void)headerFree(h);
362 h = NULL;
363
364 if (SHA1 == NULL)
365 goto exit;
366 he->tag = (rpmTag) RPMSIGTAG_SHA1;
367 he->t = RPM_STRING_TYPE;
368 he->p.str = SHA1;
369 he->c = 1;
370 xx = headerPut(sigh, he, 0);
371 SHA1 = _free(SHA1);
372 if (!xx)
373 goto exit;
374 ret = 0;
375 } break;
376 case RPMSIGTAG_DSA:
377 fd = Fopen(file, "r.fdio");
378 if (fd == NULL || Ferror(fd))
379 goto exit;
380 { const char item[] = "Header";
381 msg = NULL;
382 rc = rpmpkgRead(item, fd, &h, &msg);
383 if (rc != RPMRC_OK) {
384 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
385 msg = _free(msg);
386 goto exit;
387 }
388 msg = _free(msg);
389 }
390 (void) Fclose(fd); fd = NULL;
391
392 if (rpmTempFile(NULL, &fn, &fd))
393 goto exit;
394 { const char item[] = "Header";
395 msg = NULL;
396 rc = rpmpkgWrite(item, fd, h, &msg);
397 if (rc != RPMRC_OK) {
398 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
399 msg = _free(msg);
400 goto exit;
401 }
402 msg = _free(msg);
403 }
404 (void) Fclose(fd); fd = NULL;
405
406 if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase))
407 goto exit;
408 he->tag = (rpmTag) sigTag;
409 he->t = RPM_BIN_TYPE;
410 he->p.ptr = pkt;
411 he->c = pktlen;
412 xx = headerPut(sigh, he, 0);
413 if (!xx)
414 goto exit;
415 ret = 0;
416 break;
417 }
418
419 exit:
420 if (fn) {
421 (void) Unlink(fn);
422 fn = _free(fn);
423 }
424 (void)headerFree(h);
425 h = NULL;
426 if (fd != NULL) (void) Fclose(fd);
427 return ret;
428 }
429 /*@=mustmod@*/
430
431 int rpmAddSignature(Header sigh, const char * file, rpmSigTag sigTag,
432 const char * passPhrase)
433 {
434 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
435 struct stat st;
436 rpmuint8_t * pkt;
437 rpmuint32_t pktlen;
438 int ret = -1; /* assume failure. */
439 int xx;
440
441 switch (sigTag) {
442 default:
443 assert(0); /* XXX never happens. */
444 /*@notreached@*/ break;
445 case RPMSIGTAG_SIZE:
446 if (Stat(file, &st) != 0)
447 break;
448 pktlen = (rpmuint32_t)st.st_size;
449 he->tag = (rpmTag) sigTag;
450 he->t = RPM_UINT32_TYPE;
451 he->p.ui32p = &pktlen;
452 he->c = 1;
453 /*@-compmempass@*/
454 xx = headerPut(sigh, he, 0);
455 /*@=compmempass@*/
456 if (!xx)
457 break;
458 ret = 0;
459 break;
460 case RPMSIGTAG_MD5:
461 pktlen = 128/8;
462 pkt = memset(alloca(pktlen), 0, pktlen);
463 if (dodigest(PGPHASHALGO_MD5, file, (unsigned char *)pkt, 0, NULL))
464 break;
465 he->tag = (rpmTag) sigTag;
466 he->t = RPM_BIN_TYPE;
467 he->p.ptr = pkt;
468 he->c = pktlen;
469 xx = headerPut(sigh, he, 0);
470 if (!xx)
471 break;
472 ret = 0;
473 break;
474 case RPMSIGTAG_GPG:
475 ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
476 break;
477 case RPMSIGTAG_RSA:
478 case RPMSIGTAG_DSA:
479 case RPMSIGTAG_SHA1:
480 ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
481 break;
482 }
483
484 return ret;
485 }
486
487 int rpmCheckPassPhrase(const char * passPhrase)
488 {
489 const char *pw;
490 int p[2];
491 pid_t pid;
492 int status;
493 int rc;
494 int xx;
495
496 p[0] = p[1] = 0;
497 xx = pipe(p);
498
499 if (!(pid = fork())) {
500 const char * cmd;
501 char *const *av;
502 int fdno;
503
504 xx = close(STDIN_FILENO);
505 xx = close(STDOUT_FILENO);
506 xx = close(p[1]);
507 if (!rpmIsVerbose())
508 xx = close(STDERR_FILENO);
509 if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
510 xx = dup2(fdno, STDIN_FILENO);
511 xx = close(fdno);
512 }
513 if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
514 xx = dup2(fdno, STDOUT_FILENO);
515 xx = close(fdno);
516 }
517 xx = dup2(p[0], 3);
518
519 unsetenv("MALLOC_CHECK_");
520 { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
521
522 if (gpg_path && *gpg_path != '\0')
523 (void) setenv("GNUPGHOME", gpg_path, 1);
524
525 cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
526 rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
527 if (!rc)
528 rc = execve(av[0], av+1, environ);
529
530 rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
531 strerror(errno));
532 }
533 }
534
535 pw = rpmkuPassPhrase(passPhrase);
536 if (pw == NULL) {
537 rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
538 strerror(errno));
539 return 1;
540 }
541
542 xx = close(p[0]);
543 xx = (int) write(p[1], pw, strlen(pw));
544 xx = (int) write(p[1], "\n", 1);
545 xx = close(p[1]);
546
547 if (pw != NULL) {
548 (void) memset((void *)pw, 0, strlen(pw));
549 pw = _free(pw);
550 }
551
552 /*@+longunsignedintegral@*/
553 (void) waitpid(pid, &status, 0);
554 /*@=longunsignedintegral@*/
555
556 return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
557 }
558
559 static /*@observer@*/ const char * rpmSigString(rpmRC res)
560 /*@*/
561 {
562 const char * str;
563 switch (res) {
564 case RPMRC_OK: str = "OK"; break;
565 case RPMRC_FAIL: str = "BAD"; break;
566 case RPMRC_NOKEY: str = "NOKEY"; break;
567 case RPMRC_NOTTRUSTED: str = "NOTRUSTED"; break;
568 default:
569 case RPMRC_NOTFOUND: str = "UNKNOWN"; break;
570 }
571 return str;
572 }
573
574 static rpmRC
575 verifySize(const pgpDig dig, /*@out@*/ char * t)
576 /*@modifies *t @*/
577 {
578 const void * sig = pgpGetSig(dig);
579 rpmRC res;
580 rpmuint32_t size = 0xffffffff;
581
582 *t = '\0';
583 t = stpcpy(t, _("Header+Payload size: "));
584
585 if (sig == NULL || dig == NULL || dig->nbytes == 0) {
586 res = RPMRC_NOKEY;
587 t = stpcpy(t, rpmSigString(res));
588 goto exit;
589 }
590
591 memcpy(&size, sig, sizeof(size));
592
593 if (size !=(rpmuint32_t) dig->nbytes) {
594 res = RPMRC_FAIL;
595 t = stpcpy(t, rpmSigString(res));
596 sprintf(t, " Expected(%u) != (%u)\n", (unsigned)size, (unsigned)dig->nbytes);
597 } else {
598 res = RPMRC_OK;
599 t = stpcpy(t, rpmSigString(res));
600 sprintf(t, " (%u)", (unsigned)dig->nbytes);
601 }
602
603 exit:
604 return res;
605 }
606
607 static rpmRC
608 verifyMD5(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX md5ctx)
609 /*@globals internalState @*/
610 /*@modifies *t, internalState @*/
611 {
612 const void * sig = pgpGetSig(dig);
613 rpmuint32_t siglen = pgpGetSiglen(dig);
614 rpmRC res;
615 rpmuint8_t * md5sum = NULL;
616 size_t md5len = 0;
617
618 assert(dig != NULL);
619 assert(md5ctx != NULL);
620 assert(sig != NULL);
621
622 *t = '\0';
623
624 /* Identify the hash. */
625 t = stpcpy(t, rpmDigestName(md5ctx));
626 t = stpcpy(t, _(" digest: "));
627
628 if (sig == NULL) { /* XXX can't happen, DYING */
629 res = RPMRC_NOKEY;
630 t = stpcpy(t, rpmSigString(res));
631 goto exit;
632 }
633
634 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
635 (void) rpmswEnter(op, 0);
636 (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0);
637 (void) rpmswExit(op, 0);
638 if (op != NULL) op->count--; /* XXX one too many */
639 }
640
641 if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
642 res = RPMRC_FAIL;
643 t = stpcpy(t, rpmSigString(res));
644 t = stpcpy(t, " Expected(");
645 (void) pgpHexCvt(t, sig, siglen);
646 t += strlen(t);
647 t = stpcpy(t, ") != (");
648 } else {
649 res = RPMRC_OK;
650 t = stpcpy(t, rpmSigString(res));
651 t = stpcpy(t, " (");
652 }
653 (void) pgpHexCvt(t, md5sum, md5len);
654 t += strlen(t);
655 t = stpcpy(t, ")");
656
657 exit:
658 md5sum = _free(md5sum);
659 return res;
660 }
661
669 static rpmRC
670 verifySHA1(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX shactx)
671 /*@globals internalState @*/
672 /*@modifies *t, internalState @*/
673 {
674 const void * sig = pgpGetSig(dig);
675 #ifdef NOTYET
676 rpmuint32_t siglen = pgpGetSiglen(dig);
677 #endif
678 rpmRC res;
679 const char * SHA1 = NULL;
680
681 assert(dig != NULL);
682 assert(shactx != NULL);
683 assert(sig != NULL);
684
685 *t = '\0';
686 t = stpcpy(t, _("Header "));
687
688 /* Identify the hash. */
689 t = stpcpy(t, rpmDigestName(shactx));
690 t = stpcpy(t, _(" digest: "));
691
692 if (sig == NULL) { /* XXX can't happen, DYING */
693 res = RPMRC_NOKEY;
694 t = stpcpy(t, rpmSigString(res));
695 goto exit;
696 }
697
698 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
699 (void) rpmswEnter(op, 0);
700 (void) rpmDigestFinal(rpmDigestDup(shactx), &SHA1, NULL, 1);
701 (void) rpmswExit(op, 0);
702 }
703
704 if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
705 res = RPMRC_FAIL;
706 t = stpcpy(t, rpmSigString(res));
707 t = stpcpy(t, " Expected(");
708 t = stpcpy(t, sig);
709 t = stpcpy(t, ") != (");
710 } else {
711 res = RPMRC_OK;
712 t = stpcpy(t, rpmSigString(res));
713 t = stpcpy(t, " (");
714 }
715 if (SHA1)
716 t = stpcpy(t, SHA1);
717 t = stpcpy(t, ")");
718
719 exit:
720 SHA1 = _free(SHA1);
721 return res;
722 }
723
731 static rpmRC
732 verifyRSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX rsactx)
733 /*@globals internalState @*/
734 /*@modifies dig, *t, internalState */
735 {
736 const void * sig = pgpGetSig(dig);
737 #ifdef NOTYET
738 rpmuint32_t siglen = pgpGetSiglen(dig);
739 #endif
740 pgpDigParams sigp = pgpGetSignature(dig);
741 rpmRC res = RPMRC_OK;
742 int xx;
743
744 assert(dig != NULL);
745 assert(rsactx != NULL);
746 assert(sigp != NULL);
747 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA);
748 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(rsactx));
749 assert(pgpGetSigtag(dig) == RPMSIGTAG_RSA);
750 assert(sig != NULL);
751
752 *t = '\0';
753 if (dig->hdrctx == rsactx)
754 t = stpcpy(t, _("Header "));
755
756 /* Identify the signature version. */
757 *t++ = 'V';
758 switch (sigp->version) {
759 case 3: *t++ = '3'; break;
760 case 4: *t++ = '4'; break;
761 }
762
763 /* Identify the RSA/hash. */
764 { const char * hashname = rpmDigestName(rsactx);
765 t = stpcpy(t, " RSA");
766 if (strcmp(hashname, "UNKNOWN")) {
767 *t++ = '/';
768 t = stpcpy(t, hashname);
769 }
770 }
771 t = stpcpy(t, _(" signature: "));
772
773 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
774 DIGEST_CTX ctx = rpmDigestDup(rsactx);
775
776 (void) rpmswEnter(op, 0);
777 if (sigp->hash != NULL)
778 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
779
780 if (sigp->version == (rpmuint8_t) 4) {
781 rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
782 rpmuint8_t trailer[6];
783 nb = (rpmuint32_t) htonl(nb);
784 trailer[0] = sigp->version;
785 trailer[1] = (rpmuint8_t)0xff;
786 memcpy(trailer+2, &nb, sizeof(nb));
787 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
788 }
789 (void) rpmswExit(op, sigp->hashlen);
790 if (op != NULL) op->count--; /* XXX one too many */
791
792 if ((xx = pgpImplSetRSA(ctx, dig, sigp)) != 0) {
793 res = RPMRC_FAIL;
794 goto exit;
795 }
796 }
797
798 /* Retrieve the matching public key. */
799 res = pgpFindPubkey(dig);
800 if (res != RPMRC_OK)
801 goto exit;
802
803 /* Verify the RSA signature. */
804 { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */
805 (void) rpmswEnter(op, 0);
806 xx = pgpImplVerifyRSA(dig);
807 (void) rpmswExit(op, 0);
808 res = (xx ? RPMRC_OK : RPMRC_FAIL);
809 }
810
811 exit:
812 /* Identify the pubkey fingerprint. */
813 t = stpcpy(t, rpmSigString(res));
814 if (sigp != NULL) {
815 t = stpcpy(t, ", key ID ");
816 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
817 t += strlen(t);
818 }
819 return res;
820 }
821
829 static rpmRC
830 verifyDSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX dsactx)
831 /*@globals internalState @*/
832 /*@modifies dig, *t, internalState */
833 {
834 const void * sig = pgpGetSig(dig);
835 #ifdef NOTYET
836 rpmuint32_t siglen = pgpGetSiglen(dig);
837 #endif
838 pgpDigParams sigp = pgpGetSignature(dig);
839 rpmRC res;
840 int xx;
841
842 assert(dig != NULL);
843 assert(dsactx != NULL);
844 assert(sigp != NULL);
845 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA);
846 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(dsactx));
847 assert(pgpGetSigtag(dig) == RPMSIGTAG_DSA);
848 assert(sig != NULL);
849
850 *t = '\0';
851 if (dig != NULL && dig->hdrsha1ctx == dsactx)
852 t = stpcpy(t, _("Header "));
853
854 /* Identify the signature version. */
855 *t++ = 'V';
856 switch (sigp->version) {
857 case 3: *t++ = '3'; break;
858 case 4: *t++ = '4'; break;
859 }
860
861 /* Identify the DSA/hash. */
862 { const char * hashname = rpmDigestName(dsactx);
863 t = stpcpy(t, " DSA");
864 if (strcmp(hashname, "UNKNOWN") && strcmp(hashname, "SHA1")) {
865 *t++ = '/';
866 t = stpcpy(t, hashname);
867 }
868 }
869 t = stpcpy(t, _(" signature: "));
870
871 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */
872 DIGEST_CTX ctx = rpmDigestDup(dsactx);
873
874 (void) rpmswEnter(op, 0);
875 if (sigp->hash != NULL)
876 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
877
878 if (sigp->version == (rpmuint8_t) 4) {
879 rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
880 rpmuint8_t trailer[6];
881 nb = (rpmuint32_t) htonl(nb);
882 trailer[0] = sigp->version;
883 trailer[1] = (rpmuint8_t)0xff;
884 memcpy(trailer+2, &nb, sizeof(nb));
885 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
886 }
887 (void) rpmswExit(op, sigp->hashlen);
888 if (op != NULL) op->count--; /* XXX one too many */
889
890 if (pgpImplSetDSA(ctx, dig, sigp)) {
891 res = RPMRC_FAIL;
892 goto exit;
893 }
894 }
895
896 /* Retrieve the matching public key. */
897 res = pgpFindPubkey(dig);
898 if (res != RPMRC_OK)
899 goto exit;
900
901 /* Verify the DSA signature. */
902 { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */
903 (void) rpmswEnter(op, 0);
904 xx = pgpImplVerifyDSA(dig);
905 res = (xx ? RPMRC_OK : RPMRC_FAIL);
906 (void) rpmswExit(op, 0);
907 }
908
909 exit:
910 /* Identify the pubkey fingerprint. */
911 t = stpcpy(t, rpmSigString(res));
912 if (sigp != NULL) {
913 t = stpcpy(t, ", key ID ");
914 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
915 t += strlen(t);
916 }
917 return res;
918 }
919
920 rpmRC
921 rpmVerifySignature(void * _dig, char * result)
922 {
923 pgpDig dig = _dig;
924 const void * sig = pgpGetSig(dig);
925 rpmuint32_t siglen = pgpGetSiglen(dig);
926 rpmSigTag sigtag = pgpGetSigtag(dig);
927 rpmRC res;
928
929 if (dig == NULL || sig == NULL || siglen == 0) {
930 sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
931 return RPMRC_NOTFOUND;
932 }
933
934 switch (sigtag) {
935 case RPMSIGTAG_SIZE:
936 res = verifySize(dig, result);
937 break;
938 case RPMSIGTAG_MD5:
939 res = verifyMD5(dig, result, dig->md5ctx);
940 break;
941 case RPMSIGTAG_SHA1:
942 res = verifySHA1(dig, result, dig->hdrsha1ctx);
943 break;
944 case RPMSIGTAG_RSA:
945 res = verifyRSA(dig, result, dig->hdrctx);
946 break;
947 case RPMSIGTAG_DSA:
948 res = verifyDSA(dig, result, dig->hdrsha1ctx);
949 break;
950 default:
951 sprintf(result, _("Signature: UNKNOWN (%u)\n"), (unsigned)sigtag);
952 res = RPMRC_NOTFOUND;
953 break;
954 }
955 return res;
956 }