Proposal for a design for signed kernel/modules/etc

Eric McCorkle eric at metricspace.net
Mon Mar 27 19:53:37 UTC 2017


On 03/27/2017 14:37, Shawn Webb wrote:
> Hey Eric,
> 
> Thank you for writing this! ELF binary signing has been on my
> ever-growing list of things to research and develop. If you'd like help,
> please let me know.

I'll probably spin up a branch on my github in the near future.

> As git has shown, having a modular/configurable crypto interface is the
> best route. Right now, git is stuck using SHA1 because they didn't
> support users being able to choose which hashing algorithm to use.

Oh yes!  And all current pubkey crypto has an expiration date probably
between a decade and a century from now.

> You might want to take a look at Microsoft's Authenticode. Microsoft
> made some mistakes early on that allowed attackers to easily trojan
> signed binaries. Your proposal up to this point makes those same
> mistakes. It's been a few years since I researched Authenticode, so I
> don't have any links or documentation handy.
> 
> The conclusion Microsoft came to is that the file as a whole must be
> signed, including offset metadata. Essentially, you'd determine how
> large the .sig section needs to be ahead of time, create it and fill it
> with zeros, then sign the whole file, stuffing the signature in the
> zeroed .sig section. Same concept as calculating checksums of ICMP
> packets.
> 
> This prevents attackers from modifying critical pieces of metadata,
> pointing them to maliciuos payloads. It also prevents attackers from
> appending malicious data to the end of a loadable segment (something
> Authenticode suffered from early on).

Yeah, now that I think about it, there's various forms of evil you could
pull off.  I don't doubt that someone *could* design a scheme that would
defeat all these attacks, but... is it worth it?  Probably not.

Better to just sign the whole file and seal off all the attack vectors,
on second thought.

> Userland shouldn't be trusted to enforce digital signatures. What if
> someone at link time specifies a non-default RTLD? To enforce digital
> signatures of userland binaries/libraries, the ELF image activator
> should be modified to verify the DT_NEEDED entries.

True, I was assuming dlopen just mmaps everything... (I was getting
hungry by that point).  As with the whole-file sigs, it would probably
be better just to have a single syscall that securely loads dynamic
libraries (but that's out-of-scope for now).

> 
> The only other major thing to discuss is supporting public key chaining.
> Ideally, digital signature support should also support chaining multiple
> keys (similar to X.509 PKI). If the accepted solution supported cert
> chaining, then the solution would be more modular. I don't want to go
> down the route of the SSL/TLS PKI mess, but supporting chaining is a
> must in some enterprise environments.
> 
> If we were to support chaining, we could even stuff the pubkey half of
> the key material into another ELF section, so that if a key becomes
> compromised, the old pubkey can be revoked from the trust store and a
> new binary can be generated with new key material. The trusted root
> doesn't need to be cycled as often. HardenedBSD, for example,
> distributes the pubkey that corresponds to the signing privkey inside
> the update tarball for binary updates[1]. This allows us to change key
> material often if desired without the user even noticing.

I can see a two-tiered scheme where you have a "vendor key", which is
used to sign various "application keys", which are used to sign the
kernel and modules.  The signed executables can then supply their
application keys (signed by the vendor key) to the loader/kernel, which
first checks the signature on the key, then on the file.  This way, you
could generate and use a different key for each build, and sign it with
the same vendor key.

There's at least three use cases in play here:

1) FreeBSD would want to publish ready-made installations, probably
signed by a key they control.  This ensures that someone who just wants
to install binary packages and go doesn't load any kernel/modules other
than the ones coming from FreeBSD.

2) I run an enterprise network, and I want to build everything
internally on some build-box, and make sure I only run things that got
built there, or that came from FreeBSD.

3) I have a highly secure network that is set up like in (2), except I
only allow things I build internally to run.

3) I have my laptop, and I want to build everything on the laptop and
make sure I don't boot anything I didn't build.

For all of these, I'd want to bake in at least the vendor key(s).  I
could do this pretty easily by converting the key(s) to a header, then
using it in buildworld/kerrnel.

For (1), FreeBSD would have a vendor key, which it uses to sign the
kernel/modules it publishes, and that would be baked in to those
applications.

For (2), I'd have my own vendor key for my organization, and I'd use
that in addition to FreeBSD's key.  This would allow anything signed by
either of the two organizations.

For (3), I'd only use my own vendor key, and not FreeBSD's, so that only
things I build internally can boot.

For (4), I theoretically only need one level of key.  I'd presumably
generate a key pair every buildworld/kernel, then throw away the private
key when I finished.  OTOH, I'd need to remember to reinstall loader (or
GRUB/coreboot, and I might not want to go around flashing my BIOS every
time I upgrade) every time, so there's a case for a two-level scheme at
which point it's a microcosm of (4).

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20170327/c95c3888/attachment.sig>


More information about the freebsd-hackers mailing list