static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp, off_t sigStart, off_t sigTargetSize, char *SHA1, uint8_t *MD5) { off_t archiveSize; rpmRC rc = RPMRC_OK; if (Fseek(fd, sigStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } /* Get payload size from signature tag */ archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE); if (!archiveSize) { archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE); } /* Set reserved space to 0 */ addMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL); /* Replace old digests in sigh */ rc = rpmGenerateSignature(SHA1, MD5, sigTargetSize, archiveSize, fd); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("generateSignature failed\n")); goto exit; } if (Fseek(fd, sigStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } headerFree(*sigp); rc = rpmReadSignature(fd, sigp, RPMSIGTYPE_HEADERSIG, NULL); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n")); goto exit; } exit: return rc; }
/* * This is more than just a little insane: * In order to write the signature, we need to know the size and * the size and digests of the header and payload, which are located * after the signature on disk. We also need a digest of the compressed * payload for the main header, and of course the payload is after the * header on disk. So we need to create placeholders for both the * signature and main header that exactly match the final sizes, calculate * the payload digest, then generate and write the real main header to * be able to FINALLY calculate the digests we need for the signature * header. In other words, we need to write things in the exact opposite * order to how the RPM format is laid on disk. */ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp, const char *fileName, char **cookie) { FD_t fd = NULL; char * rpmio_flags = NULL; char * SHA1 = NULL; char * SHA256 = NULL; uint8_t * MD5 = NULL; char * pld = NULL; uint32_t pld_algo = PGPHASHALGO_SHA256; /* TODO: macro configuration */ rpmRC rc = RPMRC_FAIL; /* assume failure */ rpm_loff_t archiveSize = 0; off_t sigStart, hdrStart, payloadStart, payloadEnd; if (pkgidp) *pkgidp = NULL; rpmio_flags = getIOFlags(pkg); if (!rpmio_flags) goto exit; finalizeDeps(pkg); /* Create and add the cookie */ if (cookie) { rasprintf(cookie, "%s %d", buildHost(), (int) (*getBuildTime())); headerPutString(pkg->header, RPMTAG_COOKIE, *cookie); } /* Create a dummy payload digest to get the header size right */ pld = nullDigest(pld_algo, 1); headerPutUint32(pkg->header, RPMTAG_PAYLOADDIGESTALGO, &pld_algo, 1); headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld); pld = _free(pld); /* Check for UTF-8 encoding of string tags, add encoding tag if all good */ if (checkForEncoding(pkg->header, 1)) goto exit; /* Open the output file */ fd = Fopen(fileName, "w+.ufdio"); if (fd == NULL || Ferror(fd)) { rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"), fileName, Fstrerror(fd)); goto exit; } /* Write the lead section into the package. */ if (rpmLeadWrite(fd, pkg->header)) { rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); goto exit; } /* Save the position of signature section */ sigStart = Ftell(fd); /* Generate and write a placeholder signature header */ SHA1 = nullDigest(PGPHASHALGO_SHA1, 1); SHA256 = nullDigest(PGPHASHALGO_SHA256, 1); MD5 = nullDigest(PGPHASHALGO_MD5, 0); if (rpmGenerateSignature(SHA256, SHA1, MD5, 0, 0, fd)) goto exit; SHA1 = _free(SHA1); SHA256 = _free(SHA256); MD5 = _free(MD5); /* Write a placeholder header. */ hdrStart = Ftell(fd); if (writeHdr(fd, pkg->header)) goto exit; /* Write payload section (cpio archive) */ payloadStart = Ftell(fd); if (cpio_doio(fd, pkg, rpmio_flags, &archiveSize)) goto exit; payloadEnd = Ftell(fd); /* Re-read payload to calculate compressed digest */ fdInitDigestID(fd, pld_algo, RPMTAG_PAYLOADDIGEST, 0); if (fdConsume(fd, payloadStart, payloadEnd - payloadStart)) goto exit; fdFiniDigest(fd, RPMTAG_PAYLOADDIGEST, (void **)&pld, NULL, 1); /* Insert the payload digest in main header */ headerDel(pkg->header, RPMTAG_PAYLOADDIGEST); headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld); pld = _free(pld); /* Write the final header */ if (fdJump(fd, hdrStart)) goto exit; if (writeHdr(fd, pkg->header)) goto exit; /* Calculate digests: SHA on header, legacy MD5 on header + payload */ fdInitDigestID(fd, PGPHASHALGO_MD5, RPMTAG_SIGMD5, 0); fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMTAG_SHA1HEADER, 0); fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMTAG_SHA256HEADER, 0); if (fdConsume(fd, hdrStart, payloadStart - hdrStart)) goto exit; fdFiniDigest(fd, RPMTAG_SHA1HEADER, (void **)&SHA1, NULL, 1); fdFiniDigest(fd, RPMTAG_SHA256HEADER, (void **)&SHA256, NULL, 1); if (fdConsume(fd, 0, payloadEnd - payloadStart)) goto exit; fdFiniDigest(fd, RPMTAG_SIGMD5, (void **)&MD5, NULL, 0); if (fdJump(fd, sigStart)) goto exit; /* Generate the signature. Now with right values */ if (rpmGenerateSignature(SHA256, SHA1, MD5, payloadEnd - hdrStart, archiveSize, fd)) goto exit; rc = RPMRC_OK; exit: free(rpmio_flags); free(SHA1); free(SHA256); /* XXX Fish the pkgid out of the signature header. */ if (pkgidp != NULL) { if (MD5 != NULL) { *pkgidp = MD5; } } else { free(MD5); } Fclose(fd); if (rc == RPMRC_OK) rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName); else (void) unlink(fileName); return rc; }