Merge branch '2021-03-12-assorted-improvements' into next

- More log enhancements
- A few warning fixes in some cases
- Secure Channel Protocol 03 (SCP03) support for TEEs
This commit is contained in:
Tom Rini 2021-03-15 08:41:14 -04:00
commit 1876b390f3
23 changed files with 407 additions and 34 deletions

View File

@ -142,6 +142,8 @@ config SANDBOX
imply AVB_VERIFY
imply LIBAVB
imply CMD_AVB
imply SCP03
imply CMD_SCP03
imply UDP_FUNCTION_FASTBOOT
imply VIRTIO_MMIO
imply VIRTIO_PCI

View File

@ -2022,12 +2022,19 @@ config HASH_VERIFY
help
Add -v option to verify data against a hash.
config CMD_SCP03
bool "scp03 - SCP03 enable and rotate/provision operations"
depends on SCP03
help
This command provides access to a Trusted Application
running in a TEE to request Secure Channel Protocol 03
(SCP03) enablement and/or rotation of its SCP03 keys.
config CMD_TPM_V1
bool
config CMD_TPM_V2
bool
select CMD_LOG
config CMD_TPM
bool "Enable the 'tpm' command"

View File

@ -193,6 +193,9 @@ obj-$(CONFIG_CMD_BLOB) += blob.o
# Android Verified Boot 2.0
obj-$(CONFIG_CMD_AVB) += avb.o
# Foundries.IO SCP03
obj-$(CONFIG_CMD_SCP03) += scp03.o
obj-$(CONFIG_ARM) += arm/
obj-$(CONFIG_RISCV) += riscv/
obj-$(CONFIG_SANDBOX) += sandbox/

52
cmd/scp03.c Normal file
View File

@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2021, Foundries.IO
*
*/
#include <common.h>
#include <command.h>
#include <env.h>
#include <scp03.h>
int do_scp03_enable(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
if (argc != 1)
return CMD_RET_USAGE;
if (tee_enable_scp03()) {
printf("TEE failed to enable SCP03\n");
return CMD_RET_FAILURE;
}
printf("SCP03 is enabled\n");
return CMD_RET_SUCCESS;
}
int do_scp03_provision(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
if (argc != 1)
return CMD_RET_USAGE;
if (tee_provision_scp03()) {
printf("TEE failed to provision SCP03 keys\n");
return CMD_RET_FAILURE;
}
printf("SCP03 is provisioned\n");
return CMD_RET_SUCCESS;
}
static char text[] =
"provides a command to enable SCP03 and provision the SCP03 keys\n"
" enable - enable SCP03 on the TEE\n"
" provision - provision SCP03 on the TEE\n";
U_BOOT_CMD_WITH_SUBCMDS(scp03, "Secure Channel Protocol 03 control", text,
U_BOOT_SUBCMD_MKENT(enable, 1, 1, do_scp03_enable),
U_BOOT_SUBCMD_MKENT(provision, 1, 1, do_scp03_provision));

View File

@ -588,6 +588,14 @@ config AVB_BUF_SIZE
endif # AVB_VERIFY
config SCP03
bool "Build SCP03 - Secure Channel Protocol O3 - controls"
depends on OPTEE || SANDBOX
depends on TEE
help
This option allows U-Boot to enable and or provision SCP03 on an OPTEE
controlled Secured Element.
config SPL_HASH
bool # "Support hashing API (SHA1, SHA256, etc.)"
help

View File

@ -137,3 +137,4 @@ obj-$(CONFIG_CMD_LOADB) += xyzModem.o
obj-$(CONFIG_$(SPL_TPL_)YMODEM_SUPPORT) += xyzModem.o
obj-$(CONFIG_AVB_VERIFY) += avb_verify.o
obj-$(CONFIG_SCP03) += scp03.o

View File

