]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
lib: uuid: add UUID v5 support
authorCaleb Connolly <caleb.connolly@linaro.org>
Fri, 30 Aug 2024 12:34:32 +0000 (13:34 +0100)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Thu, 12 Sep 2024 15:35:37 +0000 (17:35 +0200)
Add support for generating version 5 UUIDs, these are determistic and work
by hashing a "namespace" UUID together with some unique data. One intended
usecase is to allow for dynamically generate payload UUIDs for UEFI
capsule updates, so that supported boards can have their own UUIDs
without needing to hardcode them.

In addition, move the common bit twiddling code from gen_ran_uuid into a
separate function and rewrite it not to use clrsetbits (which is not
available when building as part of host tools).

Tests for this are added in an upcoming patch.

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
include/uuid.h
lib/Kconfig
lib/uuid.c

index f5a941250f481bec4f6547206b8c0347c02bef8b..1f4fa103b5e9d45fb9b4eab2313bb260ece4928f 100644 (file)
@@ -11,6 +11,7 @@
 #define __UUID_H__
 
 #include <linux/bitops.h>
+#include <linux/kconfig.h>
 
 /*
  * UUID - Universally Unique IDentifier - 128 bits unique number.
@@ -46,8 +47,8 @@
  * When converting to a binary UUID, le means the field should be converted
  * to little endian and be means it should be converted to big endian.
  *
- * UUID is also used as GUID (Globally Unique Identifier) with the same binary
- * format but it differs in string format like below.
+ * UUID is also used as GUID (Globally Unique Identifier) with the same format
+ * but with some fields stored in little endian.
  *
  * GUID:
  * 0        9    14   19   24
@@ -143,6 +144,18 @@ void gen_rand_uuid(unsigned char *uuid_bin);
  */
 void gen_rand_uuid_str(char *uuid_str, int str_format);
 
+struct efi_guid;
+
+/**
+ * gen_v5_guid() - generate little endian v5 GUID from namespace and other seed data.
+ *
+ * @namespace:   pointer to UUID namespace salt
+ * @guid:        pointer to allocated GUID output
+ * @...:         NULL terminated list of seed data as pairs of pointers
+ *               to data and their lengths
+ */
+void gen_v5_guid(const struct uuid *namespace, struct efi_guid *guid, ...);
+
 /**
  * uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
  * @uuid_str:  pointer to UUID string
index 86919410cd763dfd8b691db80d2c6ab8f12154eb..1dd4f271595781ba52920c4b6b3d8d29494653cf 100644 (file)
@@ -73,6 +73,7 @@ config HAVE_PRIVATE_LIBGCC
 
 config LIB_UUID
        bool
+       select SHA1
 
 config RANDOM_UUID
        bool "GPT Random UUID generation"
index dfa2320ba2679c69d88a95d26d5b721724bc1ae9..c9dfdf007a18b4943740d4ddd9f8a79cdaf139ea 100644 (file)
@@ -22,6 +22,7 @@
 #include <malloc.h>
 #include <dm/uclass.h>
 #include <rng.h>
+#include <u-boot/sha1.h>
 
 int uuid_str_valid(const char *uuid)
 {
@@ -369,6 +370,56 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
        }
 }
 
+static void configure_uuid(struct uuid *uuid, unsigned char version)
+{
+       uint16_t tmp;
+
+       /* Configure variant/version bits */
+       tmp = be16_to_cpu(uuid->time_hi_and_version);
+       tmp = (tmp & ~UUID_VERSION_MASK) | (version << UUID_VERSION_SHIFT);
+       uuid->time_hi_and_version = cpu_to_be16(tmp);
+
+       uuid->clock_seq_hi_and_reserved &= ~UUID_VARIANT_MASK;
+       uuid->clock_seq_hi_and_reserved |= (UUID_VARIANT << UUID_VARIANT_SHIFT);
+}
+
+void gen_v5_guid(const struct uuid *namespace, struct efi_guid *guid, ...)
+{
+       sha1_context ctx;
+       va_list args;
+       const uint8_t *data;
+       uint32_t *tmp32;
+       uint16_t *tmp16;
+       uint8_t hash[SHA1_SUM_LEN];
+
+       sha1_starts(&ctx);
+       /* Hash the namespace UUID as salt */
+       sha1_update(&ctx, (unsigned char *)namespace, UUID_BIN_LEN);
+       va_start(args, guid);
+
+       while ((data = va_arg(args, const uint8_t *))) {
+               unsigned int len = va_arg(args, size_t);
+
+               sha1_update(&ctx, data, len);
+       }
+
+       va_end(args);
+       sha1_finish(&ctx, hash);
+
+       /* Truncate the hash into output UUID, it is already big endian */
+       memcpy(guid, hash, sizeof(*guid));
+
+       configure_uuid((struct uuid *)guid, 5);
+
+       /* Make little endian */
+       tmp32 = (uint32_t *)&guid->b[0];
+       *tmp32 = cpu_to_le32(be32_to_cpu(*tmp32));
+       tmp16 = (uint16_t *)&guid->b[4];
+       *tmp16 = cpu_to_le16(be16_to_cpu(*tmp16));
+       tmp16 = (uint16_t *)&guid->b[6];
+       *tmp16 = cpu_to_le16(be16_to_cpu(*tmp16));
+}
+
 #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
 void gen_rand_uuid(unsigned char *uuid_bin)
 {
@@ -395,13 +446,7 @@ void gen_rand_uuid(unsigned char *uuid_bin)
        for (i = 0; i < 4; i++)
                ptr[i] = rand();
 
-       clrsetbits_be16(&uuid->time_hi_and_version,
-                       UUID_VERSION_MASK,
-                       UUID_VERSION << UUID_VERSION_SHIFT);
-
-       clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
-                    UUID_VARIANT_MASK,
-                    UUID_VARIANT << UUID_VARIANT_SHIFT);
+       configure_uuid(uuid, UUID_VERSION);
 
        memcpy(uuid_bin, uuid, 16);
 }