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