| /* |
| * |
| * Embedded Linux library |
| * |
| * Copyright (C) 2011-2014 Intel Corporation. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #define _GNU_SOURCE |
| #include <stdio.h> |
| |
| #include "checksum.h" |
| #include "random.h" |
| #include "private.h" |
| #include "uuid.h" |
| |
| const uint8_t L_UUID_NAMESPACE_DNS[16] = { |
| 0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, |
| 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, |
| }; |
| |
| const uint8_t L_UUID_NAMESPACE_URL[16] = { |
| 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, |
| 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, |
| }; |
| |
| const uint8_t L_UUID_NAMESPACE_OID[16] = { |
| 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, |
| 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, |
| }; |
| |
| const uint8_t L_UUID_NAMESPACE_X500[16] = { |
| 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, |
| 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8, |
| }; |
| |
| /* RFC 4122, Section 4.3 */ |
| static bool name_from_namespace(int version, const uint8_t nsid[16], |
| const void *name, |
| size_t name_size, uint8_t out_uuid[16]) |
| { |
| enum l_checksum_type type; |
| struct l_checksum *hash; |
| struct iovec iov[2]; |
| |
| if (unlikely(!out_uuid)) |
| return false; |
| |
| switch (version) { |
| case 3: |
| type = L_CHECKSUM_MD5; |
| break; |
| case 5: |
| type = L_CHECKSUM_SHA1; |
| break; |
| default: |
| return false; |
| } |
| |
| hash = l_checksum_new(type); |
| if (!hash) |
| return false; |
| |
| iov[0].iov_base = (void *) nsid; |
| iov[0].iov_len = 16; |
| iov[1].iov_base = (void *) name; |
| iov[1].iov_len = name_size; |
| |
| /* Compute the hash of the name space ID concatenated with the name. */ |
| l_checksum_updatev(hash, iov, 2); |
| |
| /* o Set octets zero through 3 of the time_low field to octets zero |
| * through 3 of the hash. |
| * |
| * o Set octets zero and one of the time_mid field to octets 4 and 5 of |
| * the hash. |
| * |
| * o Set octets zero and one of the time_hi_and_version field to octets |
| * 6 and 7 of the hash. |
| * o Set the four most significant bits (bits 12 through 15) of the |
| * time_hi_and_version field to the appropriate 4-bit version number |
| * from Section 4.1.3. |
| * |
| * o Set the clock_seq_hi_and_reserved field to octet 8 of the hash. |
| * o Set the two most significant bits (bits 6 and 7) of the |
| * clock_seq_hi_and_reserved to zero and one, respectively. |
| * |
| * o Set the clock_seq_low field to octet 9 of the hash. |
| * |
| * o Set octets zero through five of the node field to octets 10 |
| * through 15 of the hash. |
| */ |
| |
| l_checksum_get_digest(hash, out_uuid, 16); |
| |
| /* Set 4 MSB bits of time_hi_and_version field */ |
| out_uuid[6] &= 0x0f; |
| out_uuid[6] |= version << 4; |
| |
| /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ |
| out_uuid[8] &= 0x3f; |
| out_uuid[8] |= 0x80; |
| |
| l_checksum_free(hash); |
| |
| return true; |
| } |
| |
| LIB_EXPORT bool l_uuid_v3(const uint8_t nsid[16], const void *name, |
| size_t name_size, uint8_t out_uuid[16]) |
| { |
| return name_from_namespace(3, nsid, name, name_size, out_uuid); |
| } |
| |
| LIB_EXPORT bool l_uuid_v5(const uint8_t nsid[16], const void *name, |
| size_t name_size, uint8_t out_uuid[16]) |
| { |
| return name_from_namespace(5, nsid, name, name_size, out_uuid); |
| } |
| |
| /* RFC 4122, Section 4.4 */ |
| LIB_EXPORT bool l_uuid_v4(uint8_t out_uuid[16]) |
| { |
| if (unlikely(!out_uuid)) |
| return false; |
| |
| if (!l_getrandom(out_uuid, 16)) |
| return false; |
| |
| /* |
| * o Set the two most significant bits (bits 6 and 7) of the |
| * clock_seq_hi_and_reserved to zero and one, respectively. |
| * |
| * o Set the four most significant bits (bits 12 through 15) of the |
| * time_hi_and_version field to the 4-bit version number from |
| * Section 4.1.3. |
| * |
| * o Set all the other bits to randomly (or pseudo-randomly) chosen |
| * values. |
| */ |
| |
| /* Set 4 MSB bits of time_hi_and_version field */ |
| out_uuid[6] &= 0x0f; |
| out_uuid[6] |= 4 << 4; |
| |
| /* Set 2 MSB of clock_seq_hi_and_reserved to 10 */ |
| out_uuid[8] &= 0x3f; |
| out_uuid[8] |= 0x80; |
| |
| return true; |
| } |
| |
| /** |
| * l_uuid_is_valid: |
| * @uuid: UUID to check. |
| * |
| * Checks whether the given UUID is valid according to RFC 4122. This function |
| * checks that the version field is set properly and the variant of the UUID |
| * is set to RFC 4122. |
| * |
| * Returns: Whether the UUID is valid |
| **/ |
| LIB_EXPORT bool l_uuid_is_valid(const uint8_t uuid[16]) |
| { |
| unsigned int version; |
| unsigned int variant; |
| |
| if (!uuid) |
| return false; |
| |
| variant = uuid[8] >> 6; |
| if (variant != 2) |
| return false; |
| |
| version = uuid[6] >> 4; |
| if (version < 1 || version > 5) |
| return false; |
| |
| return true; |
| } |
| |
| LIB_EXPORT enum l_uuid_version l_uuid_get_version(const uint8_t uuid[16]) |
| { |
| unsigned int version; |
| |
| version = uuid[6] >> 4; |
| return version; |
| } |
| |
| LIB_EXPORT bool l_uuid_to_string(const uint8_t uuid[16], |
| char *dest, size_t dest_size) |
| { |
| int n; |
| |
| n = snprintf(dest, dest_size, "%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| "%02x%02x-%02x%02x%02x%02x%02x%02x", |
| uuid[0], uuid[1], uuid[2], uuid[3], |
| uuid[4], uuid[5], |
| uuid[6], uuid[7], |
| uuid[8], uuid[9], |
| uuid[10], uuid[11], uuid[12], |
| uuid[13], uuid[14], uuid[15]); |
| |
| if (n < 0 || (size_t) n >= dest_size) |
| return false; |
| |
| return true; |
| } |
| |
| LIB_EXPORT bool l_uuid_from_string(const char *src, uint8_t uuid[16]) |
| { |
| uint8_t buf[16]; |
| int n; |
| |
| /* |
| * textual representation: 32 hex digits + 4 group separators |
| */ |
| if (strlen(src) < 16 * 2 + 4) |
| return false; |
| |
| n = sscanf(src, |
| "%02hhx%02hhx%02hhx%02hhx-" |
| "%02hhx%02hhx-" |
| "%02hhx%02hhx-" |
| "%02hhx%02hhx-" |
| "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", |
| &buf[0], &buf[1], &buf[2], &buf[3], |
| &buf[4], &buf[5], |
| &buf[6], &buf[7], |
| &buf[8], &buf[9], |
| &buf[10], &buf[11], &buf[12], |
| &buf[13], &buf[14], &buf[15]); |
| |
| if (n != 16) |
| return false; |
| |
| if (!l_uuid_is_valid(buf)) |
| return false; |
| |
| memcpy(uuid, buf, sizeof(buf)); |
| return true; |
| } |