rpm
5.2.1
|
00001 00005 #include "system.h" 00006 00007 #include <rpmio.h> 00008 #include <rpmurl.h> 00009 #include <rpmcb.h> /* XXX rpmIsVerbose() */ 00010 #define _RPMPGP_INTERNAL 00011 #include <rpmpgp.h> 00012 #include <rpmmacro.h> /* XXX for rpmGetPath() */ 00013 #include <rpmku.h> 00014 00015 #include <rpmtag.h> 00016 #include "rpmdb.h" 00017 #include <pkgio.h> /* XXX expects <rpmts.h> */ 00018 #include "legacy.h" /* XXX for dodogest() */ 00019 #include "signature.h" 00020 00021 #include "debug.h" 00022 00023 /*@access FD_t@*/ /* XXX ufdio->read arg1 is void ptr */ 00024 /*@access Header@*/ /* XXX compared with NULL */ 00025 /*@access DIGEST_CTX@*/ /* XXX compared with NULL */ 00026 /*@access pgpDig@*/ 00027 /*@access pgpDigParams@*/ 00028 00029 int rpmTempFile(const char * prefix, const char ** fnptr, void * fdptr) 00030 { 00031 const char * tpmacro = "%{?_tmppath}%{!?_tmppath:/var/tmp/}"; 00032 const char * tempfn = NULL; 00033 const char * tfn = NULL; 00034 static int _initialized = 0; 00035 int temput; 00036 FD_t fd = NULL; 00037 unsigned int ran; 00038 00039 if (!prefix) prefix = ""; 00040 00041 /* Create the temp directory if it doesn't already exist. */ 00042 if (!_initialized) { 00043 _initialized = 1; 00044 tempfn = rpmGenPath(prefix, tpmacro, NULL); 00045 if (rpmioMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1)) 00046 goto errxit; 00047 } 00048 00049 /* XXX should probably use mkstemp here */ 00050 ran = (unsigned) time(NULL); 00051 srand(ran); 00052 ran = rand() % 100000; 00053 00054 /* maybe this should use link/stat? */ 00055 00056 do { 00057 char tfnbuf[64]; 00058 #ifndef NOTYET 00059 sprintf(tfnbuf, "rpm-tmp.%u", ran++); 00060 tempfn = _free(tempfn); 00061 tempfn = rpmGenPath(prefix, tpmacro, tfnbuf); 00062 #else 00063 strcpy(tfnbuf, "rpm-tmp.XXXXXX"); 00064 tempfn = _free(tempfn); 00065 tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf)); 00066 #endif 00067 00068 temput = urlPath(tempfn, &tfn); 00069 if (*tfn == '\0') goto errxit; 00070 00071 switch (temput) { 00072 case URL_IS_DASH: 00073 case URL_IS_HKP: 00074 goto errxit; 00075 /*@notreached@*/ /*@switchbreak@*/ break; 00076 case URL_IS_HTTPS: 00077 case URL_IS_HTTP: 00078 case URL_IS_FTP: 00079 default: 00080 /*@switchbreak@*/ break; 00081 } 00082 00083 fd = Fopen(tempfn, "w+x.fdio"); 00084 /* XXX FIXME: errno may not be correct for ufdio */ 00085 } while ((fd == NULL || Ferror(fd)) && errno == EEXIST); 00086 00087 if (fd == NULL || Ferror(fd)) { 00088 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tempfn); 00089 goto errxit; 00090 } 00091 00092 switch(temput) { 00093 case URL_IS_PATH: 00094 case URL_IS_UNKNOWN: 00095 { struct stat sb, sb2; 00096 if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) { 00097 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn); 00098 goto errxit; 00099 } 00100 00101 if (sb.st_nlink != 1) { 00102 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn); 00103 goto errxit; 00104 } 00105 00106 if (fstat(Fileno(fd), &sb2) == 0) { 00107 if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) { 00108 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn); 00109 goto errxit; 00110 } 00111 } 00112 } break; 00113 default: 00114 break; 00115 } 00116 00117 if (fnptr) 00118 *fnptr = tempfn; 00119 else 00120 tempfn = _free(tempfn); 00121 if (fdptr) 00122 *(FD_t *)fdptr = fd; 00123 00124 return 0; 00125 00126 errxit: 00127 tempfn = _free(tempfn); 00128 if (fnptr) 00129 *fnptr = NULL; 00130 /*@-usereleased@*/ 00131 if (fd != NULL) (void) Fclose(fd); 00132 /*@=usereleased@*/ 00133 return 1; 00134 } 00135 00136 00146 static int makeGPGSignature(const char * file, rpmSigTag * sigTagp, 00147 /*@out@*/ rpmuint8_t ** pktp, /*@out@*/ rpmuint32_t * pktlenp, 00148 /*@null@*/ const char * passPhrase) 00149 /*@globals rpmGlobalMacroContext, h_errno, 00150 fileSystem, internalState @*/ 00151 /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext, 00152 fileSystem, internalState @*/ 00153 { 00154 char * sigfile = alloca(strlen(file)+sizeof(".sig")); 00155 pid_t pid; 00156 int status; 00157 int inpipe[2]; 00158 FILE * fpipe; 00159 struct stat st; 00160 const char * cmd; 00161 char *const *av; 00162 pgpDig dig = NULL; 00163 pgpDigParams sigp = NULL; 00164 const char * pw = NULL; 00165 int rc; 00166 00167 (void) stpcpy( stpcpy(sigfile, file), ".sig"); 00168 00169 addMacro(NULL, "__plaintext_filename", NULL, file, -1); 00170 addMacro(NULL, "__signature_filename", NULL, sigfile, -1); 00171 00172 inpipe[0] = inpipe[1] = 0; 00173 if (pipe(inpipe) < 0) { 00174 rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m")); 00175 return 1; 00176 } 00177 00178 if (!(pid = fork())) { 00179 const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); 00180 00181 (void) dup2(inpipe[0], 3); 00182 (void) close(inpipe[1]); 00183 00184 if (gpg_path && *gpg_path != '\0') 00185 (void) setenv("GNUPGHOME", gpg_path, 1); 00186 00187 unsetenv("MALLOC_CHECK_"); 00188 cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); 00189 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00190 if (!rc) 00191 rc = execve(av[0], av+1, environ); 00192 00193 rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg", 00194 strerror(errno)); 00195 _exit(EXIT_FAILURE); 00196 } 00197 00198 delMacro(NULL, "__plaintext_filename"); 00199 delMacro(NULL, "__signature_filename"); 00200 00201 pw = rpmkuPassPhrase(passPhrase); 00202 if (pw == NULL) { 00203 rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"), 00204 strerror(errno)); 00205 return 1; 00206 } 00207 00208 fpipe = fdopen(inpipe[1], "w"); 00209 (void) close(inpipe[0]); 00210 if (fpipe) { 00211 fprintf(fpipe, "%s\n", (pw ? pw : "")); 00212 (void) fclose(fpipe); 00213 } 00214 00215 if (pw != NULL) { 00216 (void) memset((void *)pw, 0, strlen(pw)); 00217 pw = _free(pw); 00218 } 00219 00220 /*@+longunsignedintegral@*/ 00221 (void) waitpid(pid, &status, 0); 00222 /*@=longunsignedintegral@*/ 00223 if (!WIFEXITED(status) || WEXITSTATUS(status)) { 00224 rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status)); 00225 return 1; 00226 } 00227 00228 if (Stat(sigfile, &st)) { 00229 /* GPG failed to write signature */ 00230 if (sigfile) (void) Unlink(sigfile); /* Just in case */ 00231 rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n")); 00232 return 1; 00233 } 00234 00235 *pktlenp = (rpmuint32_t)st.st_size; 00236 rpmlog(RPMLOG_DEBUG, D_("GPG sig size: %u\n"), (unsigned)*pktlenp); 00237 *pktp = xmalloc(*pktlenp); 00238 00239 { FD_t fd; 00240 00241 rc = 0; 00242 fd = Fopen(sigfile, "r.ufdio"); 00243 if (fd != NULL && !Ferror(fd)) { 00244 rc = (int) Fread(*pktp, sizeof((*pktp)[0]), *pktlenp, fd); 00245 if (sigfile) (void) Unlink(sigfile); 00246 (void) Fclose(fd); 00247 } 00248 if ((rpmuint32_t)rc != *pktlenp) { 00249 *pktp = _free(*pktp); 00250 rpmlog(RPMLOG_ERR, _("unable to read the signature\n")); 00251 return 1; 00252 } 00253 } 00254 00255 rpmlog(RPMLOG_DEBUG, D_("Got %u bytes of GPG sig\n"), (unsigned)*pktlenp); 00256 00257 /* Parse the signature, change signature tag as appropriate. */ 00258 dig = pgpDigNew(0); 00259 00260 (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0); 00261 sigp = pgpGetSignature(dig); 00262 00263 /* Identify the type of signature being returned. */ 00264 switch (*sigTagp) { 00265 default: 00266 assert(0); /* XXX never happens. */ 00267 /*@notreached@*/ break; 00268 case RPMSIGTAG_SIZE: 00269 case RPMSIGTAG_MD5: 00270 case RPMSIGTAG_SHA1: 00271 break; 00272 case RPMSIGTAG_DSA: 00273 /* XXX check hash algorithm too? */ 00274 if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA) 00275 *sigTagp = RPMSIGTAG_RSA; 00276 break; 00277 case RPMSIGTAG_RSA: 00278 if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA) 00279 *sigTagp = RPMSIGTAG_DSA; 00280 break; 00281 } 00282 00283 dig = pgpDigFree(dig, "makeGPGSignature"); 00284 00285 return 0; 00286 } 00287 00296 /*@-mustmod@*/ /* sigh is modified */ 00297 static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag, 00298 /*@null@*/ const char * passPhrase) 00299 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00300 /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/ 00301 { 00302 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00303 Header h = NULL; 00304 FD_t fd = NULL; 00305 rpmuint8_t * pkt; 00306 rpmuint32_t pktlen; 00307 const char * fn = NULL; 00308 const char * msg; 00309 rpmRC rc; 00310 int ret = -1; /* assume failure. */ 00311 int xx; 00312 00313 switch (sigTag) { 00314 default: 00315 assert(0); /* XXX never happens. */ 00316 /*@notreached@*/ break; 00317 case RPMSIGTAG_SIZE: 00318 case RPMSIGTAG_MD5: 00319 case RPMSIGTAG_PGP5: /* XXX legacy */ 00320 case RPMSIGTAG_PGP: 00321 case RPMSIGTAG_GPG: 00322 goto exit; 00323 /*@notreached@*/ break; 00324 case RPMSIGTAG_SHA1: 00325 { const char * SHA1 = NULL; 00326 fd = Fopen(file, "r.fdio"); 00327 if (fd == NULL || Ferror(fd)) 00328 goto exit; 00329 { const char item[] = "Header"; 00330 msg = NULL; 00331 rc = rpmpkgRead(item, fd, &h, &msg); 00332 if (rc != RPMRC_OK) { 00333 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00334 msg = _free(msg); 00335 goto exit; 00336 } 00337 msg = _free(msg); 00338 } 00339 (void) Fclose(fd); fd = NULL; 00340 00341 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { 00342 unsigned char * hmagic = NULL; 00343 size_t nmagic = 0; 00344 DIGEST_CTX ctx; 00345 00346 he->tag = RPMTAG_HEADERIMMUTABLE; 00347 if (!headerGet(h, he, 0) || he->p.ptr == NULL) 00348 { 00349 (void)headerFree(h); 00350 h = NULL; 00351 goto exit; 00352 } 00353 (void) headerGetMagic(NULL, &hmagic, &nmagic); 00354 ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); 00355 if (hmagic && nmagic > 0) 00356 (void) rpmDigestUpdate(ctx, hmagic, nmagic); 00357 (void) rpmDigestUpdate(ctx, he->p.ptr, he->c); 00358 (void) rpmDigestFinal(ctx, &SHA1, NULL, 1); 00359 he->p.ptr = _free(he->p.ptr); 00360 } 00361 (void)headerFree(h); 00362 h = NULL; 00363 00364 if (SHA1 == NULL) 00365 goto exit; 00366 he->tag = (rpmTag) RPMSIGTAG_SHA1; 00367 he->t = RPM_STRING_TYPE; 00368 he->p.str = SHA1; 00369 he->c = 1; 00370 xx = headerPut(sigh, he, 0); 00371 SHA1 = _free(SHA1); 00372 if (!xx) 00373 goto exit; 00374 ret = 0; 00375 } break; 00376 case RPMSIGTAG_DSA: 00377 fd = Fopen(file, "r.fdio"); 00378 if (fd == NULL || Ferror(fd)) 00379 goto exit; 00380 { const char item[] = "Header"; 00381 msg = NULL; 00382 rc = rpmpkgRead(item, fd, &h, &msg); 00383 if (rc != RPMRC_OK) { 00384 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00385 msg = _free(msg); 00386 goto exit; 00387 } 00388 msg = _free(msg); 00389 } 00390 (void) Fclose(fd); fd = NULL; 00391 00392 if (rpmTempFile(NULL, &fn, &fd)) 00393 goto exit; 00394 { const char item[] = "Header"; 00395 msg = NULL; 00396 rc = rpmpkgWrite(item, fd, h, &msg); 00397 if (rc != RPMRC_OK) { 00398 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg); 00399 msg = _free(msg); 00400 goto exit; 00401 } 00402 msg = _free(msg); 00403 } 00404 (void) Fclose(fd); fd = NULL; 00405 00406 if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)) 00407 goto exit; 00408 he->tag = (rpmTag) sigTag; 00409 he->t = RPM_BIN_TYPE; 00410 he->p.ptr = pkt; 00411 he->c = pktlen; 00412 xx = headerPut(sigh, he, 0); 00413 if (!xx) 00414 goto exit; 00415 ret = 0; 00416 break; 00417 } 00418 00419 exit: 00420 if (fn) { 00421 (void) Unlink(fn); 00422 fn = _free(fn); 00423 } 00424 (void)headerFree(h); 00425 h = NULL; 00426 if (fd != NULL) (void) Fclose(fd); 00427 return ret; 00428 } 00429 /*@=mustmod@*/ 00430 00431 int rpmAddSignature(Header sigh, const char * file, rpmSigTag sigTag, 00432 const char * passPhrase) 00433 { 00434 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00435 struct stat st; 00436 rpmuint8_t * pkt; 00437 rpmuint32_t pktlen; 00438 int ret = -1; /* assume failure. */ 00439 int xx; 00440 00441 switch (sigTag) { 00442 default: 00443 assert(0); /* XXX never happens. */ 00444 /*@notreached@*/ break; 00445 case RPMSIGTAG_SIZE: 00446 if (Stat(file, &st) != 0) 00447 break; 00448 pktlen = (rpmuint32_t)st.st_size; 00449 he->tag = (rpmTag) sigTag; 00450 he->t = RPM_UINT32_TYPE; 00451 he->p.ui32p = &pktlen; 00452 he->c = 1; 00453 /*@-compmempass@*/ 00454 xx = headerPut(sigh, he, 0); 00455 /*@=compmempass@*/ 00456 if (!xx) 00457 break; 00458 ret = 0; 00459 break; 00460 case RPMSIGTAG_MD5: 00461 pktlen = 128/8; 00462 pkt = memset(alloca(pktlen), 0, pktlen); 00463 if (dodigest(PGPHASHALGO_MD5, file, (unsigned char *)pkt, 0, NULL)) 00464 break; 00465 he->tag = (rpmTag) sigTag; 00466 he->t = RPM_BIN_TYPE; 00467 he->p.ptr = pkt; 00468 he->c = pktlen; 00469 xx = headerPut(sigh, he, 0); 00470 if (!xx) 00471 break; 00472 ret = 0; 00473 break; 00474 case RPMSIGTAG_GPG: 00475 ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase); 00476 break; 00477 case RPMSIGTAG_RSA: 00478 case RPMSIGTAG_DSA: 00479 case RPMSIGTAG_SHA1: 00480 ret = makeHDRSignature(sigh, file, sigTag, passPhrase); 00481 break; 00482 } 00483 00484 return ret; 00485 } 00486 00487 int rpmCheckPassPhrase(const char * passPhrase) 00488 { 00489 const char *pw; 00490 int p[2]; 00491 pid_t pid; 00492 int status; 00493 int rc; 00494 int xx; 00495 00496 p[0] = p[1] = 0; 00497 xx = pipe(p); 00498 00499 if (!(pid = fork())) { 00500 const char * cmd; 00501 char *const *av; 00502 int fdno; 00503 00504 xx = close(STDIN_FILENO); 00505 xx = close(STDOUT_FILENO); 00506 xx = close(p[1]); 00507 if (!rpmIsVerbose()) 00508 xx = close(STDERR_FILENO); 00509 if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) { 00510 xx = dup2(fdno, STDIN_FILENO); 00511 xx = close(fdno); 00512 } 00513 if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) { 00514 xx = dup2(fdno, STDOUT_FILENO); 00515 xx = close(fdno); 00516 } 00517 xx = dup2(p[0], 3); 00518 00519 unsetenv("MALLOC_CHECK_"); 00520 { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); 00521 00522 if (gpg_path && *gpg_path != '\0') 00523 (void) setenv("GNUPGHOME", gpg_path, 1); 00524 00525 cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL); 00526 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00527 if (!rc) 00528 rc = execve(av[0], av+1, environ); 00529 00530 rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg", 00531 strerror(errno)); 00532 } 00533 } 00534 00535 pw = rpmkuPassPhrase(passPhrase); 00536 if (pw == NULL) { 00537 rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"), 00538 strerror(errno)); 00539 return 1; 00540 } 00541 00542 xx = close(p[0]); 00543 xx = (int) write(p[1], pw, strlen(pw)); 00544 xx = (int) write(p[1], "\n", 1); 00545 xx = close(p[1]); 00546 00547 if (pw != NULL) { 00548 (void) memset((void *)pw, 0, strlen(pw)); 00549 pw = _free(pw); 00550 } 00551 00552 /*@+longunsignedintegral@*/ 00553 (void) waitpid(pid, &status, 0); 00554 /*@=longunsignedintegral@*/ 00555 00556 return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0); 00557 } 00558 00559 static /*@observer@*/ const char * rpmSigString(rpmRC res) 00560 /*@*/ 00561 { 00562 const char * str; 00563 switch (res) { 00564 case RPMRC_OK: str = "OK"; break; 00565 case RPMRC_FAIL: str = "BAD"; break; 00566 case RPMRC_NOKEY: str = "NOKEY"; break; 00567 case RPMRC_NOTTRUSTED: str = "NOTRUSTED"; break; 00568 default: 00569 case RPMRC_NOTFOUND: str = "UNKNOWN"; break; 00570 } 00571 return str; 00572 } 00573 00574 static rpmRC 00575 verifySize(const pgpDig dig, /*@out@*/ char * t) 00576 /*@modifies *t @*/ 00577 { 00578 const void * sig = pgpGetSig(dig); 00579 rpmRC res; 00580 rpmuint32_t size = 0xffffffff; 00581 00582 *t = '\0'; 00583 t = stpcpy(t, _("Header+Payload size: ")); 00584 00585 if (sig == NULL || dig == NULL || dig->nbytes == 0) { 00586 res = RPMRC_NOKEY; 00587 t = stpcpy(t, rpmSigString(res)); 00588 goto exit; 00589 } 00590 00591 memcpy(&size, sig, sizeof(size)); 00592 00593 if (size !=(rpmuint32_t) dig->nbytes) { 00594 res = RPMRC_FAIL; 00595 t = stpcpy(t, rpmSigString(res)); 00596 sprintf(t, " Expected(%u) != (%u)\n", (unsigned)size, (unsigned)dig->nbytes); 00597 } else { 00598 res = RPMRC_OK; 00599 t = stpcpy(t, rpmSigString(res)); 00600 sprintf(t, " (%u)", (unsigned)dig->nbytes); 00601 } 00602 00603 exit: 00604 return res; 00605 } 00606 00607 static rpmRC 00608 verifyMD5(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX md5ctx) 00609 /*@globals internalState @*/ 00610 /*@modifies *t, internalState @*/ 00611 { 00612 const void * sig = pgpGetSig(dig); 00613 rpmuint32_t siglen = pgpGetSiglen(dig); 00614 rpmRC res; 00615 rpmuint8_t * md5sum = NULL; 00616 size_t md5len = 0; 00617 00618 assert(dig != NULL); 00619 assert(md5ctx != NULL); 00620 assert(sig != NULL); 00621 00622 *t = '\0'; 00623 00624 /* Identify the hash. */ 00625 t = stpcpy(t, rpmDigestName(md5ctx)); 00626 t = stpcpy(t, _(" digest: ")); 00627 00628 if (sig == NULL) { /* XXX can't happen, DYING */ 00629 res = RPMRC_NOKEY; 00630 t = stpcpy(t, rpmSigString(res)); 00631 goto exit; 00632 } 00633 00634 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00635 (void) rpmswEnter(op, 0); 00636 (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0); 00637 (void) rpmswExit(op, 0); 00638 if (op != NULL) op->count--; /* XXX one too many */ 00639 } 00640 00641 if (md5len != siglen || memcmp(md5sum, sig, md5len)) { 00642 res = RPMRC_FAIL; 00643 t = stpcpy(t, rpmSigString(res)); 00644 t = stpcpy(t, " Expected("); 00645 (void) pgpHexCvt(t, sig, siglen); 00646 t += strlen(t); 00647 t = stpcpy(t, ") != ("); 00648 } else { 00649 res = RPMRC_OK; 00650 t = stpcpy(t, rpmSigString(res)); 00651 t = stpcpy(t, " ("); 00652 } 00653 (void) pgpHexCvt(t, md5sum, md5len); 00654 t += strlen(t); 00655 t = stpcpy(t, ")"); 00656 00657 exit: 00658 md5sum = _free(md5sum); 00659 return res; 00660 } 00661 00669 static rpmRC 00670 verifySHA1(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX shactx) 00671 /*@globals internalState @*/ 00672 /*@modifies *t, internalState @*/ 00673 { 00674 const void * sig = pgpGetSig(dig); 00675 #ifdef NOTYET 00676 rpmuint32_t siglen = pgpGetSiglen(dig); 00677 #endif 00678 rpmRC res; 00679 const char * SHA1 = NULL; 00680 00681 assert(dig != NULL); 00682 assert(shactx != NULL); 00683 assert(sig != NULL); 00684 00685 *t = '\0'; 00686 t = stpcpy(t, _("Header ")); 00687 00688 /* Identify the hash. */ 00689 t = stpcpy(t, rpmDigestName(shactx)); 00690 t = stpcpy(t, _(" digest: ")); 00691 00692 if (sig == NULL) { /* XXX can't happen, DYING */ 00693 res = RPMRC_NOKEY; 00694 t = stpcpy(t, rpmSigString(res)); 00695 goto exit; 00696 } 00697 00698 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00699 (void) rpmswEnter(op, 0); 00700 (void) rpmDigestFinal(rpmDigestDup(shactx), &SHA1, NULL, 1); 00701 (void) rpmswExit(op, 0); 00702 } 00703 00704 if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) { 00705 res = RPMRC_FAIL; 00706 t = stpcpy(t, rpmSigString(res)); 00707 t = stpcpy(t, " Expected("); 00708 t = stpcpy(t, sig); 00709 t = stpcpy(t, ") != ("); 00710 } else { 00711 res = RPMRC_OK; 00712 t = stpcpy(t, rpmSigString(res)); 00713 t = stpcpy(t, " ("); 00714 } 00715 if (SHA1) 00716 t = stpcpy(t, SHA1); 00717 t = stpcpy(t, ")"); 00718 00719 exit: 00720 SHA1 = _free(SHA1); 00721 return res; 00722 } 00723 00731 static rpmRC 00732 verifyRSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX rsactx) 00733 /*@globals internalState @*/ 00734 /*@modifies dig, *t, internalState */ 00735 { 00736 const void * sig = pgpGetSig(dig); 00737 #ifdef NOTYET 00738 rpmuint32_t siglen = pgpGetSiglen(dig); 00739 #endif 00740 pgpDigParams sigp = pgpGetSignature(dig); 00741 rpmRC res = RPMRC_OK; 00742 int xx; 00743 00744 assert(dig != NULL); 00745 assert(rsactx != NULL); 00746 assert(sigp != NULL); 00747 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA); 00748 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(rsactx)); 00749 assert(pgpGetSigtag(dig) == RPMSIGTAG_RSA); 00750 assert(sig != NULL); 00751 00752 *t = '\0'; 00753 if (dig->hdrctx == rsactx) 00754 t = stpcpy(t, _("Header ")); 00755 00756 /* Identify the signature version. */ 00757 *t++ = 'V'; 00758 switch (sigp->version) { 00759 case 3: *t++ = '3'; break; 00760 case 4: *t++ = '4'; break; 00761 } 00762 00763 /* Identify the RSA/hash. */ 00764 { const char * hashname = rpmDigestName(rsactx); 00765 t = stpcpy(t, " RSA"); 00766 if (strcmp(hashname, "UNKNOWN")) { 00767 *t++ = '/'; 00768 t = stpcpy(t, hashname); 00769 } 00770 } 00771 t = stpcpy(t, _(" signature: ")); 00772 00773 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00774 DIGEST_CTX ctx = rpmDigestDup(rsactx); 00775 00776 (void) rpmswEnter(op, 0); 00777 if (sigp->hash != NULL) 00778 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); 00779 00780 if (sigp->version == (rpmuint8_t) 4) { 00781 rpmuint32_t nb = (rpmuint32_t) sigp->hashlen; 00782 rpmuint8_t trailer[6]; 00783 nb = (rpmuint32_t) htonl(nb); 00784 trailer[0] = sigp->version; 00785 trailer[1] = (rpmuint8_t)0xff; 00786 memcpy(trailer+2, &nb, sizeof(nb)); 00787 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer)); 00788 } 00789 (void) rpmswExit(op, sigp->hashlen); 00790 if (op != NULL) op->count--; /* XXX one too many */ 00791 00792 if ((xx = pgpImplSetRSA(ctx, dig, sigp)) != 0) { 00793 res = RPMRC_FAIL; 00794 goto exit; 00795 } 00796 } 00797 00798 /* Retrieve the matching public key. */ 00799 res = pgpFindPubkey(dig); 00800 if (res != RPMRC_OK) 00801 goto exit; 00802 00803 /* Verify the RSA signature. */ 00804 { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */ 00805 (void) rpmswEnter(op, 0); 00806 xx = pgpImplVerifyRSA(dig); 00807 (void) rpmswExit(op, 0); 00808 res = (xx ? RPMRC_OK : RPMRC_FAIL); 00809 } 00810 00811 exit: 00812 /* Identify the pubkey fingerprint. */ 00813 t = stpcpy(t, rpmSigString(res)); 00814 if (sigp != NULL) { 00815 t = stpcpy(t, ", key ID "); 00816 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); 00817 t += strlen(t); 00818 } 00819 return res; 00820 } 00821 00829 static rpmRC 00830 verifyDSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX dsactx) 00831 /*@globals internalState @*/ 00832 /*@modifies dig, *t, internalState */ 00833 { 00834 const void * sig = pgpGetSig(dig); 00835 #ifdef NOTYET 00836 rpmuint32_t siglen = pgpGetSiglen(dig); 00837 #endif 00838 pgpDigParams sigp = pgpGetSignature(dig); 00839 rpmRC res; 00840 int xx; 00841 00842 assert(dig != NULL); 00843 assert(dsactx != NULL); 00844 assert(sigp != NULL); 00845 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA); 00846 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(dsactx)); 00847 assert(pgpGetSigtag(dig) == RPMSIGTAG_DSA); 00848 assert(sig != NULL); 00849 00850 *t = '\0'; 00851 if (dig != NULL && dig->hdrsha1ctx == dsactx) 00852 t = stpcpy(t, _("Header ")); 00853 00854 /* Identify the signature version. */ 00855 *t++ = 'V'; 00856 switch (sigp->version) { 00857 case 3: *t++ = '3'; break; 00858 case 4: *t++ = '4'; break; 00859 } 00860 00861 /* Identify the DSA/hash. */ 00862 { const char * hashname = rpmDigestName(dsactx); 00863 t = stpcpy(t, " DSA"); 00864 if (strcmp(hashname, "UNKNOWN") && strcmp(hashname, "SHA1")) { 00865 *t++ = '/'; 00866 t = stpcpy(t, hashname); 00867 } 00868 } 00869 t = stpcpy(t, _(" signature: ")); 00870 00871 { rpmop op = pgpStatsAccumulator(dig, 10); /* RPMTS_OP_DIGEST */ 00872 DIGEST_CTX ctx = rpmDigestDup(dsactx); 00873 00874 (void) rpmswEnter(op, 0); 00875 if (sigp->hash != NULL) 00876 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); 00877 00878 if (sigp->version == (rpmuint8_t) 4) { 00879 rpmuint32_t nb = (rpmuint32_t) sigp->hashlen; 00880 rpmuint8_t trailer[6]; 00881 nb = (rpmuint32_t) htonl(nb); 00882 trailer[0] = sigp->version; 00883 trailer[1] = (rpmuint8_t)0xff; 00884 memcpy(trailer+2, &nb, sizeof(nb)); 00885 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer)); 00886 } 00887 (void) rpmswExit(op, sigp->hashlen); 00888 if (op != NULL) op->count--; /* XXX one too many */ 00889 00890 if (pgpImplSetDSA(ctx, dig, sigp)) { 00891 res = RPMRC_FAIL; 00892 goto exit; 00893 } 00894 } 00895 00896 /* Retrieve the matching public key. */ 00897 res = pgpFindPubkey(dig); 00898 if (res != RPMRC_OK) 00899 goto exit; 00900 00901 /* Verify the DSA signature. */ 00902 { rpmop op = pgpStatsAccumulator(dig, 11); /* RPMTS_OP_SIGNATURE */ 00903 (void) rpmswEnter(op, 0); 00904 xx = pgpImplVerifyDSA(dig); 00905 res = (xx ? RPMRC_OK : RPMRC_FAIL); 00906 (void) rpmswExit(op, 0); 00907 } 00908 00909 exit: 00910 /* Identify the pubkey fingerprint. */ 00911 t = stpcpy(t, rpmSigString(res)); 00912 if (sigp != NULL) { 00913 t = stpcpy(t, ", key ID "); 00914 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); 00915 t += strlen(t); 00916 } 00917 return res; 00918 } 00919 00920 rpmRC 00921 rpmVerifySignature(void * _dig, char * result) 00922 { 00923 pgpDig dig = _dig; 00924 const void * sig = pgpGetSig(dig); 00925 rpmuint32_t siglen = pgpGetSiglen(dig); 00926 rpmSigTag sigtag = pgpGetSigtag(dig); 00927 rpmRC res; 00928 00929 if (dig == NULL || sig == NULL || siglen == 0) { 00930 sprintf(result, _("Verify signature: BAD PARAMETERS\n")); 00931 return RPMRC_NOTFOUND; 00932 } 00933 00934 switch (sigtag) { 00935 case RPMSIGTAG_SIZE: 00936 res = verifySize(dig, result); 00937 break; 00938 case RPMSIGTAG_MD5: 00939 res = verifyMD5(dig, result, dig->md5ctx); 00940 break; 00941 case RPMSIGTAG_SHA1: 00942 res = verifySHA1(dig, result, dig->hdrsha1ctx); 00943 break; 00944 case RPMSIGTAG_RSA: 00945 res = verifyRSA(dig, result, dig->hdrctx); 00946 break; 00947 case RPMSIGTAG_DSA: 00948 res = verifyDSA(dig, result, dig->hdrsha1ctx); 00949 break; 00950 default: 00951 sprintf(result, _("Signature: UNKNOWN (%u)\n"), (unsigned)sigtag); 00952 res = RPMRC_NOTFOUND; 00953 break; 00954 } 00955 return res; 00956 }