Page MenuHomeFreeBSD

D16563.diff
No OneTemporary

D16563.diff

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(&timestamp, 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

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)

Event Timeline