Particularly when using secure boot with signed TLVs, it may be required
to issue and sign TLVs for specific units. As typically all units of a
board are compiled to validate TLVs against the same key, a "binding"
mechanism is needed if interchange of TLVs across those units must be
prevented. This mapping binds against the UID of the SoC, rendering a
signed TLV with such a field invalid for all but the one unit.

When generating TLVs that use this mapping, the exact binary
representation of the SoC UID must be provided as present in the
respective registers.

Add the special mapping tlv_bind_soc_uid that aborts TLV parsing if the
supplied binary does not match the SoC UID register value.

Include this mapping in barebox_tlv_v1_mappings with tag 0x0024 to make
it available in testing and in other setups using the generic tlv
parsers.

Set up tlv_register_default as a late initcall so that it's loaded after
the SoC UID was initialized.

Signed-off-by: Jonas Rebmann <[email protected]>
---
 common/tlv/barebox.c | 25 ++++++++++++++++++++++++-
 include/tlv/tlv.h    |  1 +
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/common/tlv/barebox.c b/common/tlv/barebox.c
index 24de3eeaaa..88961942eb 100644
--- a/common/tlv/barebox.c
+++ b/common/tlv/barebox.c
@@ -1,8 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+#include "barebox-info.h"
 #include <common.h>
 #include <net.h>
 #include <tlv/tlv.h>
+#include <param.h>
+#include <string.h>
+
 
 int tlv_handle_serial(struct tlv_device *dev, struct tlv_mapping *map, u16 
len, const u8 *val)
 {
@@ -150,6 +154,23 @@ int tlv_format_dec(struct tlv_device *dev, struct 
tlv_mapping *map, u16 len, con
        }
 }
 
+int tlv_bind_soc_uid(struct tlv_device *dev, struct tlv_mapping *map, u16 len, 
const u8 *val)
+{
+       const void *soc_uid = 0;
+       size_t soc_uid_len = 0;
+
+       if (barebox_get_soc_uid_bin(&soc_uid, &soc_uid_len))
+               return -EACCES;
+
+       if (soc_uid && (size_t)len == soc_uid_len && !memcmp(val, soc_uid, len))
+               return tlv_format(dev, map, "%*phN", len, val);
+
+       dev_err(&dev->dev, "%s: tlv bound to SoC UID %*phN, got %*phN\n", 
__func__,
+               len, val, (int)soc_uid_len, soc_uid);
+
+       return -EACCES;
+}
+
 struct tlv_mapping barebox_tlv_v1_mappings[] = {
        /* Detailed release information string for the device */
        { 0x0002, tlv_format_str, "device-hardware-release" },
@@ -169,6 +190,8 @@ struct tlv_mapping barebox_tlv_v1_mappings[] = {
        { 0x0011, tlv_handle_eth_address, "ethernet-address" },
        /* A sequence of multiple Ethernet addresses */
        { 0x0012, tlv_handle_eth_address_seq, "ethernet-address" },
+       /* Reject TLV if supplied binary data does not match UID SoC register */
+       { 0x0024, tlv_bind_soc_uid, "bound-soc-uid"},
        { /* sentintel */ },
 };
 
@@ -212,4 +235,4 @@ static int tlv_register_default(void)
        }
        return 0;
 }
-device_initcall(tlv_register_default);
+late_initcall(tlv_register_default);
diff --git a/include/tlv/tlv.h b/include/tlv/tlv.h
index 536f61646c..54e3afed45 100644
--- a/include/tlv/tlv.h
+++ b/include/tlv/tlv.h
@@ -37,6 +37,7 @@ extern int tlv_format_hex(struct tlv_device *dev, struct 
tlv_mapping *map, u16 l
 extern int tlv_format_mac(struct tlv_device *dev, struct tlv_mapping *map, u16 
len, const u8 *val);
 extern int tlv_format_blob(struct tlv_device *dev, struct tlv_mapping *map, 
u16 len, const u8 *val);
 extern int tlv_handle_serial(struct tlv_device *dev, struct tlv_mapping *map, 
u16 len, const u8 *val);
+extern int tlv_bind_soc_uid(struct tlv_device *dev, struct tlv_mapping *map, 
u16 len, const u8 *val);
 extern int tlv_handle_eth_address(struct tlv_device *dev, struct tlv_mapping 
*map, u16 len, const u8 *val);
 extern int tlv_handle_eth_address_seq(struct tlv_device *dev, struct 
tlv_mapping *map, u16 len, const u8 *val);
 

-- 
2.51.2.535.g419c72cb8a


Reply via email to