Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 27 Mar 2017 13:54:44 -0400
From:      Eric McCorkle <eric@metricspace.net>
To:        "freebsd-hackers@freebsd.org" <freebsd-hackers@FreeBSD.org>
Cc:        freebsd-security@freebsd.org
Subject:   Proposal for a design for signed kernel/modules/etc
Message-ID:  <6f6b47ed-84e0-e4c0-9df5-350620cff45b@metricspace.net>

next in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
--5tJFchSClLXPlLXBTeF3xliHxegxS2CGS
Content-Type: multipart/mixed; boundary="VfKDQGqN42otawkWgJ1TC8hPFp8JNnhaw";
 protected-headers="v1"
From: Eric McCorkle <eric@metricspace.net>
To: "freebsd-hackers@freebsd.org" <freebsd-hackers@FreeBSD.org>
Cc: freebsd-security@freebsd.org
Message-ID: <6f6b47ed-84e0-e4c0-9df5-350620cff45b@metricspace.net>
Subject: Proposal for a design for signed kernel/modules/etc

--VfKDQGqN42otawkWgJ1TC8hPFp8JNnhaw
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

Hello everyone,

The following is a design proposal for signed kernel and kernel module
loading, both at boot- and runtime (with the possibility open for signed
executables and libraries if someone wanted to go that route).  I'm
interested in feedback on the idea before I start actually writing code
for it.

=3D=3D Goals =3D=3D

1) Be able to check for a correct cryptographic signature for any kernel
or modules loaded at boot time for some platforms (EFI at a minimum).

2) Be able to check for a correct cryptographic signature for any kernel
module loaded during normal operations (whether or not to do this could
be controlled by a sysctl, securelevel, or some similar mechanism)

3) Work with what's in base already and minimize new additions (ideally,
just a small utility to sign executables)

4) Minimize administrative overhead and ideally, require no changes at
all to maintain signed kernel/modules

5) Have a clear path for supporting signed executables/libraries (I'm
not planning on pursuing this, but it's worth considering that someone
might want to)

6) The design *MUST* support the case where a system builds locally and
uses its own key(s) for signing kernels and modules (and anything else)
and *MUST* allow the administrator complete control over which key(s)
are valid for a given system (ie. no "master keys" controlled by central
organizations)

7) The design must allow for the adoption of new ciphers (there is an
inevitable shift to post-quantum ciphers coming in the near future)

=3D=3D Non-Goals =3D=3D

* Hardware/firmware-based attacks are considered out-of-scope (there is
no viable method for defending against them at the OS level)

* Boot platforms that don't provide their own signature-checking
framework up to loader/kernel can't be properly secured, and are
considered out-of-scope

* Boot platforms that impose size restrictions prohibiting incorporation
of RSA and ED25519 crypto code (ex. i386 BIOS) are considered out-of-scop=
e

* GRUB support is desirable, however it is not necessary to support GRUB
out-of-the-box (meaning a design requiring reasonable modifications to
GRUB is acceptable).

* I am not aiming to support signed executables/libraries now, only to
avoid shutting the door on them.

=3D=3D Existing Solution(s) =3D=3D

EFI has a decent design with regard to key management (platform key,
which signs system keys, which sign the actual loader); however, its
cipher suite is sorely lacking (many broken hashes and weak ciphers, RSA
2048 being the "strongest", no ECC).  It also only works with the COFF
format, and is only available at boot time.  However, it does provide a
chain of custody up to loader (to the extent that anyone trusts
closed-source firmware blobs, SHA1, and 512-2048 bit RSA keys...)  Many
implementations also have master keys "baked in" that would allow
anything signed by random third parties (Microsoft) to boot regardless
of local configurations, or they don't provide any sort of control over
(or even access to) the keys at all.

EFI obviously isn't viable beyond boot time, and misses most of the
goals even there.  Its key management hierarchy is an overall good
design, however.

