/* * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "uuid.h" #include #include #include static uint8_t hex_to_nibble(char hex) { uint8_t nibble = 0; if (hex >= '0' && hex <= '9') { nibble = hex - '0'; } else { nibble = ((hex | 0x20) - 'a') + 10; } return nibble; } static char nibble_to_hex(uint8_t nibble) { char hex; nibble &= 0x0f; if (nibble <= 9) hex = '0' + nibble; else hex = 'a' + nibble - 10; return hex; } static uint8_t hex_to_byte(const char *hex) { /* Takes a validated input and returns the byte value */ uint8_t byte = hex_to_nibble(hex[0]) << 4; byte |= (hex_to_nibble(hex[1]) & 0x0f); return byte; } size_t uuid_is_valid(const char *canonical_form) { size_t valid_chars = 0; /* Note that a valid canonical uuid may be part of a longer string * such as a urn. */ size_t input_len = strnlen(canonical_form, UUID_CANONICAL_FORM_LEN); if (input_len == UUID_CANONICAL_FORM_LEN) { size_t i; valid_chars = UUID_CANONICAL_FORM_LEN; for (i = 0; i < UUID_CANONICAL_FORM_LEN; ++i) { if (i == 8 || i == 13 || i == 18 || i == 23) { if (canonical_form[i] != '-') return 0; } else { if (!isxdigit((int)canonical_form[i])) return 0; } } } return valid_chars; } bool uuid_is_equal(const uint8_t *octets_a, const uint8_t *octets_b) { return memcmp(octets_a, octets_b, UUID_OCTETS_LEN) == 0; } bool uuid_is_nil(const uint8_t *octets) { return memcmp(uuid_get_nil()->octets, octets, UUID_OCTETS_LEN) == 0; } const struct uuid_octets *uuid_get_nil(void) { static const struct uuid_octets nil_uuid = {0}; return &nil_uuid; } size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf_size) { size_t octet_index = 0; const char *pos; size_t valid_chars = uuid_is_valid(canonical_form); if ((buf_size < UUID_OCTETS_LEN) || (valid_chars != UUID_CANONICAL_FORM_LEN)) { /* Invalid input */ return 0; } /* * UUID string has been validates as having the following form: * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx * 4 2 2 2 6 */ pos = &canonical_form[0]; while (octet_index < 4) { buf[octet_index++] = hex_to_byte(pos); pos += 2; } pos = &canonical_form[9]; while (octet_index < 6) { buf[octet_index++] = hex_to_byte(pos); pos += 2; } pos = &canonical_form[14]; while (octet_index < 8) { buf[octet_index++] = hex_to_byte(pos); pos += 2; } pos = &canonical_form[19]; while (octet_index < 10) { buf[octet_index++] = hex_to_byte(pos); pos += 2; } pos = &canonical_form[24]; while (octet_index < 16) { buf[octet_index++] = hex_to_byte(pos); pos += 2; } return valid_chars; } /* * The byte order is reversed for the integer sections of the UUID. Converts * from standard to GUID octet representations an visa versa. */ void uuid_reverse_octets(const struct uuid_octets *input_octets, uint8_t *buf, size_t buf_size) { if (buf_size >= UUID_OCTETS_LEN) { /* Reverse bytes in each section */ buf[0] = input_octets->octets[3]; buf[1] = input_octets->octets[2]; buf[2] = input_octets->octets[1]; buf[3] = input_octets->octets[0]; buf[4] = input_octets->octets[5]; buf[5] = input_octets->octets[4]; buf[6] = input_octets->octets[7]; buf[7] = input_octets->octets[6]; buf[8] = input_octets->octets[8]; buf[9] = input_octets->octets[9]; buf[10] = input_octets->octets[10]; buf[11] = input_octets->octets[11]; buf[12] = input_octets->octets[12]; buf[13] = input_octets->octets[13]; buf[14] = input_octets->octets[14]; buf[15] = input_octets->octets[15]; } } size_t uuid_parse_to_guid_octets(const char *canonical_form, uint8_t *buf, size_t buf_size) { size_t valid_chars; struct uuid_octets standard_encoding; valid_chars = uuid_parse_to_octets(canonical_form, standard_encoding.octets, sizeof(standard_encoding.octets)); if (valid_chars == UUID_CANONICAL_FORM_LEN) { uuid_reverse_octets(&standard_encoding, buf, buf_size); } return valid_chars; } void uuid_octets_from_canonical(struct uuid_octets *uuid_octets, const char *canonical_form) { size_t valid_chars = uuid_parse_to_octets(canonical_form, uuid_octets->octets, sizeof(uuid_octets->octets)); /* Input string is assumed to be valid. Should not be used if canonical * string originates from an untrusted source. */ assert(valid_chars == UUID_CANONICAL_FORM_LEN); } void uuid_guid_octets_from_canonical(struct uuid_octets *uuid_octets, const char *canonical_form) { size_t valid_chars = uuid_parse_to_guid_octets(canonical_form, uuid_octets->octets, sizeof(uuid_octets->octets)); assert(valid_chars == UUID_CANONICAL_FORM_LEN); } void uuid_canonical_from_octets(struct uuid_canonical *canonical_form, const struct uuid_octets *uuid_octets) { unsigned int octet_index = 0; unsigned int char_index = 0; while (octet_index < UUID_OCTETS_LEN) { canonical_form->characters[char_index++] = nibble_to_hex(uuid_octets->octets[octet_index] >> 4); canonical_form->characters[char_index++] = nibble_to_hex(uuid_octets->octets[octet_index] & 0x0f); ++octet_index; if ((octet_index == 4) || (octet_index == 6) || (octet_index == 8) || (octet_index == 10)) canonical_form->characters[char_index++] = '-'; } canonical_form->characters[char_index] = '\0'; } void uuid_canonical_from_guid_octets(struct uuid_canonical *canonical_form, const struct uuid_octets *uuid_octets) { struct uuid_octets reversed_octets; uuid_reverse_octets(uuid_octets, reversed_octets.octets, sizeof(reversed_octets.octets)); uuid_canonical_from_octets(canonical_form, &reversed_octets); }