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 24 static void *zalloc(void *opaque __unused, unsigned int items, 25 unsigned int size) 26 { 27 return malloc(items * size); 28 } 29 30 static void zfree(void *opaque __unused, void *address) 31 { 32 free(address); 33 } 34 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 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 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 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 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 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 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 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