Skip to content

Commit

Permalink
Place file signatures into the signature header where they belong
Browse files Browse the repository at this point in the history
The original file signing puts the file signatures into the main header
immutable region, invalidating all previous signatures and digests so
the package no longer appears to be what it was when it came out of the
assembly line. Which is bad. Doing that also requires recalculating
everything again which is just added complexity, and since it adds
stuff to different place from the rest of the signing, it requires yet
complexity to deal with that. Moving the file signatures into the
signature header solves all that and allows removing a big pile of
now unnecessary code.

Because this means retrofitting tags bass-ackwards into the signature
header, the tag definitions are backwards to everything else. Other
options would certainly be possible, but this makes things look more
normal on the signature header side. "Users" only ever see the
unchanged file signature tags as they have always been.

This also means the signature header can be MUCH bigger than ever before,
so bump up the limit (to 64MB, arbitrary something for now), and
permit string array types to be migrated from the signature header
on package read.

Caveats:
This loses the check for identical existing signatures to keep the
complexity down, it's hardly a critical thing and can be added back later.
While file signing could now be done separately to other signing, that
is not handled here.
  • Loading branch information
pmatilai committed Oct 10, 2017
1 parent 13644fa commit f558e88
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 164 deletions.
2 changes: 1 addition & 1 deletion lib/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -1867,7 +1867,7 @@ rpmRC hdrblobRead(FD_t fd, int magic, int exact_size, rpmTagVal regionTag, hdrbl

if (regionTag == RPMTAG_HEADERSIGNATURES) {
il_max = 32;
dl_max = 8192;
dl_max = 64 * 1024;
}

memset(block, 0, sizeof(block));
Expand Down
4 changes: 3 additions & 1 deletion lib/package.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ void headerMergeLegacySigs(Header h, Header sigh)
case RPMSIGTAG_SHA256:
case RPMSIGTAG_DSA:
case RPMSIGTAG_RSA:
case RPMSIGTAG_FILESIGNATURELENGTH:
case RPMSIGTAG_FILESIGNATURES:
default:
if (!(td.tag >= HEADER_SIGBASE && td.tag < HEADER_TAGBASE))
continue;
Expand All @@ -76,11 +78,11 @@ void headerMergeLegacySigs(Header h, Header sigh)
continue;
break;
case RPM_STRING_TYPE:
case RPM_STRING_ARRAY_TYPE:
case RPM_BIN_TYPE:
if (td.count >= 16*1024)
continue;
break;
case RPM_STRING_ARRAY_TYPE:
case RPM_I18NSTRING_TYPE:
continue;
break;
Expand Down
4 changes: 4 additions & 0 deletions lib/rpmtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ typedef enum rpmTag_e {
RPMTAG_LONGARCHIVESIZE = RPMTAG_SIG_BASE+15, /* l */
/* RPMTAG_SIG_BASE+16 reserved */
RPMTAG_SHA256HEADER = RPMTAG_SIG_BASE+17, /* s */
/* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
/* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURES */

RPMTAG_NAME = 1000, /* s */
#define RPMTAG_N RPMTAG_NAME /* s */
Expand Down Expand Up @@ -422,6 +424,8 @@ typedef enum rpmSigTag_e {
RPMSIGTAG_LONGSIZE = RPMTAG_LONGSIGSIZE, /*!< internal Header+Payload size (64bit) in bytes. */
RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */
RPMSIGTAG_SHA256 = RPMTAG_SHA256HEADER,
RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 18,
RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 19,
} rpmSigTag;


Expand Down
161 changes: 8 additions & 153 deletions sign/rpmgensig.c
Original file line number Diff line number Diff line change
Expand Up @@ -469,74 +469,12 @@ static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)
}
}

#ifdef WITH_IMAEVM
static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp,
off_t sigStart, off_t sigTargetSize,
char *SHA256, 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 */
rpmPushMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL);

/* Replace old digests in sigh */
rc = rpmGenerateSignature(SHA256, 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, NULL);
if (rc != RPMRC_OK) {
rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));
goto exit;
}

exit:
return rc;
}
#endif

static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
Header *sigp, Header *hdrp,
off_t sigStart, off_t headerStart)
static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
{
#ifdef WITH_IMAEVM
FD_t ofd = NULL;
char *trpm = NULL;
rpmRC rc;
char *key;
char *keypass;
char *SHA1 = NULL;
char *SHA256 = NULL;
uint8_t *MD5 = NULL;
off_t sigTargetSize;
rpmRC rc = RPMRC_OK;
struct rpmtd_s osigtd;
char *o_sha1 = NULL;

unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE);

key = rpmExpand("%{?_file_signing_key}", NULL);

Expand All @@ -546,94 +484,10 @@ static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
keypass = NULL;
}

rc = rpmSignFiles(*hdrp, key, keypass);
if (rc != RPMRC_OK) {
goto exit;
}

*hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE);
if (*hdrp == NULL) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("headerReload failed\n"));
goto exit;
}

ofd = rpmMkTempFile(NULL, &trpm);
if (ofd == NULL || Ferror(ofd)) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
goto exit;
}

/* Copy archive to temp file */
if (copyFile(&fd, rpm, &ofd, trpm)) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
goto exit;
}

if (Fseek(fd, headerStart, SEEK_SET) < 0) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
rpm, Fstrerror(fd));
goto exit;
}
rc = rpmSignFiles(*sigp, *hdrp, key, keypass);

/* Start MD5 calculation */
fdInitDigestID(fd, PGPHASHALGO_MD5, RPMSIGTAG_MD5, 0);

/* Write header to rpm and recalculate digests */
fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMSIGTAG_SHA1, 0);
fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMSIGTAG_SHA256, 0);
rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES);
if (rc != RPMRC_OK) {
rpmlog(RPMLOG_ERR, _("headerWrite failed\n"));
goto exit;
}
fdFiniDigest(fd, RPMSIGTAG_SHA1, (void **)&SHA1, NULL, 1);
/* Only add SHA256 if it was there to begin with */
if (headerIsEntry(*sigp, RPMSIGTAG_SHA256))
fdFiniDigest(fd, RPMSIGTAG_SHA256, (void **)&SHA256, NULL, 1);

/* Copy archive from temp file */
if (Fseek(ofd, 0, SEEK_SET) < 0) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
rpm, Fstrerror(fd));
goto exit;
}
if (copyFile(&ofd, trpm, &fd, rpm)) {
rc = RPMRC_FAIL;
rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
goto exit;
}
unlink(trpm);

sigTargetSize = Ftell(fd) - headerStart;
fdFiniDigest(fd, RPMSIGTAG_MD5, (void **)&MD5, NULL, 0);

if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) {
o_sha1 = xstrdup(osigtd.data);
rpmtdFreeData(&osigtd);
}

if (strcmp(SHA1, o_sha1) == 0)
rpmlog(RPMLOG_WARNING,
_("%s already contains identical file signatures\n"),
rpm);
else
replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA256, SHA1, MD5);

exit:
free(trpm);
free(MD5);
free(SHA1);
free(SHA256);
free(o_sha1);
free(keypass);
free(key);
if (ofd)
(void) closeFile(&ofd);
return rc;
#else
rpmlog(RPMLOG_ERR, _("file signing support not built in\n"));
Expand Down Expand Up @@ -695,13 +549,14 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)
goto exit;
}

if (signfiles) {
includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);
}

unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);

if (signfiles) {
if (includeFileSignatures(&sigh, &h))
goto exit;
}

if (deleting) { /* Nuke all the signature tags. */
deleteSigs(sigh);
} else {
Expand Down
14 changes: 7 additions & 7 deletions sign/rpmsignfiles.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ char *keypass)
return siglen + 1;
}

rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
{
struct rpmtd_s digests, td;
int algo;
Expand All @@ -107,19 +107,19 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
return RPMRC_FAIL;
}

headerDel(h, RPMTAG_FILESIGNATURELENGTH);
headerDel(h, RPMTAG_FILESIGNATURES);
headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);
headerDel(sigh, RPMTAG_FILESIGNATURES);
siglen = signatureLength(algoname, diglen, key, keypass);

rpmtdReset(&td);
td.tag = RPMTAG_FILESIGNATURELENGTH;
td.tag = RPMSIGTAG_FILESIGNATURELENGTH;
td.type = RPM_INT32_TYPE;
td.data = &siglen;
td.count = 1;
headerPut(h, &td, HEADERPUT_DEFAULT);
headerPut(sigh, &td, HEADERPUT_DEFAULT);

rpmtdReset(&td);
td.tag = RPMTAG_FILESIGNATURES;
td.tag = RPMSIGTAG_FILESIGNATURES;
td.type = RPM_STRING_ARRAY_TYPE;
td.data = NULL; /* set in the loop below */
td.count = 1;
Expand All @@ -133,7 +133,7 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
goto exit;
}
td.data = &signature;
if (!headerPut(h, &td, HEADERPUT_APPEND)) {
if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
free(signature);
rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
rc = RPMRC_FAIL;
Expand Down
5 changes: 3 additions & 2 deletions sign/rpmsignfiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ extern "C" {
#endif

/**
* Sign file digests in header and store the signatures in header
* Sign file digests in header into signature header
* @param sigh package signature header
* @param h package header
* @param key signing key
* @param keypass signing key password
* @return RPMRC_OK on success
*/
RPM_GNUC_INTERNAL
rpmRC rpmSignFiles(Header h, const char *key, char *keypass);
rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass);

#ifdef _cplusplus
}
Expand Down

0 comments on commit f558e88

Please sign in to comment.