Extend libsecureboot(old libve) to obtain trusted certificates from UEFI and implement revocation

UEFI related headers were copied from edk2.

A new build option "MK_LOADER_EFI_SECUREBOOT" was added to allow
loading of trusted anchors from UEFI.

Certificate revocation support is also introduced.
The forbidden certificates are loaded from dbx variable.
Verification fails in two cases:

There is a direct match between cert in dbx and the one in the chain.
The CA used to sign the chain is found in dbx.
One can also insert a hash of TBS section of a certificate into dbx.
In this case verifications fails only if a direct match with a
certificate in chain is found.

Submitted by: Kornel Duleba <mindal@semihalf.com>
Reviewed by: sjg
Obtained from: Semihalf
Sponsored by: Stormshield
Differential Revision:	https://reviews.freebsd.org/D19093
This commit is contained in:
Marcin Wojtas 2019-03-06 06:39:42 +00:00
parent ce37b71e68
commit 13ea0450a9
16 changed files with 1362 additions and 36 deletions

View File

@ -31,6 +31,17 @@ BRSSL_SRCS+= \
${BEARSSL}/tools/xmem.c \
${BEARSSL}/tools/vector.c
BRSSL_DEPS= \
brf.c \
vets.c \
veta.c
.if ${MK_LOADER_EFI_SECUREBOOT} != "no"
BRSSL_DEPS+= \
efi_init.c \
efi_variables.c
.endif
# we do not need/want nested objdirs
OBJS_SRCS_FILTER = T R
@ -134,7 +145,7 @@ vse.h:
echo 'NULL };' ) > ${.TARGET}
.for s in ${BRSSL_SRCS} brf.c vets.c veta.c
.for s in ${BRSSL_SRCS} ${BRSSL_DEPS}
.ifdef BRSSL_SED
$s: brssl.h
.endif

View File

@ -16,6 +16,19 @@ SRCS+= \
vepcr.c \
verify_file.c \
# Build library with support for the UEFI based authentication
.if ${MK_LOADER_EFI_SECUREBOOT} == "yes"
SRCS+= \
efi/efi_variables.c \
efi/efi_init.c
# Add includes required by efi part
CFLAGS+= \
-I${SRCTOP}/stand/efi/include \
-I${SRCTOP}/lib/libsecureboot/efi/include \
-I${SRCTOP}/stand/efi/include/${MACHINE}
.endif
# this is the list of paths (relative to a file
# that we need to verify) used to find a signed manifest.
# the signature extensions in VE_SIGNATURE_EXT_LIST

View File

@ -0,0 +1,74 @@
/*-
* Copyright (c) 2019 Stormshield.
* Copyright (c) 2019 Semihalf.
*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#define NEED_BRSSL_H
#include "../libsecureboot-priv.h"
#include <brssl.h>
void
ve_efi_init(void)
{
br_x509_certificate *xcs;
hash_data *digests;
size_t num;
int result;
static int once = 0;
if (once > 0)
return;
once = 1;
result = efi_secure_boot_enabled();
if (result <= 0)
return;
xcs = efi_get_trusted_certs(&num);
if (num > 0 && xcs != NULL) {
num = ve_trust_anchors_add(xcs, num);
free_certificates(xcs, num);
}
xcs = efi_get_forbidden_certs(&num);
if (num > 0 && xcs != NULL) {
num = ve_forbidden_anchors_add(xcs, num);
free_certificates(xcs, num);
}
digests = efi_get_forbidden_digests(&num);
if (num > 0 && digests != NULL) {
ve_forbidden_digest_add(digests, num);
/*
* Don't free the buffors for digests,
* since they are shallow copied.
*/
xfree(digests);
}
return;
}

View File

