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>