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