GRUB currently supports signature checking.  It can be configured to
require signatures for any of its own modules as well as any kernel or
modules that it loads.  These signatures are stored *outside* the
executable/library, in a file with an added .sig extension.  The format
is that of an external signature for the entire ELF file as produced by
the gnupg program.

Linux (I believe) also supports signature checking for modules using the
same convention.

While functional, this design doesn't meet the goals I outlined:

* It relies on the gnupg framework, which is not part of FreeBSD base,
and adding it would be a chore (and would end up duplicating a lot of
functionality provided by OpenSSL)

* It stores the signature separate from the file, which leads to x2 the
number of files, would require modifying existing scripts, and
complicates administrative tasks.  It also leads to failure modes like
stale signatures.

* There are potential legitimate modifications to non-code parts of an
ELF file (such as the .comment section or other similar sections) that
would require re-signing the entire file.

* The previous two problems really start to look bad when you consider
signed executables and libraries, possibly with third-party
build/install scripts...

* Finally, the gnupg signature format doesn't actually seem to be
documented anywhere, or at least not anywhere that doesn't require a lot
of digging...


An alternate solution, which I believe is used in some places is to wrap
the entire executable in a PGP envelope-like format.  This solves the
issue of an external signature file, but would require extensive
modification to the ELF parsing code, let alone the binutils programs
that read/modify ELF files.  This solution also isn't
backwards-compatible at all.  Old loaders/kernels will choke on the
signed libraries.

=3D=3D Proposal=3D=3D

My proposal is to store cryptographic signatures within the ELF files
themselves in a non-loadable section (similar to the .comment section).

As background, the ELF file format has a number of different section
types, only some of which comprise the program/library/module's runtime
state.  The ELF specification and tools provide some "standard" sections
with defined meanings, but nothing stops anyone from adding their own
sections.  The ELF file format is quite flexible, and it is not
difficult to add custom metadata to an ELF file. [0]

In this proposal, cryptographic signatures would be stored in a
=2Esignature (or .sig) section.  This section would contain an array of
signature constructs: one for each loadable segment in the ELF file.
Signatures are computed for the contents of the segment's file data (ie.
the data from p_offset to p_filesz, for the corresponding program header
entry) along with all data from its program header entry except for
p_offset and p_filesz.  This scheme allows the actual data to be moved
around in the file, so long as it (or the relevant program header data)
isn't modified.

The exact format of this data can be discussed, but a design where the
signature array corresponds to the program header array seems quite
reasonable.  The format of the signatures themselves should be something
from a well-defined standard, reasonably extensible, and supported by
tools in base.

=3D=3D Summary of Changes =3D=3D

The following changes would be required:

1) Add a userland utility for signing ELF files (call it "signelf").
This would be a pretty straightforward application of OpenSSL and libelf.=


2) Modify ELF-parsing code in loader and kernel to check signatures and
indicate whether a given file had good signatures for all of its
loadable segments.

3) Have loader/kernel issue warnings or reject kernels/modules with
incomplete/incorrect/no signatures

4) Decide how to go about building public key data into loader/kernel or
how to register keys with the kernel (it is probably OK to implement a
"bake it in" solution first, then figure out dynamic registration of
keys as a follow-up; somebody out there is sure to want just the "bake
it in" solution with no dynamic registration for security reasons, and
we need it for loader anyway).

5) Submit a patch against GRUB to support the ELF metadata method in
addition to their existing method.

The most involved part of this is adding the public-key crypto code into
loader and the kernel.  My recommendation for this is to grab the RSA
and ED25519 code from NaCL.  It's compact, self-contained, written by
crypto people with a good handle on the systems side of things (DJB's
group), and licensed under a BSD-compatible license.  Also, the
loader/kernel side code only needs signature-checking, not full
public-key functionality.

=3D=3D Rationale =3D=3D

