static TEE_Result load_header(const struct shdr *signed_ta, struct shdr **sec_shdr) { size_t s; if (!tee_vbuf_is_non_sec(signed_ta, sizeof(*signed_ta))) return TEE_ERROR_SECURITY; s = SHDR_GET_SIZE(signed_ta); if (!tee_vbuf_is_non_sec(signed_ta, s)) return TEE_ERROR_SECURITY; /* Copy signed header into secure memory */ *sec_shdr = malloc(s); if (!*sec_shdr) return TEE_ERROR_OUT_OF_MEMORY; memcpy(*sec_shdr, signed_ta, s); return TEE_SUCCESS; }
static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid, struct user_ta_store_handle **h) { struct ree_fs_ta_handle *handle; struct shdr *shdr = NULL; struct mobj *mobj = NULL; void *hash_ctx = NULL; uint32_t hash_algo = 0; struct shdr *ta = NULL; size_t ta_size = 0; TEE_Result res; size_t offs; handle = calloc(1, sizeof(*handle)); if (!handle) return TEE_ERROR_OUT_OF_MEMORY; /* Request TA from tee-supplicant */ res = rpc_load(uuid, &ta, &ta_size, &mobj); if (res != TEE_SUCCESS) goto error; /* Make secure copy of signed header */ shdr = shdr_alloc_and_copy(ta, ta_size); if (!shdr) { res = TEE_ERROR_SECURITY; goto error_free_payload; } /* Validate header signature */ res = shdr_verify_signature(shdr); if (res != TEE_SUCCESS) goto error_free_payload; if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA) { res = TEE_ERROR_SECURITY; goto error_free_payload; } /* * Initialize a hash context and run the algorithm over the signed * header (less the final file hash and its signature of course) */ hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo); res = crypto_hash_alloc_ctx(&hash_ctx, hash_algo); if (res != TEE_SUCCESS) goto error_free_payload; res = crypto_hash_init(hash_ctx, hash_algo); if (res != TEE_SUCCESS) goto error_free_hash; res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)shdr, sizeof(*shdr)); if (res != TEE_SUCCESS) goto error_free_hash; offs = SHDR_GET_SIZE(shdr); if (shdr->img_type == SHDR_BOOTSTRAP_TA) { TEE_UUID bs_uuid; struct shdr_bootstrap_ta bs_hdr; if (ta_size < SHDR_GET_SIZE(shdr) + sizeof(bs_hdr)) { res = TEE_ERROR_SECURITY; goto error_free_hash; } memcpy(&bs_hdr, ((uint8_t *)ta + offs), sizeof(bs_hdr)); /* * There's a check later that the UUID embedded inside the * ELF is matching, but since we now have easy access to * the expected uuid of the TA we check it a bit earlier * here. */ tee_uuid_from_octets(&bs_uuid, bs_hdr.uuid); if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) { res = TEE_ERROR_SECURITY; goto error_free_hash; } res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)&bs_hdr, sizeof(bs_hdr)); if (res != TEE_SUCCESS) goto error_free_hash; offs += sizeof(bs_hdr); } if (ta_size != offs + shdr->img_size) { res = TEE_ERROR_SECURITY; goto error_free_hash; } handle->nw_ta = ta; handle->nw_ta_size = ta_size; handle->offs = offs; handle->hash_algo = hash_algo; handle->hash_ctx = hash_ctx; handle->shdr = shdr; handle->mobj = mobj; *h = (struct user_ta_store_handle *)handle; return TEE_SUCCESS; error_free_hash: crypto_hash_free_ctx(hash_ctx, hash_algo); error_free_payload: thread_rpc_free_payload(mobj); error: shdr_free(shdr); free(handle); return res; }
static TEE_Result install_ta(struct shdr *shdr, const uint8_t *nw, size_t nw_size) { TEE_Result res; struct tee_tadb_ta_write *ta; uint32_t hash_algo = 0; void *hash_ctx = NULL; size_t offs; const size_t buf_size = 2 * 4096; void *buf; struct tee_tadb_property property; struct shdr_bootstrap_ta bs_ta; if (shdr->img_type != SHDR_BOOTSTRAP_TA) return TEE_ERROR_SECURITY; if (nw_size < (sizeof(struct shdr_bootstrap_ta) + SHDR_GET_SIZE(shdr))) return TEE_ERROR_SECURITY; if (shdr->hash_size > buf_size) return TEE_ERROR_SECURITY; buf = malloc(buf_size); if (!buf) return TEE_ERROR_OUT_OF_MEMORY; /* * Initialize a hash context and run the algorithm over the signed * header (less the final file hash and its signature of course) */ hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo); res = crypto_hash_alloc_ctx(&hash_ctx, hash_algo); if (res) goto err; res = crypto_hash_init(hash_ctx, hash_algo); if (res) goto err_free_hash_ctx; res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)shdr, sizeof(*shdr)); if (res) goto err_free_hash_ctx; offs = SHDR_GET_SIZE(shdr); memcpy(&bs_ta, nw + offs, sizeof(bs_ta)); /* Check that we're not downgrading a TA */ res = check_install_conflict(&bs_ta); if (res) goto err_free_hash_ctx; res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)&bs_ta, sizeof(bs_ta)); if (res) goto err_free_hash_ctx; offs += sizeof(bs_ta); memset(&property, 0, sizeof(property)); COMPILE_TIME_ASSERT(sizeof(property.uuid) == sizeof(bs_ta.uuid)); tee_uuid_from_octets(&property.uuid, bs_ta.uuid); property.version = bs_ta.version; property.custom_size = 0; property.bin_size = nw_size - offs; DMSG("Installing %pUl", (void *)&property.uuid); res = tee_tadb_ta_create(&property, &ta); if (res) goto err_free_hash_ctx; while (offs < nw_size) { size_t l = MIN(buf_size, nw_size - offs); memcpy(buf, nw + offs, l); res = crypto_hash_update(hash_ctx, hash_algo, buf, l); if (res) goto err_ta_finalize; res = tee_tadb_ta_write(ta, buf, l); if (res) goto err_ta_finalize; offs += l; } res = crypto_hash_final(hash_ctx, hash_algo, buf, shdr->hash_size); if (res) goto err_ta_finalize; if (consttime_memcmp(buf, SHDR_GET_HASH(shdr), shdr->hash_size)) { res = TEE_ERROR_SECURITY; goto err_ta_finalize; } crypto_hash_free_ctx(hash_ctx, hash_algo); free(buf); return tee_tadb_ta_close_and_commit(ta); err_ta_finalize: tee_tadb_ta_close_and_delete(ta); err_free_hash_ctx: crypto_hash_free_ctx(hash_ctx, hash_algo); err: free(buf); return res; }