1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5 
6 #include <ctype.h>
7 #include <endian.h>
8 #ifdef OPENSSL_FOUND
9 #include <openssl/evp.h>
10 #endif
11 #include <stdint.h>
12 #include <string.h>
13 #include <tee_api_types.h>
14 #include <tee_client_api.h>
15 #include "xtest_uuid_helpers.h"
16 
hex(char c)17 static int hex(char c)
18 {
19 	char lc = tolower(c);
20 
21 	if (isdigit(lc))
22 		return lc - '0';
23 	if (isxdigit(lc))
24 		return lc - 'a' + 10;
25 	return -1;
26 }
27 
parse_hex(const char * s,size_t nchars,uint32_t * res)28 static uint32_t parse_hex(const char *s, size_t nchars, uint32_t *res)
29 {
30 	uint32_t v = 0;
31 	size_t n = 0;
32 	int c = 0;
33 
34 	for (n = 0; n < nchars; n++) {
35 		c = hex(s[n]);
36 		if (c == -1) {
37 			*res = TEE_ERROR_BAD_FORMAT;
38 			goto out;
39 		}
40 		v = (v << 4) + c;
41 	}
42 	*res = TEE_SUCCESS;
43 out:
44 	return v;
45 }
46 
xtest_uuid_from_str(TEEC_UUID * uuid,const char * s)47 TEEC_Result xtest_uuid_from_str(TEEC_UUID *uuid, const char *s)
48 {
49 	TEEC_Result res = TEEC_SUCCESS;
50 	TEEC_UUID u = { };
51 	const char *p = s;
52 	size_t i = 0;
53 
54 	if (!p || strnlen(p, 37) != 36)
55 		return TEEC_ERROR_BAD_FORMAT;
56 	if (p[8] != '-' || p[13] != '-' || p[18] != '-' || p[23] != '-')
57 		return TEEC_ERROR_BAD_FORMAT;
58 
59 	u.timeLow = parse_hex(p, 8, &res);
60 	if (res)
61 		goto out;
62 	p += 9;
63 	u.timeMid = parse_hex(p, 4, &res);
64 	if (res)
65 		goto out;
66 	p += 5;
67 	u.timeHiAndVersion = parse_hex(p, 4, &res);
68 	if (res)
69 		goto out;
70 	p += 5;
71 	for (i = 0; i < 8; i++) {
72 		u.clockSeqAndNode[i] = parse_hex(p, 2, &res);
73 		if (res)
74 			goto out;
75 		if (i == 1)
76 			p += 3;
77 		else
78 			p += 2;
79 	}
80 	*uuid = u;
81 out:
82 	return res;
83 }
84 
85 #ifdef OPENSSL_FOUND
xtest_uuid_v5(TEEC_UUID * uuid,const TEEC_UUID * ns,const void * name,size_t size)86 TEEC_Result xtest_uuid_v5(TEEC_UUID *uuid, const TEEC_UUID *ns,
87 			  const void *name, size_t size)
88 {
89 	TEEC_Result res = TEEC_SUCCESS;
90 	EVP_MD_CTX *mdctx = NULL;
91 	const EVP_MD *md = NULL;
92 	unsigned char hash[EVP_MAX_MD_SIZE] = { };
93 	unsigned int md_len = 0;
94 	unsigned char nsbe[16] = { };
95 	uint32_t be32 = 0;
96 	uint16_t be16 = 0;
97 	int ret = 0;
98 
99 	/* Convert from host to big endian */
100 	be32 = htobe32(ns->timeLow);
101 	memcpy(&nsbe[0], &be32, sizeof(be32));
102 	be16 = htobe16(ns->timeMid);
103 	memcpy(&nsbe[4], &be16, sizeof(be16));
104 	be16 = htobe16(ns->timeHiAndVersion);
105 	memcpy(&nsbe[6], &be16, sizeof(be16));
106 	memcpy(&nsbe[8], &ns->clockSeqAndNode, sizeof(ns->clockSeqAndNode));
107 
108 	mdctx = EVP_MD_CTX_create();
109 	if (!mdctx)
110 		return TEEC_ERROR_OUT_OF_MEMORY;
111 	md = EVP_sha1();
112 	if (!md) {
113 		res = TEEC_ERROR_NOT_SUPPORTED;
114 		goto out;
115 	}
116 	ret = EVP_DigestInit_ex(mdctx, md, NULL);
117 	if (!ret) {
118 		res = TEEC_ERROR_GENERIC;
119 		goto out;
120 	}
121 	ret = EVP_DigestUpdate(mdctx, nsbe, sizeof(nsbe));
122 	if (!ret) {
123 		res = TEEC_ERROR_GENERIC;
124 		goto out;
125 	}
126 	ret = EVP_DigestUpdate(mdctx, name, size);
127 	if (!ret) {
128 		res = TEEC_ERROR_GENERIC;
129 		goto out;
130 	}
131 	ret = EVP_DigestFinal_ex(mdctx, hash, &md_len);
132 	if (!ret) {
133 		res = TEEC_ERROR_GENERIC;
134 		goto out;
135 	}
136 
137 	/* Mark it as UUIDv5 */
138 	hash[6] = (hash[6] & 0x0F) | 0x50;
139 	hash[8] = (hash[8] & 0x3F) | 0x80;
140 
141 	/* Convert from big endian to host */
142 	memcpy(&be32, &hash[0], sizeof(uint32_t));
143 	uuid->timeLow = be32toh(be32);
144 	memcpy(&be16, &hash[4], sizeof(uint16_t));
145 	uuid->timeMid = be16toh(be16);
146 	memcpy(&be16, &hash[6], sizeof(uint16_t));
147 	uuid->timeHiAndVersion = be16toh(be16);
148 	memcpy(uuid->clockSeqAndNode, &hash[8], sizeof(uuid->clockSeqAndNode));
149 out:
150 	EVP_MD_CTX_destroy(mdctx);
151 	return res;
152 }
153 #endif /*OPENSSL_FOUND*/
154