blob: 7bf33ede8152e6249e1800d82f49db99822ed422 [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
26static uint8_t hex_to_byte(const char *hex)
27{
28 /* Takes a validated input and returns the byte value */
29 uint8_t byte = hex_to_nibble(hex[0]) << 4;
30 byte |= (hex_to_nibble(hex[1]) & 0x0f);
31 return byte;
32}
Julian Halla7e89b02020-11-23 17:33:31 +010033
34size_t uuid_is_valid(const char *canonical_form)
35{
Julian Hall7d7b24c2021-08-13 13:40:38 +010036 size_t valid_chars = 0;
Julian Halla7e89b02020-11-23 17:33:31 +010037
Julian Hall31d4fdd2022-12-01 16:52:01 +000038 /* Note that a vaild canonical uuid may be part of a longer string
39 * such as a urn.
40 */
41 size_t input_len = strnlen(canonical_form, UUID_CANONICAL_FORM_LEN);
42
43 if (input_len == UUID_CANONICAL_FORM_LEN) {
Julian Halla7e89b02020-11-23 17:33:31 +010044
Julian Hall7d7b24c2021-08-13 13:40:38 +010045 size_t i;
46 valid_chars = UUID_CANONICAL_FORM_LEN;
Julian Halla7e89b02020-11-23 17:33:31 +010047
Julian Hall7d7b24c2021-08-13 13:40:38 +010048 for (i = 0; i < UUID_CANONICAL_FORM_LEN; ++i) {
Julian Halla7e89b02020-11-23 17:33:31 +010049
Julian Hall7d7b24c2021-08-13 13:40:38 +010050 if (i == 8 || i == 13 || i == 18 || i == 23) {
51 if (canonical_form[i] != '-') return 0;
52 }
53 else {
Julian Hall31d4fdd2022-12-01 16:52:01 +000054 if (!isxdigit((int)canonical_form[i])) return 0;
Julian Hall7d7b24c2021-08-13 13:40:38 +010055 }
56 }
57 }
Julian Halla7e89b02020-11-23 17:33:31 +010058
Julian Hall7d7b24c2021-08-13 13:40:38 +010059 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +010060}
61
Julian Hall31d4fdd2022-12-01 16:52:01 +000062bool uuid_is_equal(const uint8_t *octets_a, const uint8_t *octets_b)
63{
64 return memcmp(octets_a, octets_b, UUID_OCTETS_LEN) == 0;
65}
66
67bool uuid_is_nil(const uint8_t *octets)
68{
69 return memcmp(uuid_get_nil()->octets, octets, UUID_OCTETS_LEN) == 0;
70}
71
72const struct uuid_octets *uuid_get_nil(void)
73{
74 static const struct uuid_octets nil_uuid = {0};
75
76 return &nil_uuid;
77}
78
Julian Halla7e89b02020-11-23 17:33:31 +010079size_t uuid_parse_to_octets(const char *canonical_form, uint8_t *buf, size_t buf_size)
80{
Julian Hall7d7b24c2021-08-13 13:40:38 +010081 size_t octet_index = 0;
82 const char *pos;
83 size_t valid_chars = uuid_is_valid(canonical_form);
Julian Halla7e89b02020-11-23 17:33:31 +010084
Julian Hall7d7b24c2021-08-13 13:40:38 +010085 if ((buf_size < UUID_OCTETS_LEN) ||
86 (valid_chars != UUID_CANONICAL_FORM_LEN)) {
87 /* Invalid input */
88 return 0;
89 }
Julian Halla7e89b02020-11-23 17:33:31 +010090
Julian Hall7d7b24c2021-08-13 13:40:38 +010091 /*
92 * UUID string has been validates as having the following form:
93 * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
94 * 4 2 2 2 6
95 */
96 pos = &canonical_form[0];
97 while (octet_index < 4) {
98 buf[octet_index++] = hex_to_byte(pos);
99 pos += 2;
100 }
Julian Halla7e89b02020-11-23 17:33:31 +0100101
Julian Hall7d7b24c2021-08-13 13:40:38 +0100102 pos = &canonical_form[9];
103 while (octet_index < 6) {
104 buf[octet_index++] = hex_to_byte(pos);
105 pos += 2;
106 }
Julian Halla7e89b02020-11-23 17:33:31 +0100107
Julian Hall7d7b24c2021-08-13 13:40:38 +0100108 pos = &canonical_form[14];
109 while (octet_index < 8) {
110 buf[octet_index++] = hex_to_byte(pos);
111 pos += 2;
112 }
Julian Halla7e89b02020-11-23 17:33:31 +0100113
Julian Hall7d7b24c2021-08-13 13:40:38 +0100114 pos = &canonical_form[19];
115 while (octet_index < 10) {
116 buf[octet_index++] = hex_to_byte(pos);
117 pos += 2;
118 }
Julian Halla7e89b02020-11-23 17:33:31 +0100119
Julian Hall7d7b24c2021-08-13 13:40:38 +0100120 pos = &canonical_form[24];
121 while (octet_index < 16) {
122 buf[octet_index++] = hex_to_byte(pos);
123 pos += 2;
124 }
Julian Halla7e89b02020-11-23 17:33:31 +0100125
Julian Hall7d7b24c2021-08-13 13:40:38 +0100126 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +0100127}
128
129/*
Julian Hall31d4fdd2022-12-01 16:52:01 +0000130 * The byte order is reversed for the integer sections of the UUID. Converts
131 * from standard to GUID octet representations an visa versa.
Julian Halla7e89b02020-11-23 17:33:31 +0100132 */
Julian Hall31d4fdd2022-12-01 16:52:01 +0000133void uuid_reverse_octets(const struct uuid_octets *input_octets,
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100134 uint8_t *buf, size_t buf_size)
135{
136 if (buf_size >= UUID_OCTETS_LEN) {
137 /* Reverse bytes in each section */
Julian Hall31d4fdd2022-12-01 16:52:01 +0000138 buf[0] = input_octets->octets[3];
139 buf[1] = input_octets->octets[2];
140 buf[2] = input_octets->octets[1];
141 buf[3] = input_octets->octets[0];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100142
Julian Hall31d4fdd2022-12-01 16:52:01 +0000143 buf[4] = input_octets->octets[5];
144 buf[5] = input_octets->octets[4];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100145
Julian Hall31d4fdd2022-12-01 16:52:01 +0000146 buf[6] = input_octets->octets[7];
147 buf[7] = input_octets->octets[6];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100148
Julian Hall31d4fdd2022-12-01 16:52:01 +0000149 buf[8] = input_octets->octets[8];
150 buf[9] = input_octets->octets[9];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100151
Julian Hall31d4fdd2022-12-01 16:52:01 +0000152 buf[10] = input_octets->octets[10];
153 buf[11] = input_octets->octets[11];
154 buf[12] = input_octets->octets[12];
155 buf[13] = input_octets->octets[13];
156 buf[14] = input_octets->octets[14];
157 buf[15] = input_octets->octets[15];
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100158 }
159}
160
Julian Hall31d4fdd2022-12-01 16:52:01 +0000161size_t uuid_parse_to_guid_octets(const char *canonical_form,
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100162 uint8_t *buf, size_t buf_size)
Julian Halla7e89b02020-11-23 17:33:31 +0100163{
Julian Hall7d7b24c2021-08-13 13:40:38 +0100164 size_t valid_chars;
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100165 struct uuid_octets standard_encoding;
Julian Halla7e89b02020-11-23 17:33:31 +0100166
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100167 valid_chars = uuid_parse_to_octets(canonical_form,
168 standard_encoding.octets, sizeof(standard_encoding.octets));
Julian Halla7e89b02020-11-23 17:33:31 +0100169
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100170 if (valid_chars == UUID_CANONICAL_FORM_LEN) {
Julian Halla7e89b02020-11-23 17:33:31 +0100171
Julian Hall7c2ae0c2022-09-29 08:27:07 +0100172 uuid_reverse_octets(&standard_encoding, buf, buf_size);
Julian Hall7d7b24c2021-08-13 13:40:38 +0100173 }
Julian Halla7e89b02020-11-23 17:33:31 +0100174
Julian Hall7d7b24c2021-08-13 13:40:38 +0100175 return valid_chars;
Julian Halla7e89b02020-11-23 17:33:31 +0100176}
Julian Hall31d4fdd2022-12-01 16:52:01 +0000177
178void uuid_octets_from_canonical(struct uuid_octets *uuid_octets,
179 const char *canonical_form)
180{
181 size_t valid_chars = uuid_parse_to_octets(canonical_form,
182 uuid_octets->octets, sizeof(uuid_octets->octets));
183
184 /* Input string is assumed to be valid. Should not be used if canonical
185 * string originates from an untrusted source.
186 */
187 assert(valid_chars == UUID_CANONICAL_FORM_LEN);
188}
189
190void uuid_guid_octets_from_canonical(struct uuid_octets *uuid_octets,
191 const char *canonical_form)
192{
193 size_t valid_chars = uuid_parse_to_guid_octets(canonical_form,
194 uuid_octets->octets, sizeof(uuid_octets->octets));
195
196 assert(valid_chars == UUID_CANONICAL_FORM_LEN);
197}