Commit Graph

81 Commits

Author SHA1 Message Date
Panu Matilainen ee4356ef27 Issue a warning when signing created an OpenPGP v3 signature
https://bugzilla.redhat.com/show_bug.cgi?id=2141686 revealed that much
of the rpm-ecosystem is still using the obsolete v3 OpenPGP signature
format, I think largely due to workarounds for legacy rpm versions (from
around the turn of the millennium) that have just been forgotten in
place. Lets at least issue a wake-up warning when that happens.

Unfortunately this is can't really be tested as current GnuPG versions
just ignore any --force-v3-sigs arguments.

Fixes: #2286
2022-11-25 08:47:49 +01:00
Panu Matilainen cf02319645 Use proper name (OpenPGP) when referring to the standard in messages 2022-11-25 08:47:49 +01:00
Demi Marie Obenour 40571a74cf Remove NSS references
RPM doesn’t use NSS anymore.
2022-03-18 16:35:11 +02:00
Denys Vlasenko 8763969a4a Do not unset $MALLOC_CHECK_
How do we even _know_ user wants to debug malloc in rpmbuild,
maybe user wants to debug it in _the child_?

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2022-01-24 14:35:24 +02:00
Evgeniy Taishev 9b4c50dd67 Close file before replacing signed 2022-01-18 11:06:58 +01:00
Michal Domonkos ae3d2d234a Fix use-after-free in haveSignature()
pgpPrtParams() may leave sig2 unchanged and if we're not in the very
first iteration of the while() loop, we could pass a freed pointer to
pgpDigParamsCmp().  Fix by setting it to NULL after freeing.

Found by Coverity, after commit bd36c5d (subkey binding validation),
although note that the commit didn't introduce this bug; it just seems
to have been a false negative that got "fixed" by the changes in
pgpPrtParams() in that commit.
2022-01-10 13:23:46 +02:00
Demi Marie Obenour 23770e1a4f rpmsign: support EdDSA signatures
They were previously rejected
2021-03-15 13:58:54 +02:00
Panu Matilainen 07858c0d60 Eliminate remaining uses of unsafe headerCopyLoad() in the codebase
There's no way to safely validate an object to which only a void
pointer is given. Use headerImport() and pass a size to make
verification possible, headerCopyLoad() has been long deprecated anyway.
2021-03-11 10:58:48 +02:00
Jes Sorensen ae4b1b1fe8 rpmsign: Add argument to specify algorithm for fsverity signatures
The argument --verity-algo can be used to specify the algorithm for
the fsverity signatures. If nothing is specified, this will default to
sha256. The available algorithms depend on libfsverity, currently
sha256 and sha512 are supported.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
2020-09-04 13:22:38 +03:00
Jes Sorensen 7b2e7fc06a Add --delfilesign flag to delete IMA and fsverity file signatures
This allows a user to remove both types of file signatures from the
package. Previously there was no way to delete IMA signatures, only
replace them by first removing the package signature and then
resigning the package and the files.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
2020-09-04 13:22:38 +03:00
Jes Sorensen cc7e3c8830 Implement rpmSignVerity()
This generates the root Merkle tree hash and signs it using the
specified key and certificate.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
2020-09-04 13:22:38 +03:00
Panu Matilainen 8fefd2bd21 Work around buggy signature region preventing resigning (RhBug:1851508)
Various proprietary packages in the wild have subtly malformed data
in the signature header, in particular wrt the immutable region size,
presumably from using some in-house/3rd party signing tools which do
not understand the immutable region business at all. This can prevent
resigning and signature deletion on such packages due to the more
thorough checking that rpmsign does.

As the old wisdom goes, be liberal in what you accept... we can easily
work around the crud by just taking a fresh copy of the contents that
are legit as such (otherwise the package would be uninstallable).
2020-08-13 15:52:19 +02:00
Michal Domonkos 0268b6ef23 GPG: refactor: clean up exit label
Remove the redundant close()/fclose() and waitpid() calls.
2020-06-24 08:53:56 +03:00
Michal Domonkos 52c0198e24 GPG: Switch back to pipe(7) for signing
When it comes to IPC with the GPG subprocess that we spawn to sign
packages for us, there has been an evolution of changes over the years.