@ -0,0 +1,278 @@
/*-
* Copyright (c) 2019 Stormshield.
* Copyright (c) 2019 Semihalf.
*
* 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.
*
* $FreeBSD$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stand.h>
#include <string.h>
#include <efi.h>
#include <efilib.h>
#include <Guid/ImageAuthentication.h>
#define NEED_BRSSL_H
#include "../libsecureboot-priv.h"
#include <brssl.h>
static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID;
static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID;
static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID;
static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID;
static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID;
/*
* Check if Secure Boot is enabled in firmware.
* We evaluate two variables - Secure Boot and Setup Mode.
* Secure Boot is enforced only if the first one equals 1 and the other 0.
*/
int
efi_secure_boot_enabled(void)
{
UINT8 SecureBoot;
UINT8 SetupMode;
size_t length;
EFI_STATUS status;
length = sizeof(SecureBoot);
status = efi_global_getenv("SecureBoot", &SecureBoot, &length);
if (status != EFI_SUCCESS) {
if (status == EFI_NOT_FOUND)
return (0);
printf("Failed to read \"SecureBoot\" variable\n");
return (-efi_status_to_errno(status));
}
length = sizeof(SetupMode);
status = efi_global_getenv("SetupMode", &SetupMode, &length);
if (status != EFI_SUCCESS)
SetupMode = 0;
printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode);
return (SecureBoot == 1 && SetupMode == 0);
}
/*
* Iterate through UEFI variable and extract X509 certificates from it.
* The EFI_* structures and related guids are defined in UEFI standard.
*/
static br_x509_certificate*
efi_get_certs(const char *name, size_t *count)
{
br_x509_certificate *certs;
UINT8 *database;
EFI_SIGNATURE_LIST *list;
EFI_SIGNATURE_DATA *entry;
size_t db_size;
ssize_t cert_count;
EFI_STATUS status;
database = NULL;
certs = NULL;
db_size = 0;
cert_count = 0;
/*
* Read variable length and allocate memory for it
*/
status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
if (status != EFI_BUFFER_TOO_SMALL)
return (NULL);
database = malloc(db_size);
if (database == NULL)
return (NULL);
status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size);
if (status != EFI_SUCCESS)
goto fail;
for (list = (EFI_SIGNATURE_LIST*) database;
db_size >= list->SignatureListSize && db_size > 0;
db_size -= list->SignatureListSize,
list = (EFI_SIGNATURE_LIST*)
((UINT8*)list + list->SignatureListSize)) {
/* We are only interested in entries containing X509 certs. */
if (memcmp(&efiCertX509GUID,
&list->SignatureType,
sizeof(EFI_GUID)) != 0) {
continue;
}
entry = (EFI_SIGNATURE_DATA*)
((UINT8*)list +
sizeof(EFI_SIGNATURE_LIST) +
list->SignatureHeaderSize);
certs = realloc(certs,
(cert_count + 1) * sizeof(br_x509_certificate));
if (certs == NULL) {
cert_count = 0;
goto fail;
}
certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID);
certs[cert_count].data = malloc(certs[cert_count].data_len);
if (certs[cert_count].data == NULL)
goto fail;
memcpy(certs[cert_count].data,
entry->SignatureData,
certs[cert_count].data_len);
cert_count++;
}
*count = cert_count;
xfree(database);
return (certs);
fail:
free_certificates(certs, cert_count);
xfree(database);
return (NULL);
}
/*
* Extract digests from UEFI "dbx" variable.
* UEFI standard specifies three types of digest - sha256, sha386, sha512.
*/
hash_data*
efi_get_forbidden_digests(size_t *count)
{
UINT8 *database;
hash_data *digests;
EFI_SIGNATURE_LIST *list;
EFI_SIGNATURE_DATA *entry;
size_t db_size, header_size, hash_size;
int digest_count, entry_count;
EFI_STATUS status;
db_size = 0;
digest_count = 0;
database = NULL;
digests = NULL;
status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
if (status != EFI_BUFFER_TOO_SMALL)
return (NULL);
database = malloc(db_size);
if (database == NULL)
return (NULL);
status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size);
if (status != EFI_SUCCESS)
goto fail;
for (list = (EFI_SIGNATURE_LIST*) database;
db_size >= list->SignatureListSize && db_size > 0;
db_size -= list->SignatureListSize,
list = (EFI_SIGNATURE_LIST*)
((UINT8*)list + list->SignatureListSize)) {
/* We are only interested in entries that contain digests. */
if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha256_SIZE;
} else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha384_SIZE;
} else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType,
sizeof(EFI_GUID)) == 0) {
hash_size = br_sha512_SIZE;
} else {
continue;
}
/*
* A single entry can have multiple digests
* of the same type for some reason.
*/
header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize;
/* Calculate the number of entries basing on structure size */
entry_count = list->SignatureListSize - header_size;
entry_count /= list->SignatureSize;
entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size);
while (entry_count-- > 0) {
digests = realloc(digests,
(digest_count + 1) * sizeof(hash_data));
if (digests == NULL) {
digest_count = 0;
goto fail;
}
digests[digest_count].data = malloc(hash_size);
if (digests[digest_count].data == NULL)
goto fail;
memcpy(digests[digest_count].data,
entry->SignatureData,
hash_size);
digests[digest_count].hash_size = hash_size;
entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize);
digest_count++;
}
}
xfree(database);
if (count != NULL)
*count = digest_count;
return (digests);
fail:
while (digest_count--)
xfree(digests[digest_count].data);
xfree(database);
xfree(digests);
return (NULL);
}
/* Copy x509 certificates from db */
br_x509_certificate*
efi_get_trusted_certs(size_t *count)
{
return (efi_get_certs("db", count));
}
/* Copy forbidden certificates from dbx */
br_x509_certificate*
efi_get_forbidden_certs(size_t *count)
{
return (efi_get_certs("dbx", count));
}

View File