The ELF metadata approach eliminates all of the disadvantages of the
GRUB external signatures method, while maintaining compatibility with
existing systems.  Older systems will simply ignore the .signature
metadata section and function normally and from a sysadmin standpoint,
signed executables/libraries are just slightly larger versions of the
unsigned variants.  Moreover, ELF metadata that isn't part of the
executable sections can be freely modified, and signed ELF files can be
re-signed.

Having a separate signature for each segment in the program header table
is slightly more complicated than the simplest solution of having one
signature for all program header sections.  However, this approach
provides more flexibility going forward.  It also accounts for the fact
that we might not want to sign all portions of the file.  Finally, as
designed, it allows the file to be modified freely as long as the
runtime behavior isn't affected.

There is a rather simple design possibility if anyone wanted to go the
signed executable/library route: have an mmap variant with an additional
parameter pointing to the signature would lead to a very simple
modification of the userland dlopen functionality.  Normal mmap would
just become a wrapper around the secure variant, which passes in NULL
for the signature (alternatively, you could pass in a default key built
into the local libc, or something similar).

=3D=3D Conclusion =3D=3D

This seems like a good point in the design space: it doesn't break
anything, it doesn't require massive changes or rearchitecting of
anything, it provides everything I want to provide now, and it leaves
the door open to things people might want to do in the future.

Please provide feedback, comments, and suggestions.


[0]: There actually is at least one example of something like this of
which I'm aware.  The Intel C Compiler (icc, "proton" by Intel internal
naming) has an interprocedural optimization mode which produces .o files
containing the compiler's intermediate representation in a special
section as well as object code in the usual sections (incidentally, in
the distant past, icc would actually produce separate .o and .il files;
this was later changed to the ELF metadata solution, for the very reason
that it complicated build scripts quite a bit).  This allows "normal"
compilers and compilation modes to use the object code, while icc uses
the intermediate representation.


--VfKDQGqN42otawkWgJ1TC8hPFp8JNnhaw--

--5tJFchSClLXPlLXBTeF3xliHxegxS2CGS
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEzzhiNNveVG6nWjcH1w0wQIFco2cFAljZUeQACgkQ1w0wQIFc
o2cyhxAA2HlLeBeH5yEwzJyAq0oAkL0YVkFmrFUQpWh/jUWPvpWPmiWP/5m/lKnW
ET1wttA2/2rIKa1N/G/Srm2NOSt38YHb4rTAs3fvcUi62mg4t7Lq1HDD1S9vLBtD
EUe1agw9tHtGREmwVmkUaAKuprgNyDAhm0mbgjJpIk1KQpNHUojREIO8fzZUVzow
KVtdRfmVJZOKFjk9Nl3Z7dDQoyWtQxnbP1Yss3jKXpgHwOfqgmFyqqGf0FtJ9G+Y
IW7rb8wfMC8vTkblYFjR10jzpgd7wQNGa+bHb0qWQU5pdJA8mlLKnGVfUDxM2W8K
4eTNpKLHAi1avTz9oZ3tzigSgBBcf6s9kkfu50+lKpf8Cke/mH24sCGpLfCqb1Tu
spcg0FbouvUhVMXT2zkZ9YgfTRyFcTcw+OIjCeWLr4vexIyMkdVwAPsZ7BK6E/bi
odg9Pmm4Hy3SilSw8CIHGyUfx5UVZjUM4Ep6Y3jRoQ7CKiHC/lZK918R01qmJ5sR
oDTyQnWo09Pf+w9/i6PP6Qo4313MJc/fk6QkWccbeWgaug9zVMw52nIS1d7i/lCw
rS6Shq7pywEreAcc2FnMHXgafYJFVp+gPsNSTFXLCUjJS1ZbZUYGYA4XVkfnfBFf
5bCjT8R4amdp/OU5cOEEiMjGXqDnVjTX4XudFMEuHgZlC2CjBkU=
=y53H
-----END PGP SIGNATURE-----

--5tJFchSClLXPlLXBTeF3xliHxegxS2CGS--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6f6b47ed-84e0-e4c0-9df5-350620cff45b>