diff mbox series

[RFC,1/4] lib: uuid: add UUID v5 support

Message ID 20240426-b4-dynamic-uuid-v1-1-e8154e00ec44@linaro.org
State New
Headers show
Series efi: CapsuleUpdate: support for dynamic GUIDs | expand

Commit Message

Caleb Connolly April 26, 2024, 2:19 p.m. UTC
Add support for generate 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.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
 include/uuid.h | 16 ++++++++++++++++
 lib/Kconfig    |  8 ++++++++
 lib/uuid.c     | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

Comments

Ilias Apalodimas May 24, 2024, 6:01 a.m. UTC | #1
[...]

>  #include <dm/uclass.h>
>  #include <rng.h>
> +#include <u-boot/sha1.h>
>
>  int uuid_str_valid(const char *uuid)
>  {
>         int i, valid;
> @@ -368,8 +369,40 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
>                 }
>         }
>  }
>
> +#if CONFIG_IS_ENABLED(UUID_GEN_V5)
> +void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...)
> +{
> +       sha1_context ctx;
> +       va_list args;
> +       const u8 *data;
> +       u8 hash[SHA1_SUM_LEN];
> +
> +       sha1_starts(&ctx);
> +       /* Hash the namespace UUID as salt */
> +       sha1_update(&ctx, (char *)namespace, UUID_BIN_LEN);
> +       va_start(args, uuid);

Should we use sha1 here? Is it described somewhere in UUIDv5 requirements?
If not I'd rather have a sha256

> +
> +       while ((data = va_arg(args, const u8 *)))
> +               sha1_update(&ctx, (char *)data, va_arg(args, int));

sha1_update second argument is an unsigned int

> +
> +       va_end(args);
> +       sha1_finish(&ctx, hash);
> +
> +       /* Truncate the hash into output UUID and convert it to big endian */
> +       cpu_to_be32_array((u32 *)uuid, (u32 *)hash, 4);
> +
> +       /* Configure variant/version bits */
> +       clrsetbits_be16(&uuid->time_hi_and_version,
> +                       UUID_VERSION_MASK,
> +                       5 << UUID_VERSION_SHIFT);
> +       clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
> +                    UUID_VARIANT_MASK,
> +                    UUID_VARIANT << UUID_VARIANT_SHIFT);
> +}
> +#endif
> +
>  #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
>  void gen_rand_uuid(unsigned char *uuid_bin)
>  {
>         u32 ptr[4];
>
> --
> 2.44.0
>

Thanks
/Ilias
Caleb Connolly May 24, 2024, 12:20 p.m. UTC | #2
On 24/05/2024 08:01, Ilias Apalodimas wrote:
> [...]
> 
>>   #include <dm/uclass.h>
>>   #include <rng.h>
>> +#include <u-boot/sha1.h>
>>
>>   int uuid_str_valid(const char *uuid)
>>   {
>>          int i, valid;
>> @@ -368,8 +369,40 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
>>                  }
>>          }
>>   }
>>
>> +#if CONFIG_IS_ENABLED(UUID_GEN_V5)
>> +void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...)
>> +{
>> +       sha1_context ctx;
>> +       va_list args;
>> +       const u8 *data;
>> +       u8 hash[SHA1_SUM_LEN];
>> +
>> +       sha1_starts(&ctx);
>> +       /* Hash the namespace UUID as salt */
>> +       sha1_update(&ctx, (char *)namespace, UUID_BIN_LEN);
>> +       va_start(args, uuid);
> 
> Should we use sha1 here? Is it described somewhere in UUIDv5 requirements?
> If not I'd rather have a sha256

The spec says sha1 yeah, this doesn't need to be cryptographically 
secure (the inputs are generally known) but just not have collisions.

That said, we don't need to be spec compliant - just consistent. So I'm 
fine either way. I'd err on the side of what's fastest to compute (if 
that even matters here).
> 
>> +
>> +       while ((data = va_arg(args, const u8 *)))
>> +               sha1_update(&ctx, (char *)data, va_arg(args, int));
> 
> sha1_update second argument is an unsigned int

Ah thanks.
> 
>> +
>> +       va_end(args);
>> +       sha1_finish(&ctx, hash);
>> +
>> +       /* Truncate the hash into output UUID and convert it to big endian */
>> +       cpu_to_be32_array((u32 *)uuid, (u32 *)hash, 4);
>> +
>> +       /* Configure variant/version bits */
>> +       clrsetbits_be16(&uuid->time_hi_and_version,
>> +                       UUID_VERSION_MASK,
>> +                       5 << UUID_VERSION_SHIFT);
>> +       clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
>> +                    UUID_VARIANT_MASK,
>> +                    UUID_VARIANT << UUID_VARIANT_SHIFT);
>> +}
>> +#endif
>> +
>>   #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
>>   void gen_rand_uuid(unsigned char *uuid_bin)
>>   {
>>          u32 ptr[4];
>>
>> --
>> 2.44.0
>>
> 
> Thanks
> /Ilias
Ilias Apalodimas May 24, 2024, 12:23 p.m. UTC | #3
On Fri, 24 May 2024 at 15:20, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
>
>
> On 24/05/2024 08:01, Ilias Apalodimas wrote:
> > [...]
> >
> >>   #include <dm/uclass.h>
> >>   #include <rng.h>
> >> +#include <u-boot/sha1.h>
> >>
> >>   int uuid_str_valid(const char *uuid)
> >>   {
> >>          int i, valid;
> >> @@ -368,8 +369,40 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
> >>                  }
> >>          }
> >>   }
> >>
> >> +#if CONFIG_IS_ENABLED(UUID_GEN_V5)
> >> +void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...)
> >> +{
> >> +       sha1_context ctx;
> >> +       va_list args;
> >> +       const u8 *data;
> >> +       u8 hash[SHA1_SUM_LEN];
> >> +
> >> +       sha1_starts(&ctx);
> >> +       /* Hash the namespace UUID as salt */
> >> +       sha1_update(&ctx, (char *)namespace, UUID_BIN_LEN);
> >> +       va_start(args, uuid);
> >
> > Should we use sha1 here? Is it described somewhere in UUIDv5 requirements?
> > If not I'd rather have a sha256
>
> The spec says sha1 yeah, this doesn't need to be cryptographically
> secure (the inputs are generally known) but just not have collisions.
>
> That said, we don't need to be spec compliant - just consistent. So I'm
> fine either way. I'd err on the side of what's fastest to compute (if
> that even matters here).

Ok, that's fine, we can stick to the spec

Cheers
/Ilias
> >
> >> +
> >> +       while ((data = va_arg(args, const u8 *)))
> >> +               sha1_update(&ctx, (char *)data, va_arg(args, int));
> >
> > sha1_update second argument is an unsigned int
>
> Ah thanks.
> >
> >> +
> >> +       va_end(args);
> >> +       sha1_finish(&ctx, hash);
> >> +
> >> +       /* Truncate the hash into output UUID and convert it to big endian */
> >> +       cpu_to_be32_array((u32 *)uuid, (u32 *)hash, 4);
> >> +
> >> +       /* Configure variant/version bits */
> >> +       clrsetbits_be16(&uuid->time_hi_and_version,
> >> +                       UUID_VERSION_MASK,
> >> +                       5 << UUID_VERSION_SHIFT);
> >> +       clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
> >> +                    UUID_VARIANT_MASK,
> >> +                    UUID_VARIANT << UUID_VARIANT_SHIFT);
> >> +}
> >> +#endif
> >> +
> >>   #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
> >>   void gen_rand_uuid(unsigned char *uuid_bin)
> >>   {
> >>          u32 ptr[4];
> >>
> >> --
> >> 2.44.0
> >>
> >
> > Thanks
> > /Ilias
>
> --
> // Caleb (they/them)
diff mbox series

Patch

diff --git a/include/uuid.h b/include/uuid.h
index f5a941250f48..229b938d866a 100644
--- a/include/uuid.h
+++ b/include/uuid.h
@@ -142,8 +142,24 @@  void gen_rand_uuid(unsigned char *uuid_bin);
  * @param          - uuid output type: UUID - 0, GUID - 1
  */
 void gen_rand_uuid_str(char *uuid_str, int str_format);
 
+#if CONFIG_IS_ENABLED(UUID_GEN_V5)
+/**
+ * gen_uuid_v5() - generate UUID v5 from namespace and other seed data.
+ *
+ * @namespace:   pointer to UUID namespace salt
+ * @uuid:        pointer to allocated UUID output
+ * @...:         NULL terminated list of seed data as pairs of pointers
+ *               to data and their lengths
+ */
+void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...);
+#else
+static inline void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...)
+{
+}
+#endif
+
 /**
  * uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
  * @uuid_str:	pointer to UUID string
  * @uuid_bin:	pointer to allocated array for little endian output [16B]
diff --git a/lib/Kconfig b/lib/Kconfig
index 189e6eb31aa1..2941532f25cf 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -80,8 +80,16 @@  config RANDOM_UUID
 	help
 	  Enable the generation of partitions with random UUIDs if none
 	  are provided.
 
+config UUID_GEN_V5
+	bool "Enable UUID version 5 generation"
+	select LIB_UUID
+	depends on SHA1
+	help
+	  Enable the generation of version 5 UUIDs, these are determistic and
+	  generated from a namespace UUID, and a string (such as a board name).
+
 config SPL_LIB_UUID
 	depends on SPL
 	bool
 
diff --git a/lib/uuid.c b/lib/uuid.c
index 2d7d99535e72..e7fda8dc736d 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -21,8 +21,9 @@ 
 #include <part_efi.h>
 #include <malloc.h>
 #include <dm/uclass.h>
 #include <rng.h>
+#include <u-boot/sha1.h>
 
 int uuid_str_valid(const char *uuid)
 {
 	int i, valid;
@@ -368,8 +369,40 @@  void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
 		}
 	}
 }
 
+#if CONFIG_IS_ENABLED(UUID_GEN_V5)
+void gen_uuid_v5(struct uuid *namespace, struct uuid *uuid, ...)
+{
+	sha1_context ctx;
+	va_list args;
+	const u8 *data;
+	u8 hash[SHA1_SUM_LEN];
+
+	sha1_starts(&ctx);
+	/* Hash the namespace UUID as salt */
+	sha1_update(&ctx, (char *)namespace, UUID_BIN_LEN);
+	va_start(args, uuid);
+
+	while ((data = va_arg(args, const u8 *)))
+		sha1_update(&ctx, (char *)data, va_arg(args, int));
+
+	va_end(args);
+	sha1_finish(&ctx, hash);
+
+	/* Truncate the hash into output UUID and convert it to big endian */
+	cpu_to_be32_array((u32 *)uuid, (u32 *)hash, 4);
+
+	/* Configure variant/version bits */
+	clrsetbits_be16(&uuid->time_hi_and_version,
+			UUID_VERSION_MASK,
+			5 << UUID_VERSION_SHIFT);
+	clrsetbits_8(&uuid->clock_seq_hi_and_reserved,
+		     UUID_VARIANT_MASK,
+		     UUID_VARIANT << UUID_VARIANT_SHIFT);
+}
+#endif
+
 #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
 void gen_rand_uuid(unsigned char *uuid_bin)
 {
 	u32 ptr[4];