Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144523275
D16563.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
73 KB
Referenced Files
None
Subscribers
None
D16563.diff
View Options
Index: contrib/elftoolchain/libelf/_libelf.h
===================================================================
--- contrib/elftoolchain/libelf/_libelf.h
+++ contrib/elftoolchain/libelf/_libelf.h
@@ -29,6 +29,8 @@
#ifndef __LIBELF_H_
#define __LIBELF_H_
+#include <stdbool.h>
+
#include <sys/queue.h>
#include "_libelf_config.h"
@@ -229,6 +231,8 @@
int _libelf_setshnum(Elf *_e, void *_eh, int _elfclass, size_t _shnum);
int _libelf_setshstrndx(Elf *_e, void *_eh, int _elfclass,
size_t _shstrndx);
+Elf_Data * _libelf_getdata(Elf_Scn *s, Elf_Data *ed, bool updating);
+Elf_Data * _libelf_rawdata(Elf_Scn *s, Elf_Data *ed, bool updating);
Elf_Data *_libelf_xlate(Elf_Data *_d, const Elf_Data *_s,
unsigned int _encoding, int _elfclass, int _direction);
int _libelf_xlate_shtype(uint32_t _sht);
Index: contrib/elftoolchain/libelf/elf_data.c
===================================================================
--- contrib/elftoolchain/libelf/elf_data.c
+++ contrib/elftoolchain/libelf/elf_data.c
@@ -29,13 +29,14 @@
#include <libelf.h>
#include <stdint.h>
#include <stdlib.h>
+#include <stdbool.h>
#include "_libelf.h"
ELFTC_VCSID("$Id: elf_data.c 3466 2016-05-11 18:35:44Z emaste $");
Elf_Data *
-elf_getdata(Elf_Scn *s, Elf_Data *ed)
+_libelf_getdata(Elf_Scn *s, Elf_Data *ed, bool updating)
{
Elf *e;
unsigned int sh_type;
@@ -94,7 +95,9 @@
if ((elftype = _libelf_xlate_shtype(sh_type)) < ELF_T_FIRST ||
elftype > ELF_T_LAST || (sh_type != SHT_NOBITS &&
- (sh_offset > e->e_rawsize || sh_size > e->e_rawsize - sh_offset))) {
+ (!updating &&
+ (sh_offset > e->e_rawsize ||
+ sh_size > e->e_rawsize - sh_offset)))) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
@@ -165,6 +168,12 @@
return (&d->d_data);
}
+Elf_Data *
+elf_getdata(Elf_Scn *s, Elf_Data *ed)
+{
+ return (_libelf_getdata(s, ed, false));
+}
+
Elf_Data *
elf_newdata(Elf_Scn *s)
{
@@ -209,7 +218,7 @@
*/
Elf_Data *
-elf_rawdata(Elf_Scn *s, Elf_Data *ed)
+_libelf_rawdata(Elf_Scn *s, Elf_Data *ed, bool updating)
{
Elf *e;
int elf_class;
@@ -254,7 +263,9 @@
}
if (sh_type != SHT_NOBITS &&
- (sh_offset > e->e_rawsize || sh_size > e->e_rawsize - sh_offset)) {
+ (!updating &&
+ (sh_offset > e->e_rawsize ||
+ sh_size > e->e_rawsize - sh_offset))) {
LIBELF_SET_ERROR(SECTION, 0);
return (NULL);
}
@@ -274,3 +285,9 @@
return (&d->d_data);
}
+
+Elf_Data *
+elf_rawdata(Elf_Scn *s, Elf_Data *ed)
+{
+ return (_libelf_rawdata(s, ed, false));
+}
Index: contrib/elftoolchain/libelf/elf_update.c
===================================================================
--- contrib/elftoolchain/libelf/elf_update.c
+++ contrib/elftoolchain/libelf/elf_update.c
@@ -182,7 +182,8 @@
* Otherwise, we need to bring in the section's data
* from the underlying ELF object.
*/
- if (e->e_cmd != ELF_C_WRITE && elf_getdata(s, NULL) == NULL)
+ if (e->e_cmd != ELF_C_WRITE &&
+ _libelf_getdata(s, NULL, true) == NULL)
return (0);
}
Index: share/man/man5/Makefile
===================================================================
--- share/man/man5/Makefile
+++ share/man/man5/Makefile
@@ -63,6 +63,7 @@
resolver.5 \
services.5 \
shells.5 \
+ signed-elf.5 \
src.conf.5 \
stab.5 \
style.Makefile.5 \
Index: share/man/man5/signed-elf.5
===================================================================
--- /dev/null
+++ share/man/man5/signed-elf.5
@@ -0,0 +1,307 @@
+.\" Copyright (c) 2017 Eric McCorkle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 24, 2017
+.Dt SIGNED-ELF 5
+.Os
+.Sh NAME
+.Nm signed-elf
+.Nd "cryptographically signed ELF binaries"
+.Sh DESCRIPTION
+Signed ELF binaries are files in the Executable Linkable Format
+.Pq Xr elf 5
+that contain extra metadata bearing a cryptographic signature that
+allows the contents of the file to be verified against a public key.
+.Ss Format Specification
+The signed ELF format makes use of features intrinsic to the ELF file
+format to store signatures. The signature data for a signed ELF is
+stored in a section named
+.Sy .sign .
+The
+.Sy .sign
+section is similar in
+nature to the
+.Sy .comment
+section and typically will not be included in
+any loadable segment. The signature data itself is stored as a
+DER-encoded CMS detached signature, typically without metadata such
+as certificates and chains, MIME capabilities, attributes, or other
+such extras. The signature is computed in binary mode using the
+contents of the entire file, but with the entire
+.Sy .sign
+section
+containing zero data.
+.Ss Ciphers and Hashes
+The CMS format is designed to allow for a variable selection of
+ciphers. In order to maintain strong security properties, the signed
+ELF specification imposes the following restrictions on ciphers and
+hashes:
+.Bl -bullet -offset indent
+.It
+The allowed hash algorithms are as follows: SHA256, SHA384, SHA512,
+SHA3 (Keccak), Blake-2b, Skein, and Whirlpool. The default hash is
+SHA256.
+.It
+RSA digital signatures are allowed with key lengths of 4096 bits or higher
+.It
+ECDSA/EdDSA signatures are allowed for curves satisfying all of the
+safety properties described by the SafeCurves project (at the time of
+writing, this list consists of the following curves: M-221, E-222,
+Curve1174, Curve25519, E-382, M-383, Curve383187, Curve41417,
+Goldilocks-448, M-511, and E-521).
+.El
+.Pp
+Any signature which does not use an allowed hash and cipher will be
+rejected.
+.Pp
+These restrictions may be changed at a later date, but will generally
+progress in the direction of stronger security properties.
+.Ss Creation and Verification
+The procedure for generating a signature typically requires
+modification of the ELF file. The procedure is as follows:
+.Bl -enum -offset indent
+.It
+The size of the signature is calculated. (This requires that the
+signature size be invariant with respect to the data being signed- a
+property possessed by CMS detached signatures.)
+.It
+The
+.Sy .sign
+section is added and initialized to the proper size. (Often
+times this necessitates the creation of string table and section
+header entries and some file offsets may change as a result.)
+.It
+The
+.Sy .sign
+section is filled with zeros.
+.It
+The signature is computed using the entire file as input.
+.It
+The Signature is written into the
+.Sy .sign
+section in CMS detached
+format using the DER enconding.
+.El
+.Pp
+The verification procedure is as follows:
+.Bl -enum -offset indent
+.It
+The
+.Sy .sign
+section is located, and the CMS detached signature is loaded
+.It
+The
+.Sy .sign
+section is overwritten with zeros.
+.It
+The signature is verified using the entire file as input.
+.El
+.Ss Usage
+Signed ELF files are primarily intended to be verified by mechanisms such as
+.Xr loader 8 ,
+.Xr kldload 8 ,
+.Xr execve 2 ,
+and similar mechanisms as part of a chain-of-trust security protocol
+designed to prevent tampering with executable files, shared libraries,
+kernel modules, and the like. As such, signed ELF files will almost
+always be of the executable or shared object variety, as these are
+typically not modified following their creation. While it is possible
+to sign archives and linkable objects in the same manner, it typically
+makes no sense to do so. The security properties of cryptographic
+signatures prevent even the slightest modification of the data they
+protect, and both linkable objects and archives are specifically
+designed to be modified and composed into final products.
+.Pp
+It should be noted, however, that some applications (often programming
+language runtime systems) are known to (ab)use linkable objects or
+archives in ways that more closely resemble the intended use of
+executable or shared objects: as a runtime-supported executable, as a
+kind of loadable module, or for even more exotic uses. In such cases,
+signing such files may well serve a useful purpose.
+.Sh CERTIFICATES
+Signed ELF files require public-key certificates for verification
+(note that new signatures can only be produced using the corresponding
+private key). The
+.Xr openssl 1
+tool suite provides a number of utilities for creating and managing
+private keys and public-key certificates.
+.Pp
+A FreeBSD installation maintains a set of trusted public key
+certificates to serve as a trust root, and at least one signing key to
+serve as a trust root. The default location for these certificates
+and keys is
+.Pa /etc/trust
+with signing keys being stored in
+.Pa /etc/trust/priv
+and public key certificates in
+.Pa /etc/trust/certs
+(this allows differing permissions on the two directories), and with
+trust root keys and certificates being stored in a similar fashion
+under
+.Pa /etc/trust/root/priv
+and
+.Pa /etc/trust/root/certs.
+The default public and private keys use for signing locally-produced
+binaries are located at
+.Pa /etc/trust/priv/local.pem
+and
+.Pa /etc/trust/priv/local.pub.pem
+respectively. Additional public key certificates may be stored in
+.Pa /etc/trust/certs
+that have no corresponding private key. This can be used to grant
+trust to binaries produced by a third party.
+.Sh UTILITIES
+There are several ways of creating, modifying, and verifying signed
+ELF binaries.
+.Ss Preferred Method
+The preferred method for creating and verifying signed ELF files is the
+.Xr signelf 8
+utility. (See the man page for usage details.)
+.Ss Signing with Binutils and OpenSSL
+Signed ELF files can also be created and verified using the
+.Xr objcopy 1
+and
+.Xr openssl 1
+utilities. This method can be used in cases where
+.Xr signelf 5
+is not available for some reason, and can also be used to support
+signed ELF files on foreign operating systems.
+.Pp
+A signed ELF file can be created using
+.Xr objcopy 1
+and
+.Xr openssl 1
+with the following procedure:
+.Pp
+First, add the
+.Sy .sign
+section:
+.Pp
+.Dl "$ objcopy --add-section .sign=zeros myexe"
+.Pp
+Where
+.Pa zeros
+is a file exactly as large as a signature which contains zeros. Next,
+sign the binary:
+.Pp
+.Dl "$ openssl cms -sign -outform DER -md sha256 -binary -nosmimecap \\"
+.Dl " -nocerts -noattr -signer cert.pem \\"
+.Dl " -inkey key.pem -in myexe -out signature"
+.Pp
+Last, update the
+.Sy .sign
+section to contain the signature data:
+.Pp
+.Dl "$ objcopy --update-section .sign=signature myexe"
+.Pp
+.Ss Verification with Binutils and OpenSSL
+A signature can be verified with
+.Xr objcopy 1
+and
+.Xr openssl 1
+by the following procedure:
+.Pp
+First, extract the signature:
+.Pp
+.Dl "$ objcopy --update-section .sign=signature myexe"
+.Pp
+Now, zero out the signature:
+.Pp
+.Dl "$ objcopy --update-section .sign=zeros myexe myexe.tmp"
+.Pp
+Last, verify the signature:
+.Pp
+.Dl "$ openssl cms -verify -nointern -inform DER -binary \\"
+.Dl " -in signature -content signelf -certfile cert.pem \\"
+.Dl " -CApath /etc/trust/certs -out /dev/null"
+.Pp
+The check against the system trusted keys can be omitted as follows:
+.Pp
+.Dl "$ openssl cms -verify -nointern -noverify -inform DER -binary \\"
+.Dl " -in signature -content signelf -certfile cert.pem \\"
+.Dl " -out /dev/null"
+.Pp
+.Ss Deleting Signatures
+Lastly, signatures can be deleted from a file using the
+.Xr objcopy 3
+utility:
+.Pp
+.Dl "$ objcopy -R .sign myexe"
+.Pp
+.Sh WARNINGS
+Any modification of a signed ELF binary- however slight -will cause
+signature verification to fail (as intended). Furthermore, due to the
+nature of the ELF format, signatures will likely be retained if a
+signed ELF binary is used as input to a tool such as
+.Xr objcopy 1
+or similar utilities, which will result in an ELF binary containing a
+bad signature.
+.Pp
+It is therefore recommended to only sign executables and shared
+objects after at the end of all compilation steps.
+.Pp
+As of the time of writing, it is reasonably likely that quantum
+computing devices capable of attacking public-key ciphers will become
+available in the foreseeable future. Should this become a reality, the
+security of RSA- and ECC-based public key algorithms will be compromised.
+This has major implications for any systems utilizing ELF signatures (or
+public-key cryptography generally): namely that such systems should avoid
+hardwired or burned-in keys, that they should assume keys will be
+periodically changed, and that they should incorporate key expiration
+and revocation into their designs. Additionally, users should assume that
+the cipher suite will undergo significant changes to incorporate post-quantum
+ciphers and remove quantum-vulnerable ones.
+.Sh SEE ALSO
+.Xr trust-config 7 ,
+.Xr elf 5 ,
+.Xr signelf 5 ,
+.Xr openssl 1 ,
+.Xr cms 1 ,
+.Xr objcopy 1
+.Rs
+.%A Hewlett Packard
+.%B Elf-64 Object File Format
+.Re
+.Rs
+.%A Unix System Laboratories
+.%T Object Files
+.%B "Executable and Linking Format (ELF)"
+.Re
+.Rs
+.%A Internet Engineering Task Force (IETF)
+.%B RFC 2315 (CMS)
+.Re
+.Rs
+.%A Daniel J. Bernstein and Tanja Lange.
+.%T SafeCurves: choosing safe curves for elliptic-curve cryptography.
+.%B https://safecurves.cr.yp.to/
+.Re
+.Sh HISTORY
+The signed ELF binary specification first appeared in
+.Fx 12.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Eric L. McCorkle Aq Mt emc2@metricspace.net .
Index: share/man/man7/Makefile
===================================================================
--- share/man/man7/Makefile
+++ share/man/man7/Makefile
@@ -31,6 +31,7 @@
stdint.7 \
sticky.7 \
tests.7 \
+ trust-config.7 \
tuning.7
MLINKS= intro.7 miscellaneous.7
Index: share/man/man7/trust-config.7
===================================================================
--- /dev/null
+++ share/man/man7/trust-config.7
@@ -0,0 +1,243 @@
+.\" Copyright (c) 2017 Eric McCorkle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 25, 2017
+.Dt TRUST-CONFIG 7
+.Os
+.Sh NAME
+.Nm trust-config
+.Nd "trust system configuration"
+.Sh DESCRIPTION
+The trust system configuration specifices the the trust root
+certificates, intermediate certificates, and provides the trusted
+signing keys, allowing users to create signed executables (see
+.Xr signed-elf 5)
+as well as other signed assets. It provides the default keys to
+.Xr signelf 8
+and other utilities, and controls which keys are included in critical
+system components as the builtin trust root set.
+.Sh TERMINOLOGY
+The trust configuration controls the behavior of a system consisting
+of several parts with interlocking functions; thus, it is essential to
+be clear about the terminology used to describe both the system and
+its configuration.
+.Ss Trust Root Certificates
+The
+.Sy trust root certificates
+are a set of public (verification) certificates which are built
+directly in to critical system components. The trust root
+certificates are then used to verify intermediate certificates,
+revocation lists, signed executables, and other signed assets.
+.Pp
+System components such as the kernel and
+.Xr loader 8
+which play an essential role in the chain of custody from boot to user
+must necessarily include the trust root set into their binaries (which
+are presumably verified by earlier boot stages or stored in flash
+memory). The build process must therefore collect a set of desired
+keys and build them into these components. The
+.Sy trust root configuration
+is the set of certificates and additional information that controls
+this aspect of the build process.
+.Ss Intermediate Certificates
+The
+.Sy intermediate certificates
+are a set of public (verification) certificates which have a valid
+signature chain back to a trust root certificate. The combined set of
+intermediate and root certificates are known as the
+.Sy trust certificates .
+.Ss Trusted Signing Keys
+The
+.Sy trusted signing keys
+are a set of private keys that correspond to public keys in the trust
+certificates. These are used to produce signatures for various assets
+that can be verified by the trust certficates.
+.Ss Trust System Configuration
+The
+.Sy trust system configuration
+is the combination of the trust root configuration and the trusted
+signing keys.
+.Sh FILES
+The trust system configuration consists of the following files and
+directories:
+.Bl -bullet indent
+.It
+.Pa /etc/trust/ :
+The base directory for the trust system configuration
+.It
+.Pa /etc/trust/certs/ :
+The directory containing the intermediate trust certificates
+.It
+.Pa /etc/trust/priv/ :
+The directory containing the intermediate signing keys
+.It
+.Pa /etc/trust/root :
+The base directory for the trust root configuration
+.It
+.Pa /etc/trust/root/certs/ :
+The directory containing the trust root certificates
+.It
+.Pa /etc/trust/root/priv/ :
+The directory containing the trust root signing keys
+.El
+.Pp
+The trusted signing key directories
+.Pa /etc/trust/priv/
+and
+.Pa /etc/trust/root/priv/
+contain PEM-encoded private keys or PKCS#8 data structures. The
+standard file naming convention for a key named
+.Qq mykey
+is
+.Pa mykey.pem .
+.Pp
+The trusted certificate directories
+.Pa /etc/trust/certs/
+and
+.Pa /etc/trust/root/certs/
+contain PEM-encoded X509 certificates, and is generally compatible
+with OpenSSL CA directory parameters or configuration options.
+Certificates under
+.Pa /etc/trust/root/certs/
+will typically be self-signed certificates, though nothing prevents
+the inclusion of certificates signed by a third party. Note, however,
+that signatures on trust root keys are ignored by all trust system
+components. Certificates under
+.Pa /etc/trust/certs/
+must have a valid chain of signatures back to a certificate under
+.Pa /etc/trust/root/certs/ .
+.Ss Trusted Signing Keys
+Some certificates in the trust certificate directories correspond to
+trusted signing keys in
+.Pa /etc/trust/priv
+or
+.Pa /etc/trust/root/priv.
+The naming convention for signing keys and their corresponding
+certificates is as follows. Signing key filenames consist of the
+key's name, followed by ".pem". The corresponding certificate
+consists of the same name, followed by ".pub.pem". Certificates in
+the
+.Pa /etc/trust/certs/
+may be optionally preceeded by up to four numerals (0-9), followed by
+a "." (this allows administrators to control the order in which
+intermediate certificates will be encountered when listing a directory).
+.Pp
+For example, the filename for a private key named
+.Qq mykey
+would be
+.Pa mykey.pem ,
+and its corresponding certificate would be
+.Pa mykey.pub.pem
+(or possibly
+.Pa 00.mykey.pub.pem ,
+if it were stored in
+.Pa /etc/trust/certs/
+). Additionally, keys in
+.Pa /etc/trust/priv
+may only correspond to keys in
+.Pa /etc/trust/certs/ ;
+similarly, keys in
+.Pa /etc/trust/root/priv
+may only correspond to keys in
+.Pa /etc/trust/root/certs/ .
+It is an illegal configuration to have a key in
+.Pa /etc/trust/priv
+and a corresponding cert in
+.Pa /etc/trust/root/certs/ ,
+or vice versa. It is also an illegal configuration to have
+certificates or keys with the same name in both
+.Pa /etc/trust/root/ ,
+and
+.Pa /etc/trust/ .
+
+.Ss Third-Party Trust Keys
+It is not required that all public key certificates in the trust root
+configuration have a corresponding trusted signing key (with one
+exception; see below). There are many circumstances in which this may
+be desirable, such as administration of large networks or distribution
+of pre-built binaries from a trusted source. Public-key certificates
+in the trust root configuration without a corresponding trusted
+signing key are known as
+.Qq third-party keys .
+.Pp
+It is important to consider the security implications of third-party
+keys before accepting such a key into a trust root configuration.
+Because of the severity of these implications, there is no requirement
+that any configuration include any third-party key(s), nor will there
+ever be such a requirement.
+.Pp
+Furthermore, the
+.Xr signelf 5
+utility is perfectly capable of overwriting signatures from
+third-party keys with a signature generated by a locally-controlled
+keypair; thus, assets signed by a third party can easily be inspected
+and re-signed locally at the behest of the system administrator.
+.Ss Local Keypair
+The key name
+.Qq local
+(which corresponds to the private key path
+.Pa /etc/trust/root/priv/local.pem
+and the public key path
+.Pa /etc/trust/root/certs/local.pub.pem
+by the file naming conventions) is used as the default keypair by
+tools such as
+.Xr signelf 8 .
+This keypair is known as the
+.Ar local keypair ,
+should be generated locally on each installation, and should generally
+not be exported to other installations. Most user-oriented systems
+and all systems that build the base system or packages locally for
+their own use should have a local keypair.
+.Pp
+It is possible for some installations to lack a local keypair,
+particularly on infrastructure-type systems that are set up using
+standardized images or configuration management systems. Such systems
+generally do not build anything locally and rely on pre-built packages
+for installation and upgrades.
+.Pp
+However, it is an illegal configuration for there to be a public key
+certificate named
+.Pa /etc/trust/root/certs/local.pub.pem
+without a corresponding private key.
+.Sh DEFAULT
+The default trust system configuration consists solely of a local
+keypair which is generated during OS installation. Any additional
+trusted keys (including third-party keys) are signed by the local
+keypair and loaded as intermediate keys rather than being added
+directly to the trust root configuration. This is the preferred
+configuration, and alternatives should only be used if there is a
+specific and compelling reason to do so.
+.Sh SEE ALSO
+.Xr trust 7 ,
+.Xr signed-elf 5 ,
+.Xr signelf 5 ,
+.Xr openssl 1
+.Sh HISTORY
+The trust system first appeared in
+.Fx 12.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Eric L. McCorkle Aq Mt emc2@metricspace.net .
Index: usr.sbin/Makefile
===================================================================
--- usr.sbin/Makefile
+++ usr.sbin/Makefile
@@ -82,6 +82,7 @@
setfib \
setfmac \
setpmac \
+ signelf \
smbmsg \
snapinfo \
spi \
Index: usr.sbin/signelf/Makefile
===================================================================
--- /dev/null
+++ usr.sbin/signelf/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+PROG=signelf
+MAN=signelf.8
+SRCS=signelf.c sign.c verify.c util.c
+
+LIBADD=crypto elf
+
+.include <bsd.prog.mk>
Index: usr.sbin/signelf/sign.c
===================================================================
--- /dev/null
+++ usr.sbin/signelf/sign.c
@@ -0,0 +1,746 @@
+/*-
+ * Copyright (c) 2018 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/param.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/cms.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#include "signelf.h"
+
+#define VPRINTF(...) (verbose ? fprintf(stderr, __VA_ARGS__) : 0)
+
+static char keypath[MAXPATHLEN + 1];
+static char pubpath[MAXPATHLEN + 1];
+static char **signpaths;
+static size_t nsignpaths = 0;
+static size_t max_signpaths = 16;
+static bool verbose = false;
+static bool ephemeral = false;
+static char ephemeralpath[MAXPATHLEN + 1];
+static EVP_PKEY *sign_priv;
+static X509 *sign_cert;
+static size_t sigsize;
+static size_t first_resizable;
+
+static void
+add_signpath(char *signpath)
+{
+ if (max_signpaths <= nsignpaths) {
+ void *tmp;
+
+ max_signpaths *= 2;
+ tmp = realloc(signpaths, max_signpaths * sizeof(signpaths[0]));
+ check_malloc_error(tmp);
+ signpaths = tmp;
+ }
+
+ signpaths[nsignpaths] = strdup(signpath);
+ nsignpaths++;
+}
+
+static void
+set_keypath(const char *path)
+{
+ strncpy(keypath, path, MAXPATHLEN);
+}
+
+static void
+set_pubpath(const char *path)
+{
+ strncpy(pubpath, path, MAXPATHLEN);
+}
+
+static void
+set_ephemeralpath(const char *path)
+{
+ strncpy(ephemeralpath, path, MAXPATHLEN);
+}
+
+static void
+load_keys(void)
+{
+ FILE *f;
+ EVP_PKEY *priv;
+ X509 *cert;
+
+ /* Load the private key */
+ f = fopen(keypath, "r");
+ check_file_error(f, "Error opening private key");
+ priv = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ check_ssl_error("loading private key");
+ fclose(f);
+
+ /* Load the public key */
+ f = fopen(pubpath, "r");
+ check_file_error(f, "Error opening public key");
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ check_ssl_error("loading public key");
+ fclose(f);
+
+ if (ephemeral) {
+ ASN1_TIME *asntime;
+ X509_NAME *name;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(priv, NULL);
+ ASN1_INTEGER timestamp;
+
+ VPRINTF("Generating ephemeral key...");
+
+ /* Generate the ephemeral private key */
+ check_ssl_error("generating ephemeral private key");
+ EVP_PKEY_keygen_init(ctx);
+ check_ssl_error("generating ephemeral private key");
+ EVP_PKEY_keygen(ctx, &sign_priv);
+ check_ssl_error("generating ephemeral private key");
+ EVP_PKEY_CTX_free(ctx);
+
+ VPRINTF("done\n");
+
+ /* Create ephemeral public key cert */
+ sign_cert = X509_new();
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_pubkey(sign_cert, sign_priv);
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_version(sign_cert, 2);
+ check_ssl_error("creating ephemeral public key cert");
+ ASN1_INTEGER_set(×tamp, time(NULL));
+ check_ssl_error("creating ephemeral public key cert");
+ asntime = X509_get_notBefore(cert);
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_notBefore(sign_cert, asntime);
+ check_ssl_error("creating ephemeral public key cert");
+ asntime = X509_get_notAfter(cert);
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_notAfter(sign_cert, asntime);
+ check_ssl_error("creating ephemeral public key cert");
+ name = X509_get_subject_name(cert);
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_subject_name(sign_cert, name);
+ check_ssl_error("creating ephemeral public key cert");
+ name = X509_get_issuer_name(cert);
+ check_ssl_error("creating ephemeral public key cert");
+ X509_set_issuer_name(sign_cert, name);
+ check_ssl_error("creating ephemeral public key cert");
+
+ /* Sign ephemeral public key */
+ X509_sign(sign_cert, priv, EVP_sha256());
+ check_ssl_error("signing ephemeral public key");
+ } else {
+ sign_priv = priv;
+ sign_cert = cert;
+ }
+}
+
+static void
+write_ephemeral(void)
+{
+ if (ephemeral) {
+ FILE *f;
+
+ VPRINTF("Writing ephemeral key to %s\n", ephemeralpath);
+
+ f = fopen(ephemeralpath, "w");
+ check_file_error(f, "Error writing ephemeral key");
+ PEM_write_X509(f, sign_cert);
+ check_ssl_error("writing out ephemeral key");
+ fclose(f);
+
+ }
+}
+
+static CMS_ContentInfo *
+make_sig(void *buf, size_t len)
+{
+ BIO *bio;
+ CMS_ContentInfo *cms;
+
+ bio = BIO_new_mem_buf(buf, len);
+ cms = CMS_sign(sign_cert, sign_priv, NULL, bio,
+ CMS_DETACHED | CMS_BINARY | CMS_NOCERTS |
+ CMS_NOSMIMECAP | CMS_NOATTR);
+
+ return cms;
+}
+
+static void
+compute_sigsize(void)
+{
+ char buf[0];
+ int len;
+ CMS_ContentInfo *cms = make_sig(buf, sizeof(buf));
+
+ len = i2d_CMS_ContentInfo(cms, NULL);
+ check_ssl_error("computing signature size");
+ sigsize = len;
+ CMS_ContentInfo_free(cms);
+}
+
+static int parse_args(const int argc, char* argv[])
+{
+ int ch;
+ int i;
+
+ while ((ch = getopt(argc, argv, "e:k:p:v")) != -1) {
+ switch (ch) {
+ default:
+ usage();
+
+ return (1);
+ case 'e':
+ ephemeral = true;
+ set_ephemeralpath(optarg);
+ break;
+ case 'k':
+ set_keypath(optarg);
+ break;
+ case 'p':
+ set_pubpath(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case '?':
+ usage();
+ break;
+ }
+ }
+
+ for(i = optind; i < argc; i++) {
+ add_signpath(argv[i]);
+ }
+
+ return (0);
+}
+
+static bool
+prefer_type(GElf_Word old, GElf_Word new)
+{
+ /* Always prefer anything to NULL, and prefer a NOTE section
+ * over anything.
+ */
+ if (new == SHT_NULL || old == SHT_NOTE) {
+ return (false);
+ }
+ if (old == SHT_NULL || new == SHT_NOTE) {
+ return (true);
+ }
+
+ /* Next, prefer static information over anything else. */
+ if (new == SHT_SYMTAB || new == SHT_STRTAB) {
+ return (true);
+ }
+ if (old == SHT_SYMTAB || old == SHT_STRTAB) {
+ return (false);
+ }
+
+ /* Default: prefer newer over older */
+ return (true);
+}
+
+/* Figure out if the given section and everything after can be resized. */
+static void
+find_first_resizable(Elf *elf)
+{
+ Elf_Scn *curr;
+ GElf_Ehdr ehdr;
+ size_t phnum;
+ size_t curridx;
+
+ gelf_getehdr(elf, &ehdr);
+ check_elf_error();
+ phnum = ehdr.e_phnum;
+
+ /* Check the section and all sections that follow it. */
+ for (curridx = ehdr.e_shnum - 1; curridx > 0; curridx--) {
+ GElf_Shdr shdr;
+ size_t idx;
+ size_t sbegin;
+ size_t send;
+
+ curr = elf_getscn(elf, curridx);
+ check_elf_error();
+ gelf_getshdr(curr, &shdr);
+ check_elf_error();
+ sbegin = shdr.sh_offset;
+ send = sbegin + shdr.sh_size;
+
+ /* Check if the current section's file offsets are
+ * used in the program header at all. If they are,
+ * then we can't move them.
+ */
+ for (idx = 0; idx < phnum; idx++) {
+ GElf_Phdr phdr;
+ size_t pbegin;
+ size_t pend;
+
+ gelf_getphdr(elf, idx, &phdr);
+ check_elf_error();
+ pbegin = phdr.p_offset;
+ pend = pbegin + phdr.p_filesz;
+
+
+ if ((pbegin <= sbegin && sbegin < pend) ||
+ (pbegin <= send && send <= pend) ||
+ (sbegin <= pbegin && pbegin < send) ||
+ (sbegin <= pend && pend <= send)) {
+ first_resizable = curridx + 1;
+ return;
+ }
+ }
+ }
+
+ first_resizable = 0;
+}
+
+static bool
+section_resizable(Elf_Scn *scn)
+{
+ size_t idx;
+
+ idx = elf_ndxscn(scn);
+ check_elf_error();
+
+ return (idx >= first_resizable);
+}
+
+static size_t
+align(size_t offset, size_t align)
+{
+ if (offset == 0) {
+ return (0);
+ } else {
+ size_t mask = align - 1;
+
+ return (((offset - 1) & ~mask) + align);
+ }
+}
+
+static void
+fix_offsets(Elf *elf)
+{
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ Elf_Scn *curr;
+ size_t offset;
+ size_t shdr_start;
+ size_t shdr_size;
+ size_t shdr_end;
+ size_t aligned;
+ size_t idx;
+
+ gelf_getehdr(elf, &ehdr);
+ check_elf_error();
+ shdr_start = ehdr.e_shoff;
+ shdr_size = ehdr.e_shnum * ehdr.e_shentsize;
+ idx = first_resizable;
+
+ /* This can happen if the very last section is not resizable,
+ * in which case we can't do anything at all here.
+ */
+ if (idx >= ehdr.e_shnum) {
+ return;
+ }
+
+ curr = elf_getscn(elf, idx);
+ check_elf_error();
+ shdr_end = shdr_start + shdr_size;
+ gelf_getshdr(curr, &shdr);
+ check_elf_error();
+ offset = shdr.sh_offset;
+
+ /* Fix up the offsets of the section and all sections that follow it */
+ while (curr != NULL) {
+ /* Grab all the data elements, so that they get
+ * written back to the file when we update.
+ * Otherwise, they'll get corrupted.
+ */
+ Elf_Data *data;
+
+ for(data = elf_getdata(curr, NULL); data != NULL;
+ data = elf_getdata(curr, data));
+
+ /* The section header might be between two offsets */
+ if ((offset <= shdr_start && shdr_start <= shdr.sh_offset) ||
+ (offset <= shdr_end && shdr_end <= shdr.sh_offset) ||
+ (shdr_start <= offset && offset <= shdr_end) ||
+ (shdr_start <= shdr.sh_offset &&
+ shdr.sh_offset <= shdr_end)) {
+ aligned = align(offset, 8);
+ ehdr.e_shoff = aligned;
+ gelf_update_ehdr(elf, &ehdr);
+ check_elf_error();
+ offset = ehdr.e_shoff + shdr_size;
+ }
+
+ aligned = align(offset, shdr.sh_addralign);
+ shdr.sh_offset = aligned;
+
+ offset = shdr.sh_offset + shdr.sh_size;
+ gelf_update_shdr(curr, &shdr);
+ check_elf_error();
+ curr = elf_nextscn(elf, curr);
+ check_elf_error();
+
+ if (curr != NULL) {
+ gelf_getshdr(curr, &shdr);
+ check_elf_error();
+ }
+ }
+
+ /* The section header might have been at the very end */
+ if ((shdr_start <= offset && offset <= shdr_end)) {
+ aligned = align(offset, 8);
+ ehdr.e_shoff = aligned;
+ gelf_update_ehdr(elf, &ehdr);
+ check_elf_error();
+ offset += shdr_size;
+ }
+}
+
+static size_t
+strtab_insert_sign(Elf_Scn *scn)
+{
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ char *strtab;
+ size_t idx;
+
+ data = elf_getdata(scn, NULL);
+ check_elf_error();
+ strtab = data->d_buf;
+ idx = data->d_size;
+ data->d_buf = realloc(data->d_buf, data->d_size + sizeof (SIGN_NAME));
+ check_malloc_error(data->d_buf);
+ strncpy((char *)data->d_buf + data->d_size, SIGN_NAME,
+ sizeof (SIGN_NAME));
+ data->d_size += sizeof (SIGN_NAME);
+
+ /* Update the section header */
+ gelf_getshdr(scn, &shdr);
+ check_elf_error();
+ shdr.sh_size += sizeof (SIGN_NAME);
+ gelf_update_shdr(scn, &shdr);
+ check_elf_error();
+
+ return (idx);
+}
+
+static size_t
+strtab_find_sign(Elf_Scn *scn)
+{
+ Elf_Data *data;
+ char *strtab;
+ size_t offset;
+ char *str;
+
+ data = elf_getdata(scn, NULL);
+ check_elf_error();
+ strtab = data->d_buf;
+
+ /* ELF conventions: offset 0 is the empty string, so we start at 1 */
+ for(offset = 1; offset < data->d_size;
+ offset += strlen(strtab + offset) + 1) {
+ str = strstr(strtab + offset, SIGN_NAME);
+
+ if (str != NULL) {
+ return (str - strtab);
+ }
+ }
+
+ return (0);
+}
+
+/* Try to find ".sign" in the strtab, or insert it if it's not there. */
+static size_t
+get_sign_idx(Elf_Scn *strtab)
+{
+ size_t idx;
+
+ if ((idx = strtab_find_sign(strtab)) == 0) {
+ /* If we can't resize the strtab, give up */
+ if (!section_resizable(strtab)) {
+ fprintf(stderr, "Cannot resize strtab");
+ exit(1);
+ }
+
+ /* Insert ".sign" into the strtab and fixup all the
+ * subsequent offsets.
+ */
+ idx = strtab_insert_sign(strtab);
+ }
+
+ return (idx);
+}
+
+/* Set the section name. To do this, we need to figure out what
+ * strtab to use.
+ */
+static void
+set_sign_name(Elf *elf, Elf_Scn *newscn)
+{
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
+ Elf_Scn *curr = NULL;
+ GElf_Word type = SHT_NULL;
+ size_t sym, idx = 0;
+ Elf_Scn *strtab;
+
+ /* First, figure out which strtab section to use. */
+ gelf_getehdr(elf, &ehdr);
+ check_elf_error();
+
+ if (ehdr.e_shstrndx == SHN_UNDEF) {
+ /* This shouldn't happen, but check for it anyway. */
+ fprintf(stderr, "File contains no section header names\n");
+ exit(1);
+ } else if (ehdr.e_shstrndx != SHN_XINDEX) {
+ /* We're not using extended section numbering */
+ idx = ehdr.e_shstrndx;
+ } else {
+ /* Scan through the sections, looking for the best
+ * strtab to use.
+ */
+ for(curr = elf_nextscn(elf, curr); curr != NULL;
+ curr = elf_nextscn(elf, curr)) {
+ GElf_Shdr currshdr;
+
+ check_elf_error();
+ gelf_getshdr(curr, &currshdr);
+ check_elf_error();
+
+ /* If this section has a better type, update the
+ * preferred index
+ */
+ if(prefer_type(currshdr.sh_type, type)) {
+ type = currshdr.sh_type;
+ idx = currshdr.sh_link;
+ }
+ }
+
+ /* Set the link */
+ gelf_getshdr(newscn, &shdr);
+ check_elf_error();
+ shdr.sh_link = idx;
+ gelf_update_shdr(newscn, &shdr);
+ check_elf_error();
+ }
+
+
+ /* Now find or create the index of the ".sign" string. */
+ strtab = elf_getscn(elf, idx);
+ check_elf_error();
+ sym = get_sign_idx(strtab);
+
+ /* Set the name */
+ gelf_getshdr(newscn, &shdr);
+ check_elf_error();
+ shdr.sh_name = sym;
+ gelf_update_shdr(newscn, &shdr);
+ check_elf_error();
+}
+
+static void
+sign_elf(Elf *elf)
+{
+ size_t idx;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ unsigned char *buf;
+ size_t filesize;
+ void *filedata;
+ CMS_ContentInfo *cms;
+ size_t siglen;
+
+ find_first_resizable(elf);
+ idx = find_sig(elf);
+ elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT);
+
+ if (idx != 0) {
+ /* Resize the section and fixup offsets */
+ GElf_Shdr shdr;
+
+ scn = elf_getscn(elf, idx);
+ check_elf_error();
+ data = elf_getdata(scn, NULL);
+ check_elf_error();
+
+ if (data->d_size != sigsize) {
+ if (!section_resizable(scn)) {
+ fprintf(stderr,
+ "Cannot resize signature section\n");
+ exit(1);
+ }
+
+ /* Set the section size and fix up all the
+ * following sections
+ */
+ gelf_getshdr(scn, &shdr);
+ check_elf_error();
+ shdr.sh_size = sigsize;
+ gelf_update_shdr(scn, &shdr);
+ check_elf_error();
+ fix_offsets(elf);
+
+ data->d_size = sigsize;
+ data->d_buf = realloc(data->d_buf, sigsize);
+ check_malloc_error(data->d_buf);
+ }
+ } else {
+ /* Create the .sign section */
+ GElf_Shdr shdr;
+ GElf_Ehdr ehdr;
+
+ /* Create a new section */
+ scn = elf_newscn(elf);
+ idx = elf_ndxscn(scn);
+ check_elf_error();
+ gelf_getehdr(elf, &ehdr);
+ check_elf_error();
+ ehdr.e_shnum += 1;
+ gelf_update_ehdr(elf, &ehdr);
+ check_elf_error();
+
+ /* Set up the data */
+ data = elf_newdata(scn);
+ check_elf_error();
+ data->d_align = 1;
+ data->d_off = 0;
+ data->d_size = sigsize;
+ data->d_buf = malloc(sigsize);
+ check_malloc_error(data->d_buf);
+
+ /* Set the section name and type */
+ gelf_getshdr(scn, &shdr);
+ check_elf_error();
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_size = sigsize;
+ shdr.sh_addralign = 1;
+ gelf_update_shdr(scn, &shdr);
+ check_elf_error();
+
+ set_sign_name(elf, scn);
+ fix_offsets(elf);
+ }
+
+ /* Set the signature section to all zeros */
+ memset(data->d_buf, 0, sigsize);
+ data->d_size = sigsize;
+
+ /* Update the file and get a pointer to the raw data */
+ elf_update(elf, ELF_C_WRITE);
+ check_elf_error();
+ filedata = elf_rawfile(elf, &filesize);
+ check_elf_error();
+
+ /* The section and data pointers aren't good after elf_update,
+ * so refresh them.
+ */
+ elf_nextscn(elf, NULL);
+ scn = elf_getscn(elf, idx);
+ check_elf_error();
+ data = elf_getdata(scn, NULL);
+ check_elf_error();
+
+ /* Actually compute the signature */
+ cms = make_sig(filedata, filesize);
+
+ siglen = i2d_CMS_ContentInfo(cms, NULL);
+
+ if(siglen != sigsize) {
+ fprintf(stderr, "Signature size %zu is not expected %zu\n",
+ siglen, sigsize);
+ abort();
+ }
+
+ /* Write back all the data. */
+ buf = data->d_buf;
+ siglen = i2d_CMS_ContentInfo(cms, &buf);
+ elf_update(elf, ELF_C_WRITE);
+}
+
+int
+sign_main(int argc, char *argv[])
+{
+ int err;
+ unsigned int i;
+
+ set_keypath(DEFAULT_KEYPATH);
+ signpaths = malloc(max_signpaths * sizeof(signpaths[0]));
+ err = parse_args(argc, argv);
+
+ VPRINTF("Loading key from %s and cert from %s, signing",
+ keypath, pubpath);
+
+ for(i = 0; i < nsignpaths; i++) {
+ VPRINTF(" %s", signpaths[i]);
+ }
+
+ VPRINTF(" %s\n", ephemeral ? "with ephemeral key" : "directly\n");
+
+ load_keys();
+ write_ephemeral();
+ compute_sigsize();
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ fprintf(stderr, "ELF library cannot handle version %u\n",
+ EV_CURRENT);
+ }
+
+ for(i = 0; i < nsignpaths; i++) {
+ int fd;
+ Elf *elf;
+
+ VPRINTF("Signing %s\n", signpaths[i]);
+ fd = open(signpaths[i], O_RDWR);
+ check_fd_error(fd);
+ elf = elf_begin(fd, ELF_C_RDWR, NULL);
+ check_elf_error();
+ sign_elf(elf);
+ elf_end(elf);
+ }
+
+ return (err);
+}
Index: usr.sbin/signelf/signelf.h
===================================================================
--- /dev/null
+++ usr.sbin/signelf/signelf.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2018 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef _SIGNELF_H_
+#define _SIGNELF_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+
+#include <libelf.h>
+
+#define DEFAULT_TRUSTDIR "/etc/trust/root"
+#define DEFAULT_PRIVDIR DEFAULT_TRUSTDIR "priv/"
+#define DEFAULT_CERTDIR DEFAULT_TRUSTDIR "certs/"
+#define DEFAULT_KEYPATH DEFAULT_PRIVDIR "local.pem"
+#define DEFAULT_PUBKEYPATH DEFAULT_CERTDIR "local.pub.pem"
+
+#define SIGN_NAME ".sign"
+
+extern void usage(void);
+
+extern void check_elf_error(void);
+extern void check_fd_error(int fd);
+extern void check_file_error(const FILE *ptr, const char* str);
+extern void check_malloc_error(const void *ptr);
+extern void check_ssl_error(const char *op);
+
+extern size_t find_sig(Elf *elf);
+
+extern int sign_main(int argc, char *argv[]);
+extern int verify_main(int argc, char *argv[]);
+extern int unsign_main(int argc, char *argv[]);
+#endif
Index: usr.sbin/signelf/signelf.8
===================================================================
--- /dev/null
+++ usr.sbin/signelf/signelf.8
@@ -0,0 +1,267 @@
+.\" Copyright (c) 2017 Eric McCorkle
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 24, 2017
+.Dt SIGNELF 8
+.Os
+.Sh NAME
+.Nm signelf
+.Nd "sign or verify ELF binaries"
+.Sh SYNOPSIS
+.Nm
+.Cm sign
+.Op Fl e Ar ephemeral cert
+.Op Fl k Ar private key
+.Op Fl p Ar public key cert
+.Op Fl v
+.Ar files
+.Nm
+.Cm verify
+.Op Fl p Ar public key cert
+.Ar files
+.Sh DESCRIPTION
+The
+.Nm
+utility signs binary executables and libraries in the Executable
+Linkable Format (ELF) and verifies signatures on signed binaries.
+Signed ELF binaries carry an additional section containing a
+cryptograpic signature, which can be used to verify the contents of
+the executable. For details on the format of signed ELF binaries, see the
+.Xr signed-elf 5
+man page.
+.Ss Ephemeral Keys
+The
+.Nm
+utility can generate an ephemeral key-pair for signing a batch of ELF
+binaries. After signing is complete, the ephemeral private key will
+be discarded (at which point it will be impossible to sign any more
+binaries with so that the ephemeral public key can verify them), while
+the public key will be written out as a PEM-encoded X509 certificate
+and signed with the user-supplied key-pair.
+.Sh SUBCOMMANDS
+The
+.Nm
+utility provides two subcommands. The following is a description of
+their functioning:
+.Pp
+.Bl -tag -width 2n
+.It Xo
+.Nm
+.Cm sign
+.Op Fl e Ar ecert
+.Op Fl k Ar pkey
+.Op Fl p Ar pcert
+.Op Fl v
+.Ar files
+.Xc
+.Pp
+Sign each ELF binary in
+.Ar files .
+Any existing signatures in
+.Ar files
+will be overwritten.
+.Bl -tag -width indent
+.It Fl e
+Generate an ephemeral key-pair which will be used to sign the
+.Ar files .
+Once signing is complete, the ephemeral private key will be destroyed,
+while the public key will be output as a PEM-encoded X509 certificate
+to
+.Ar ecert
+and will be signed with the user-supplied key-pair.
+.It Fl k
+Use the private key in
+.Ar pkey
+(which must be a PEM-encoded private key or PKCS#8 store) as the
+private key for signing binaries or the ephemeral key. If this option
+is not provided, the default private key
+.Pa /etc/trust/root/priv/local.pem
+will be used.
+.It Fl p
+Use the PEM-encoded X509 certificate
+.Ar pcert
+as the public key for signing binaries or the ephemeral key. If this
+option is not provided, the default public key
+.Pa /etc/trust/root/certs/local.pub.pem
+will be used.
+.It Fl v
+Generate verbose output.
+.El
+.It Xo
+.Nm
+.Cm verify
+.Op Fl p Ar pcert
+.Ar files
+.Xc
+.Pp
+Verify signatures on each ELF binary in
+.Ar files .
+(Note that by default, no output is generated if verification succeeds.)
+.Bl -tag -width indent
+.It Fl p
+Use the PEM-encoded X509 certificate in
+.Ar pcert
+as the public key for verifying the binaries. If this option is not
+provided, the default public key
+.Pa /etc/trust/priv/local.pem
+will be used.
+.It Fl v
+Generate verbose output.
+.El
+.El
+.Sh FILES
+The default location for signing keys and certificates is
+.Pa /etc/trust
+with private keys being stored in
+.Pa /etc/trust/priv
+and corresponding public key certificates in
+.Pa /etc/trust/certs
+(this allows differing permissions on the two directories), and with
+trust root keys and certificates being stored in a similar fashion
+in
+.Pa /etc/trust/root/priv
+and
+.Pa /etc/trust/root/certs.
+The default private and public keys are located at
+.Pa /etc/trust/priv/local.pem
+and
+.Pa /etc/trust/certs/local.pub.pem
+respectively. See the
+.Xr trust-config 5
+man page for more details.
+.Sh WARNINGS
+The
+.Nm
+utility relies on the predictable behaviors of
+.Xr binutils 7 ,
+.Xr ld 1 ,
+and other system utilities used to produce ELF files in the normal
+course of compiling and linking programs. The
+.Nm
+utility should operate reliably on executables and shared objects
+produced in such a fashion. However, the ELF format is quite
+general, and
+.Nm
+cannot account for all possible uses of the format. It is
+not recommended to attempt to use
+.Nm
+on any ELF file not produced by the standard means of compiling and
+linking programs.
+.Pp
+Also, once an ELF binary has been signed,
+.Sy any
+modification of the file- however slight -will cause signature
+verification to fail (as intended). Furthermore, due to the nature of
+the ELF format, signatures will likely be retained if a signed binary
+is used as input to a tool such as
+.Xr objcopy 1
+or similar utilities, which will result in an ELF binary containing a
+bad signature.
+.Pp
+It is therefore recommended to only use
+.Nm
+on executables and shared objects after at the end of all compilation steps.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The following are examples of typical usage of the
+.Nm
+utility:
+.Ss Signing
+.Dl "$ signelf sign myexe"
+.Pp
+Sign the executable
+.Ar myexe
+directly using the default key and cert (located at
+.Pa /etc/trust/priv/local.pem
+and
+.Pa /etc/trust/certs/local.pub.pem
+respectively).
+.Pp
+.Dl "$ signelf sign -e ephemeral myexe"
+.Pp
+Generate an ephemeral signing key and sign the executable
+.Ar myexe
+using it. The ephemeral key will be signed using the default key and
+cert (located at
+.Pa /etc/trust/priv/local.pem
+and
+.Pa /etc/trust/certs/local.pub.pem
+respectively) and saved as
+.Pa ephemeral
+in PEM format. Note that the private key is
+.Sy not
+retained, meaning the
+certificate is only good for verifying signatures.
+.Ss Verification
+.Dl "$ signelf verify myexe"
+.Pp
+Verify the signature in the executable
+.Ar myexe
+using the default cert (located at
+.Pa /etc/trust/certs/local.pub.pem
+).
+.Pp
+.Dl "$ signelf verify -p cert.pem myexe"
+.Pp
+Verify the signature in the executable
+.Ar myexe
+using the certificate located at
+.Pa cert.pem
+(this can be used to verify signatures using an ephemeral key's
+certificate).
+.Ss Removing Signatures
+Lastly, signatures can be deleted from a file using the
+.Xr objcopy 3
+utility:
+.Pp
+.Dl "$ objcopy -R .sign myexe"
+.Ss Using Binutils and OpenSSL
+The basic functioning of
+.Nm
+can be replicated using the
+.Xr openssl 1
+and
+.Xr objcopy 1
+utilities. See the
+.Qq UTILITIES
+section of the
+.Xr signed-elf 5
+man page for details.
+.Sh SEE ALSO
+.Xr elf 5 ,
+.Xr signed-elf 5 ,
+.Xr trust-config 5
+.Xr openssl 1 ,
+.Xr cms 1
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 12.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Eric L. McCorkle Aq Mt emc2@metricspace.net .
Index: usr.sbin/signelf/signelf.c
===================================================================
--- /dev/null
+++ usr.sbin/signelf/signelf.c
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2018 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "signelf.h"
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+
+static const char* cmd;
+
+static const char * const usage_detail =
+ " Commands:\n"
+ "\n"
+ " sign: add signatures to one or more executables or shared objects\n"
+ "\n"
+ " Options:\n"
+ "\n"
+ " -e <path> Sign with ephemeral keys, save public key to file\n"
+ " -k <path> Path to private (signing) key\n"
+ " -p <path> Path to public (verification) key certificate\n"
+ " -v Verbose mode\n"
+ "\n"
+ " verify: check signatures on one or more executables or shared objects\n"
+ "\n"
+ " Options:\n"
+ "\n"
+ " -p <path> Path to public (verification) key certificate\n"
+ " -v Verbose mode\n"
+ "\n";
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s <command> [option]* [filename]+\n\n%s\n",
+ cmd, usage_detail);
+}
+
+int
+main(const int argc, char* argv[])
+{
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+
+ cmd = argv[0];
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "sign")) {
+ return (sign_main(argc - 1, argv + 1));
+ } else if (!strcmp(argv[1], "verify")) {
+ return (verify_main(argc - 1, argv + 1));
+ } else {
+ fprintf(stderr, "Invalid command %s\n", argv[1]);
+ }
+ } else {
+ fprintf(stderr, "Need a command\n");
+ }
+
+ usage();
+
+ return (1);
+}
Index: usr.sbin/signelf/util.c
===================================================================
--- /dev/null
+++ usr.sbin/signelf/util.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2018 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libelf.h>
+#include <gelf.h>
+
+#include "signelf.h"
+
+#include <openssl/err.h>
+
+void
+check_elf_error(void)
+{
+ int err;
+
+ if ((err = elf_errno()) != 0) {
+ fprintf(stderr, "Error handling ELF file: %s\n",
+ elf_errmsg(err));
+ exit(errno);
+ }
+}
+
+void
+check_fd_error(int fd) {
+ if (fd < 0) {
+ perror("Error opening file");
+ exit(errno);
+ }
+}
+
+void
+check_file_error(const FILE *ptr, const char* str) {
+ if (ptr == NULL) {
+ perror(str);
+ exit(errno);
+ }
+}
+
+void
+check_malloc_error(const void *ptr) {
+ if (ptr == NULL) {
+ perror("Could not allocate memory");
+ abort();
+ }
+}
+
+void
+check_ssl_error(const char *op) {
+ unsigned long err = ERR_get_error();
+
+ if (err != 0) {
+ fprintf(stderr, "Error in %s (%s) while %s: %s\n",
+ ERR_lib_error_string(err), ERR_func_error_string(err), op,
+ ERR_reason_error_string(err));
+ exit(err);
+ }
+}
+
+size_t
+find_sig(Elf *elf)
+{
+ Elf_Scn *curr = NULL;
+ GElf_Ehdr ehdr;
+ bool link_strtab = false;
+ size_t strtabidx;
+ size_t out = 0;
+
+ /* Try to get the strtab index */
+ gelf_getehdr(elf, &ehdr);
+ check_elf_error();
+
+ /* See elf(5) man page for meaning of this. */
+ if (ehdr.e_shstrndx == SHN_UNDEF) {
+ fprintf(stderr, "File contains no section header names\n");
+ exit(1);
+ } else if (ehdr.e_shstrndx == SHN_XINDEX) {
+ link_strtab = true;
+ } else {
+ strtabidx = ehdr.e_shstrndx;
+ }
+
+ for(curr = elf_nextscn(elf, curr); curr != NULL;
+ curr = elf_nextscn(elf, curr)) {
+ GElf_Shdr shdr;
+ char *str;
+
+ check_elf_error();
+ gelf_getshdr(curr, &shdr);
+ check_elf_error();
+
+ /* See elf(5) man page for meaning of this. */
+ if (link_strtab) {
+ strtabidx = shdr.sh_link;
+ }
+
+ str = elf_strptr(elf, strtabidx, shdr.sh_name);
+ check_elf_error();
+
+ if(!strcmp(str, ".sign")) {
+ break;
+ }
+ }
+
+ if (curr != NULL) {
+ out = elf_ndxscn(curr);
+ check_elf_error();
+ }
+
+ return (out);
+}
Index: usr.sbin/signelf/verify.c
===================================================================
--- /dev/null
+++ usr.sbin/signelf/verify.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 2018 Eric McCorkle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/cms.h>
+#include <openssl/x509.h>
+
+#include "signelf.h"
+
+#define VPRINTF(...) (verbose ? fprintf(stderr, __VA_ARGS__) : 0)
+
+static char pubpath[MAXPATHLEN + 1];
+static char **signpaths;
+static size_t nsignpaths = 0;
+static size_t max_signpaths = 16;
+static bool verbose = false;
+static STACK_OF(X509) *verifycerts;
+
+static void check_malloc(const void *ptr) {
+ if (ptr == NULL) {
+ perror("Could not allocate memory");
+ abort();
+ }
+}
+
+static void add_signpath(char *signpath)
+{
+ if (max_signpaths <= nsignpaths) {
+ void *tmp;
+
+ max_signpaths *= 2;
+ tmp = realloc(signpaths, max_signpaths * sizeof(signpaths[0]));
+ check_malloc(tmp);
+ signpaths = tmp;
+ }
+
+ signpaths[nsignpaths] = strdup(signpath);
+ nsignpaths++;
+}
+
+static void
+load_cert(void)
+{
+ FILE *f;
+ X509 *cert;
+
+ /* Load the public key */
+ f = fopen(pubpath, "r");
+ check_file_error(f, "Error opening public key");
+ cert = PEM_read_X509(f, NULL, NULL, NULL);
+ check_ssl_error("loading public key");
+ fclose(f);
+
+ verifycerts = sk_X509_new_null();
+ check_ssl_error("setting up public key");
+ sk_X509_push(verifycerts, cert);
+ check_ssl_error("setting up public key");
+}
+
+static void set_pubpath(const char *path)
+{
+ strncpy(pubpath, path, MAXPATHLEN);
+}
+
+static int parse_args(const int argc, char* argv[])
+{
+ int ch;
+ int i;
+
+ while ((ch = getopt(argc, argv, "p:v")) != -1) {
+ switch (ch) {
+ default:
+ usage();
+
+ return (1);
+ case 'p':
+ set_pubpath(optarg);
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case '?':
+ usage();
+ break;
+ }
+ }
+
+ if (!strcmp(pubpath, "")) {
+ set_pubpath(DEFAULT_PUBKEYPATH);
+ }
+
+ for(i = optind; i < argc; i++) {
+ add_signpath(argv[i]);
+ }
+
+ return (0);
+}
+
+static bool
+verify_elf(Elf *elf, const char path[])
+{
+ size_t idx;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ CMS_ContentInfo *cms;
+ const unsigned char *buf;
+ void *ptr;
+ size_t filesize;
+ int out;
+ unsigned long err;
+ BIO *bio;
+
+ /* Find the signature section */
+ idx = find_sig(elf);
+
+ if (idx == 0) {
+ fprintf(stderr, "No signature in %s\n", path);
+ return (false);
+ }
+
+ scn = elf_getscn(elf, idx);
+ check_elf_error();
+ data = elf_rawdata(scn, NULL);
+ check_elf_error();
+
+ /* Load the signature */
+ buf = data->d_buf;
+
+ cms = NULL;
+ d2i_CMS_ContentInfo(&cms, &buf, data->d_size);
+ check_ssl_error("parsing signature");
+
+ /* Prepare the file data for verification */
+ memset(data->d_buf, 0, data->d_size);
+ ptr = elf_rawfile(elf, &filesize);
+ bio = BIO_new_mem_buf(ptr, filesize);
+ check_ssl_error("preparing data");
+
+ /* Perform verification */
+ out = CMS_verify(cms, verifycerts, NULL, bio, NULL, CMS_NOINTERN);
+ err = ERR_get_error();
+
+ if (err != 0) {
+ fprintf(stderr, "Signature verification for %s failed: %s\n",
+ path, ERR_reason_error_string(err));
+ exit(err);
+ } else if (out) {
+ VPRINTF("Verification successful for %s\n", path);
+ } else {
+ fprintf(stderr, "Verification failed for %s\n", path);
+ }
+
+ return (out);
+}
+
+int
+verify_main(int argc, char *argv[])
+{
+ int err;
+ unsigned int i;
+ bool ok = true;
+
+ signpaths = malloc(max_signpaths * sizeof(signpaths[0]));
+ err = parse_args(argc, argv);
+
+ VPRINTF("Loading verification key from %s, verifying", pubpath);
+
+ for(i = 0; i < nsignpaths; i++) {
+ VPRINTF(" %s", signpaths[i]);
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ fprintf(stderr, "ELF library cannot handle version %u\n",
+ EV_CURRENT);
+ }
+
+ load_cert();
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ fprintf(stderr, "ELF library cannot handle version %u\n",
+ EV_CURRENT);
+ }
+
+ for(i = 0; i < nsignpaths; i++) {
+ int fd;
+ Elf *elf;
+ void *ptr;
+ struct stat st;
+
+ VPRINTF("Signing %s\n", signpaths[i]);
+ fd = open(signpaths[i], O_RDONLY);
+ check_fd_error(fd);
+
+ if (fstat(fd, &st) != 0) {
+ perror("Error getting file size");
+ exit(errno);
+ }
+
+ ptr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+
+ if (ptr == MAP_FAILED) {
+ perror("Error mapping file contents");
+ exit(errno);
+ }
+
+ elf = elf_memory(ptr, st.st_size);
+ check_elf_error();
+ ok &= verify_elf(elf, signpaths[i]);
+ elf_end(elf);
+ }
+
+ return (ok ? 0 : 1);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Feb 10, 4:10 AM (2 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28612967
Default Alt Text
D16563.diff (73 KB)
Attached To
Mode
D16563: Add signelf utility
Attached
Detach File
Event Timeline
Log In to Comment