@ -153,7 +153,7 @@ static bool log_passes_filters(struct log_device *ldev, struct log_rec *rec)
{
struct log_filter *filt;
if (rec->force_debug)
if (rec->flags & LOGRECF_FORCE_DEBUG)
return true;
/* If there are no filters, filter on the default log level */
@ -218,8 +218,11 @@ static int log_dispatch(struct log_rec *rec, const char *fmt, va_list args)
if ((ldev->flags & LOGDF_ENABLE) &&
log_passes_filters(ldev, rec)) {
if (!rec->msg) {
vsnprintf(buf, sizeof(buf), fmt, args);
int len;
len = vsnprintf(buf, sizeof(buf), fmt, args);
rec->msg = buf;
gd->log_cont = len && buf[len - 1] != '\n';
}
ldev->drv->emit(ldev, rec);
}
@ -245,7 +248,11 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file,
rec.cat = cat;
rec.level = level & LOGL_LEVEL_MASK;
rec.force_debug = level & LOGL_FORCE_DEBUG;
rec.flags = 0;
if (level & LOGL_FORCE_DEBUG)
rec.flags |= LOGRECF_FORCE_DEBUG;
if (gd->log_cont)
rec.flags |= LOGRECF_CONT;
rec.file = file;
rec.line = line;
rec.func = func;
@ -255,7 +262,8 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file,
gd->log_drop_count++;
/* display dropped traces with console puts and DEBUG_UART */
if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL || rec.force_debug) {
if (rec.level <= CONFIG_LOG_DEFAULT_LEVEL ||
rec.flags & LOGRECF_FORCE_DEBUG) {
char buf[CONFIG_SYS_CBSIZE];
va_start(args, fmt);

View File

@ -15,6 +15,7 @@ DECLARE_GLOBAL_DATA_PTR;
static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
{
int fmt = gd->log_fmt;
bool add_space = false;
/*
* The output format is designed to give someone a fighting chance of
@ -26,18 +27,21 @@ static int log_console_emit(struct log_device *ldev, struct log_rec *rec)
* - function is an identifier and ends with ()
* - message has a space before it unless it is on its own
*/
if (fmt & BIT(LOGF_LEVEL))
printf("%s.", log_get_level_name(rec->level));
if (fmt & BIT(LOGF_CAT))
printf("%s,", log_get_cat_name(rec->cat));
if (fmt & BIT(LOGF_FILE))
printf("%s:", rec->file);
if (fmt & BIT(LOGF_LINE))
printf("%d-", rec->line);
if (fmt & BIT(LOGF_FUNC))
printf("%s()", rec->func);
if (!(rec->flags & LOGRECF_CONT) && fmt != BIT(LOGF_MSG)) {
add_space = true;
if (fmt & BIT(LOGF_LEVEL))
printf("%s.", log_get_level_name(rec->level));
if (fmt & BIT(LOGF_CAT))
printf("%s,", log_get_cat_name(rec->cat));
if (fmt & BIT(LOGF_FILE))
printf("%s:", rec->file);
if (fmt & BIT(LOGF_LINE))
printf("%d-", rec->line);
if (fmt & BIT(LOGF_FUNC))
printf("%s()", rec->func);
}
if (fmt & BIT(LOGF_MSG))
printf("%s%s", fmt != BIT(LOGF_MSG) ? " " : "", rec->msg);
printf("%s%s", add_space ? " " : "", rec->msg);
return 0;
}

53
common/scp03.c Normal file
View File

@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2021, Foundries.IO
*
*/
#include <common.h>
#include <scp03.h>
#include <tee.h>
#include <tee/optee_ta_scp03.h>
static int scp03_enable(bool provision)
{
const struct tee_optee_ta_uuid uuid = PTA_SCP03_UUID;
struct tee_open_session_arg session;
struct tee_invoke_arg invoke;
struct tee_param param;
struct udevice *tee = NULL;
tee = tee_find_device(tee, NULL, NULL, NULL);
if (!tee)
return -ENODEV;
memset(&session, 0, sizeof(session));
tee_optee_ta_uuid_to_octets(session.uuid, &uuid);
if (tee_open_session(tee, &session, 0, NULL))
return -ENXIO;
memset(&param, 0, sizeof(param));
param.attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
param.u.value.a = provision;
memset(&invoke, 0, sizeof(invoke));
invoke.func = PTA_CMD_ENABLE_SCP03;
invoke.session = session.session;
if (tee_invoke_func(tee, &invoke, 1, &param))
return -EIO;
tee_close_session(tee, session.session);
return 0;
}
int tee_enable_scp03(void)
{
return scp03_enable(false);
}
int tee_provision_scp03(void)
{
return scp03_enable(true);
}

View File

@ -82,7 +82,7 @@ console::
You can issue commands as your would normally. If the command you want is
not supported you can add it to include/configs/sandbox.h.
To exit, type 'reset' or press Ctrl-C.
To exit, type 'poweroff' or press Ctrl-C.
Console / LCD support

View File

@ -96,16 +96,45 @@ Also debug() and error() will generate log records - these use LOG_CATEGORY
as the category, so you should #define this right at the top of the source
file to ensure the category is correct.
Generally each log format_string ends with a newline. If it does not, then the
next log statement will have the LOGRECF_CONT flag set. This can be used to
continue the statement on the same line as the previous one without emitting
new header information (such as category/level). This behaviour is implemented
with log_console. Here is an example that prints a list all on one line with
the tags at the start:
.. code-block:: c
log_debug("Here is a list:");
for (i = 0; i < count; i++)
log_debug(" item %d", i);
log_debug("\n");
Also see the special category LOGL_CONT and level LOGC_CONT.
You can also define CONFIG_LOG_ERROR_RETURN to enable the log_ret() macro. This
can be used whenever your function returns an error value:
.. code-block:: c
return log_ret(uclass_first_device(UCLASS_MMC, &dev));
return log_ret(uclass_first_device_err(UCLASS_MMC, &dev));
This will write a log record when an error code is detected (a value < 0). This
can make it easier to trace errors that are generated deep in the call stack.
The log_msg_ret() variant will print a short string if CONFIG_LOG_ERROR_RETURN
is enabled. So long as the string is unique within the function you can normally
determine exactly which call failed:
.. code-block:: c
ret = gpio_request_by_name(dev, "cd-gpios", 0, &desc, GPIOD_IS_IN);
if (ret)
return log_msg_ret("gpio", ret);
Some functions return 0 for success and any other value is an error. For these,
log_retz() and log_msg_retz() are available.
Convenience functions
~~~~~~~~~~~~~~~~~~~~~

View File

@ -33,3 +33,4 @@ Shell commands
qfw
sbi
true
scp03

33
doc/usage/scp03.rst Normal file
View File

@ -0,0 +1,33 @@
.. SPDX-License-Identifier: GPL-2.0+
scp03 command
=============
Synopsis
--------
::
scp03 enable
scp03 provision
Description
-----------
The *scp03* command calls into a Trusted Application executing in a
Trusted Execution Environment to enable (if present) the Secure
Channel Protocol 03 stablished between the processor and the secure
element.
This protocol encrypts all the communication between the processor and
the secure element using a set of pre-defined keys. These keys can be
rotated (provisioned) using the *provision* request.
See also
--------
For some information on the internals implemented in the TEE, please
check the GlobalPlatform documentation on `Secure Channel Protocol '03'`_
.. _Secure Channel Protocol '03':
https://globalplatform.org/wp-content/uploads/2014/07/GPC_2.3_D_SCP03_v1.1.2_PublicRelease.pdf

View File

@ -31,6 +31,12 @@ config OPTEE_TA_RPC_TEST
permits to test reverse RPC calls to TEE supplicant. Should
be used only in sandbox env.
config OPTEE_TA_SCP03
bool "Support SCP03 TA"
default y
help
Enables support for controlling (enabling, provisioning) the
Secure Channel Protocol 03 operation in the OP-TEE SCP03 TA.
endmenu
endif

View File

@ -8,6 +8,7 @@
#include <tee.h>
#include <tee/optee_ta_avb.h>
#include <tee/optee_ta_rpc_test.h>
#include <tee/optee_ta_scp03.h>
#include "optee/optee_msg.h"
#include "optee/optee_private.h"
@ -68,6 +69,7 @@ void *optee_alloc_and_init_page_list(void *buf, ulong len,
return NULL;
}
#if defined(CONFIG_OPTEE_TA_SCP03) || defined(CONFIG_OPTEE_TA_AVB)
static u32 get_attr(uint n, uint num_params, struct tee_param *params)
{
if (n >= num_params)
@ -79,7 +81,7 @@ static u32 get_attr(uint n, uint num_params, struct tee_param *params)
static u32 check_params(u8 p0, u8 p1, u8 p2, u8 p3, uint num_params,
struct tee_param *params)
{
u8 p[] = { p0, p1, p2, p3};
u8 p[] = { p0, p1, p2, p3 };
uint n;
for (n = 0; n < ARRAY_SIZE(p); n++)
@ -97,6 +99,50 @@ bad_params:
return TEE_ERROR_BAD_PARAMETERS;
}
#endif
#ifdef CONFIG_OPTEE_TA_SCP03
static u32 pta_scp03_open_session(struct udevice *dev, uint num_params,
struct tee_param *params)
{
/*
* We don't expect additional parameters when opening a session to
* this TA.
*/
return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
}
static u32 pta_scp03_invoke_func(struct udevice *dev, u32 func, uint num_params,
struct tee_param *params)
{
u32 res;
static bool enabled;
switch (func) {
case PTA_CMD_ENABLE_SCP03:
res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE,
TEE_PARAM_ATTR_TYPE_NONE,
num_params, params);
if (res)
return res;
if (!enabled) {
enabled = true;
} else {
}
if (params[0].u.value.a)
return TEE_SUCCESS;
default:
return TEE_ERROR_NOT_SUPPORTED;
}
}
#endif
#ifdef CONFIG_OPTEE_TA_AVB
static u32 ta_avb_open_session(struct udevice *dev, uint num_params,
@ -357,6 +403,12 @@ static const struct ta_entry ta_entries[] = {
.invoke_func = ta_rpc_test_invoke_func,
},
#endif
#ifdef CONFIG_OPTEE_TA_SCP03
{ .uuid = PTA_SCP03_UUID,
.open_session = pta_scp03_open_session,
.invoke_func = pta_scp03_invoke_func,
},
#endif
};
static void sandbox_tee_get_version(struct udevice *dev,

View File

@ -285,7 +285,7 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
length = get_unaligned_be32(sent);
sent += sizeof(length);
if (length != send_size) {
printf("TPM2: Unmatching length, received: %ld, expected: %d\n",
printf("TPM2: Unmatching length, received: %zd, expected: %d\n",
send_size, length);
rc = TPM2_RC_SIZE;
sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);

View File

@ -410,6 +410,12 @@ struct global_data {
* This value is used as logging level for continuation messages.
*/
int logl_prev;
/**
* @log_cont: Previous log line did not finished wtih \n
*
* This allows for chained log messages on the same line
*/
bool log_cont;
#endif
#if CONFIG_IS_ENABLED(BLOBLIST)
/**

View File

@ -316,12 +316,40 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line,
__ret); \
__ret; \
})
/*
* Similar to the above, but any non-zero value is consider an error, not just
* values less than 0.
*/
#define log_retz(_ret) ({ \
int __ret = (_ret); \
if (__ret) \
log(LOG_CATEGORY, LOGL_ERR, "returning err=%d\n", __ret); \
__ret; \
})
#define log_msg_retz(_msg, _ret) ({ \
int __ret = (_ret); \
if (__ret) \
log(LOG_CATEGORY, LOGL_ERR, "%s: returning err=%d\n", _msg, \
__ret); \
__ret; \
})
#else
/* Non-logging versions of the above which just return the error code */
#define log_ret(_ret) (_ret)
#define log_msg_ret(_msg, _ret) ((void)(_msg), _ret)
#define log_retz(_ret) (_ret)
#define log_msg_retz(_msg, _ret) ((void)(_msg), _ret)
#endif
/** * enum log_rec_flags - Flags for a log record */
enum log_rec_flags {
/** @LOGRECF_FORCE_DEBUG: Force output of debug record */
LOGRECF_FORCE_DEBUG = BIT(0),
/** @LOGRECF_CONT: Continuation of previous log record */
LOGRECF_CONT = BIT(1),
};
/**
* struct log_rec - a single log record
*
@ -337,18 +365,18 @@ void __assert_fail(const char *assertion, const char *file, unsigned int line,
*
* @cat: Category, representing a uclass or part of U-Boot
* @level: Severity level, less severe is higher
* @force_debug: Force output of debug
* @file: Name of file where the log record was generated (not allocated)
* @line: Line number where the log record was generated
* @flags: Flags for log record (enum log_rec_flags)
* @file: Name of file where the log record was generated (not allocated)
* @func: Function where the log record was generated (not allocated)
* @msg: Log message (allocated)
*/
struct log_rec {
enum log_category_t cat;
enum log_level_t level;
bool force_debug;
u16 line;
u8 flags;
const char *file;
int line;
const char *func;
const char *msg;
};

21
include/scp03.h Normal file
View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2021, Foundries.IO
*
*/
#ifndef _SCP03_H
#define _SCP03_H
/*
* Requests to OPTEE to enable or provision the Secure Channel Protocol on its
* Secure Element
*
* If key provisioning is requested, OPTEE shall generate new SCP03 keys and
* write them to the Secure Element.
*
* Both functions return < 0 on error else 0.
*/
int tee_enable_scp03(void);
int tee_provision_scp03(void);
#endif /* _SCP03_H */

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* (C) Copyright 2021, Foundries.IO
*
*/
#ifndef __TA_SCP03_H
#define __TA_SCP03_H
#define PTA_SCP03_UUID { 0xbe0e5821, 0xe718, 0x4f77, \
{ 0xab, 0x3e, 0x8e, 0x6c, 0x73, 0xa9, 0xc7, 0x35 } }
/*
* Enable Secure Channel Protocol functionality (SCP03) on the Secure Element.
* Setting the operation value to something different than NULL will trigger
* the SCP03 provisioning request.
*
* in params[0].a = operation
*/
#define PTA_CMD_ENABLE_SCP03 0
#endif /*__TA_SCP03_H*/

