Index: usr.sbin/Makefile =================================================================== --- usr.sbin/Makefile +++ usr.sbin/Makefile @@ -194,6 +194,7 @@ SUBDIR.${MK_QUOTAS}+= edquota SUBDIR.${MK_QUOTAS}+= quotaon SUBDIR.${MK_QUOTAS}+= repquota +SUBDIR.${MK_SECUREBOOT}+= binsign SUBDIR.${MK_SENDMAIL}+= editmap SUBDIR.${MK_SENDMAIL}+= mailstats SUBDIR.${MK_SENDMAIL}+= makemap Index: usr.sbin/binsign/Makefile =================================================================== --- /dev/null +++ usr.sbin/binsign/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +PROG= binsign +SRCS= binsign.c +MAN= binsign.8 + +LIBADD= secureboot bearssl + +WARNS= 6 + +.include Index: usr.sbin/binsign/binsign.8 =================================================================== --- /dev/null +++ usr.sbin/binsign/binsign.8 @@ -0,0 +1,68 @@ +.\" +.\" Copyright (c) 2019 Stormshield. +.\" Copyright (c) 2019 Semihalf. +.\" 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 ``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 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. +.\" +.Dd January 2 2018 +.Dt BINSIGN 8 +.Os +.Sh NAME +.Nm binsign +.Nd Secure Boot signing utility +.Sh SYNOPSIS +.Nm +.Fl c Ar cert +.Fl k Ar key +.Ar file +.Sh DESCRIPTION +The +.Nm +utility signs any type of file by appending a signature in PKCS#1 v2 standard +together with a certificate used for the signing to its end. +Loader can be configured to verify the kernel and modules integrity +signed with this tool. +.Sh EXIT STATUS +The +.Nm +utility exits 0 on success, and 1 if an error occurs. +.Sh EXAMPLES +.Nm +-c cert.der -k cert.key file +.Pp +The cert.key and cert.der files have to contain a DER encoded +RSA private key and X509 certificate respectively. +.Pp +.Sh SEE ALSO +.Xr loader 8 +.Sh HISTORY +The +.Nm +command appeared in +.Fx 13.0 . +.Sh AUTHORS +The +.Nm +utility was developed by +.An Kornel Duleba Aq Mt mindal@semihalf.com +under sponsorship from Stormshield. Index: usr.sbin/binsign/binsign.c =================================================================== --- /dev/null +++ usr.sbin/binsign/binsign.c @@ -0,0 +1,218 @@ +/*- + * Copyright (c) 2019 Stormshield. + * Copyright (c) 2019 Semihalf. + * 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 ``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 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 +#include + +#include + +#include + +#define CERT_BUF_LEN 4096 + +static void usage() { + printf("binsign -c cert -k key file\n"); + exit(1); +} + +static bool +sign(char* cert, size_t cert_size, char* key, size_t key_size, + FILE *fp, unsigned char **output, size_t *output_size) +{ + struct stat sb; + struct signature_info sig_info; + unsigned char *buf = NULL; + int result; + unsigned char digest[br_sha256_SIZE]; + br_skey_decoder_context ctx; + const br_rsa_private_key *priv; + unsigned int signature_length; + + memset(&sb, 0, sizeof(sb)); + memset(&sig_info, 0, sizeof(sig_info)); + + result = fstat(fileno(fp), &sb); + if (result != 0) { + printf("Fstat failed\n"); + goto fail; + } + + br_skey_decoder_init(&ctx); + br_skey_decoder_push(&ctx, key, key_size); + priv = br_skey_decoder_get_rsa(&ctx); + if (priv == NULL) { + printf("Decoder failed\n"); + goto fail; + } + + signature_length = (priv->n_bitlen + 7) >> 3; + + buf = calloc(1, signature_length + cert_size + sizeof(sig_info)); + if (output == NULL) { + printf("Failed to allocate memory\n"); + goto fail; + } + + result = gen_digest(fileno(fp), sb.st_size, digest); + if (result != 0) { + printf("Failed to generate digest\n"); + goto fail; + } + + result = br_rsa_pkcs1_sign_get_default()( + BR_HASH_OID_SHA256, digest, br_sha256_SIZE, + priv, buf); + if (!result) { + printf("Failed to sign the digest\n"); + goto fail; + } + + memcpy((buf + signature_length), cert, cert_size); + + sig_info.magic = MAGIC; + sig_info.kernel_size = sb.st_size; + sig_info.signature_size = signature_length; + sig_info.cert_size = cert_size; + memcpy((buf + signature_length + cert_size), &sig_info, sizeof(sig_info)); + + *output_size = signature_length + cert_size + sizeof(sig_info); + *output = buf; + + return true; + +fail: + if (buf != NULL) + free(buf); + return false; +} + +int +main(int argc, char **argv) +{ + int ch; + const char *cert_path, *key_path, *input_path; + FILE *fp; + int result; + struct stat sb; + char *cert; + size_t cert_size; + char *priv; + size_t priv_size; + unsigned char *output; + size_t length; + + cert_path = NULL; + key_path = NULL; + + while ((ch = getopt(argc, argv, "c:k:")) != -1) { + switch (ch) { + case 'c': + cert_path = strdup(optarg); + break; + case 'k': + key_path = strdup(optarg); + break; + default: + usage(); + } + } + + if (cert_path == NULL) { + printf("-c option is mandatory\n"); + usage(); + } + + if (key_path == NULL) { + printf("-k option is mandatory\n"); + usage(); + } + + input_path = argv[optind]; + + fp = fopen(cert_path, "r"); + if (fp == NULL) { + printf("Failed to open certificate file\n"); + exit(1); + } + result = fstat(fileno(fp), &sb); + if (result != 0) { + printf("Fstat failed\n"); + return result; + } + cert_size = sb.st_size; + cert = malloc(cert_size); + if (cert == NULL) { + fclose(fp); + exit(1); + } + fread(cert, cert_size, 1, fp); + fclose(fp); + + fp = fopen(key_path, "r"); + if (fp == NULL) { + free(cert); + printf("Failed to open key file\n"); + exit(1); + } + result = fstat(fileno(fp), &sb); + if (result != 0) { + free(cert); + printf("Fstat failed\n"); + return result; + } + priv_size = sb.st_size; + priv = malloc(cert_size); + if (priv == NULL) { + fclose(fp); + free(cert); + exit(1); + } + fread(priv, priv_size, 1, fp); + fclose(fp); + + fp = fopen(input_path, "rb+"); + if (fp == NULL) { + free(cert); + free(priv); + printf("Failed to open input file\n"); + exit(1); + } + if (!sign(cert, cert_size, priv, priv_size, fp, &output, &length)) { + free(cert); + free(priv); + printf("Failed to sign binary\n"); + exit(1); + } + + /* Append signature to the end of signed file. */ + fseek(fp, 0, SEEK_END); + fwrite(output, length, 1, fp); + fclose(fp); + free(output); + free(cert); + free(priv); +}