Initially, we used temporary files to dump package data (header+payload)
to disk, and pointed GPG to those.  That being an insanely expensive
operation, we later opted for a pipe bound to stdin on the reader side
[1] to avoid the unnecessary I/O.  When GPG 2.1 came along, our own
passphrase entry logic stopped working so we decided to offload [3] that
to GPG instead, for which we also needed to swap the pipe for a named
pipe (FIFO), to free [2] stdin for GPG's own passphrase entry program
(pinentry).

Fast forward to the present, it has become apparent that the FIFO
semantics is not the right choice for us either, as it brings about a
handful of synchronization issues, all of which stem from the fact that
the GPG subprocess, which we cannot control, may or may not open the
input file (our FIFO) for reading before it terminates, causing either
process to hang.  That's because an open(2) call on a FIFO blocks until
the other end is also opened.  One particular case where such a deadlock
can happen is an expired key [4]; GPG would error out without ever
opening the input file (and rightly so), making RPM stuck.

In a nutshell, here's what the two processes do:

RPM parent:
    * spawn GPG child
    * open FIFO for writing (blocks)
    * write data
    * close FIFO

GPG child:
    * check key validity    <-- may terminate here
    * open FIFO for reading (blocks)
    * read data
    * close FIFO

Which may result in the following execution order:

* parent:   spawn GPG child
* parent:   open FIFO for writing (blocks)
* child:    check key validity (key expired!)
* child:    terminate with an error (sends SIGCHLD)
* parent:   (continues blocking...)

Now, one way to unblock the parent would be to install a SIGCHLD handler
with SA_RESTART and make it open the FIFO for reading (with O_NONBLOCK)
iff the signal comes from our GPG child (note that RPM can also be used
as a library) so that the restarted open call unblocks right away.  This
would, however, still not be entirely safe from race conditions; if
there were other subprocesses, all terminating about the same time,
their SIGCHLD instances could prevent us from receiving the one from
GPG; this is because standard signals do not queue (see signal(7) for a
detailed explanation).