@ -0,0 +1,194 @@
/** @file
GUID for EFI (NVRAM) Variables.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
@par Revision Reference:
GUID defined in UEFI 2.1
**/
#ifndef __GLOBAL_VARIABLE_GUID_H__
#define __GLOBAL_VARIABLE_GUID_H__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#ifndef EFI_GLOBAL_VARIABLE
#define EFI_GLOBAL_VARIABLE \
{ \
0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \
}
#endif /* EFI_GLOBAL_VARIABLE */
extern EFI_GUID gEfiGlobalVariableGuid;
//
// Follow UEFI 2.4 spec:
// To prevent name collisions with possible future globally defined variables,
// other internal firmware data variables that are not defined here must be
// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or
// any other GUID defined by the UEFI Specification. Implementations must
// only permit the creation of variables with a UEFI Specification-defined
// VendorGuid when these variables are documented in the UEFI Specification.
//
// Note: except the globally defined variables defined below, the spec also defines
// L"Boot####" - A boot load option.
// L"Driver####" - A driver load option.
// L"SysPrep####" - A System Prep application load option.
// L"Key####" - Describes hot key relationship with a Boot#### load option.
// The attribute for them is NV+BS+RT, #### is a printed hex value, and no 0x or h
// is included in the hex value. They can not be expressed as a #define like other globally
// defined variables, it is because we can not list the Boot0000, Boot0001, etc one by one.
//
///
/// The language codes that the firmware supports. This value is deprecated.
/// Its attribute is BS+RT.
///
#define EFI_LANG_CODES_VARIABLE_NAME L"LangCodes"
///
/// The language code that the system is configured for. This value is deprecated.
/// Its attribute is NV+BS+RT.
///
#define EFI_LANG_VARIABLE_NAME L"Lang"
///
/// The firmware's boot managers timeout, in seconds, before initiating the default boot selection.
/// Its attribute is NV+BS+RT.
///
#define EFI_TIME_OUT_VARIABLE_NAME L"Timeout"
///
/// The language codes that the firmware supports.
/// Its attribute is BS+RT.
///
#define EFI_PLATFORM_LANG_CODES_VARIABLE_NAME L"PlatformLangCodes"
///
/// The language code that the system is configured for.
/// Its attribute is NV+BS+RT.
///
#define EFI_PLATFORM_LANG_VARIABLE_NAME L"PlatformLang"
///
/// The device path of the default input/output/error output console.
/// Its attribute is NV+BS+RT.
///
#define EFI_CON_IN_VARIABLE_NAME L"ConIn"
#define EFI_CON_OUT_VARIABLE_NAME L"ConOut"
#define EFI_ERR_OUT_VARIABLE_NAME L"ErrOut"
///
/// The device path of all possible input/output/error output devices.
/// Its attribute is BS+RT.
///
#define EFI_CON_IN_DEV_VARIABLE_NAME L"ConInDev"
#define EFI_CON_OUT_DEV_VARIABLE_NAME L"ConOutDev"
#define EFI_ERR_OUT_DEV_VARIABLE_NAME L"ErrOutDev"
///
/// The ordered boot option load list.
/// Its attribute is NV+BS+RT.
///
#define EFI_BOOT_ORDER_VARIABLE_NAME L"BootOrder"
///
/// The boot option for the next boot only.
/// Its attribute is NV+BS+RT.
///
#define EFI_BOOT_NEXT_VARIABLE_NAME L"BootNext"
///
/// The boot option that was selected for the current boot.
/// Its attribute is BS+RT.
///
#define EFI_BOOT_CURRENT_VARIABLE_NAME L"BootCurrent"
///
/// The types of boot options supported by the boot manager. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME L"BootOptionSupport"
///
/// The ordered driver load option list.
/// Its attribute is NV+BS+RT.
///
#define EFI_DRIVER_ORDER_VARIABLE_NAME L"DriverOrder"
///
/// The ordered System Prep Application load option list.
/// Its attribute is NV+BS+RT.
///
#define EFI_SYS_PREP_ORDER_VARIABLE_NAME L"SysPrepOrder"
///
/// Identifies the level of hardware error record persistence
/// support implemented by the platform. This variable is
/// only modified by firmware and is read-only to the OS.
/// Its attribute is NV+BS+RT.
///
#define EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME L"HwErrRecSupport"
///
/// Whether the system is operating in setup mode (1) or not (0).
/// All other values are reserved. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_SETUP_MODE_NAME L"SetupMode"
///
/// The Key Exchange Key Signature Database.
/// Its attribute is NV+BS+RT+AT.
///
#define EFI_KEY_EXCHANGE_KEY_NAME L"KEK"
///
/// The public Platform Key.
/// Its attribute is NV+BS+RT+AT.
///
#define EFI_PLATFORM_KEY_NAME L"PK"
///
/// Array of GUIDs representing the type of signatures supported
/// by the platform firmware. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_SIGNATURE_SUPPORT_NAME L"SignatureSupport"
///
/// Whether the platform firmware is operating in Secure boot mode (1) or not (0).
/// All other values are reserved. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_SECURE_BOOT_MODE_NAME L"SecureBoot"
///
/// The OEM's default Key Exchange Key Signature Database. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_KEK_DEFAULT_VARIABLE_NAME L"KEKDefault"
///
/// The OEM's default public Platform Key. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_PK_DEFAULT_VARIABLE_NAME L"PKDefault"
///
/// The OEM's default secure boot signature store. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_DB_DEFAULT_VARIABLE_NAME L"dbDefault"
///
/// The OEM's default secure boot blacklist signature store. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_DBX_DEFAULT_VARIABLE_NAME L"dbxDefault"
///
/// The OEM's default secure boot timestamp signature store. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_DBT_DEFAULT_VARIABLE_NAME L"dbtDefault"
///
/// Allows the firmware to indicate supported features and actions to the OS.
/// Its attribute is BS+RT.
///
#define EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME L"OsIndicationsSupported"
///
/// Allows the OS to request the firmware to enable certain features and to take certain actions.
/// Its attribute is NV+BS+RT.
///
#define EFI_OS_INDICATIONS_VARIABLE_NAME L"OsIndications"
///
/// Whether the system is configured to use only vendor provided
/// keys or not. Should be treated as read-only.
/// Its attribute is BS+RT.
///
#define EFI_VENDOR_KEYS_VARIABLE_NAME L"VendorKeys"
#endif

View File

