1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2018 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/uuid.h" 7 #include "spdk/config.h" 8 #include "spdk/log.h" 9 10 #ifndef SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 11 #include <openssl/evp.h> 12 #endif /* SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 */ 13 14 #ifndef __FreeBSD__ 15 16 #include <uuid/uuid.h> 17 18 SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == sizeof(uuid_t), "Size mismatch"); 19 20 int 21 spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str) 22 { 23 return uuid_parse(uuid_str, (void *)uuid) == 0 ? 0 : -EINVAL; 24 } 25 26 int 27 spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid) 28 { 29 if (uuid_str_size < SPDK_UUID_STRING_LEN) { 30 return -EINVAL; 31 } 32 33 uuid_unparse_lower((void *)uuid, uuid_str); 34 return 0; 35 } 36 37 int 38 spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2) 39 { 40 return uuid_compare((void *)u1, (void *)u2); 41 } 42 43 void 44 spdk_uuid_generate(struct spdk_uuid *uuid) 45 { 46 uuid_generate((void *)uuid); 47 } 48 49 void 50 spdk_uuid_copy(struct spdk_uuid *dst, const struct spdk_uuid *src) 51 { 52 uuid_copy((void *)dst, (void *)src); 53 } 54 55 bool 56 spdk_uuid_is_null(const struct spdk_uuid *uuid) 57 { 58 return uuid_is_null((void *)uuid); 59 } 60 61 void 62 spdk_uuid_set_null(struct spdk_uuid *uuid) 63 { 64 uuid_clear((void *)uuid); 65 } 66 67 #else 68 69 #include <uuid.h> 70 71 SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == sizeof(uuid_t), "Size mismatch"); 72 73 int 74 spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str) 75 { 76 uint32_t status; 77 78 /* uuid_from_string() differs from uuid_parse() in the way it handles empty strings: the 79 * former succeeds and returns a NULL UUID, while the latter treats is an error and returns 80 * non-zero exit code. So, to keep the behavior consistent between Linux and FreeBSD, we 81 * explicitly check for an empty string here. 82 */ 83 if (strlen(uuid_str) == 0) { 84 return -EINVAL; 85 } 86 87 uuid_from_string(uuid_str, (uuid_t *)uuid, &status); 88 89 return status == 0 ? 0 : -EINVAL; 90 } 91 92 int 93 spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid) 94 { 95 uint32_t status; 96 char *str; 97 98 if (uuid_str_size < SPDK_UUID_STRING_LEN) { 99 return -EINVAL; 100 } 101 102 uuid_to_string((const uuid_t *)uuid, &str, &status); 103 104 if (status == uuid_s_no_memory) { 105 return -ENOMEM; 106 } 107 108 snprintf(uuid_str, uuid_str_size, "%s", str); 109 free(str); 110 111 return 0; 112 } 113 114 int 115 spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2) 116 { 117 return uuid_compare((const uuid_t *)u1, (const uuid_t *)u2, NULL); 118 } 119 120 void 121 spdk_uuid_generate(struct spdk_uuid *uuid) 122 { 123 uuid_create((uuid_t *)uuid, NULL); 124 } 125 126 void 127 spdk_uuid_copy(struct spdk_uuid *dst, const struct spdk_uuid *src) 128 { 129 memcpy(dst, src, sizeof(*dst)); 130 } 131 132 bool 133 spdk_uuid_is_null(const struct spdk_uuid *uuid) 134 { 135 return uuid_is_nil((const uuid_t *)uuid, NULL); 136 } 137 138 void 139 spdk_uuid_set_null(struct spdk_uuid *uuid) 140 { 141 uuid_create_nil((uuid_t *)uuid, NULL); 142 } 143 144 #endif 145 146 int 147 spdk_uuid_generate_sha1(struct spdk_uuid *uuid, struct spdk_uuid *ns_uuid, const char *name, 148 size_t len) 149 { 150 #ifdef SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 151 uuid_generate_sha1((void *)uuid, (void *)ns_uuid, name, len); 152 return 0; 153 #else 154 EVP_MD_CTX *mdctx; 155 const EVP_MD *md; 156 unsigned char md_value[EVP_MAX_MD_SIZE]; 157 unsigned int md_len; 158 159 md = EVP_sha1(); 160 assert(md != NULL); 161 162 mdctx = EVP_MD_CTX_new(); 163 if (mdctx == NULL) { 164 return -ENOMEM; 165 } 166 167 if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) { 168 SPDK_ERRLOG("Could not initialize EVP digest!\n"); 169 goto err; 170 } 171 if (EVP_DigestUpdate(mdctx, ns_uuid, sizeof(struct spdk_uuid)) != 1) { 172 SPDK_ERRLOG("Could update EVP digest with namespace UUID!\n"); 173 goto err; 174 } 175 if (EVP_DigestUpdate(mdctx, name, len) != 1) { 176 SPDK_ERRLOG("Could update EVP digest with assigned name!\n"); 177 goto err; 178 } 179 if (EVP_DigestFinal_ex(mdctx, md_value, &md_len) != 1) { 180 SPDK_ERRLOG("Could not generate EVP digest!\n"); 181 goto err; 182 } 183 EVP_MD_CTX_free(mdctx); 184 185 memcpy(uuid, md_value, 16); 186 /* This part mimics original uuid_generate_sha1() from libuuid/src/gen_uuid.c. 187 * The original uuid structure included from uuid.h looks like this: 188 * struct uuid { 189 * uint32_t time_low; 190 * uint16_t time_mid; 191 * uint16_t time_hi_and_version; 192 * uint16_t clock_seq; 193 * uint8_t node[6]; 194 * }; 195 * so uuid->u.raw[6] and uuid->u.raw[8] are time_hi_and_version and clock_seq respectively. 196 */ 197 uuid->u.raw[6] = (uuid->u.raw[6] & 0x0f) | 0x50; 198 uuid->u.raw[8] = (uuid->u.raw[8] & 0x3f) | 0x80; 199 200 return 0; 201 202 err: 203 EVP_MD_CTX_free(mdctx); 204 return -EINVAL; 205 206 #endif /* SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 */ 207 } 208