View File

@ -360,24 +360,24 @@ static int dm_test_acpi_cmd_list(struct unit_test_state *uts)
run_command("acpi list", 0);
addr = (ulong)map_to_sysmem(buf);
ut_assert_nextline("ACPI tables start at %lx", addr);
ut_assert_nextline("RSDP %08lx %06lx (v02 U-BOOT)", addr,
ut_assert_nextline("RSDP %08lx %06zx (v02 U-BOOT)", addr,
sizeof(struct acpi_rsdp));
addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16);
ut_assert_nextline("RSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
ut_assert_nextline("RSDT %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
addr, sizeof(struct acpi_table_header) +
3 * sizeof(u32), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16);
ut_assert_nextline("XSDT %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
ut_assert_nextline("XSDT %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
addr, sizeof(struct acpi_table_header) +
3 * sizeof(u64), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64);
ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
addr = ALIGN(addr + sizeof(struct acpi_dmar), 16);
ut_assert_nextline("DMAR %08lx %06lx (v01 U-BOOT U-BOOTBL %x INTL 0)",
ut_assert_nextline("DMAR %08lx %06zx (v01 U-BOOT U-BOOTBL %x INTL 0)",
addr, sizeof(struct acpi_dmar), U_BOOT_BUILD_DATE);
ut_assert_console_end();

View File

@ -15,8 +15,6 @@
DECLARE_GLOBAL_DATA_PTR;
#define BUFFSIZE 64
static int log_test_cont(struct unit_test_state *uts)
{
int log_fmt;
@ -29,12 +27,13 @@ static int log_test_cont(struct unit_test_state *uts)
gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG);
gd->default_log_level = LOGL_INFO;
console_record_reset_enable();
log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1);
log(LOGC_ARCH, LOGL_ERR, "ea%d\n", 1);
log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2);
gd->default_log_level = log_level;
gd->log_fmt = log_fmt;
gd->flags &= ~GD_FLG_RECORD;
ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 ERR.arch, cc2"));
ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1"));
ut_assertok(ut_check_console_line(uts, "ERR.arch, cc2"));
ut_assertok(ut_check_console_end(uts));
/* Write a third message which is not a continuation */
@ -48,6 +47,18 @@ static int log_test_cont(struct unit_test_state *uts)
ut_assertok(ut_check_console_line(uts, "INFO.efi, ie3"));
ut_assertok(ut_check_console_end(uts));
/* Write two messages without a newline between them */
gd->log_fmt = (1 << LOGF_CAT) | (1 << LOGF_LEVEL) | (1 << LOGF_MSG);
gd->default_log_level = LOGL_INFO;
console_record_reset_enable();
log(LOGC_ARCH, LOGL_ERR, "ea%d ", 1);
log(LOGC_CONT, LOGL_CONT, "cc%d\n", 2);
gd->default_log_level = log_level;
gd->log_fmt = log_fmt;
gd->flags &= ~GD_FLG_RECORD;
ut_assertok(ut_check_console_line(uts, "ERR.arch, ea1 cc2"));
ut_assertok(ut_check_console_end(uts));
return 0;
}
LOG_TEST(log_test_cont);

View File

@ -0,0 +1,27 @@
# Copyright (c) 2021 Foundries.io Ltd
#
# SPDX-License-Identifier: GPL-2.0+
#
# SCP03 command test
"""
This tests SCP03 command in U-boot.
For additional details check doc/usage/scp03.rst
"""
import pytest
import u_boot_utils as util
@pytest.mark.buildconfigspec('cmd_scp03')
def test_scp03(u_boot_console):
"""Enable and provision keys with SCP03
"""
success_str1 = "SCP03 is enabled"
success_str2 = "SCP03 is provisioned"
response = u_boot_console.run_command('scp03 enable')
assert success_str1 in response
response = u_boot_console.run_command('scp03 provision')
assert success_str2 in response