@ -0,0 +1,352 @@
/** @file
Image signature database are defined for the signed image validation.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
@par Revision Reference:
GUIDs defined in UEFI 2.5 spec.
**/
#ifndef __IMAGE_AUTHTICATION_H__
#define __IMAGE_AUTHTICATION_H__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <Guid/GlobalVariable.h>
#include <Protocol/Hash.h>
#define EFI_IMAGE_SECURITY_DATABASE_GUID \
{ \
0xd719b2cb, 0x3d3a, 0x4596, { 0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f } \
}
///
/// Varialbe name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
/// for the authorized signature database.
///
#define EFI_IMAGE_SECURITY_DATABASE L"db"
///
/// Varialbe name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
/// for the forbidden signature database.
///
#define EFI_IMAGE_SECURITY_DATABASE1 L"dbx"
///
/// Variable name with guid EFI_IMAGE_SECURITY_DATABASE_GUID
/// for the timestamp signature database.
///
#define EFI_IMAGE_SECURITY_DATABASE2 L"dbt"
#define SECURE_BOOT_MODE_ENABLE 1
#define SECURE_BOOT_MODE_DISABLE 0
#define SETUP_MODE 1
#define USER_MODE 0
//***********************************************************************
// Signature Database
//***********************************************************************
///
/// The format of a signature database.
///
#pragma pack(1)
typedef struct {
///
/// An identifier which identifies the agent which added the signature to the list.
///
EFI_GUID SignatureOwner;
///
/// The format of the signature is defined by the SignatureType.
///
UINT8 SignatureData[1];
} EFI_SIGNATURE_DATA;
typedef struct {
///
/// Type of the signature. GUID signature types are defined in below.
///
EFI_GUID SignatureType;
///
/// Total size of the signature list, including this header.
///
UINT32 SignatureListSize;
///
/// Size of the signature header which precedes the array of signatures.
///
UINT32 SignatureHeaderSize;
///
/// Size of each signature.
///
UINT32 SignatureSize;
///
/// Header before the array of signatures. The format of this header is specified
/// by the SignatureType.
/// UINT8 SignatureHeader[SignatureHeaderSize];
///
/// An array of signatures. Each signature is SignatureSize bytes in length.
/// EFI_SIGNATURE_DATA Signatures[][SignatureSize];
///
} EFI_SIGNATURE_LIST;
typedef struct {
///
/// The SHA256 hash of an X.509 certificate's To-Be-Signed contents.
///
EFI_SHA256_HASH ToBeSignedHash;
///
/// The time that the certificate shall be considered to be revoked.
///
EFI_TIME TimeOfRevocation;
} EFI_CERT_X509_SHA256;
typedef struct {
///
/// The SHA384 hash of an X.509 certificate's To-Be-Signed contents.
///
EFI_SHA384_HASH ToBeSignedHash;
///
/// The time that the certificate shall be considered to be revoked.
///
EFI_TIME TimeOfRevocation;
} EFI_CERT_X509_SHA384;
typedef struct {
///
/// The SHA512 hash of an X.509 certificate's To-Be-Signed contents.
///
EFI_SHA512_HASH ToBeSignedHash;
///
/// The time that the certificate shall be considered to be revoked.
///
EFI_TIME TimeOfRevocation;
} EFI_CERT_X509_SHA512;
#pragma pack()
///
/// This identifies a signature containing a SHA-256 hash. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
/// 32 bytes.
///
#define EFI_CERT_SHA256_GUID \
{ \
0xc1c41626, 0x504c, 0x4092, {0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28} \
}
///
/// This identifies a signature containing an RSA-2048 key. The key (only the modulus
/// since the public key exponent is known to be 0x10001) shall be stored in big-endian
/// order.
/// The SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size
/// of SignatureOwner component) + 256 bytes.
///
#define EFI_CERT_RSA2048_GUID \
{ \
0x3c5766e8, 0x269c, 0x4e34, {0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6} \
}
///
/// This identifies a signature containing a RSA-2048 signature of a SHA-256 hash. The
/// SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size of
/// SignatureOwner component) + 256 bytes.
///
#define EFI_CERT_RSA2048_SHA256_GUID \
{ \
0xe2b36190, 0x879b, 0x4a3d, {0xad, 0x8d, 0xf2, 0xe7, 0xbb, 0xa3, 0x27, 0x84} \
}
///
/// This identifies a signature containing a SHA-1 hash. The SignatureSize shall always
/// be 16 (size of SignatureOwner component) + 20 bytes.
///
#define EFI_CERT_SHA1_GUID \
{ \
0x826ca512, 0xcf10, 0x4ac9, {0xb1, 0x87, 0xbe, 0x1, 0x49, 0x66, 0x31, 0xbd} \
}
///
/// TThis identifies a signature containing a RSA-2048 signature of a SHA-1 hash. The
/// SignatureHeader size shall always be 0. The SignatureSize shall always be 16 (size of
/// SignatureOwner component) + 256 bytes.
///
#define EFI_CERT_RSA2048_SHA1_GUID \
{ \
0x67f8444f, 0x8743, 0x48f1, {0xa3, 0x28, 0x1e, 0xaa, 0xb8, 0x73, 0x60, 0x80} \
}
///
/// This identifies a signature based on an X.509 certificate. If the signature is an X.509
/// certificate then verification of the signature of an image should validate the public
/// key certificate in the image using certificate path verification, up to this X.509
/// certificate as a trusted root. The SignatureHeader size shall always be 0. The
/// SignatureSize may vary but shall always be 16 (size of the SignatureOwner component) +
/// the size of the certificate itself.
/// Note: This means that each certificate will normally be in a separate EFI_SIGNATURE_LIST.
///
#define EFI_CERT_X509_GUID \
{ \
0xa5c059a1, 0x94e4, 0x4aa7, {0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72} \
}
///
/// This identifies a signature containing a SHA-224 hash. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
/// 28 bytes.
///
#define EFI_CERT_SHA224_GUID \
{ \
0xb6e5233, 0xa65c, 0x44c9, {0x94, 0x7, 0xd9, 0xab, 0x83, 0xbf, 0xc8, 0xbd} \
}
///
/// This identifies a signature containing a SHA-384 hash. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
/// 48 bytes.
///
#define EFI_CERT_SHA384_GUID \
{ \
0xff3e5307, 0x9fd0, 0x48c9, {0x85, 0xf1, 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1} \
}
///
/// This identifies a signature containing a SHA-512 hash. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of SignatureOwner component) +
/// 64 bytes.
///
#define EFI_CERT_SHA512_GUID \
{ \
0x93e0fae, 0xa6c4, 0x4f50, {0x9f, 0x1b, 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a} \
}
///
/// This identifies a signature containing the SHA256 hash of an X.509 certificate's
/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
/// + 48 bytes for an EFI_CERT_X509_SHA256 structure. If the TimeOfRevocation is non-zero,
/// the certificate should be considered to be revoked from that time and onwards, and
/// otherwise the certificate shall be considered to always be revoked.
///
#define EFI_CERT_X509_SHA256_GUID \
{ \
0x3bd2a492, 0x96c0, 0x4079, {0xb4, 0x20, 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed } \
}
///
/// This identifies a signature containing the SHA384 hash of an X.509 certificate's
/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
/// + 64 bytes for an EFI_CERT_X509_SHA384 structure. If the TimeOfRevocation is non-zero,
/// the certificate should be considered to be revoked from that time and onwards, and
/// otherwise the certificate shall be considered to always be revoked.
///
#define EFI_CERT_X509_SHA384_GUID \
{ \
0x7076876e, 0x80c2, 0x4ee6, {0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b } \
}
///
/// This identifies a signature containing the SHA512 hash of an X.509 certificate's
/// To-Be-Signed contents, and a time of revocation. The SignatureHeader size shall
/// always be 0. The SignatureSize shall always be 16 (size of the SignatureOwner component)
/// + 80 bytes for an EFI_CERT_X509_SHA512 structure. If the TimeOfRevocation is non-zero,
/// the certificate should be considered to be revoked from that time and onwards, and
/// otherwise the certificate shall be considered to always be revoked.
///
#define EFI_CERT_X509_SHA512_GUID \
{ \
0x446dbf63, 0x2502, 0x4cda, {0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d } \
}
///
/// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315]
/// SignedData value.
///
#define EFI_CERT_TYPE_PKCS7_GUID \
{ \
0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \
}
//***********************************************************************
// Image Execution Information Table Definition
//***********************************************************************
typedef UINT32 EFI_IMAGE_EXECUTION_ACTION;
#define EFI_IMAGE_EXECUTION_AUTHENTICATION 0x00000007
#define EFI_IMAGE_EXECUTION_AUTH_UNTESTED 0x00000000
#define EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED 0x00000001
#define EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED 0x00000002
#define EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND 0x00000003
#define EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND 0x00000004
#define EFI_IMAGE_EXECUTION_POLICY_FAILED 0x00000005
#define EFI_IMAGE_EXECUTION_INITIALIZED 0x00000008
//
// EFI_IMAGE_EXECUTION_INFO is added to EFI System Configuration Table
// and assigned the GUID EFI_IMAGE_SECURITY_DATABASE_GUID.
//
typedef struct {
///
/// Describes the action taken by the firmware regarding this image.
///
EFI_IMAGE_EXECUTION_ACTION Action;
///
/// Size of all of the entire structure.
///
UINT32 InfoSize;
///
/// If this image was a UEFI device driver (for option ROM, for example) this is the
/// null-terminated, user-friendly name for the device. If the image was for an application,
/// then this is the name of the application. If this cannot be determined, then a simple
/// NULL character should be put in this position.
/// CHAR16 Name[];
///
///
/// For device drivers, this is the device path of the device for which this device driver
/// was intended. In some cases, the driver itself may be stored as part of the system
/// firmware, but this field should record the device's path, not the firmware path. For
/// applications, this is the device path of the application. If this cannot be determined,
/// a simple end-of-path device node should be put in this position.
/// EFI_DEVICE_PATH_PROTOCOL DevicePath;
///
///
/// Zero or more image signatures. If the image contained no signatures,
/// then this field is empty.
/// EFI_SIGNATURE_LIST Signature;
///
} EFI_IMAGE_EXECUTION_INFO;
typedef struct {
///
/// Number of EFI_IMAGE_EXECUTION_INFO structures.
///
UINTN NumberOfImages;
///
/// Number of image instances of EFI_IMAGE_EXECUTION_INFO structures.
///
// EFI_IMAGE_EXECUTION_INFO InformationInfo[]
} EFI_IMAGE_EXECUTION_INFO_TABLE;
extern EFI_GUID gEfiImageSecurityDatabaseGuid;
extern EFI_GUID gEfiCertSha256Guid;
extern EFI_GUID gEfiCertRsa2048Guid;
extern EFI_GUID gEfiCertRsa2048Sha256Guid;
extern EFI_GUID gEfiCertSha1Guid;
extern EFI_GUID gEfiCertRsa2048Sha1Guid;
extern EFI_GUID gEfiCertX509Guid;
extern EFI_GUID gEfiCertSha224Guid;
extern EFI_GUID gEfiCertSha384Guid;
extern EFI_GUID gEfiCertSha512Guid;
extern EFI_GUID gEfiCertX509Sha256Guid;
extern EFI_GUID gEfiCertX509Sha384Guid;
extern EFI_GUID gEfiCertX509Sha512Guid;
extern EFI_GUID gEfiCertPkcs7Guid;
#endif

