uuid.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. *
  3. * Embedded Linux library
  4. *
  5. * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25. #define _GNU_SOURCE
  26. #include <stdio.h>
  27. #include "checksum.h"
  28. #include "random.h"
  29. #include "private.h"
  30. #include "useful.h"
  31. #include "uuid.h"
  32. const uint8_t L_UUID_NAMESPACE_DNS[16] = {
  33. 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
  34. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  35. };
  36. const uint8_t L_UUID_NAMESPACE_URL[16] = {
  37. 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
  38. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  39. };
  40. const uint8_t L_UUID_NAMESPACE_OID[16] = {
  41. 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
  42. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  43. };
  44. const uint8_t L_UUID_NAMESPACE_X500[16] = {
  45. 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
  46. 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
  47. };
  48. /* RFC 4122, Section 4.3 */
  49. static bool name_from_namespace(int version, const uint8_t nsid[16],
  50. const void *name,
  51. size_t name_size, uint8_t out_uuid[16])
  52. {
  53. enum l_checksum_type type;
  54. struct l_checksum *hash;
  55. struct iovec iov[2];
  56. if (unlikely(!out_uuid))
  57. return false;
  58. switch (version) {
  59. case 3:
  60. type = L_CHECKSUM_MD5;
  61. break;
  62. case 5:
  63. type = L_CHECKSUM_SHA1;
  64. break;
  65. default:
  66. return false;
  67. }
  68. hash = l_checksum_new(type);
  69. if (!hash)
  70. return false;
  71. iov[0].iov_base = (void *) nsid;
  72. iov[0].iov_len = 16;
  73. iov[1].iov_base = (void *) name;
  74. iov[1].iov_len = name_size;
  75. /* Compute the hash of the name space ID concatenated with the name. */
  76. l_checksum_updatev(hash, iov, 2);
  77. /* o Set octets zero through 3 of the time_low field to octets zero
  78. * through 3 of the hash.
  79. *
  80. * o Set octets zero and one of the time_mid field to octets 4 and 5 of
  81. * the hash.
  82. *
  83. * o Set octets zero and one of the time_hi_and_version field to octets
  84. * 6 and 7 of the hash.
  85. * o Set the four most significant bits (bits 12 through 15) of the
  86. * time_hi_and_version field to the appropriate 4-bit version number
  87. * from Section 4.1.3.
  88. *
  89. * o Set the clock_seq_hi_and_reserved field to octet 8 of the hash.
  90. * o Set the two most significant bits (bits 6 and 7) of the
  91. * clock_seq_hi_and_reserved to zero and one, respectively.
  92. *
  93. * o Set the clock_seq_low field to octet 9 of the hash.
  94. *
  95. * o Set octets zero through five of the node field to octets 10
  96. * through 15 of the hash.
  97. */
  98. l_checksum_get_digest(hash, out_uuid, 16);
  99. /* Set 4 MSB bits of time_hi_and_version field */
  100. out_uuid[6] &= 0x0f;
  101. out_uuid[6] |= version << 4;
  102. /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */
  103. out_uuid[8] &= 0x3f;
  104. out_uuid[8] |= 0x80;
  105. l_checksum_free(hash);
  106. return true;
  107. }
  108. LIB_EXPORT bool l_uuid_v3(const uint8_t nsid[16], const void *name,
  109. size_t name_size, uint8_t out_uuid[16])
  110. {
  111. return name_from_namespace(3, nsid, name, name_size, out_uuid);
  112. }
  113. LIB_EXPORT bool l_uuid_v5(const uint8_t nsid[16], const void *name,
  114. size_t name_size, uint8_t out_uuid[16])
  115. {
  116. return name_from_namespace(5, nsid, name, name_size, out_uuid);
  117. }
  118. /* RFC 4122, Section 4.4 */
  119. LIB_EXPORT bool l_uuid_v4(uint8_t out_uuid[16])
  120. {
  121. if (unlikely(!out_uuid))
  122. return false;
  123. if (!l_getrandom(out_uuid, 16))
  124. return false;
  125. /*
  126. * o Set the two most significant bits (bits 6 and 7) of the
  127. * clock_seq_hi_and_reserved to zero and one, respectively.
  128. *
  129. * o Set the four most significant bits (bits 12 through 15) of the
  130. * time_hi_and_version field to the 4-bit version number from
  131. * Section 4.1.3.
  132. *
  133. * o Set all the other bits to randomly (or pseudo-randomly) chosen
  134. * values.
  135. */
  136. /* Set 4 MSB bits of time_hi_and_version field */
  137. out_uuid[6] &= 0x0f;
  138. out_uuid[6] |= 4 << 4;
  139. /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */
  140. out_uuid[8] &= 0x3f;
  141. out_uuid[8] |= 0x80;
  142. return true;
  143. }
  144. /**
  145. * l_uuid_is_valid:
  146. * @uuid: UUID to check.
  147. *
  148. * Checks whether the given UUID is valid according to RFC 4122. This function
  149. * checks that the version field is set properly and the variant of the UUID
  150. * is set to RFC 4122.
  151. *
  152. * Returns: Whether the UUID is valid
  153. **/
  154. LIB_EXPORT bool l_uuid_is_valid(const uint8_t uuid[16])
  155. {
  156. unsigned int version;
  157. unsigned int variant;
  158. if (!uuid)
  159. return false;
  160. variant = uuid[8] >> 6;
  161. if (variant != 2)
  162. return false;
  163. version = uuid[6] >> 4;
  164. if (version < 1 || version > 5)
  165. return false;
  166. return true;
  167. }
  168. LIB_EXPORT enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16])
  169. {
  170. unsigned int version;
  171. version = uuid[6] >> 4;
  172. return version;
  173. }
  174. LIB_EXPORT bool l_uuid_to_string(const uint8_t uuid[16],
  175. char *dest, size_t dest_size)
  176. {
  177. int n;
  178. n = snprintf(dest, dest_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
  179. "%02x%02x-%02x%02x%02x%02x%02x%02x",
  180. uuid[0], uuid[1], uuid[2], uuid[3],
  181. uuid[4], uuid[5],
  182. uuid[6], uuid[7],
  183. uuid[8], uuid[9],
  184. uuid[10], uuid[11], uuid[12],
  185. uuid[13], uuid[14], uuid[15]);
  186. if (n < 0 || (size_t) n >= dest_size)
  187. return false;
  188. return true;
  189. }
  190. LIB_EXPORT bool l_uuid_from_string(const char *src, uint8_t uuid[16])
  191. {
  192. uint8_t buf[16];
  193. int n;
  194. /*
  195. * textual representation: 32 hex digits + 4 group separators
  196. */
  197. if (strlen(src) < 16 * 2 + 4)
  198. return false;
  199. n = sscanf(src,
  200. "%02hhx%02hhx%02hhx%02hhx-"
  201. "%02hhx%02hhx-"
  202. "%02hhx%02hhx-"
  203. "%02hhx%02hhx-"
  204. "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
  205. &buf[0], &buf[1], &buf[2], &buf[3],
  206. &buf[4], &buf[5],
  207. &buf[6], &buf[7],
  208. &buf[8], &buf[9],
  209. &buf[10], &buf[11], &buf[12],
  210. &buf[13], &buf[14], &buf[15]);
  211. if (n != 16)
  212. return false;
  213. if (!l_uuid_is_valid(buf))
  214. return false;
  215. memcpy(uuid, buf, sizeof(buf));
  216. return true;
  217. }