1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2017, Linaro Limited
4  * Copyright (c) 2020, Arm Limited.
5  */
6 #include <crypto/crypto.h>
7 #include <initcall.h>
8 #include <kernel/embedded_ts.h>
9 #include <kernel/ts_store.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <trace.h>
14 #include <utee_defines.h>
15 #include <util.h>
16 #include <zlib.h>
17 
18 struct ts_store_handle {
19 	const struct embedded_ts *ts;
20 	size_t offs;
21 	z_stream strm;
22 };
23 
zalloc(void * opaque __unused,unsigned int items,unsigned int size)24 static void *zalloc(void *opaque __unused, unsigned int items,
25 		    unsigned int size)
26 {
27 	return malloc(items * size);
28 }
29 
zfree(void * opaque __unused,void * address)30 static void zfree(void *opaque __unused, void *address)
31 {
32 	free(address);
33 }
34 
decompression_init(z_stream * strm,const struct embedded_ts * ts)35 static bool decompression_init(z_stream *strm,
36 			       const struct embedded_ts *ts)
37 {
38 	int st = Z_OK;
39 
40 	strm->next_in = ts->ts;
41 	strm->avail_in = ts->size;
42 	strm->zalloc = zalloc;
43 	strm->zfree = zfree;
44 	st = inflateInit(strm);
45 	if (st != Z_OK) {
46 		EMSG("Decompression initialization error (%d)", st);
47 		return false;
48 	}
49 
50 	return true;
51 }
52 
emb_ts_open(const TEE_UUID * uuid,struct ts_store_handle ** h,const struct embedded_ts * (* find_ts)(const TEE_UUID * uuid))53 TEE_Result emb_ts_open(const TEE_UUID *uuid,
54 		       struct ts_store_handle **h,
55 		       const struct embedded_ts*
56 		       (*find_ts) (const TEE_UUID *uuid))
57 {
58 	struct ts_store_handle *handle = NULL;
59 	const struct embedded_ts *ts = NULL;
60 
61 	ts = find_ts(uuid);
62 	if (!ts)
63 		return TEE_ERROR_ITEM_NOT_FOUND;
64 
65 	handle = calloc(1, sizeof(*handle));
66 	if (!handle)
67 		return TEE_ERROR_OUT_OF_MEMORY;
68 
69 	if (ts->uncompressed_size) {
70 		if (!decompression_init(&handle->strm, ts)) {
71 			free(handle);
72 			return TEE_ERROR_BAD_FORMAT;
73 		}
74 	}
75 	handle->ts = ts;
76 	*h = handle;
77 
78 	return TEE_SUCCESS;
79 }
80 
emb_ts_get_size(const struct ts_store_handle * h,size_t * size)81 TEE_Result emb_ts_get_size(const struct ts_store_handle *h, size_t *size)
82 {
83 	const struct embedded_ts *ts = h->ts;
84 
85 	if (ts->uncompressed_size)
86 		*size = ts->uncompressed_size;
87 	else
88 		*size = ts->size;
89 
90 	return TEE_SUCCESS;
91 }
92 
emb_ts_get_tag(const struct ts_store_handle * h,uint8_t * tag,unsigned int * tag_len)93 TEE_Result emb_ts_get_tag(const struct ts_store_handle *h,
94 			  uint8_t *tag, unsigned int *tag_len)
95 {
96 	TEE_Result res = TEE_SUCCESS;
97 	void *ctx = NULL;
98 
99 	if (!tag || *tag_len < TEE_SHA256_HASH_SIZE) {
100 		*tag_len = TEE_SHA256_HASH_SIZE;
101 		return TEE_ERROR_SHORT_BUFFER;
102 	}
103 	*tag_len = TEE_SHA256_HASH_SIZE;
104 
105 	res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256);
106 	if (res)
107 		return res;
108 	res = crypto_hash_init(ctx);
109 	if (res)
110 		goto out;
111 	res = crypto_hash_update(ctx, h->ts->ts, h->ts->size);
112 	if (res)
113 		goto out;
114 	res = crypto_hash_final(ctx, tag, *tag_len);
115 out:
116 	crypto_hash_free_ctx(ctx);
117 	return res;
118 }
119 
read_uncompressed(struct ts_store_handle * h,void * data,size_t len)120 static TEE_Result read_uncompressed(struct ts_store_handle *h, void *data,
121 				    size_t len)
122 {
123 	uint8_t *src = (uint8_t *)h->ts->ts + h->offs;
124 	size_t next_offs = 0;
125 
126 	if (ADD_OVERFLOW(h->offs, len, &next_offs) ||
127 	    next_offs > h->ts->size)
128 		return TEE_ERROR_BAD_PARAMETERS;
129 	if (data)
130 		memcpy(data, src, len);
131 	h->offs = next_offs;
132 
133 	return TEE_SUCCESS;
134 }
135 
read_compressed(struct ts_store_handle * h,void * data,size_t len)136 static TEE_Result read_compressed(struct ts_store_handle *h, void *data,
137 				  size_t len)
138 {
139 	z_stream *strm = &h->strm;
140 	size_t total = 0;
141 	uint8_t *tmpbuf = NULL;
142 	TEE_Result ret = TEE_SUCCESS;
143 	size_t out = 0;
144 	int st = Z_OK;
145 
146 	if (data) {
147 		strm->next_out = data;
148 		strm->avail_out = len;
149 	} else {
150 		/*
151 		 * inflate() does not support a NULL strm->next_out. So, to
152 		 * discard data, we have to allocate a temporary buffer. 1K
153 		 * seems reasonable.
154 		 */
155 		strm->avail_out = MIN(len, 1024U);
156 		tmpbuf = malloc(strm->avail_out);
157 		if (!tmpbuf) {
158 			EMSG("Out of memory");
159 			return TEE_ERROR_OUT_OF_MEMORY;
160 		}
161 		strm->next_out = tmpbuf;
162 	}
163 	/*
164 	 * Loop until we get as many bytes as requested, or an error occurs.
165 	 * inflate() returns:
166 	 * - Z_OK when progress was made, but neither the end of the input
167 	 *   stream nor the end of the output buffer were met.
168 	 * - Z_STREAM_END when the end of the intput stream was reached.
169 	 * - Z_BUF_ERROR when there is still input to process but the output
170 	 *   buffer is full (not a "hard" error, decompression can proceeed
171 	 *   later).
172 	 */
173 	do {
174 		out = strm->total_out;
175 		st = inflate(strm, Z_SYNC_FLUSH);
176 		out = strm->total_out - out;
177 		total += out;
178 		FMSG("%zu bytes", out);
179 		if (!data) {
180 			/*
181 			 * Reset the pointer to throw away what we've just read
182 			 * and read again as much as possible.
183 			 */
184 			strm->next_out = tmpbuf;
185 			strm->avail_out = MIN(len - total, 1024U);
186 		}
187 	} while ((st == Z_OK || st == Z_BUF_ERROR) && (total != len));
188 
189 	if (st != Z_OK && st != Z_STREAM_END) {
190 		EMSG("Decompression error (%d)", st);
191 		ret = TEE_ERROR_GENERIC;
192 		goto out;
193 	}
194 	ret = TEE_SUCCESS;
195 out:
196 	free(tmpbuf);
197 
198 	return ret;
199 }
200 
emb_ts_read(struct ts_store_handle * h,void * data,size_t len)201 TEE_Result emb_ts_read(struct ts_store_handle *h, void *data, size_t len)
202 {
203 	if (h->ts->uncompressed_size)
204 		return read_compressed(h, data, len);
205 	else
206 		return read_uncompressed(h, data, len);
207 }
208 
emb_ts_close(struct ts_store_handle * h)209 void emb_ts_close(struct ts_store_handle *h)
210 {
211 	if (h->ts->uncompressed_size)
212 		inflateEnd(&h->strm);
213 	free(h);
214 }
215 
216