blob: 6d26cfa031fbeb6c252ef391d2396ebdff0de821 [file] [log] [blame]
Julian Halla7e89b02020-11-23 17:33:31 +01001/*
Julian Hall31d4fdd2022-12-01 16:52:01 +00002 * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
Julian Halla7e89b02020-11-23 17:33:31 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "uuid.h"
Julian Hall31d4fdd2022-12-01 16:52:01 +00008#include <assert.h>
Julian Halla7e89b02020-11-23 17:33:31 +01009#include <string.h>
10#include <ctype.h>
Julian Hall7d7b24c2021-08-13 13:40:38 +010011
12static uint8_t hex_to_nibble(char hex)
13{
14 uint8_t nibble = 0;
15
16 if (hex >= '0' && hex <= '9') {
17 nibble = hex - '0';
18 }
19 else {
20 nibble = ((hex | 0x20) - 'a') + 10;
21 }
22
23 return nibble;
24}
25
Julian Hall1df937d2023-03-21 10:34:36 +000026static char nibble_to_hex(uint8_t nibble)
27{
28 char hex;
29
30 nibble &= 0x0f;
31
32 if (nibble <= 9)
33 hex = '0' + nibble;
34 else
35 hex = 'a' + nibble - 10;
36
37 return hex;
38}
39
Julian Hall7d7b24c2021-08-13 13:40:38 +010040static uint8_t hex_to_byte(const char *hex)
41{
42 /* Takes a validated input and returns the byte value */
43 uint8_t byte = hex_to_nibble(hex[0]) << 4;
44 byte |= (hex_to_nibble(hex[1]) & 0x0f);
45 return byte;
46}
Julian Halla7e89b02020-11-23 17:33:31 +010047
48size_t uuid_is_valid(const char *canonical_form)
49{
Julian Hall7d7b24c2021-08-13 13:40:38 +010050 size_t valid_chars = 0;
Julian Halla7e89b02020-11-23 17:33:31 +010051
Julian Hall1df937d2023-03-21 10:34:36 +000052 /* Note that a valid canonical uuid may be part of a longer string
Julian Hall31d4fdd2022-12-01 16:52:01 +000053 * such as a urn.
54 */
55 size_t input_len = strnlen(canonical_form, UUID_CANONICAL_FORM_LEN);
56
57 if (input_len == UUID_CANONICAL_FORM_LEN) {
Julian Halla7e89b02020-11-23 17:33:31 +010058
Julian Hall7d7b24c2021-08-13 13:40:38 +010059 size_t i;
60 valid_chars = UUID_CANONICAL_FORM_LEN;
Julian Halla7e89b02020-11-23 17:33:31 +010061
Julian Hall7d7b24c2021-08-13 13:40:38 +010062 for (i = 0; i < UUID_CANONICAL_FORM_LEN; ++i) {
Julian Halla7e89b02020-11-23 17:33:31 +010063
Julian Hall7d7b24c2021-08-13 13:40:38 +010064 if (i == 8 || i == 13 || i == 18 || i == 23) {
65 if (canonical_form[i] != '-') return 0;
66 }
67 else {
Julian Hall31d4fdd2022-12-01 16:52:01 +000068 if (!isxdigit((int)canonical_form[i])) return 0;
Julian Hall7d7b24c2021-08-13 13:40:38 +010069 }
70 }
71 }
Julian Halla7e89b02020-11-23 17:33:31 +010072
Julian Hall7d7b24c2021-08-13 13:40:38 +010073 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +010074}
75
Julian Hall31d4fdd2022-12-01 16:52:01 +000076bool uuid_is_equal(const uint8_t *octets_a, const uint8_t *octets_b)
77{
78 return memcmp(octets_a, octets_b, UUID_OCTETS_LEN) == 0;
79}
80
81bool uuid_is_nil(const uint8_t *octets)
82{
83 return memcmp(uuid_get_nil()->octets, octets, UUID_OCTETS_LEN) == 0;
84}
85
86const struct uuid_octets *uuid_get_nil(void)
87{
88 static const struct uuid_octets nil_uuid = {0};
89
90 return &nil_uuid;
91}
92
Julian Halla7e89b02020-11-23 17:33:31 +010093size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf_size)
94{
Julian Hall7d7b24c2021-08-13 13:40:38 +010095 size_t octet_index = 0;
96 const char *pos;
97 size_t valid_chars = uuid_is_valid(canonical_form);
Julian Halla7e89b02020-11-23 17:33:31 +010098
Julian Hall7d7b24c2021-08-13 13:40:38 +010099 if ((buf_size < UUID_OCTETS_LEN) ||
100 (valid_chars != UUID_CANONICAL_FORM_LEN)) {
101 /* Invalid input */
102 return 0;
103 }
Julian Halla7e89b02020-11-23 17:33:31 +0100104
Julian Hall7d7b24c2021-08-13 13:40:38 +0100105 /*
106 * UUID string has been validates as having the following form:
107 * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
108 * 4 2 2 2 6
109 */
110 pos = &canonical_form[0];
111 while (octet_index < 4) {
112 buf[octet_index++] = hex_to_byte(pos);
113 pos += 2;
114 }
Julian Halla7e89b02020-11-23 17:33:31 +0100115
Julian Hall7d7b24c2021-08-13 13:40:38 +0100116 pos = &canonical_form[9];
117 while (octet_index < 6) {
118 buf[octet_index++] = hex_to_byte(pos);
119 pos += 2;
120 }
Julian Halla7e89b02020-11-23 17:33:31 +0100121
Julian Hall7d7b24c2021-08-13 13:40:38 +0100122 pos = &canonical_form[14];
123 while (octet_index < 8) {
124 buf[octet_index++] = hex_to_byte(pos);
125 pos += 2;
126 }
Julian Halla7e89b02020-11-23 17:33:31 +0100127
Julian Hall7d7b24c2021-08-13 13:40:38 +0100128 pos = &canonical_form[19];
129 while (octet_index < 10) {
130 buf[octet_index++] = hex_to_byte(pos);
131 pos += 2;
132 }
Julian Halla7e89b02020-11-23 17:33:31 +0100133
Julian Hall7d7b24c2021-08-13 13:40:38 +0100134 pos = &canonical_form[24];
135 while (octet_index < 16) {
136 buf[octet_index++] = hex_to_byte(pos);
137 pos += 2;
138 }
Julian Halla7e89b02020-11-23 17:33:31 +0100139
Julian Hall7d7b24c2021-08-13 13:40:38 +0100140 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +0100141}
142
143/*
Julian Hall31d4fdd2022-12-01 16:52:01 +0000144 * The byte order is reversed for the integer sections of the UUID. Converts
145 * from standard to GUID octet representations an visa versa.
Julian Halla7e89b02020-11-23 17:33:31 +0100146 */
Julian Hall31d4fdd2022-12-01 16:52:01 +0000147void uuid_reverse_octets(const struct uuid_octets *input_octets,
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100148 uint8_t *buf, size_t buf_size)
149{
150 if (buf_size >= UUID_OCTETS_LEN) {
151 /* Reverse bytes in each section */
Julian Hall31d4fdd2022-12-01 16:52:01 +0000152 buf[0] = input_octets->octets[3];
153 buf[1] = input_octets->octets[2];
154 buf[2] = input_octets->octets[1];
155 buf[3] = input_octets->octets[0];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100156
Julian Hall31d4fdd2022-12-01 16:52:01 +0000157 buf[4] = input_octets->octets[5];
158 buf[5] = input_octets->octets[4];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100159
Julian Hall31d4fdd2022-12-01 16:52:01 +0000160 buf[6] = input_octets->octets[7];
161 buf[7] = input_octets->octets[6];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100162
Julian Hall31d4fdd2022-12-01 16:52:01 +0000163 buf[8] = input_octets->octets[8];
164 buf[9] = input_octets->octets[9];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100165
Julian Hall31d4fdd2022-12-01 16:52:01 +0000166 buf[10] = input_octets->octets[10];
167 buf[11] = input_octets->octets[11];
168 buf[12] = input_octets->octets[12];
169 buf[13] = input_octets->octets[13];
170 buf[14] = input_octets->octets[14];
171 buf[15] = input_octets->octets[15];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100172 }
173}
174
Julian Hall31d4fdd2022-12-01 16:52:01 +0000175size_t uuid_parse_to_guid_octets(const char *canonical_form,
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100176 uint8_t *buf, size_t buf_size)
Julian Halla7e89b02020-11-23 17:33:31 +0100177{
Julian Hall7d7b24c2021-08-13 13:40:38 +0100178 size_t valid_chars;
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100179 struct uuid_octets standard_encoding;
Julian Halla7e89b02020-11-23 17:33:31 +0100180
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100181 valid_chars = uuid_parse_to_octets(canonical_form,
182 standard_encoding.octets, sizeof(standard_encoding.octets));
Julian Halla7e89b02020-11-23 17:33:31 +0100183
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100184 if (valid_chars == UUID_CANONICAL_FORM_LEN) {
Julian Halla7e89b02020-11-23 17:33:31 +0100185
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100186 uuid_reverse_octets(&standard_encoding, buf, buf_size);
Julian Hall7d7b24c2021-08-13 13:40:38 +0100187 }
Julian Halla7e89b02020-11-23 17:33:31 +0100188
Julian Hall7d7b24c2021-08-13 13:40:38 +0100189 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +0100190}
Julian Hall31d4fdd2022-12-01 16:52:01 +0000191
192void uuid_octets_from_canonical(struct uuid_octets *uuid_octets,
193 const char *canonical_form)
194{
195 size_t valid_chars = uuid_parse_to_octets(canonical_form,
196 uuid_octets->octets, sizeof(uuid_octets->octets));
197
198 /* Input string is assumed to be valid. Should not be used if canonical
199 * string originates from an untrusted source.
200 */
201 assert(valid_chars == UUID_CANONICAL_FORM_LEN);
202}
203
204void uuid_guid_octets_from_canonical(struct uuid_octets *uuid_octets,
205 const char *canonical_form)
206{
207 size_t valid_chars = uuid_parse_to_guid_octets(canonical_form,
208 uuid_octets->octets, sizeof(uuid_octets->octets));
209
210 assert(valid_chars == UUID_CANONICAL_FORM_LEN);
211}
Julian Hall1df937d2023-03-21 10:34:36 +0000212
213void uuid_canonical_from_octets(struct uuid_canonical *canonical_form,
214 const struct uuid_octets *uuid_octets)
215{
216 unsigned int octet_index = 0;
217 unsigned int char_index = 0;
218
219 while (octet_index < UUID_OCTETS_LEN) {
220
221 canonical_form->characters[char_index++] =
222 nibble_to_hex(uuid_octets->octets[octet_index] >> 4);
223
224 canonical_form->characters[char_index++] =
225 nibble_to_hex(uuid_octets->octets[octet_index] & 0x0f);
226
227 ++octet_index;
228
229 if ((octet_index == 4) ||
230 (octet_index == 6) ||
231 (octet_index == 8) ||
232 (octet_index == 10))
233 canonical_form->characters[char_index++] = '-';
234 }
235
236 canonical_form->characters[char_index] = '\0';
237}
238
239void uuid_canonical_from_guid_octets(struct uuid_canonical *canonical_form,
240 const struct uuid_octets *uuid_octets)
241{
242 struct uuid_octets reversed_octets;
243
244 uuid_reverse_octets(uuid_octets, reversed_octets.octets, sizeof(reversed_octets.octets));
245 uuid_canonical_from_octets(canonical_form, &reversed_octets);
246}