| // SPDX-License-Identifier: BSD-2-Clause |
| /* |
| * Copyright (c) 2019, Linaro Limited |
| */ |
| |
| #include <ctype.h> |
| #include <endian.h> |
| #ifdef OPENSSL_FOUND |
| #include <openssl/evp.h> |
| #endif |
| #include <stdint.h> |
| #include <string.h> |
| #include <tee_api_types.h> |
| #include <tee_client_api.h> |
| #include "xtest_uuid_helpers.h" |
| |
| static int hex(char c) |
| { |
| char lc = tolower(c); |
| |
| if (isdigit(lc)) |
| return lc - '0'; |
| if (isxdigit(lc)) |
| return lc - 'a' + 10; |
| return -1; |
| } |
| |
| static uint32_t parse_hex(const char *s, size_t nchars, uint32_t *res) |
| { |
| uint32_t v = 0; |
| size_t n = 0; |
| int c = 0; |
| |
| for (n = 0; n < nchars; n++) { |
| c = hex(s[n]); |
| if (c == -1) { |
| *res = TEE_ERROR_BAD_FORMAT; |
| goto out; |
| } |
| v = (v << 4) + c; |
| } |
| *res = TEE_SUCCESS; |
| out: |
| return v; |
| } |
| |
| TEEC_Result xtest_uuid_from_str(TEEC_UUID *uuid, const char *s) |
| { |
| TEEC_Result res = TEEC_SUCCESS; |
| TEEC_UUID u = { }; |
| const char *p = s; |
| size_t i = 0; |
| |
| if (!p || strnlen(p, 37) != 36) |
| return TEEC_ERROR_BAD_FORMAT; |
| if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-') |
| return TEEC_ERROR_BAD_FORMAT; |
| |
| u.timeLow = parse_hex(p, 8, &res); |
| if (res) |
| goto out; |
| p += 9; |
| u.timeMid = parse_hex(p, 4, &res); |
| if (res) |
| goto out; |
| p += 5; |
| u.timeHiAndVersion = parse_hex(p, 4, &res); |
| if (res) |
| goto out; |
| p += 5; |
| for (i = 0; i < 8; i++) { |
| u.clockSeqAndNode[i] = parse_hex(p, 2, &res); |
| if (res) |
| goto out; |
| if (i == 1) |
| p += 3; |
| else |
| p += 2; |
| } |
| *uuid = u; |
| out: |
| return res; |
| } |
| |
| #ifdef OPENSSL_FOUND |
| TEEC_Result xtest_uuid_v5(TEEC_UUID *uuid, const TEEC_UUID *ns, |
| const void *name, size_t size) |
| { |
| TEEC_Result res = TEEC_SUCCESS; |
| EVP_MD_CTX *mdctx = NULL; |
| const EVP_MD *md = NULL; |
| unsigned char hash[EVP_MAX_MD_SIZE] = { }; |
| unsigned int md_len = 0; |
| unsigned char nsbe[16] = { }; |
| uint32_t be32 = 0; |
| uint16_t be16 = 0; |
| int ret = 0; |
| |
| /* Convert from host to big endian */ |
| be32 = htobe32(ns->timeLow); |
| memcpy(&nsbe[0], &be32, sizeof(be32)); |
| be16 = htobe16(ns->timeMid); |
| memcpy(&nsbe[4], &be16, sizeof(be16)); |
| be16 = htobe16(ns->timeHiAndVersion); |
| memcpy(&nsbe[6], &be16, sizeof(be16)); |
| memcpy(&nsbe[8], &ns->clockSeqAndNode, sizeof(ns->clockSeqAndNode)); |
| |
| mdctx = EVP_MD_CTX_create(); |
| if (!mdctx) |
| return TEEC_ERROR_OUT_OF_MEMORY; |
| md = EVP_sha1(); |
| if (!md) { |
| res = TEEC_ERROR_NOT_SUPPORTED; |
| goto out; |
| } |
| ret = EVP_DigestInit_ex(mdctx, md, NULL); |
| if (!ret) { |
| res = TEEC_ERROR_GENERIC; |
| goto out; |
| } |
| ret = EVP_DigestUpdate(mdctx, nsbe, sizeof(nsbe)); |
| if (!ret) { |
| res = TEEC_ERROR_GENERIC; |
| goto out; |
| } |
| ret = EVP_DigestUpdate(mdctx, name, size); |
| if (!ret) { |
| res = TEEC_ERROR_GENERIC; |
| goto out; |
| } |
| ret = EVP_DigestFinal_ex(mdctx, hash, &md_len); |
| if (!ret) { |
| res = TEEC_ERROR_GENERIC; |
| goto out; |
| } |
| |
| /* Mark it as UUIDv5 */ |
| hash[6] = (hash[6] & 0x0F) | 0x50; |
| hash[8] = (hash[8] & 0x3F) | 0x80; |
| |
| /* Convert from big endian to host */ |
| memcpy(&be32, &hash[0], sizeof(uint32_t)); |
| uuid->timeLow = be32toh(be32); |
| memcpy(&be16, &hash[4], sizeof(uint16_t)); |
| uuid->timeMid = be16toh(be16); |
| memcpy(&be16, &hash[6], sizeof(uint16_t)); |
| uuid->timeHiAndVersion = be16toh(be16); |
| memcpy(uuid->clockSeqAndNode, &hash[8], sizeof(uuid->clockSeqAndNode)); |
| out: |
| EVP_MD_CTX_destroy(mdctx); |
| return res; |
| } |
| #endif /*OPENSSL_FOUND*/ |