View File

@ -0,0 +1,171 @@
/** @file
EFI_HASH_SERVICE_BINDING_PROTOCOL as defined in UEFI 2.0.
EFI_HASH_PROTOCOL as defined in UEFI 2.0.
The EFI Hash Service Binding Protocol is used to locate hashing services support
provided by a driver and to create and destroy instances of the EFI Hash Protocol
so that a multiple drivers can use the underlying hashing services.
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __EFI_HASH_PROTOCOL_H__
#define __EFI_HASH_PROTOCOL_H__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#define CONST const
#define EFI_HASH_SERVICE_BINDING_PROTOCOL_GUID \
{ \
0x42881c98, 0xa4f3, 0x44b0, {0xa3, 0x9d, 0xdf, 0xa1, 0x86, 0x67, 0xd8, 0xcd } \
}
#define EFI_HASH_PROTOCOL_GUID \
{ \
0xc5184932, 0xdba5, 0x46db, {0xa5, 0xba, 0xcc, 0x0b, 0xda, 0x9c, 0x14, 0x35 } \
}
#define EFI_HASH_ALGORITHM_SHA1_GUID \
{ \
0x2ae9d80f, 0x3fb2, 0x4095, {0xb7, 0xb1, 0xe9, 0x31, 0x57, 0xb9, 0x46, 0xb6 } \
}
#define EFI_HASH_ALGORITHM_SHA224_GUID \
{ \
0x8df01a06, 0x9bd5, 0x4bf7, {0xb0, 0x21, 0xdb, 0x4f, 0xd9, 0xcc, 0xf4, 0x5b } \
}
#define EFI_HASH_ALGORITHM_SHA256_GUID \
{ \
0x51aa59de, 0xfdf2, 0x4ea3, {0xbc, 0x63, 0x87, 0x5f, 0xb7, 0x84, 0x2e, 0xe9 } \
}
#define EFI_HASH_ALGORITHM_SHA384_GUID \
{ \
0xefa96432, 0xde33, 0x4dd2, {0xae, 0xe6, 0x32, 0x8c, 0x33, 0xdf, 0x77, 0x7a } \
}
#define EFI_HASH_ALGORITHM_SHA512_GUID \
{ \
0xcaa4381e, 0x750c, 0x4770, {0xb8, 0x70, 0x7a, 0x23, 0xb4, 0xe4, 0x21, 0x30 } \
}
#define EFI_HASH_ALGORTIHM_MD5_GUID \
{ \
0xaf7c79c, 0x65b5, 0x4319, {0xb0, 0xae, 0x44, 0xec, 0x48, 0x4e, 0x4a, 0xd7 } \
}
#define EFI_HASH_ALGORITHM_SHA1_NOPAD_GUID \
{ \
0x24c5dc2f, 0x53e2, 0x40ca, {0x9e, 0xd6, 0xa5, 0xd9, 0xa4, 0x9f, 0x46, 0x3b } \
}
#define EFI_HASH_ALGORITHM_SHA256_NOPAD_GUID \
{ \
0x8628752a, 0x6cb7, 0x4814, {0x96, 0xfc, 0x24, 0xa8, 0x15, 0xac, 0x22, 0x26 } \
}
//
// Note: Use of the following algorithms with EFI_HASH_PROTOCOL is deprecated.
// EFI_HASH_ALGORITHM_SHA1_GUID
// EFI_HASH_ALGORITHM_SHA224_GUID
// EFI_HASH_ALGORITHM_SHA256_GUID
// EFI_HASH_ALGORITHM_SHA384_GUID
// EFI_HASH_ALGORITHM_SHA512_GUID
// EFI_HASH_ALGORTIHM_MD5_GUID
//
typedef struct _EFI_HASH_PROTOCOL EFI_HASH_PROTOCOL;
typedef UINT8 EFI_MD5_HASH[16];
typedef UINT8 EFI_SHA1_HASH[20];
typedef UINT8 EFI_SHA224_HASH[28];
typedef UINT8 EFI_SHA256_HASH[32];
typedef UINT8 EFI_SHA384_HASH[48];
typedef UINT8 EFI_SHA512_HASH[64];
typedef union {
EFI_MD5_HASH *Md5Hash;
EFI_SHA1_HASH *Sha1Hash;
EFI_SHA224_HASH *Sha224Hash;
EFI_SHA256_HASH *Sha256Hash;
EFI_SHA384_HASH *Sha384Hash;
EFI_SHA512_HASH *Sha512Hash;
} EFI_HASH_OUTPUT;
/**
Returns the size of the hash which results from a specific algorithm.
@param[in] This Points to this instance of EFI_HASH_PROTOCOL.
@param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
@param[out] HashSize Holds the returned size of the algorithm's hash.
@retval EFI_SUCCESS Hash size returned successfully.
@retval EFI_INVALID_PARAMETER HashSize is NULL or HashAlgorithm is NULL.
@retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported
by this driver.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HASH_GET_HASH_SIZE)(
IN CONST EFI_HASH_PROTOCOL *This,
IN CONST EFI_GUID *HashAlgorithm,
OUT UINTN *HashSize
);
/**
Creates a hash for the specified message text.
@param[in] This Points to this instance of EFI_HASH_PROTOCOL.
@param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
@param[in] Extend Specifies whether to create a new hash (FALSE) or extend the specified
existing hash (TRUE).
@param[in] Message Points to the start of the message.
@param[in] MessageSize The size of Message, in bytes.
@param[in,out] Hash On input, if Extend is TRUE, then this parameter holds a pointer
to a pointer to an array containing the hash to extend. If Extend
is FALSE, then this parameter holds a pointer to a pointer to a
caller-allocated array that will receive the result of the hash
computation. On output (regardless of the value of Extend), the
array will contain the result of the hash computation.
@retval EFI_SUCCESS Hash returned successfully.
@retval EFI_INVALID_PARAMETER Message or Hash, HashAlgorithm is NULL or MessageSize is 0.
MessageSize is not an integer multiple of block size.
@retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this
driver. Or, Extend is TRUE, and the algorithm doesn't support extending the hash.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_HASH_HASH)(
IN CONST EFI_HASH_PROTOCOL *This,
IN CONST EFI_GUID *HashAlgorithm,
IN BOOLEAN Extend,
IN CONST UINT8 *Message,
IN UINT64 MessageSize,
IN OUT EFI_HASH_OUTPUT *Hash
);
///
/// This protocol allows creating a hash of an arbitrary message digest
/// using one or more hash algorithms.
///
struct _EFI_HASH_PROTOCOL {
EFI_HASH_GET_HASH_SIZE GetHashSize;
EFI_HASH_HASH Hash;
};
extern EFI_GUID gEfiHashServiceBindingProtocolGuid;
extern EFI_GUID gEfiHashProtocolGuid;
extern EFI_GUID gEfiHashAlgorithmSha1Guid;
extern EFI_GUID gEfiHashAlgorithmSha224Guid;
extern EFI_GUID gEfiHashAlgorithmSha256Guid;
extern EFI_GUID gEfiHashAlgorithmSha384Guid;
extern EFI_GUID gEfiHashAlgorithmSha512Guid;
extern EFI_GUID gEfiHashAlgorithmMD5Guid;
extern EFI_GUID gEfiHashAlgorithmSha1NoPadGuid;
extern EFI_GUID gEfiHashAlgorithmSha256NoPadGuid;
#endif

View File

@ -40,6 +40,7 @@ struct stat;
void ve_debug_set(int);
int ve_status_get(int);
void ve_efi_init(void);
int load_manifest(const char *, const char *, const char *, struct stat *);
int verify_file(int, const char *, off_t, int);
void verify_pcr_export(void);

View File

@ -31,8 +31,15 @@
/* public api */
#include "libsecureboot.h"
typedef struct {
unsigned char *data;
size_t hash_size;
} hash_data;
size_t ve_trust_anchors_add(br_x509_certificate *, size_t);
char *fingerprint_info_lookup(int, const char *);
size_t ve_forbidden_anchors_add(br_x509_certificate *, size_t);
void ve_forbidden_digest_add(hash_data *digest, size_t);
char *fingerprint_info_lookup(int, const char *);
br_x509_certificate * parse_certificates(unsigned char *, size_t, size_t *);
int certificate_to_trust_anchor_inner(br_x509_trust_anchor *,
@ -45,4 +52,9 @@ int verify_rsa_digest(br_rsa_public_key *pkey,
int openpgp_self_tests(void);
int efi_secure_boot_enabled(void);
br_x509_certificate* efi_get_trusted_certs(size_t *count);
br_x509_certificate* efi_get_forbidden_certs(size_t *count);
hash_data* efi_get_forbidden_digests(size_t *count);
#endif /* _LIBSECUREBOOT_PRIV_H_ */

View File

@ -7,27 +7,26 @@
# for each key will provide the appropriate certificate chain on request
# force these for Junos
MANIFEST_SKIP_ALWAYS= boot
#MANIFEST_SKIP_ALWAYS= boot
VE_HASH_LIST= \
SHA1 \
SHA256 \
SHA384
SHA384 \
SHA512
VE_SIGNATURE_LIST= \
ECDSA
ECDSA \
RSA
VE_SIGNATURE_EXT_LIST= \
esig
esig \
rsig
VE_SELF_TESTS= yes
.if ${MACHINE} == "host" && ${.CURDIR:T} == "tests"
# for testing
VE_HASH_LIST+= \
SHA512
VE_SIGNATURE_LIST+= \
RSA \
DEPRECATED_RSA_SHA1
VE_SIGNATURE_EXT_LIST+= \
@ -88,7 +87,7 @@ vc_rsa.pem: rcerts.pem _2ndLAST_PEM_USE
.endif
# we take the mtime of this as our baseline time
BUILD_UTC_FILE= ecerts.pem
#BUILD_UTC_FILE= ecerts.pem
#VE_DEBUG_LEVEL=3
#VE_VERBOSE_DEFAULT=1
@ -97,7 +96,7 @@ BUILD_UTC_FILE= ecerts.pem
.if empty(TRUST_ANCHORS)
TRUST_ANCHORS!= cd ${.CURDIR} && 'ls' -1 *.pem t*.asc 2> /dev/null
.endif
.if empty(TRUST_ANCHORS)
.if empty(TRUST_ANCHORS) && ${MK_LOADER_EFI_SECUREBOOT} != "yes"
.error Need TRUST_ANCHORS see ${.CURDIR}/README.rst
.endif
.if ${TRUST_ANCHORS:T:Mt*.pem} != ""

View File

@ -346,7 +346,7 @@ verify_file(int fd, const char *filename, off_t off, int severity)
if (verbose || severity > VE_WANT) {
#if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
printf("Verified %s %llu,%llu\n", filename,
st.st_dev, st.st_ino);
(long long)st.st_dev, (long long)st.st_ino);
#else
printf("Verified %s\n", filename);
#endif

View File

@ -49,8 +49,11 @@ __FBSDID("$FreeBSD$");
int DebugVe = 0;
typedef VECTOR(br_x509_certificate) cert_list;
typedef VECTOR(hash_data) digest_list;
static anchor_list trust_anchors = VEC_INIT;
static anchor_list forbidden_anchors = VEC_INIT;
static digest_list forbidden_digests = VEC_INIT;
void
ve_debug_set(int n)
@ -113,12 +116,75 @@ free_cert_contents(br_x509_certificate *xc)
xfree(xc->data);
}
/**
* @brief
* add certs to our trust store
/* ASN parsing related defines */
#define ASN1_PRIMITIVE_TAG 0x1F
#define ASN1_INF_LENGTH 0x80
#define ASN1_LENGTH_MASK 0x7F
/*
* Get TBS part of certificate.
* Since BearSSL doesn't provide any API to do this,
* it has to be implemented here.
*/
size_t
ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
static void*
X509_to_tbs(unsigned char* cert, size_t* output_size)
{
unsigned char *result;
size_t tbs_size;
int size, i;
if (cert == NULL)
return (NULL);
/* Strip two sequences to get to the TBS section */
for (i = 0; i < 2; i++) {
/*
* XXX: We don't need to support extended tags since
* they should not be present in certificates.
*/
if ((*cert & ASN1_PRIMITIVE_TAG) == ASN1_PRIMITIVE_TAG)
return (NULL);
cert++;
if (*cert == ASN1_INF_LENGTH)
return (NULL);
size = *cert & ASN1_LENGTH_MASK;
tbs_size = 0;
/* Size can either be stored on a single or multiple bytes */
if (*cert & (ASN1_LENGTH_MASK + 1)) {
cert++;
while (*cert == 0 && size > 0) {
cert++;
size--;
}
while (size-- > 0) {
tbs_size <<= 8;
tbs_size |= *(cert++);
}
}
if (i == 0)
result = cert;
}
tbs_size += (cert - result);
if (output_size != NULL)
*output_size = tbs_size;
return (result);
}
void
ve_forbidden_digest_add(hash_data *digest, size_t num)
{
while (num--)
VEC_ADD(forbidden_digests, digest[num]);
}
static size_t
ve_anchors_add(br_x509_certificate *xcs, size_t num, anchor_list *anchors)
{
br_x509_trust_anchor ta;
size_t u;
@ -127,11 +193,27 @@ ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
break;
}
VEC_ADD(trust_anchors, ta);
VEC_ADD(*anchors, ta);
}
return (u);
}
/**
* @brief
* add certs to our trust store
*/
size_t
ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
{
return (ve_anchors_add(xcs, num, &trust_anchors));
}
size_t
ve_forbidden_anchors_add(br_x509_certificate *xcs, size_t num)
{
return (ve_anchors_add(xcs, num, &forbidden_anchors));
}
/**
* @brief
* initialize our trust_anchors from ta_PEM
@ -139,13 +221,14 @@ ve_trust_anchors_add(br_x509_certificate *xcs, size_t num)
int
ve_trust_init(void)
{
#ifdef TRUST_ANCHOR_STR
br_x509_certificate *xcs;
#endif
static int once = -1;
size_t num;
if (once >= 0)
return (once);
once = 0;
ve_utc_set(time(NULL));
#ifdef BUILD_UTC
@ -159,14 +242,12 @@ ve_trust_init(void)
#ifdef TRUST_ANCHOR_STR
xcs = parse_certificates(__DECONST(unsigned char *, TRUST_ANCHOR_STR),
sizeof(TRUST_ANCHOR_STR), &num);
if (xcs == NULL)
return (0);
num = ve_trust_anchors_add(xcs, num);
once = (int) num;
#else
num = 0;
if (xcs != NULL)
num = ve_trust_anchors_add(xcs, num);
#endif
return (num);
once = (int) VEC_LEN(trust_anchors);
return (once);
}
/**
@ -177,7 +258,8 @@ ve_trust_init(void)
static br_x509_pkey *
verify_signer_xcs(br_x509_certificate *xcs,
size_t num,
br_name_element *elts, size_t num_elts)
br_name_element *elts, size_t num_elts,
anchor_list *anchors)
{
br_x509_minimal_context mc;
br_x509_certificate *xc;
@ -196,11 +278,11 @@ verify_signer_xcs(br_x509_certificate *xcs,
}
DEBUG_PRINTF(5, ("verify_signer: %zu trust anchors\n",
VEC_LEN(trust_anchors)));
VEC_LEN(*anchors)));
br_x509_minimal_init(&mc, &br_sha256_vtable,
&VEC_ELT(trust_anchors, 0),
VEC_LEN(trust_anchors));
&VEC_ELT(*anchors, 0),
VEC_LEN(*anchors));
#ifdef VE_ECDSA_SUPPORT
br_x509_minimal_set_ecdsa(&mc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
@ -255,10 +337,96 @@ verify_signer_xcs(br_x509_certificate *xcs,
pk = xpkeydup(tpk);
}
}
VEC_CLEAREXT(chain, &free_cert_contents);
VEC_CLEAR(chain);
return (pk);
}
/*
* Check if digest of one of the certificates from verified chain
* is present in the forbidden database.
* Since UEFI allows to store three types of digests
* all of them have to be checked separately.
*/
static int
check_forbidden_digests(br_x509_certificate *xcs, size_t num)
{
unsigned char sha256_digest[br_sha256_SIZE];
unsigned char sha384_digest[br_sha384_SIZE];
unsigned char sha512_digest[br_sha512_SIZE];
void *tbs;
hash_data *digest;
br_hash_compat_context ctx;
const br_hash_class *md;
size_t tbs_len, i;
int have_sha256, have_sha384, have_sha512;
if (VEC_LEN(forbidden_digests) == 0)
return (0);
/*
* Iterate through certificates, extract their To-Be-Signed section,
* and compare its digest against the ones in the forbidden database.
*/
while (num--) {
tbs = X509_to_tbs(xcs[num].data, &tbs_len);
if (tbs == NULL) {
printf("Failed to obtain TBS part of certificate\n");
return (1);
}
have_sha256 = have_sha384 = have_sha512 = 0;
for (i = 0; i < VEC_LEN(forbidden_digests); i++) {
digest = &VEC_ELT(forbidden_digests, i);
switch (digest->hash_size) {
case br_sha256_SIZE:
if (!have_sha256) {
have_sha256 = 1;
md = &br_sha256_vtable;
md->init(&ctx.vtable);
md->update(&ctx.vtable, tbs, tbs_len);
md->out(&ctx.vtable, sha256_digest);
}
if (!memcmp(sha256_digest,
digest->data,
br_sha256_SIZE))
return (1);
break;
case br_sha384_SIZE:
if (!have_sha384) {
have_sha384 = 1;
md = &br_sha384_vtable;
md->init(&ctx.vtable);
md->update(&ctx.vtable, tbs, tbs_len);
md->out(&ctx.vtable, sha384_digest);
}
if (!memcmp(sha384_digest,
digest->data,
br_sha384_SIZE))
return (1);
break;
case br_sha512_SIZE:
if (!have_sha512) {
have_sha512 = 1;
md = &br_sha512_vtable;
md->init(&ctx.vtable);
md->update(&ctx.vtable, tbs, tbs_len);
md->out(&ctx.vtable, sha512_digest);
}
if (!memcmp(sha512_digest,
digest->data,
br_sha512_SIZE))
return (1);
break;
}
}
}
return (0);
}
static br_x509_pkey *
verify_signer(const char *certs,
br_name_element *elts, size_t num_elts)
@ -266,15 +434,46 @@ verify_signer(const char *certs,
br_x509_certificate *xcs;
br_x509_pkey *pk;
size_t num;
pk = NULL;
ve_trust_init();
xcs = read_certificates(certs, &num);
if (xcs == NULL) {
ve_error_set("cannot read certificates\n");
return (NULL);
}
pk = verify_signer_xcs(xcs, num, elts, num_elts);
xfree(xcs);
/*
* Check if either
* 1. There is a direct match between cert from forbidden_anchors
* and a cert from chain.
* 2. CA that signed the chain is found in forbidden_anchors.
*/
if (VEC_LEN(forbidden_anchors) > 0)
pk = verify_signer_xcs(xcs, num, elts, num_elts, &forbidden_anchors);
if (pk != NULL) {
ve_error_set("Certificate is on forbidden list\n");
xfreepkey(pk);
pk = NULL;
goto out;
}
pk = verify_signer_xcs(xcs, num, elts, num_elts, &trust_anchors);
if (pk == NULL)
goto out;
/*
* Check if hash of tbs part of any certificate in chain
* is on the forbidden list.
*/
if (check_forbidden_digests(xcs, num)) {
ve_error_set("Certificate hash is on forbidden list\n");
xfreepkey(pk);
pk = NULL;
}
out:
free_certificates(xcs, num);
return (pk);
}
@ -679,7 +878,8 @@ ve_self_tests(void)
for (u = 0; u < num; u ++) {
cn.len = sizeof(cn_buf);
if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1)) != NULL) {
if ((pk = verify_signer_xcs(&xcs[u], 1, &cn, 1, &trust_anchors)) != NULL) {
free_cert_contents(&xcs[u]);
once++;
printf("Testing verify certificate: %s\tPassed\n",
cn.status ? cn_buf : "");

View File

@ -221,6 +221,7 @@ __DEFAULT_DEPENDENT_OPTIONS= \
CLANG_FULL/CLANG \
LLVM_TARGET_ALL/CLANG \
LOADER_VERIEXEC/BEARSSL \
LOADER_EFI_SECUREBOOT/LOADER_VERIEXEC \
VERIEXEC/BEARSSL \
# MK_*_SUPPORT options which default to "yes" unless their corresponding

View File

@ -81,6 +81,10 @@ HAVE_BCACHE= yes
CFLAGS+= -DEFI_STAGING_SIZE=${EFI_STAGING_SIZE}
.endif
.if ${MK_LOADER_EFI_SECUREBOOT} != "no"
CFLAGS+= -DEFI_SECUREBOOT
.endif
NEWVERSWHAT= "EFI loader" ${MACHINE}
VERSION_FILE= ${.CURDIR}/../loader/version

View File

@ -963,6 +963,17 @@ main(int argc, CHAR16 *argv[])
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
/*
* Initialize the trusted/forbidden certificates from UEFI.
* They will be later used to verify the manifest(s),
* which should contain hashes of verified files.
* This needs to be initialized before any configuration files
* are loaded.
*/
#ifdef EFI_SECUREBOOT
ve_efi_init();
#endif
/*
* Try and find a good currdev based on the image that was booted.
* It might be desirable here to have a short pause to allow falling

View File

@ -0,0 +1,5 @@
.\" $FreeBSD$
Enable building
.Xr loader 8
with support for verification based on certificates obtained from UEFI.
.Pp