Another way would be to spawn GPG from a wrapper process whose sole
purpose would be to wait(2) for GPG and to open the FIFO if it failed
(without O_NONBLOCK, to ensure the wrapper doesn't exit before the
parent's open call).  This would work as long as we could tell exactly
which errors cause GPG to not open the input file, but since that's not
documented, we would have to rely on implementation details, not to
mention the added complexity and ugliness of such a solution, so that's
also a no-go.

Lastly, why not just use O_NONBLOCK in the parent, to prevent it from
blocking in the first place?  Since GPG does not use O_NONBLOCK, this
would just push the problem down to the child; if the parent is too fast
and manages to close the FIFO before the child gets a chance to open it,
the child would get stuck once it gets there (thus making the parent
stuck on the wait call).

Luckily, it turns out we actually can take over stdin *and* have GPG use
its pinentry program at the same time!  All we need is to make sure the
GPG_TTY environment variable is set to the current terminal (see
gpg-agent(1)).  This variable is used [5] by GPG as a fall-back when it
fails to obtain the terminal connected to stdin using ttyname(3), such
as when it is redirected to a pipe.

Thus, in this commit (mostly adapted from the reverse of [2]), we revert
to using the good old pipe(7) which not only avoids race conditions (as
it does not cause open to block), but is also more suitable for this
task in general.  (For the record, GPGme also uses [6] a regular pipe
for the IPC.)  Since we have access to the original stdin before
redirection, we set GPG_TTY accordingly (if previously unset), to keep
pinentry working.

This commit also resolves the RHBZ linked in [4].  Note that, in the
case of key expiration, GPG isn't particularly specific in the error
message or exit code; all it says is "Unusable secret key" and returns
code 2.  For that reason, we can't print anything helpful to stderr
either.

[1] commit 1aace27fb9
[2] commit 6a8924b4c9
[3] commit 0bce5fcf27
[4] https://bugzilla.redhat.com/show_bug.cgi?id=1746353
[5] f3df8dbb69/agent/gpg-agent.c (L1115)
[6] 52f930c1ed/src/engine-gpg.c (L1133)
2020-06-24 08:53:56 +03:00
Panu Matilainen 8ed452dd86 Flush 1998 vintage fcntl-compatibility mess from system.h
fcntl.h is standard, include it from places that need it and drop
from system.h.
2020-04-02 13:53:38 +03:00
Panu Matilainen b1aeafef49 Stop adding rpm v3 header+payload signatures by default where not needed
On packages where a separate payload digest exists (ie those built with
rpm >= 4.14), rpm v3 header+payload signatures are nothing but expensive
legacy baggage, as the payload digest will be signed by a header-only
signature already, without having to recalculate the entire file.

Automatically detect the payload digest presence and only add V3
signatures on packages that need it, but also add an override switch
to force their addition if needed for compatibility or so. A particular
use-case would be ability to signature-level verify the entire package
on rpm older than 4.14.

Fixes: #863
2020-03-10 12:11:17 +02:00
Panu Matilainen 91834e86e0 Generalize file signing to use a generic flags field in signing arguments
There will be any number of signing flags in the future, and we don't
want to break the ABI for every single one of them by adding new
fields to the sign argument struct. Replace the signfiles field
with a bitfield in the common rpm style. No functional changes.

This is an API change of course, but we'll have to bump the soname for
the next release anyway so might as well do it now.
2020-03-10 12:11:17 +02:00
Panu Matilainen df089e178d Verify packages before signing (RhBug:1646388)
Permitting corrupted packages to be signed is bad business for everybody
involved, this is something we should've always done. Besides being an
actual security risk, it can lead to odd results with verification
especially with the payload digest on signed packages.

One point worth noting is that this means that pre 4.14-packages cannot
be signed in FIPS mode now because there's no way to validate the package
payload range due to MD5 being disabled. This seems like a feature and
not a limitation, so disabler for the verify step intentionally left out.

Optimally we'd verify the package on the same read that's passed
to gpg but for simplicitys sake that's left as an future exercise,
now we simply read the package twice.
2019-03-18 15:56:34 +02:00
Panu Matilainen 5c279fb149 Simplify RPMSIGTAG_RESERVEDSPACE shrinking
Lotsa unnecessary stuff here:
- No need for rpmtdReset(), headerGet() takes care of that
- In this path, we're always modifying an existing tag so we can
  just use headerMod() instead of constructing a new tag
- As we're always shrinking the existing tag, we don't need to
  allocate new zeros, just reduce the size. Also make sure we *are*
  really shrinking, previously it was only assumed.

No functional changes expected.
2019-03-15 12:00:06 +02:00
Panu Matilainen 1290493169 Clean up includeFileSignatures() a bit
Initialize on declaration, thou shalt not waste perfectly good
screen estate. No functional changes.
2019-03-15 11:03:45 +02:00
Panu Matilainen 8c3586804f Clean up unloadImmutableRegion() a bit
Initialize headers on declaration, in the scope where needed, remove
pointless intermediate pointer to the header data. No functional changes.
2019-03-15 11:01:02 +02:00
Panu Matilainen 05b233ddbe Plug the last data "leak" from rpmlead
Up to commit 45c2f3ffa6 we were still
using the lead to confirm source vs binary package, but now we dont
need even that. Means the zombie data structure that's supposedly been
dead for the last 20+ years is truly gone now. We still dutifully
read/write and validate it, but no actual data from it is used.
2018-04-18 14:36:01 +03:00
Panu Matilainen f558e88605 Place file signatures into the signature header where they belong
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.
2017-10-10 12:18:36 +03:00
Mark Wielaard fc930cc106 replaceSigDigests is only used with IMAEVM.
The replaceSigDigests function is only used in includeFileSignatures
when WITH_IMAEVM is defined. If not warning is generated.

Signed-off-by: Mark Wielaard <mark@klomp.org>
2017-07-21 15:11:04 +02:00
Panu Matilainen 5a6acd24a5 Dont push NULL-bodied macros (in case of get_fskpass() failure) 2017-06-09 12:33:23 +03:00
Panu Matilainen 8fae14f4df Remove bunch of redundant environ declarations
rpmsign.c used to actually use "environ" to pass to execve(), but
that call moved to librpmsign a long, long time ago. rpmdb.c and
rpmkeys.c never used it at all but guess it was copy-paste inherited
from rpmsign.c back in the day (dfbaa77152)

rpmgensig.c actually refers to environ, but this is a POSIX required
variable and while Apple has managed to screw it up, it's handled
in system.h and that must be sufficient for all relevant systems
as we also refer to environ in rpmfileutil.c open_dso() and there's
no fake environ definition there. So drop the one in rpmgensig.c too.
2017-06-09 11:37:03 +03:00
Panu Matilainen 4211ac05c7 Conditional compilation sanity for file signing
Give a nice and clear error message if file signing is requested
on a build that doesn't support it, and ifdef the entire
contents of includeFileSignatures() so we wont try to compile
in a call to rpmSignFiles(), which doesn't get built at all
due to makefile conditionals when imaevm is not enabled.
On a related note, drop the unnecessary conditional and error message
from rpmsignfiles.c: the whole file does not get built if imaevm
is not enabled so there's no need for these.
2017-06-09 10:27:55 +03:00
Panu Matilainen 9e16032b0b Move rpmsignfiles to librpmsign where it belongs
The signing library is separated from librpm and librpmbuild
specifically so it can have more exotic dependencies than is
desireable for librpm, ditto for plugin existence. However
rpmSignFiles() being in librpm drags that libimaevm dependency
to main rpm for no good reason at all. Move it where it belongs,
does not actually affect functionality.
2017-06-08 17:01:28 +03:00
Panu Matilainen 23dc36f0d5 Pass sign arguments to signature deletion too
Refactor rpmsign and python bindings to be more similar on both
addsign/delsign operations, and always pass the signing arguments
along. Deletion doesn't actually (yet) use the arguments for anything
but makes things more symmetric (I remember having doubts about
this when adding - reminder to self: if in doubt, add more arguments ;)

Yet another API break, but what the hey... Other than that, behavior is
not supposed to change here.
2017-05-29 16:11:55 +03:00
Panu Matilainen 1356ee6aea Don't both copying the header for checking pre-existing signature
Now that the lower level is returning the actual data we can
compare directly *before* inserting new data, so we dont need
to copy either. Eliminate redundant (and inadequate) helpers
while at it, preliminaries for array data as well.
2017-05-26 16:40:19 +03:00
Panu Matilainen b6f5b204f4 Further refactor signature generation
putSignature() is awfully far away from the originally calling code
to make decisions, refactor to only create the signature tag there
and return the rpmtd up through the callers to make a more informed
decision.

Doesn't actually change anything, just paving way for next steps.
2017-05-26 14:36:51 +03:00
Panu Matilainen cf897c5bd7 Refactor an unnecessary intermediate helper out of signing code
Too many layers of helpers leftover from past times only getting
in the way of doing stuff. Also rename replaceSignature() arguments
to make it more obvious which is which.

This doesn't *really* change the signing, but it does optimize the
case where the package is already has a signature by the same key
and parameters: we generate the much cheaper V4 (ie header only)
signature and compare that, and only then do the V3 signature
which has to read the entire payload. This can make a huge difference
on large packages.
2017-05-26 14:36:43 +03:00
Panu Matilainen e20764f21b Refactor signing code to return used sigtag instead of 0/1 codes
This saves us from having to unnecessarily guess what the lower
level helpers ended up using so simplifies the code a bit, and
also paves way for other types of signatures. What's not to like?
2017-05-26 14:36:37 +03:00
Panu Matilainen 34860a799a Rename sigtarget variables to v3 and v4
Makes it easier to remember which is which. At least for me it does.
2017-05-26 14:36:30 +03:00
Panu Matilainen 6eeb2f2963 Implement SHA256 header digest, creation + verification
SHA1 has been getting a bit long in the tooth for many years by now,
add a more modern digest to eventually supplant it, for now just
prefer SHA256 over SHA1 if present when verifying. Using a hardwired
algorithm instead of configurable one to keep things on the simple
side when dealing with the signature header.

Signing could add the new digest for older packages but we don't do
that to avoid surprises when people are signing older packages.
2017-03-08 14:43:55 +02:00
Panu Matilainen 0a8746dc7e Remove redundant comparison of the weaker digest
There's no point comparing the weaker MD5 for equivalence when we
can determine it by looking at a stronger digest already. Also we
don't need the digest lengths here since SHA1 is ascii anyway.
2017-03-08 13:36:37 +02:00
Panu Matilainen 6ef52f6fe5 Switch signing code to use the new ID-based digest API 2017-03-08 13:36:37 +02:00
Panu Matilainen d90adb4b34 Use headerCopy() for, well, copying a header
Most likely wouldn't have worked prior to commit
27ea3f8624.
2017-03-02 10:14:22 +02:00
Panu Matilainen 3b1f4b0c6c Cosmetics: if, while and switch are followed by a space
The missing space style-error has been recently coming common enough
somebody might think that IS the expected style, its not. Some of these
are actually very old, but fix across the board for consistency..

Strictly white-space only change.
2017-02-27 17:41:37 +02:00
Panu Matilainen c873837925 Drop unused lead return argument from rpmLeadRead()
Nothing uses this anymore so we can just drop it. Whee.
2016-10-27 10:56:34 +03:00
Panu Matilainen 3255273ae0 Change rpmLeadWrite() to take header as its arg instead of a lead
The only "user" of the lead data structure is the signing code
which just wants to copy it over to the signed package. We can
just as well regenerate it from the header. Even if it doesn't
end up identical (which it should), it doesn't make a damnest
difference because nothing that matters looks at the lead anyway.
2016-10-27 10:48:26 +03:00
Panu Matilainen 5517d26061 Rename addMacro() and delMacro() to rpmPushMacro() and rpmPopMacro()
These are not deprecated at all no matter what the header has been
saying for the past 15+ years, they're used by rpm itself all over
the place as rpmDefineMacro() serves a slightly different purpose
and there's no rpmUndefineMacro() anyway.

Lets make 'em into proper citizens and move them into rpm namespace,
and while at it, call the operations push and pop since that's much
closer to what actually happens.

Finally, add simple wrapper macros to keep external code compilable
while getting the non-namespaced stuff out of ABI.
2016-10-24 13:09:38 +03:00
Panu Matilainen 58711eb636 Eliminate last uses of rpmNewSignature() and rpmFreeSignature()
These are nothing but wrappers for headerNew() and headerFree(),
lets call things by their own names shall we?
2016-10-24 11:34:50 +03:00
Panu Matilainen 0cc5ee83f1 Bury the last remains of non-header signatures into lead
Header signatures were the new hot almost exactly twenty years ago, we
haven't supported anything else in a very, very, very, very very long time.
Drop the useless argument to rpmReadSignature() and bury the last remaining
related constant into rpmlead.c which is the only place that "needs" it.
No functional changes.
2016-10-24 08:41:32 +03:00
Thierry Vignaud 1aeddbc271 fix segfault when calling with args==NULL
the doc explicitely describe "args" as "signing parameters (or NULL for
defaults)"

