rpm
4.5
|
00001 00005 #include "system.h" 00006 00007 #include "rpmio_internal.h" 00008 #include <rpmlib.h> 00009 #include <rpmmacro.h> /* XXX for rpmGetPath() */ 00010 #include "rpmdb.h" 00011 00012 #include "rpmts.h" 00013 00014 #include "misc.h" /* XXX for dosetenv() and makeTempFile() */ 00015 #include "legacy.h" /* XXX for mdbinfile() */ 00016 #include "rpmlead.h" 00017 #include "signature.h" 00018 #include "header_internal.h" 00019 #include "debug.h" 00020 00021 /*@access FD_t@*/ /* XXX ufdio->read arg1 is void ptr */ 00022 /*@access Header@*/ /* XXX compared with NULL */ 00023 /*@access entryInfo @*/ /* XXX rpmReadSignature */ 00024 /*@access indexEntry @*/ /* XXX rpmReadSignature */ 00025 /*@access DIGEST_CTX@*/ /* XXX compared with NULL */ 00026 /*@access pgpDig@*/ 00027 /*@access pgpDigParams@*/ 00028 00029 int rpmLookupSignatureType(int action) 00030 { 00031 /*@unchecked@*/ 00032 static int disabled = 0; 00033 int rc = 0; 00034 00035 switch (action) { 00036 case RPMLOOKUPSIG_DISABLE: 00037 disabled = -2; 00038 break; 00039 case RPMLOOKUPSIG_ENABLE: 00040 disabled = 0; 00041 /*@fallthrough@*/ 00042 case RPMLOOKUPSIG_QUERY: 00043 if (disabled) 00044 break; /* Disabled */ 00045 /*@-boundsread@*/ 00046 { const char *name = rpmExpand("%{?_signature}", NULL); 00047 if (!(name && *name != '\0')) 00048 rc = 0; 00049 else if (!xstrcasecmp(name, "none")) 00050 rc = 0; 00051 else if (!xstrcasecmp(name, "pgp")) 00052 rc = RPMSIGTAG_PGP; 00053 else if (!xstrcasecmp(name, "pgp5")) /* XXX legacy */ 00054 rc = RPMSIGTAG_PGP; 00055 else if (!xstrcasecmp(name, "gpg")) 00056 rc = RPMSIGTAG_GPG; 00057 else 00058 rc = -1; /* Invalid %_signature spec in macro file */ 00059 name = _free(name); 00060 } break; 00061 /*@=boundsread@*/ 00062 } 00063 return rc; 00064 } 00065 00066 /* rpmDetectPGPVersion() returns the absolute path to the "pgp" */ 00067 /* executable of the requested version, or NULL when none found. */ 00068 00069 const char * rpmDetectPGPVersion(pgpVersion * pgpVer) 00070 { 00071 /* Actually this should support having more then one pgp version. */ 00072 /* At the moment only one version is possible since we only */ 00073 /* have one %__pgp and one %_pgp_path. */ 00074 00075 static pgpVersion saved_pgp_version = PGP_UNKNOWN; 00076 const char *pgpbin = rpmGetPath("%{?__pgp}", NULL); 00077 00078 if (saved_pgp_version == PGP_UNKNOWN) { 00079 char *pgpvbin; 00080 struct stat st; 00081 00082 /*@-boundsread@*/ 00083 if (!(pgpbin && pgpbin[0] != '\0')) { 00084 pgpbin = _free(pgpbin); 00085 saved_pgp_version = -1; 00086 return NULL; 00087 } 00088 /*@=boundsread@*/ 00089 /*@-boundswrite@*/ 00090 pgpvbin = (char *)alloca(strlen(pgpbin) + sizeof("v")); 00091 (void)stpcpy(stpcpy(pgpvbin, pgpbin), "v"); 00092 /*@=boundswrite@*/ 00093 00094 if (stat(pgpvbin, &st) == 0) 00095 saved_pgp_version = PGP_5; 00096 else if (stat(pgpbin, &st) == 0) 00097 saved_pgp_version = PGP_2; 00098 else 00099 saved_pgp_version = PGP_NOTDETECTED; 00100 } 00101 00102 /*@-boundswrite@*/ 00103 if (pgpVer && pgpbin) 00104 *pgpVer = saved_pgp_version; 00105 /*@=boundswrite@*/ 00106 return pgpbin; 00107 } 00108 00118 static inline rpmRC printSize(FD_t fd, int siglen, int pad, size_t datalen) 00119 /*@globals fileSystem @*/ 00120 /*@modifies fileSystem @*/ 00121 { 00122 int fdno = Fileno(fd); 00123 struct stat st; 00124 size_t expected; 00125 00126 /* HACK: workaround for davRead wiring. */ 00127 if (fdno == 123456789) { 00128 st.st_size = 0; 00129 /*@-sizeoftype@*/ 00130 st.st_size -= sizeof(struct rpmlead)+siglen+pad+datalen; 00131 /*@=sizeoftype@*/ 00132 } else if (fstat(fdno, &st) < 0) 00133 return RPMRC_FAIL; 00134 00135 /*@-sizeoftype@*/ 00136 expected = sizeof(struct rpmlead) + siglen + pad; 00137 expected += datalen, 00138 rpmMessage(RPMMESS_DEBUG, 00139 D_("Expected size: %12lu = lead(%d)+sigs(%d)+pad(%d)+data(%lu)\n"), 00140 (unsigned long)expected, 00141 (int)sizeof(struct rpmlead), siglen, pad, (unsigned long)datalen); 00142 /*@=sizeoftype@*/ 00143 rpmMessage(RPMMESS_DEBUG, 00144 D_(" Actual size: %12lu\n"), (unsigned long)st.st_size); 00145 00146 return RPMRC_OK; 00147 } 00148 00149 /*@unchecked@*/ 00150 static unsigned char header_magic[8] = { 00151 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00 00152 }; 00153 00154 rpmRC rpmReadSignature(FD_t fd, Header * sighp, sigType sig_type, 00155 const char ** msg) 00156 { 00157 char buf[BUFSIZ]; 00158 int_32 block[4]; 00159 int_32 il; 00160 int_32 dl; 00161 int_32 * ei = NULL; 00162 entryInfo pe; 00163 size_t nb; 00164 int_32 ril = 0; 00165 indexEntry entry = memset(alloca(sizeof(*entry)), 0, sizeof(*entry)); 00166 entryInfo info = memset(alloca(sizeof(*info)), 0, sizeof(*info)); 00167 unsigned char * dataStart; 00168 unsigned char * dataEnd = NULL; 00169 Header sigh = NULL; 00170 rpmRC rc = RPMRC_FAIL; /* assume failure */ 00171 int xx; 00172 int i; 00173 00174 /*@-boundswrite@*/ 00175 if (sighp) 00176 *sighp = NULL; 00177 00178 buf[0] = '\0'; 00179 /*@=boundswrite@*/ 00180 00181 if (sig_type != RPMSIGTYPE_HEADERSIG) 00182 goto exit; 00183 00184 memset(block, 0, sizeof(block)); 00185 if ((xx = timedRead(fd, (char *)block, sizeof(block))) != sizeof(block)) { 00186 (void) snprintf(buf, sizeof(buf), 00187 _("sigh size(%d): BAD, read returned %d\n"), (int)sizeof(block), xx); 00188 goto exit; 00189 } 00190 if (memcmp(block, header_magic, sizeof(header_magic))) { 00191 (void) snprintf(buf, sizeof(buf), 00192 _("sigh magic: BAD\n")); 00193 goto exit; 00194 } 00195 /*@-boundsread@*/ 00196 il = ntohl(block[2]); 00197 /*@=boundsread@*/ 00198 if (il < 0 || il > 32) { 00199 (void) snprintf(buf, sizeof(buf), 00200 _("sigh tags: BAD, no. of tags(%d) out of range\n"), il); 00201 goto exit; 00202 } 00203 /*@-boundsread@*/ 00204 dl = ntohl(block[3]); 00205 /*@=boundsread@*/ 00206 if (dl < 0 || dl > 8192) { 00207 (void) snprintf(buf, sizeof(buf), 00208 _("sigh data: BAD, no. of bytes(%d) out of range\n"), dl); 00209 goto exit; 00210 } 00211 00212 /*@-sizeoftype@*/ 00213 nb = (il * sizeof(struct entryInfo_s)) + dl; 00214 /*@=sizeoftype@*/ 00215 ei = xmalloc(sizeof(il) + sizeof(dl) + nb); 00216 /*@-bounds@*/ 00217 ei[0] = block[2]; 00218 ei[1] = block[3]; 00219 pe = (entryInfo) &ei[2]; 00220 /*@=bounds@*/ 00221 dataStart = (unsigned char *) (pe + il); 00222 if ((xx = timedRead(fd, (char *)pe, nb)) != nb) { 00223 (void) snprintf(buf, sizeof(buf), 00224 _("sigh blob(%d): BAD, read returned %d\n"), (int)nb, xx); 00225 goto exit; 00226 } 00227 00228 /* Check (and convert) the 1st tag element. */ 00229 xx = headerVerifyInfo(1, dl, pe, &entry->info, 0); 00230 if (xx != -1) { 00231 (void) snprintf(buf, sizeof(buf), 00232 _("tag[%d]: BAD, tag %d type %d offset %d count %d\n"), 00233 0, entry->info.tag, entry->info.type, 00234 entry->info.offset, entry->info.count); 00235 goto exit; 00236 } 00237 00238 /* Is there an immutable header region tag? */ 00239 /*@-sizeoftype@*/ 00240 if (entry->info.tag == RPMTAG_HEADERSIGNATURES 00241 && entry->info.type == RPM_BIN_TYPE 00242 && entry->info.count == REGION_TAG_COUNT) 00243 { 00244 /*@=sizeoftype@*/ 00245 00246 if (entry->info.offset >= dl) { 00247 (void) snprintf(buf, sizeof(buf), 00248 _("region offset: BAD, tag %d type %d offset %d count %d\n"), 00249 entry->info.tag, entry->info.type, 00250 entry->info.offset, entry->info.count); 00251 goto exit; 00252 } 00253 00254 /* Is there an immutable header region tag trailer? */ 00255 dataEnd = dataStart + entry->info.offset; 00256 /*@-sizeoftype@*/ 00257 /*@-bounds@*/ 00258 (void) memcpy(info, dataEnd, REGION_TAG_COUNT); 00259 /* XXX Really old packages have HEADER_IMAGE, not HEADER_SIGNATURES. */ 00260 if (info->tag == htonl(RPMTAG_HEADERIMAGE)) { 00261 int_32 stag = htonl(RPMTAG_HEADERSIGNATURES); 00262 info->tag = stag; 00263 memcpy(dataEnd, &stag, sizeof(stag)); 00264 } 00265 /*@=bounds@*/ 00266 dataEnd += REGION_TAG_COUNT; 00267 00268 xx = headerVerifyInfo(1, dl, info, &entry->info, 1); 00269 if (xx != -1 || 00270 !(entry->info.tag == RPMTAG_HEADERSIGNATURES 00271 && entry->info.type == RPM_BIN_TYPE 00272 && entry->info.count == REGION_TAG_COUNT)) 00273 { 00274 (void) snprintf(buf, sizeof(buf), 00275 _("region trailer: BAD, tag %d type %d offset %d count %d\n"), 00276 entry->info.tag, entry->info.type, 00277 entry->info.offset, entry->info.count); 00278 goto exit; 00279 } 00280 /*@=sizeoftype@*/ 00281 /*@-boundswrite@*/ 00282 memset(info, 0, sizeof(*info)); 00283 /*@=boundswrite@*/ 00284 00285 /* Is the no. of tags in the region less than the total no. of tags? */ 00286 ril = entry->info.offset/sizeof(*pe); 00287 if ((entry->info.offset % sizeof(*pe)) || ril > il) { 00288 (void) snprintf(buf, sizeof(buf), 00289 _("region size: BAD, ril(%d) > il(%d)\n"), ril, il); 00290 goto exit; 00291 } 00292 } 00293 00294 /* Sanity check signature tags */ 00295 /*@-boundswrite@*/ 00296 memset(info, 0, sizeof(*info)); 00297 /*@=boundswrite@*/ 00298 for (i = 1; i < il; i++) { 00299 xx = headerVerifyInfo(1, dl, pe+i, &entry->info, 0); 00300 if (xx != -1) { 00301 (void) snprintf(buf, sizeof(buf), 00302 _("sigh tag[%d]: BAD, tag %d type %d offset %d count %d\n"), 00303 i, entry->info.tag, entry->info.type, 00304 entry->info.offset, entry->info.count); 00305 goto exit; 00306 } 00307 } 00308 00309 /* OK, blob looks sane, load the header. */ 00310 sigh = headerLoad(ei); 00311 if (sigh == NULL) { 00312 (void) snprintf(buf, sizeof(buf), _("sigh load: BAD\n")); 00313 goto exit; 00314 } 00315 sigh->flags |= HEADERFLAG_ALLOCATED; 00316 00317 { int sigSize = headerSizeof(sigh, HEADER_MAGIC_YES); 00318 int pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */ 00319 int_32 * archSize = NULL; 00320 00321 /* Position at beginning of header. */ 00322 if (pad && (xx = timedRead(fd, (char *)block, pad)) != pad) { 00323 (void) snprintf(buf, sizeof(buf), 00324 _("sigh pad(%d): BAD, read %d bytes\n"), pad, xx); 00325 goto exit; 00326 } 00327 00328 /* Print package component sizes. */ 00329 if (headerGetEntry(sigh, RPMSIGTAG_SIZE, NULL, &archSize, NULL)) { 00330 size_t datasize = *(uint_32 *)archSize; 00331 rc = printSize(fd, sigSize, pad, datasize); 00332 if (rc != RPMRC_OK) 00333 (void) snprintf(buf, sizeof(buf), 00334 _("sigh sigSize(%d): BAD, fstat(2) failed\n"), sigSize); 00335 } 00336 } 00337 00338 exit: 00339 /*@-boundswrite@*/ 00340 if (sighp && sigh && rc == RPMRC_OK) 00341 *sighp = headerLink(sigh); 00342 sigh = headerFree(sigh); 00343 00344 if (msg != NULL) { 00345 buf[sizeof(buf)-1] = '\0'; 00346 *msg = xstrdup(buf); 00347 } 00348 /*@=boundswrite@*/ 00349 00350 return rc; 00351 } 00352 00353 int rpmWriteSignature(FD_t fd, Header sigh) 00354 { 00355 static byte buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 00356 int sigSize, pad; 00357 int rc; 00358 00359 rc = headerWrite(fd, sigh, HEADER_MAGIC_YES); 00360 if (rc) 00361 return rc; 00362 00363 sigSize = headerSizeof(sigh, HEADER_MAGIC_YES); 00364 pad = (8 - (sigSize % 8)) % 8; 00365 if (pad) { 00366 /*@-boundswrite@*/ 00367 if (Fwrite(buf, sizeof(buf[0]), pad, fd) != pad) 00368 rc = 1; 00369 /*@=boundswrite@*/ 00370 } 00371 rpmMessage(RPMMESS_DEBUG, D_("Signature: size(%d)+pad(%d)\n"), sigSize, pad); 00372 return rc; 00373 } 00374 00375 Header rpmNewSignature(void) 00376 { 00377 Header sigh = headerNew(); 00378 return sigh; 00379 } 00380 00381 Header rpmFreeSignature(Header sigh) 00382 { 00383 return headerFree(sigh); 00384 } 00385 00395 static int makePGPSignature(const char * file, /*@unused@*/ int_32 * sigTagp, 00396 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp, 00397 /*@null@*/ const char * passPhrase) 00398 /*@globals errno, rpmGlobalMacroContext, h_errno, 00399 fileSystem, internalState @*/ 00400 /*@modifies errno, *pktp, *pktlenp, rpmGlobalMacroContext, 00401 fileSystem, internalState @*/ 00402 { 00403 char * sigfile = alloca(1024); 00404 int pid, status; 00405 int inpipe[2]; 00406 struct stat st; 00407 const char * cmd; 00408 char *const *av; 00409 #ifdef NOTYET 00410 pgpDig dig = NULL; 00411 pgpDigParams sigp = NULL; 00412 #endif 00413 int rc; 00414 00415 /*@-boundswrite@*/ 00416 (void) stpcpy( stpcpy(sigfile, file), ".sig"); 00417 /*@=boundswrite@*/ 00418 00419 addMacro(NULL, "__plaintext_filename", NULL, file, -1); 00420 addMacro(NULL, "__signature_filename", NULL, sigfile, -1); 00421 00422 inpipe[0] = inpipe[1] = 0; 00423 /*@-boundsread@*/ 00424 (void) pipe(inpipe); 00425 /*@=boundsread@*/ 00426 00427 if (!(pid = fork())) { 00428 const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL); 00429 const char *path; 00430 pgpVersion pgpVer; 00431 00432 (void) dup2(inpipe[0], 3); 00433 (void) close(inpipe[1]); 00434 00435 (void) dosetenv("PGPPASSFD", "3", 1); 00436 /*@-boundsread@*/ 00437 if (pgp_path && *pgp_path != '\0') 00438 (void) dosetenv("PGPPATH", pgp_path, 1); 00439 /*@=boundsread@*/ 00440 00441 /* dosetenv("PGPPASS", passPhrase, 1); */ 00442 00443 unsetenv("MALLOC_CHECK_"); 00444 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { 00445 switch(pgpVer) { 00446 case PGP_2: 00447 cmd = rpmExpand("%{?__pgp_sign_cmd}", NULL); 00448 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00449 /*@-boundsread@*/ 00450 if (!rc) 00451 rc = execve(av[0], av+1, environ); 00452 /*@=boundsread@*/ 00453 break; 00454 case PGP_5: 00455 cmd = rpmExpand("%{?__pgp5_sign_cmd}", NULL); 00456 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00457 /*@-boundsread@*/ 00458 if (!rc) 00459 rc = execve(av[0], av+1, environ); 00460 /*@=boundsread@*/ 00461 break; 00462 case PGP_UNKNOWN: 00463 case PGP_NOTDETECTED: 00464 errno = ENOENT; 00465 break; 00466 } 00467 } 00468 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp", 00469 strerror(errno)); 00470 _exit(RPMERR_EXEC); 00471 } 00472 00473 delMacro(NULL, "__plaintext_filename"); 00474 delMacro(NULL, "__signature_filename"); 00475 00476 (void) close(inpipe[0]); 00477 if (passPhrase) 00478 (void) write(inpipe[1], passPhrase, strlen(passPhrase)); 00479 (void) write(inpipe[1], "\n", 1); 00480 (void) close(inpipe[1]); 00481 00482 (void)waitpid(pid, &status, 0); 00483 if (!WIFEXITED(status) || WEXITSTATUS(status)) { 00484 rpmError(RPMERR_SIGGEN, _("pgp failed\n")); 00485 return 1; 00486 } 00487 00488 if (stat(sigfile, &st)) { 00489 /* PGP failed to write signature */ 00490 if (sigfile) (void) unlink(sigfile); /* Just in case */ 00491 rpmError(RPMERR_SIGGEN, _("pgp failed to write signature\n")); 00492 return 1; 00493 } 00494 00495 /*@-boundswrite@*/ 00496 *pktlenp = st.st_size; 00497 rpmMessage(RPMMESS_DEBUG, D_("PGP sig size: %d\n"), *pktlenp); 00498 *pktp = xmalloc(*pktlenp); 00499 /*@=boundswrite@*/ 00500 00501 /*@-boundsread@*/ 00502 { FD_t fd; 00503 00504 rc = 0; 00505 fd = Fopen(sigfile, "r.fdio"); 00506 if (fd != NULL && !Ferror(fd)) { 00507 rc = timedRead(fd, *pktp, *pktlenp); 00508 if (sigfile) (void) unlink(sigfile); 00509 (void) Fclose(fd); 00510 } 00511 if (rc != *pktlenp) { 00512 /*@-boundswrite@*/ 00513 *pktp = _free(*pktp); 00514 /*@=boundswrite@*/ 00515 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n")); 00516 return 1; 00517 } 00518 } 00519 00520 rpmMessage(RPMMESS_DEBUG, D_("Got %d bytes of PGP sig\n"), *pktlenp); 00521 /*@=boundsread@*/ 00522 00523 #ifdef NOTYET 00524 /* Parse the signature, change signature tag as appropriate. */ 00525 dig = pgpNewDig(); 00526 00527 (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0); 00528 sigp = &dig->signature; 00529 00530 dig = pgpFreeDig(dig); 00531 #endif 00532 00533 return 0; 00534 } 00535 00545 static int makeGPGSignature(const char * file, int_32 * sigTagp, 00546 /*@out@*/ byte ** pktp, /*@out@*/ int_32 * pktlenp, 00547 /*@null@*/ const char * passPhrase) 00548 /*@globals rpmGlobalMacroContext, h_errno, 00549 fileSystem, internalState @*/ 00550 /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext, 00551 fileSystem, internalState @*/ 00552 { 00553 char * sigfile = alloca(strlen(file)+sizeof(".sig")); 00554 int pid, status; 00555 int inpipe[2]; 00556 FILE * fpipe; 00557 struct stat st; 00558 const char * cmd; 00559 char *const *av; 00560 pgpDig dig = NULL; 00561 pgpDigParams sigp = NULL; 00562 int rc; 00563 00564 /*@-boundswrite@*/ 00565 (void) stpcpy( stpcpy(sigfile, file), ".sig"); 00566 /*@=boundswrite@*/ 00567 00568 addMacro(NULL, "__plaintext_filename", NULL, file, -1); 00569 addMacro(NULL, "__signature_filename", NULL, sigfile, -1); 00570 00571 inpipe[0] = inpipe[1] = 0; 00572 /*@-boundsread@*/ 00573 (void) pipe(inpipe); 00574 /*@=boundsread@*/ 00575 00576 if (!(pid = fork())) { 00577 const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); 00578 00579 (void) dup2(inpipe[0], 3); 00580 (void) close(inpipe[1]); 00581 00582 /*@-boundsread@*/ 00583 if (gpg_path && *gpg_path != '\0') 00584 (void) dosetenv("GNUPGHOME", gpg_path, 1); 00585 /*@=boundsread@*/ 00586 00587 unsetenv("MALLOC_CHECK_"); 00588 cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL); 00589 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00590 /*@-boundsread@*/ 00591 if (!rc) 00592 rc = execve(av[0], av+1, environ); 00593 /*@=boundsread@*/ 00594 00595 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg", 00596 strerror(errno)); 00597 _exit(RPMERR_EXEC); 00598 } 00599 00600 delMacro(NULL, "__plaintext_filename"); 00601 delMacro(NULL, "__signature_filename"); 00602 00603 fpipe = fdopen(inpipe[1], "w"); 00604 (void) close(inpipe[0]); 00605 if (fpipe) { 00606 fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : "")); 00607 (void) fclose(fpipe); 00608 } 00609 00610 (void) waitpid(pid, &status, 0); 00611 if (!WIFEXITED(status) || WEXITSTATUS(status)) { 00612 rpmError(RPMERR_SIGGEN, _("gpg exec failed (%d)\n"), WEXITSTATUS(status)); 00613 return 1; 00614 } 00615 00616 if (stat(sigfile, &st)) { 00617 /* GPG failed to write signature */ 00618 if (sigfile) (void) unlink(sigfile); /* Just in case */ 00619 rpmError(RPMERR_SIGGEN, _("gpg failed to write signature\n")); 00620 return 1; 00621 } 00622 00623 /*@-boundswrite@*/ 00624 *pktlenp = st.st_size; 00625 rpmMessage(RPMMESS_DEBUG, D_("GPG sig size: %d\n"), *pktlenp); 00626 *pktp = xmalloc(*pktlenp); 00627 /*@=boundswrite@*/ 00628 00629 /*@-boundsread@*/ 00630 { FD_t fd; 00631 00632 rc = 0; 00633 fd = Fopen(sigfile, "r.fdio"); 00634 if (fd != NULL && !Ferror(fd)) { 00635 rc = timedRead(fd, *pktp, *pktlenp); 00636 if (sigfile) (void) unlink(sigfile); 00637 (void) Fclose(fd); 00638 } 00639 if (rc != *pktlenp) { 00640 /*@-boundswrite@*/ 00641 *pktp = _free(*pktp); 00642 /*@=boundswrite@*/ 00643 rpmError(RPMERR_SIGGEN, _("unable to read the signature\n")); 00644 return 1; 00645 } 00646 } 00647 00648 rpmMessage(RPMMESS_DEBUG, D_("Got %d bytes of GPG sig\n"), *pktlenp); 00649 /*@=boundsread@*/ 00650 00651 /* Parse the signature, change signature tag as appropriate. */ 00652 dig = pgpNewDig(); 00653 00654 (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0); 00655 sigp = &dig->signature; 00656 00657 switch (*sigTagp) { 00658 case RPMSIGTAG_SIZE: 00659 case RPMSIGTAG_MD5: 00660 case RPMSIGTAG_SHA1: 00661 break; 00662 case RPMSIGTAG_GPG: 00663 /* XXX check MD5 hash too? */ 00664 if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA) 00665 *sigTagp = RPMSIGTAG_PGP; 00666 break; 00667 case RPMSIGTAG_PGP5: /* XXX legacy */ 00668 case RPMSIGTAG_PGP: 00669 if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA) 00670 *sigTagp = RPMSIGTAG_GPG; 00671 break; 00672 case RPMSIGTAG_DSA: 00673 /* XXX check MD5 hash too? */ 00674 if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA) 00675 *sigTagp = RPMSIGTAG_RSA; 00676 break; 00677 case RPMSIGTAG_RSA: 00678 if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA) 00679 *sigTagp = RPMSIGTAG_DSA; 00680 break; 00681 } 00682 00683 dig = pgpFreeDig(dig); 00684 00685 return 0; 00686 } 00687 00696 static int makeHDRSignature(Header sigh, const char * file, int_32 sigTag, 00697 /*@null@*/ const char * passPhrase) 00698 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00699 /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/ 00700 { 00701 Header h = NULL; 00702 FD_t fd = NULL; 00703 byte * pkt; 00704 int_32 pktlen; 00705 const char * fn = NULL; 00706 const char * SHA1 = NULL; 00707 int ret = -1; /* assume failure. */ 00708 00709 switch (sigTag) { 00710 case RPMSIGTAG_SIZE: 00711 case RPMSIGTAG_MD5: 00712 case RPMSIGTAG_PGP5: /* XXX legacy */ 00713 case RPMSIGTAG_PGP: 00714 case RPMSIGTAG_GPG: 00715 goto exit; 00716 /*@notreached@*/ break; 00717 case RPMSIGTAG_SHA1: 00718 fd = Fopen(file, "r.fdio"); 00719 if (fd == NULL || Ferror(fd)) 00720 goto exit; 00721 h = headerRead(fd, HEADER_MAGIC_YES); 00722 if (h == NULL) 00723 goto exit; 00724 (void) Fclose(fd); fd = NULL; 00725 00726 if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { 00727 DIGEST_CTX ctx; 00728 void * uh; 00729 int_32 uht, uhc; 00730 00731 if (!headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc) 00732 || uh == NULL) 00733 { 00734 h = headerFree(h); 00735 goto exit; 00736 } 00737 ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); 00738 (void) rpmDigestUpdate(ctx, header_magic, sizeof(header_magic)); 00739 (void) rpmDigestUpdate(ctx, uh, uhc); 00740 (void) rpmDigestFinal(ctx, &SHA1, NULL, 1); 00741 uh = headerFreeData(uh, uht); 00742 } 00743 h = headerFree(h); 00744 00745 if (SHA1 == NULL) 00746 goto exit; 00747 if (!headerAddEntry(sigh, RPMSIGTAG_SHA1, RPM_STRING_TYPE, SHA1, 1)) 00748 goto exit; 00749 ret = 0; 00750 break; 00751 case RPMSIGTAG_DSA: 00752 fd = Fopen(file, "r.fdio"); 00753 if (fd == NULL || Ferror(fd)) 00754 goto exit; 00755 h = headerRead(fd, HEADER_MAGIC_YES); 00756 if (h == NULL) 00757 goto exit; 00758 (void) Fclose(fd); fd = NULL; 00759 if (makeTempFile(NULL, &fn, &fd)) 00760 goto exit; 00761 if (headerWrite(fd, h, HEADER_MAGIC_YES)) 00762 goto exit; 00763 (void) Fclose(fd); fd = NULL; 00764 if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase) 00765 || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen)) 00766 goto exit; 00767 ret = 0; 00768 break; 00769 case RPMSIGTAG_RSA: 00770 fd = Fopen(file, "r.fdio"); 00771 if (fd == NULL || Ferror(fd)) 00772 goto exit; 00773 h = headerRead(fd, HEADER_MAGIC_YES); 00774 if (h == NULL) 00775 goto exit; 00776 (void) Fclose(fd); fd = NULL; 00777 if (makeTempFile(NULL, &fn, &fd)) 00778 goto exit; 00779 if (headerWrite(fd, h, HEADER_MAGIC_YES)) 00780 goto exit; 00781 (void) Fclose(fd); fd = NULL; 00782 if (makePGPSignature(fn, &sigTag, &pkt, &pktlen, passPhrase) 00783 || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen)) 00784 goto exit; 00785 ret = 0; 00786 break; 00787 } 00788 00789 exit: 00790 if (fn) { 00791 (void) unlink(fn); 00792 fn = _free(fn); 00793 } 00794 SHA1 = _free(SHA1); 00795 h = headerFree(h); 00796 if (fd != NULL) (void) Fclose(fd); 00797 return ret; 00798 } 00799 00800 int rpmAddSignature(Header sigh, const char * file, int_32 sigTag, 00801 const char * passPhrase) 00802 { 00803 struct stat st; 00804 byte * pkt; 00805 int_32 pktlen; 00806 int ret = -1; /* assume failure. */ 00807 00808 switch (sigTag) { 00809 case RPMSIGTAG_SIZE: 00810 if (stat(file, &st) != 0) 00811 break; 00812 pktlen = st.st_size; 00813 if (!headerAddEntry(sigh, sigTag, RPM_INT32_TYPE, &pktlen, 1)) 00814 break; 00815 ret = 0; 00816 break; 00817 case RPMSIGTAG_MD5: 00818 pktlen = 16; 00819 pkt = memset(alloca(pktlen), 0, pktlen); 00820 if (dodigest(PGPHASHALGO_MD5, file, pkt, 0, NULL) 00821 || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen)) 00822 break; 00823 ret = 0; 00824 break; 00825 case RPMSIGTAG_PGP5: /* XXX legacy */ 00826 case RPMSIGTAG_PGP: 00827 if (makePGPSignature(file, &sigTag, &pkt, &pktlen, passPhrase) 00828 || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen)) 00829 break; 00830 #ifdef NOTYET /* XXX needs hdrmd5ctx, like hdrsha1ctx. */ 00831 /* XXX Piggyback a header-only RSA signature as well. */ 00832 ret = makeHDRSignature(sigh, file, RPMSIGTAG_RSA, passPhrase); 00833 #endif 00834 ret = 0; 00835 break; 00836 case RPMSIGTAG_GPG: 00837 if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase) 00838 || !headerAddEntry(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen)) 00839 break; 00840 /* XXX Piggyback a header-only DSA signature as well. */ 00841 ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase); 00842 break; 00843 case RPMSIGTAG_RSA: 00844 case RPMSIGTAG_DSA: 00845 case RPMSIGTAG_SHA1: 00846 ret = makeHDRSignature(sigh, file, sigTag, passPhrase); 00847 break; 00848 } 00849 00850 return ret; 00851 } 00852 00853 static int checkPassPhrase(const char * passPhrase, const int sigTag) 00854 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00855 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00856 { 00857 int passPhrasePipe[2]; 00858 int pid, status; 00859 int rc; 00860 int xx; 00861 00862 passPhrasePipe[0] = passPhrasePipe[1] = 0; 00863 /*@-boundsread@*/ 00864 xx = pipe(passPhrasePipe); 00865 /*@=boundsread@*/ 00866 if (!(pid = fork())) { 00867 const char * cmd; 00868 char *const *av; 00869 int fdno; 00870 00871 xx = close(STDIN_FILENO); 00872 xx = close(STDOUT_FILENO); 00873 xx = close(passPhrasePipe[1]); 00874 if (! rpmIsVerbose()) 00875 xx = close(STDERR_FILENO); 00876 if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) { 00877 xx = dup2(fdno, STDIN_FILENO); 00878 xx = close(fdno); 00879 } 00880 if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) { 00881 xx = dup2(fdno, STDOUT_FILENO); 00882 xx = close(fdno); 00883 } 00884 xx = dup2(passPhrasePipe[0], 3); 00885 00886 unsetenv("MALLOC_CHECK_"); 00887 switch (sigTag) { 00888 case RPMSIGTAG_DSA: 00889 case RPMSIGTAG_GPG: 00890 { const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL); 00891 00892 /*@-boundsread@*/ 00893 if (gpg_path && *gpg_path != '\0') 00894 (void) dosetenv("GNUPGHOME", gpg_path, 1); 00895 /*@=boundsread@*/ 00896 00897 cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL); 00898 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00899 /*@-boundsread@*/ 00900 if (!rc) 00901 rc = execve(av[0], av+1, environ); 00902 /*@=boundsread@*/ 00903 00904 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "gpg", 00905 strerror(errno)); 00906 } /*@notreached@*/ break; 00907 case RPMSIGTAG_RSA: 00908 case RPMSIGTAG_PGP5: /* XXX legacy */ 00909 case RPMSIGTAG_PGP: 00910 { const char *pgp_path = rpmExpand("%{?_pgp_path}", NULL); 00911 const char *path; 00912 pgpVersion pgpVer; 00913 00914 (void) dosetenv("PGPPASSFD", "3", 1); 00915 /*@-boundsread@*/ 00916 if (pgp_path && *pgp_path != '\0') 00917 xx = dosetenv("PGPPATH", pgp_path, 1); 00918 /*@=boundsread@*/ 00919 00920 if ((path = rpmDetectPGPVersion(&pgpVer)) != NULL) { 00921 switch(pgpVer) { 00922 case PGP_2: 00923 cmd = rpmExpand("%{?__pgp_check_password_cmd}", NULL); 00924 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00925 /*@-boundsread@*/ 00926 if (!rc) 00927 rc = execve(av[0], av+1, environ); 00928 /*@=boundsread@*/ 00929 /*@innerbreak@*/ break; 00930 case PGP_5: /* XXX legacy */ 00931 cmd = rpmExpand("%{?__pgp5_check_password_cmd}", NULL); 00932 rc = poptParseArgvString(cmd, NULL, (const char ***)&av); 00933 /*@-boundsread@*/ 00934 if (!rc) 00935 rc = execve(av[0], av+1, environ); 00936 /*@=boundsread@*/ 00937 /*@innerbreak@*/ break; 00938 case PGP_UNKNOWN: 00939 case PGP_NOTDETECTED: 00940 /*@innerbreak@*/ break; 00941 } 00942 } 00943 rpmError(RPMERR_EXEC, _("Could not exec %s: %s\n"), "pgp", 00944 strerror(errno)); 00945 _exit(RPMERR_EXEC); 00946 } /*@notreached@*/ break; 00947 default: /* This case should have been screened out long ago. */ 00948 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n")); 00949 _exit(RPMERR_SIGGEN); 00950 /*@notreached@*/ break; 00951 } 00952 } 00953 00954 xx = close(passPhrasePipe[0]); 00955 xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase)); 00956 xx = write(passPhrasePipe[1], "\n", 1); 00957 xx = close(passPhrasePipe[1]); 00958 00959 (void) waitpid(pid, &status, 0); 00960 00961 return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0); 00962 } 00963 00964 char * rpmGetPassPhrase(const char * prompt, const int sigTag) 00965 { 00966 char *pass = NULL; 00967 int aok = 0; 00968 00969 switch (sigTag) { 00970 case RPMSIGTAG_DSA: 00971 case RPMSIGTAG_GPG: 00972 /*@-boundsread@*/ 00973 { const char *name = rpmExpand("%{?_gpg_name}", NULL); 00974 aok = (name && *name != '\0'); 00975 name = _free(name); 00976 } 00977 /*@=boundsread@*/ 00978 if (aok) 00979 break; 00980 rpmError(RPMERR_SIGGEN, 00981 _("You must set \"%%_gpg_name\" in your macro file\n")); 00982 break; 00983 case RPMSIGTAG_RSA: 00984 case RPMSIGTAG_PGP5: /* XXX legacy */ 00985 case RPMSIGTAG_PGP: 00986 /*@-boundsread@*/ 00987 { const char *name = rpmExpand("%{?_pgp_name}", NULL); 00988 aok = (name && *name != '\0'); 00989 name = _free(name); 00990 } 00991 /*@=boundsread@*/ 00992 if (aok) 00993 break; 00994 rpmError(RPMERR_SIGGEN, 00995 _("You must set \"%%_pgp_name\" in your macro file\n")); 00996 break; 00997 default: 00998 /* Currently the calling function (rpm.c:main) is checking this and 00999 * doing a better job. This section should never be accessed. 01000 */ 01001 rpmError(RPMERR_SIGGEN, _("Invalid %%_signature spec in macro file\n")); 01002 break; 01003 } 01004 01005 if (aok) { 01006 pass = Getpass(prompt); 01007 01008 if (pass != NULL && checkPassPhrase(pass, sigTag)) 01009 pass = NULL; 01010 } 01011 01012 return pass; 01013 } 01014 01015 static /*@observer@*/ const char * rpmSigString(rpmRC res) 01016 /*@*/ 01017 { 01018 const char * str; 01019 switch (res) { 01020 case RPMRC_OK: str = "OK"; break; 01021 case RPMRC_FAIL: str = "BAD"; break; 01022 case RPMRC_NOKEY: str = "NOKEY"; break; 01023 case RPMRC_NOTTRUSTED: str = "NOTRUSTED"; break; 01024 default: 01025 case RPMRC_NOTFOUND: str = "UNKNOWN"; break; 01026 } 01027 return str; 01028 } 01029 01030 /*@-boundswrite@*/ 01031 static rpmRC 01032 verifySizeSignature(const rpmts ts, /*@out@*/ char * t) 01033 /*@modifies *t @*/ 01034 { 01035 const void * sig = rpmtsSig(ts); 01036 pgpDig dig = rpmtsDig(ts); 01037 rpmRC res; 01038 int_32 size = 0x7fffffff; 01039 01040 *t = '\0'; 01041 t = stpcpy(t, _("Header+Payload size: ")); 01042 01043 if (sig == NULL || dig == NULL || dig->nbytes == 0) { 01044 res = RPMRC_NOKEY; 01045 t = stpcpy(t, rpmSigString(res)); 01046 goto exit; 01047 } 01048 01049 memcpy(&size, sig, sizeof(size)); 01050 01051 if (size != dig->nbytes) { 01052 res = RPMRC_FAIL; 01053 t = stpcpy(t, rpmSigString(res)); 01054 sprintf(t, " Expected(%d) != (%d)\n", (int)size, (int)dig->nbytes); 01055 } else { 01056 res = RPMRC_OK; 01057 t = stpcpy(t, rpmSigString(res)); 01058 sprintf(t, " (%d)", (int)dig->nbytes); 01059 } 01060 01061 exit: 01062 t = stpcpy(t, "\n"); 01063 return res; 01064 } 01065 /*@=boundswrite@*/ 01066 01067 /*@-boundswrite@*/ 01068 static rpmRC 01069 verifyMD5Signature(const rpmts ts, /*@out@*/ char * t, 01070 /*@null@*/ DIGEST_CTX md5ctx) 01071 /*@globals internalState @*/ 01072 /*@modifies *t, internalState @*/ 01073 { 01074 const void * sig = rpmtsSig(ts); 01075 int_32 siglen = rpmtsSiglen(ts); 01076 pgpDig dig = rpmtsDig(ts); 01077 rpmRC res; 01078 byte * md5sum = NULL; 01079 size_t md5len = 0; 01080 01081 *t = '\0'; 01082 t = stpcpy(t, _("MD5 digest: ")); 01083 01084 if (md5ctx == NULL || sig == NULL || dig == NULL) { 01085 res = RPMRC_NOKEY; 01086 t = stpcpy(t, rpmSigString(res)); 01087 goto exit; 01088 } 01089 01090 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01091 (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0); 01092 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01093 rpmtsOp(ts, RPMTS_OP_DIGEST)->count--; /* XXX one too many */ 01094 01095 if (md5len != siglen || memcmp(md5sum, sig, md5len)) { 01096 res = RPMRC_FAIL; 01097 t = stpcpy(t, rpmSigString(res)); 01098 t = stpcpy(t, " Expected("); 01099 (void) pgpHexCvt(t, sig, siglen); 01100 t += strlen(t); 01101 t = stpcpy(t, ") != ("); 01102 } else { 01103 res = RPMRC_OK; 01104 t = stpcpy(t, rpmSigString(res)); 01105 t = stpcpy(t, " ("); 01106 } 01107 (void) pgpHexCvt(t, md5sum, md5len); 01108 t += strlen(t); 01109 t = stpcpy(t, ")"); 01110 01111 exit: 01112 md5sum = _free(md5sum); 01113 t = stpcpy(t, "\n"); 01114 return res; 01115 } 01116 /*@=boundswrite@*/ 01117 01118 /*@-boundswrite@*/ 01126 static rpmRC 01127 verifySHA1Signature(const rpmts ts, /*@out@*/ char * t, 01128 /*@null@*/ DIGEST_CTX sha1ctx) 01129 /*@globals internalState @*/ 01130 /*@modifies *t, internalState @*/ 01131 { 01132 const void * sig = rpmtsSig(ts); 01133 #ifdef NOTYET 01134 int_32 siglen = rpmtsSiglen(ts); 01135 #endif 01136 pgpDig dig = rpmtsDig(ts); 01137 rpmRC res; 01138 const char * SHA1 = NULL; 01139 01140 *t = '\0'; 01141 t = stpcpy(t, _("Header SHA1 digest: ")); 01142 01143 if (sha1ctx == NULL || sig == NULL || dig == NULL) { 01144 res = RPMRC_NOKEY; 01145 t = stpcpy(t, rpmSigString(res)); 01146 goto exit; 01147 } 01148 01149 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01150 (void) rpmDigestFinal(rpmDigestDup(sha1ctx), &SHA1, NULL, 1); 01151 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01152 01153 if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) { 01154 res = RPMRC_FAIL; 01155 t = stpcpy(t, rpmSigString(res)); 01156 t = stpcpy(t, " Expected("); 01157 t = stpcpy(t, sig); 01158 t = stpcpy(t, ") != ("); 01159 } else { 01160 res = RPMRC_OK; 01161 t = stpcpy(t, rpmSigString(res)); 01162 t = stpcpy(t, " ("); 01163 } 01164 if (SHA1) 01165 t = stpcpy(t, SHA1); 01166 t = stpcpy(t, ")"); 01167 01168 exit: 01169 SHA1 = _free(SHA1); 01170 t = stpcpy(t, "\n"); 01171 return res; 01172 } 01173 /*@=boundswrite@*/ 01174 01180 static inline unsigned char nibble(char c) 01181 /*@*/ 01182 { 01183 if (c >= '0' && c <= '9') 01184 return (c - '0'); 01185 if (c >= 'A' && c <= 'F') 01186 return (c - 'A') + 10; 01187 if (c >= 'a' && c <= 'f') 01188 return (c - 'a') + 10; 01189 return 0; 01190 } 01191 01192 /*@-boundswrite@*/ 01200 static rpmRC 01201 verifyRSASignature(rpmts ts, /*@out@*/ char * t, 01202 /*@null@*/ DIGEST_CTX md5ctx) 01203 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01204 /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */ 01205 { 01206 const void * sig = rpmtsSig(ts); 01207 #ifdef NOTYET 01208 int_32 siglen = rpmtsSiglen(ts); 01209 #endif 01210 int_32 sigtag = rpmtsSigtag(ts); 01211 pgpDig dig = rpmtsDig(ts); 01212 pgpDigParams sigp = rpmtsSignature(ts); 01213 const char * prefix = NULL; 01214 rpmRC res = RPMRC_OK; 01215 int xx; 01216 01217 assert(dig != NULL); 01218 assert(sigp != NULL); 01219 *t = '\0'; 01220 if (dig != NULL && dig->hdrmd5ctx == md5ctx) 01221 t = stpcpy(t, _("Header ")); 01222 *t++ = 'V'; 01223 switch (sigp->version) { 01224 case 3: *t++ = '3'; break; 01225 case 4: *t++ = '4'; break; 01226 } 01227 01228 if (md5ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) { 01229 res = RPMRC_NOKEY; 01230 } 01231 01232 /* Verify the desired signature match. */ 01233 switch (sigp->pubkey_algo) { 01234 case PGPPUBKEYALGO_RSA: 01235 if (sigtag == RPMSIGTAG_PGP || sigtag == RPMSIGTAG_PGP5 || sigtag == RPMSIGTAG_RSA) 01236 break; 01237 /*@fallthrough@*/ 01238 default: 01239 res = RPMRC_NOKEY; 01240 break; 01241 } 01242 01243 /* Verify the desired hash match. */ 01244 /* XXX Values from PKCS#1 v2.1 (aka RFC-3447) */ 01245 /*@-branchstate@*/ 01246 switch (sigp->hash_algo) { 01247 case PGPHASHALGO_MD5: 01248 t = stpcpy(t, " RSA/MD5"); 01249 prefix = "3020300c06082a864886f70d020505000410"; 01250 break; 01251 case PGPHASHALGO_SHA1: 01252 t = stpcpy(t, " RSA/SHA1"); 01253 prefix = "3021300906052b0e03021a05000414"; 01254 break; 01255 case PGPHASHALGO_RIPEMD160: 01256 t = stpcpy(t, " RSA/RIPEMD160"); 01257 prefix = "3021300906052b2403020105000414"; 01258 break; 01259 case PGPHASHALGO_MD2: 01260 t = stpcpy(t, " RSA/MD2"); 01261 prefix = "3020300c06082a864886f70d020205000410"; 01262 break; 01263 case PGPHASHALGO_TIGER192: 01264 t = stpcpy(t, " RSA/TIGER192"); 01265 prefix = "3029300d06092b06010401da470c0205000418"; 01266 break; 01267 case PGPHASHALGO_HAVAL_5_160: 01268 res = RPMRC_NOKEY; 01269 prefix = NULL; 01270 break; 01271 case PGPHASHALGO_SHA256: 01272 t = stpcpy(t, " RSA/SHA256"); 01273 prefix = "3031300d060960864801650304020105000420"; 01274 break; 01275 case PGPHASHALGO_SHA384: 01276 t = stpcpy(t, " RSA/SHA384"); 01277 prefix = "3041300d060960864801650304020205000430"; 01278 break; 01279 case PGPHASHALGO_SHA512: 01280 t = stpcpy(t, " RSA/SHA512"); 01281 prefix = "3051300d060960864801650304020305000440"; 01282 break; 01283 default: 01284 res = RPMRC_NOKEY; 01285 prefix = NULL; 01286 break; 01287 } 01288 /*@=branchstate@*/ 01289 01290 t = stpcpy(t, _(" signature: ")); 01291 if (res != RPMRC_OK) { 01292 goto exit; 01293 } 01294 01295 assert(md5ctx != NULL); /* XXX can't happen. */ 01296 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01297 { DIGEST_CTX ctx = rpmDigestDup(md5ctx); 01298 byte signhash16[2]; 01299 const char * s; 01300 01301 if (sigp->hash != NULL) 01302 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); 01303 01304 #ifdef NOTYET /* XXX not for binary/text signatures as in packages. */ 01305 if (!(sigp->sigtype == PGPSIGTYPE_BINARY || sigp->sigtype == PGP_SIGTYPE_TEXT)) { 01306 int nb = dig->nbytes + sigp->hashlen; 01307 byte trailer[6]; 01308 nb = htonl(nb); 01309 trailer[0] = 0x4; 01310 trailer[1] = 0xff; 01311 memcpy(trailer+2, &nb, sizeof(nb)); 01312 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer)); 01313 } 01314 #endif 01315 01316 xx = rpmDigestFinal(ctx, &dig->md5, &dig->md5len, 1); 01317 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen); 01318 rpmtsOp(ts, RPMTS_OP_DIGEST)->count--; /* XXX one too many */ 01319 01320 /* Compare leading 16 bits of digest for quick check. */ 01321 s = dig->md5; 01322 signhash16[0] = (nibble(s[0]) << 4) | nibble(s[1]); 01323 signhash16[1] = (nibble(s[2]) << 4) | nibble(s[3]); 01324 if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) { 01325 res = RPMRC_FAIL; 01326 goto exit; 01327 } 01328 } 01329 01330 /* Generate RSA modulus parameter. */ 01331 { unsigned int nbits = MP_WORDS_TO_BITS(dig->c.size); 01332 unsigned int nb = (nbits + 7) >> 3; 01333 const char * hexstr; 01334 char * tt; 01335 01336 assert(prefix != NULL); 01337 hexstr = tt = xmalloc(2 * nb + 1); 01338 memset(tt, 'f', (2 * nb)); 01339 tt[0] = '0'; tt[1] = '0'; 01340 tt[2] = '0'; tt[3] = '1'; 01341 tt += (2 * nb) - strlen(prefix) - strlen(dig->md5) - 2; 01342 *tt++ = '0'; *tt++ = '0'; 01343 tt = stpcpy(tt, prefix); 01344 tt = stpcpy(tt, dig->md5); 01345 01346 mpnzero(&dig->rsahm); (void) mpnsethex(&dig->rsahm, hexstr); 01347 01348 hexstr = _free(hexstr); 01349 01350 } 01351 01352 /* Retrieve the matching public key. */ 01353 res = rpmtsFindPubkey(ts); 01354 if (res != RPMRC_OK) 01355 goto exit; 01356 01357 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0); 01358 /*@-type@*/ /* XXX FIX: avoid beecrypt API incompatibility. */ 01359 #if HAVE_BEECRYPT_API_H 01360 xx = rsavrfy(&dig->rsa_pk.n, &dig->rsa_pk.e, &dig->c, &dig->rsahm); 01361 #else 01362 xx = rsavrfy(&dig->rsa_pk, &dig->rsahm, &dig->c); 01363 #endif 01364 /*@=type@*/ 01365 if (xx) 01366 res = RPMRC_OK; 01367 else 01368 res = RPMRC_FAIL; 01369 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0); 01370 01371 exit: 01372 t = stpcpy(t, rpmSigString(res)); 01373 if (sigp != NULL) { 01374 t = stpcpy(t, ", key ID "); 01375 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); 01376 t += strlen(t); 01377 } 01378 t = stpcpy(t, "\n"); 01379 return res; 01380 } 01381 /*@=boundswrite@*/ 01382 01390 /*@-boundswrite@*/ 01391 static rpmRC 01392 verifyDSASignature(rpmts ts, /*@out@*/ char * t, 01393 /*@null@*/ DIGEST_CTX sha1ctx) 01394 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01395 /*@modifies ts, *t, rpmGlobalMacroContext, fileSystem, internalState */ 01396 { 01397 const void * sig = rpmtsSig(ts); 01398 #ifdef NOTYET 01399 int_32 siglen = rpmtsSiglen(ts); 01400 #endif 01401 int_32 sigtag = rpmtsSigtag(ts); 01402 pgpDig dig = rpmtsDig(ts); 01403 pgpDigParams sigp = rpmtsSignature(ts); 01404 rpmRC res; 01405 int xx; 01406 01407 assert(dig != NULL); 01408 assert(sigp != NULL); 01409 *t = '\0'; 01410 if (dig != NULL && dig->hdrsha1ctx == sha1ctx) 01411 t = stpcpy(t, _("Header ")); 01412 *t++ = 'V'; 01413 switch (sigp->version) { 01414 case 3: *t++ = '3'; break; 01415 case 4: *t++ = '4'; break; 01416 } 01417 t = stpcpy(t, _(" DSA signature: ")); 01418 01419 if (sha1ctx == NULL || sig == NULL || dig == NULL || sigp == NULL) { 01420 res = RPMRC_NOKEY; 01421 goto exit; 01422 } 01423 01424 /* XXX sanity check on sigtag and signature agreement. */ 01425 if (!((sigtag == RPMSIGTAG_GPG || sigtag == RPMSIGTAG_DSA) 01426 && sigp->pubkey_algo == PGPPUBKEYALGO_DSA 01427 && sigp->hash_algo == PGPHASHALGO_SHA1)) 01428 { 01429 res = RPMRC_NOKEY; 01430 goto exit; 01431 } 01432 01433 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DIGEST), 0); 01434 { DIGEST_CTX ctx = rpmDigestDup(sha1ctx); 01435 byte signhash16[2]; 01436 01437 if (sigp->hash != NULL) 01438 xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen); 01439 01440 if (sigp->version == 4) { 01441 int nb = sigp->hashlen; 01442 byte trailer[6]; 01443 nb = htonl(nb); 01444 trailer[0] = sigp->version; 01445 trailer[1] = 0xff; 01446 memcpy(trailer+2, &nb, sizeof(nb)); 01447 xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer)); 01448 } 01449 xx = rpmDigestFinal(ctx, &dig->sha1, &dig->sha1len, 1); 01450 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DIGEST), sigp->hashlen); 01451 rpmtsOp(ts, RPMTS_OP_DIGEST)->count--; /* XXX one too many */ 01452 01453 mpnzero(&dig->hm); (void) mpnsethex(&dig->hm, dig->sha1); 01454 01455 /* Compare leading 16 bits of digest for quick check. */ 01456 signhash16[0] = (*dig->hm.data >> 24) & 0xff; 01457 signhash16[1] = (*dig->hm.data >> 16) & 0xff; 01458 if (memcmp(signhash16, sigp->signhash16, sizeof(signhash16))) { 01459 res = RPMRC_FAIL; 01460 goto exit; 01461 } 01462 } 01463 01464 /* Retrieve the matching public key. */ 01465 res = rpmtsFindPubkey(ts); 01466 if (res != RPMRC_OK) 01467 goto exit; 01468 01469 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0); 01470 if (dsavrfy(&dig->p, &dig->q, &dig->g, 01471 &dig->hm, &dig->y, &dig->r, &dig->s)) 01472 res = RPMRC_OK; 01473 else 01474 res = RPMRC_FAIL; 01475 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_SIGNATURE), 0); 01476 01477 exit: 01478 t = stpcpy(t, rpmSigString(res)); 01479 if (sigp != NULL) { 01480 t = stpcpy(t, ", key ID "); 01481 (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4); 01482 t += strlen(t); 01483 } 01484 t = stpcpy(t, "\n"); 01485 return res; 01486 } 01487 /*@=boundswrite@*/ 01488 01489 rpmRC 01490 rpmVerifySignature(const rpmts ts, char * result) 01491 { 01492 const void * sig = rpmtsSig(ts); 01493 int_32 siglen = rpmtsSiglen(ts); 01494 int_32 sigtag = rpmtsSigtag(ts); 01495 pgpDig dig = rpmtsDig(ts); 01496 rpmRC res; 01497 01498 if (sig == NULL || siglen <= 0 || dig == NULL) { 01499 sprintf(result, _("Verify signature: BAD PARAMETERS\n")); 01500 return RPMRC_NOTFOUND; 01501 } 01502 01503 switch (sigtag) { 01504 case RPMSIGTAG_SIZE: 01505 res = verifySizeSignature(ts, result); 01506 break; 01507 case RPMSIGTAG_MD5: 01508 res = verifyMD5Signature(ts, result, dig->md5ctx); 01509 break; 01510 case RPMSIGTAG_SHA1: 01511 res = verifySHA1Signature(ts, result, dig->hdrsha1ctx); 01512 break; 01513 case RPMSIGTAG_RSA: 01514 res = verifyRSASignature(ts, result, dig->hdrmd5ctx); 01515 break; 01516 case RPMSIGTAG_PGP5: /* XXX legacy */ 01517 case RPMSIGTAG_PGP: 01518 res = verifyRSASignature(ts, result, 01519 ((dig->signature.hash_algo == PGPHASHALGO_MD5) 01520 ? dig->md5ctx : dig->sha1ctx)); 01521 break; 01522 case RPMSIGTAG_DSA: 01523 res = verifyDSASignature(ts, result, dig->hdrsha1ctx); 01524 break; 01525 case RPMSIGTAG_GPG: 01526 res = verifyDSASignature(ts, result, dig->sha1ctx); 01527 break; 01528 case RPMSIGTAG_LEMD5_1: 01529 case RPMSIGTAG_LEMD5_2: 01530 sprintf(result, _("Broken MD5 digest: UNSUPPORTED\n")); 01531 res = RPMRC_NOTFOUND; 01532 break; 01533 default: 01534 sprintf(result, _("Signature: UNKNOWN (%d)\n"), sigtag); 01535 res = RPMRC_NOTFOUND; 01536 break; 01537 } 01538 return res; 01539 }