This no more true since commit 6e9eab345a
As such, with rpm-4.13, some callers will segfault (eg: perl-RPM4's
testsuite)
2016-05-26 10:51:36 +02:00
Lubos Kardos 258e306568 Fix signing with non-ASCII uid keys (rhbz:1243963)
Removed setting LC_ALL to "C" because since commit [1] the gpg program
gets password by yourself from terminal so there is no sense in
setting LC_ALL to "C" if the terminal settings is e. g. UTF-8. That was
only confusing gpg program and it was not able to properly get and
display non-ASCII characters.

[1] 0bce5fcf27
2016-05-23 10:19:39 +02:00
Florian Festi eae65aad6f Drop const to fix compiler warning 2016-04-27 11:19:23 +02:00
Stefan Berger e065ea3b21 Fix various memory leaks in file signature related functions.
Fix various memory leaks in file signature related functions.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
2016-04-26 15:22:23 +02:00
Stefan Berger 5cc41e45fb Fix indentation and formatting
Fix the indentation and formatting in signature related files.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
2016-04-26 15:22:23 +02:00
Fionnuala Gunter 3e73013340 Fix file signatures issue with sig header size changes
When file signatures are added to a package the signature digests are
replaced. Sometimes the resulting signature header has a different size.
To solve this, gpg reserved space is omitted. This forces the rpm to be
rewritten when file signatures are added.

Changelog:
-no longer effects delsign
2015-09-01 10:48:54 +02:00