1*ee546289SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 2*ee546289SJens Wiklander /* 3*ee546289SJens Wiklander * Copyright (c) 2019, Linaro Limited 4*ee546289SJens Wiklander */ 5*ee546289SJens Wiklander 6*ee546289SJens Wiklander #include <crypto/crypto.h> 7*ee546289SJens Wiklander #include <crypto/internal_aes-gcm.h> 8*ee546289SJens Wiklander #include <kernel/panic.h> 9*ee546289SJens Wiklander #include <mm/core_memprot.h> 10*ee546289SJens Wiklander #include <mm/core_mmu.h> 11*ee546289SJens Wiklander #include <mm/fobj.h> 12*ee546289SJens Wiklander #include <mm/tee_mm.h> 13*ee546289SJens Wiklander #include <stdlib.h> 14*ee546289SJens Wiklander #include <string.h> 15*ee546289SJens Wiklander #include <tee_api_types.h> 16*ee546289SJens Wiklander #include <types_ext.h> 17*ee546289SJens Wiklander #include <util.h> 18*ee546289SJens Wiklander 19*ee546289SJens Wiklander #ifdef CFG_WITH_PAGER 20*ee546289SJens Wiklander 21*ee546289SJens Wiklander #define RWP_AE_KEY_BITS 256 22*ee546289SJens Wiklander 23*ee546289SJens Wiklander struct rwp_aes_gcm_iv { 24*ee546289SJens Wiklander uint32_t iv[3]; 25*ee546289SJens Wiklander }; 26*ee546289SJens Wiklander 27*ee546289SJens Wiklander #define RWP_AES_GCM_TAG_LEN 16 28*ee546289SJens Wiklander 29*ee546289SJens Wiklander struct rwp_state { 30*ee546289SJens Wiklander uint64_t iv; 31*ee546289SJens Wiklander uint8_t tag[RWP_AES_GCM_TAG_LEN]; 32*ee546289SJens Wiklander }; 33*ee546289SJens Wiklander 34*ee546289SJens Wiklander struct fobj_rwp { 35*ee546289SJens Wiklander uint8_t *store; 36*ee546289SJens Wiklander struct rwp_state *state; 37*ee546289SJens Wiklander struct fobj fobj; 38*ee546289SJens Wiklander }; 39*ee546289SJens Wiklander 40*ee546289SJens Wiklander static struct fobj_ops ops_rw_paged; 41*ee546289SJens Wiklander 42*ee546289SJens Wiklander static struct internal_aes_gcm_key rwp_ae_key; 43*ee546289SJens Wiklander 44*ee546289SJens Wiklander void fobj_generate_authenc_key(void) 45*ee546289SJens Wiklander { 46*ee546289SJens Wiklander uint8_t key[RWP_AE_KEY_BITS / 8] = { 0 }; 47*ee546289SJens Wiklander 48*ee546289SJens Wiklander if (crypto_rng_read(key, sizeof(key)) != TEE_SUCCESS) 49*ee546289SJens Wiklander panic("failed to generate random"); 50*ee546289SJens Wiklander if (internal_aes_gcm_expand_enc_key(key, sizeof(key), &rwp_ae_key)) 51*ee546289SJens Wiklander panic("failed to expand key"); 52*ee546289SJens Wiklander } 53*ee546289SJens Wiklander 54*ee546289SJens Wiklander static void fobj_init(struct fobj *fobj, const struct fobj_ops *ops, 55*ee546289SJens Wiklander unsigned int num_pages) 56*ee546289SJens Wiklander { 57*ee546289SJens Wiklander fobj->ops = ops; 58*ee546289SJens Wiklander fobj->num_pages = num_pages; 59*ee546289SJens Wiklander refcount_set(&fobj->refc, 1); 60*ee546289SJens Wiklander } 61*ee546289SJens Wiklander 62*ee546289SJens Wiklander static void fobj_uninit(struct fobj *fobj) 63*ee546289SJens Wiklander { 64*ee546289SJens Wiklander assert(!refcount_val(&fobj->refc)); 65*ee546289SJens Wiklander } 66*ee546289SJens Wiklander 67*ee546289SJens Wiklander struct fobj *fobj_rw_paged_alloc(unsigned int num_pages) 68*ee546289SJens Wiklander { 69*ee546289SJens Wiklander tee_mm_entry_t *mm = NULL; 70*ee546289SJens Wiklander struct fobj_rwp *rwp = NULL; 71*ee546289SJens Wiklander size_t size = 0; 72*ee546289SJens Wiklander 73*ee546289SJens Wiklander assert(num_pages); 74*ee546289SJens Wiklander 75*ee546289SJens Wiklander rwp = calloc(1, sizeof(*rwp)); 76*ee546289SJens Wiklander if (!rwp) 77*ee546289SJens Wiklander return NULL; 78*ee546289SJens Wiklander 79*ee546289SJens Wiklander rwp->state = calloc(num_pages, sizeof(*rwp->state)); 80*ee546289SJens Wiklander if (!rwp->state) 81*ee546289SJens Wiklander goto err; 82*ee546289SJens Wiklander 83*ee546289SJens Wiklander if (MUL_OVERFLOW(num_pages, SMALL_PAGE_SIZE, &size)) 84*ee546289SJens Wiklander goto err; 85*ee546289SJens Wiklander mm = tee_mm_alloc(&tee_mm_sec_ddr, size); 86*ee546289SJens Wiklander if (!mm) 87*ee546289SJens Wiklander goto err; 88*ee546289SJens Wiklander rwp->store = phys_to_virt(tee_mm_get_smem(mm), MEM_AREA_TA_RAM); 89*ee546289SJens Wiklander assert(rwp->store); /* to assist debugging if it would ever happen */ 90*ee546289SJens Wiklander if (!rwp->store) 91*ee546289SJens Wiklander goto err; 92*ee546289SJens Wiklander 93*ee546289SJens Wiklander fobj_init(&rwp->fobj, &ops_rw_paged, num_pages); 94*ee546289SJens Wiklander 95*ee546289SJens Wiklander return &rwp->fobj; 96*ee546289SJens Wiklander 97*ee546289SJens Wiklander err: 98*ee546289SJens Wiklander tee_mm_free(mm); 99*ee546289SJens Wiklander free(rwp->state); 100*ee546289SJens Wiklander free(rwp); 101*ee546289SJens Wiklander 102*ee546289SJens Wiklander return NULL; 103*ee546289SJens Wiklander } 104*ee546289SJens Wiklander 105*ee546289SJens Wiklander static struct fobj_rwp *to_rwp(struct fobj *fobj) 106*ee546289SJens Wiklander { 107*ee546289SJens Wiklander assert(fobj->ops == &ops_rw_paged); 108*ee546289SJens Wiklander 109*ee546289SJens Wiklander return container_of(fobj, struct fobj_rwp, fobj); 110*ee546289SJens Wiklander } 111*ee546289SJens Wiklander 112*ee546289SJens Wiklander static void rwp_free(struct fobj *fobj) 113*ee546289SJens Wiklander { 114*ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 115*ee546289SJens Wiklander 116*ee546289SJens Wiklander fobj_uninit(fobj); 117*ee546289SJens Wiklander tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rwp->store))); 118*ee546289SJens Wiklander free(rwp->state); 119*ee546289SJens Wiklander free(rwp); 120*ee546289SJens Wiklander } 121*ee546289SJens Wiklander 122*ee546289SJens Wiklander static TEE_Result rwp_load_page(struct fobj *fobj, unsigned int page_idx, 123*ee546289SJens Wiklander void *va) 124*ee546289SJens Wiklander { 125*ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 126*ee546289SJens Wiklander struct rwp_state *state = rwp->state + page_idx; 127*ee546289SJens Wiklander uint8_t *src = rwp->store + page_idx * SMALL_PAGE_SIZE; 128*ee546289SJens Wiklander struct rwp_aes_gcm_iv iv = { 129*ee546289SJens Wiklander .iv = { (vaddr_t)state, state->iv >> 32, state->iv } 130*ee546289SJens Wiklander }; 131*ee546289SJens Wiklander 132*ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 133*ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 134*ee546289SJens Wiklander 135*ee546289SJens Wiklander if (!state->iv) { 136*ee546289SJens Wiklander /* 137*ee546289SJens Wiklander * iv still zero which means that this is previously unused 138*ee546289SJens Wiklander * page. 139*ee546289SJens Wiklander */ 140*ee546289SJens Wiklander memset(va, 0, SMALL_PAGE_SIZE); 141*ee546289SJens Wiklander return TEE_SUCCESS; 142*ee546289SJens Wiklander } 143*ee546289SJens Wiklander 144*ee546289SJens Wiklander return internal_aes_gcm_dec(&rwp_ae_key, &iv, sizeof(iv), 145*ee546289SJens Wiklander NULL, 0, src, SMALL_PAGE_SIZE, va, 146*ee546289SJens Wiklander state->tag, sizeof(state->tag)); 147*ee546289SJens Wiklander } 148*ee546289SJens Wiklander KEEP_PAGER(rwp_load_page); 149*ee546289SJens Wiklander 150*ee546289SJens Wiklander static TEE_Result rwp_save_page(struct fobj *fobj, unsigned int page_idx, 151*ee546289SJens Wiklander const void *va) 152*ee546289SJens Wiklander { 153*ee546289SJens Wiklander struct fobj_rwp *rwp = to_rwp(fobj); 154*ee546289SJens Wiklander struct rwp_state *state = rwp->state + page_idx; 155*ee546289SJens Wiklander size_t tag_len = sizeof(state->tag); 156*ee546289SJens Wiklander uint8_t *dst = rwp->store + page_idx * SMALL_PAGE_SIZE; 157*ee546289SJens Wiklander struct rwp_aes_gcm_iv iv; 158*ee546289SJens Wiklander 159*ee546289SJens Wiklander memset(&iv, 0, sizeof(iv)); 160*ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 161*ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 162*ee546289SJens Wiklander assert(state->iv + 1 > state->iv); 163*ee546289SJens Wiklander 164*ee546289SJens Wiklander state->iv++; 165*ee546289SJens Wiklander /* 166*ee546289SJens Wiklander * IV is constructed as recommended in section "8.2.1 Deterministic 167*ee546289SJens Wiklander * Construction" of "Recommendation for Block Cipher Modes of 168*ee546289SJens Wiklander * Operation: Galois/Counter Mode (GCM) and GMAC", 169*ee546289SJens Wiklander * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf 170*ee546289SJens Wiklander */ 171*ee546289SJens Wiklander 172*ee546289SJens Wiklander iv.iv[0] = (vaddr_t)state; 173*ee546289SJens Wiklander iv.iv[1] = state->iv >> 32; 174*ee546289SJens Wiklander iv.iv[2] = state->iv; 175*ee546289SJens Wiklander 176*ee546289SJens Wiklander return internal_aes_gcm_enc(&rwp_ae_key, &iv, sizeof(iv), 177*ee546289SJens Wiklander NULL, 0, va, SMALL_PAGE_SIZE, dst, 178*ee546289SJens Wiklander state->tag, &tag_len); 179*ee546289SJens Wiklander } 180*ee546289SJens Wiklander KEEP_PAGER(rwp_save_page); 181*ee546289SJens Wiklander 182*ee546289SJens Wiklander static struct fobj_ops ops_rw_paged __rodata_unpaged = { 183*ee546289SJens Wiklander .free = rwp_free, 184*ee546289SJens Wiklander .load_page = rwp_load_page, 185*ee546289SJens Wiklander .save_page = rwp_save_page, 186*ee546289SJens Wiklander }; 187*ee546289SJens Wiklander 188*ee546289SJens Wiklander struct fobj_rop { 189*ee546289SJens Wiklander uint8_t *hashes; 190*ee546289SJens Wiklander uint8_t *store; 191*ee546289SJens Wiklander struct fobj fobj; 192*ee546289SJens Wiklander }; 193*ee546289SJens Wiklander 194*ee546289SJens Wiklander static struct fobj_ops ops_ro_paged; 195*ee546289SJens Wiklander 196*ee546289SJens Wiklander struct fobj *fobj_ro_paged_alloc(unsigned int num_pages, void *hashes, 197*ee546289SJens Wiklander void *store) 198*ee546289SJens Wiklander { 199*ee546289SJens Wiklander struct fobj_rop *rop = NULL; 200*ee546289SJens Wiklander 201*ee546289SJens Wiklander assert(num_pages && hashes && store); 202*ee546289SJens Wiklander 203*ee546289SJens Wiklander rop = calloc(1, sizeof(*rop)); 204*ee546289SJens Wiklander if (!rop) 205*ee546289SJens Wiklander return NULL; 206*ee546289SJens Wiklander 207*ee546289SJens Wiklander rop->hashes = hashes; 208*ee546289SJens Wiklander rop->store = store; 209*ee546289SJens Wiklander fobj_init(&rop->fobj, &ops_ro_paged, num_pages); 210*ee546289SJens Wiklander 211*ee546289SJens Wiklander return &rop->fobj; 212*ee546289SJens Wiklander } 213*ee546289SJens Wiklander 214*ee546289SJens Wiklander static struct fobj_rop *to_rop(struct fobj *fobj) 215*ee546289SJens Wiklander { 216*ee546289SJens Wiklander assert(fobj->ops == &ops_ro_paged); 217*ee546289SJens Wiklander 218*ee546289SJens Wiklander return container_of(fobj, struct fobj_rop, fobj); 219*ee546289SJens Wiklander } 220*ee546289SJens Wiklander 221*ee546289SJens Wiklander static void rop_free(struct fobj *fobj) 222*ee546289SJens Wiklander { 223*ee546289SJens Wiklander struct fobj_rop *rop = to_rop(fobj); 224*ee546289SJens Wiklander 225*ee546289SJens Wiklander fobj_uninit(fobj); 226*ee546289SJens Wiklander tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, virt_to_phys(rop->store))); 227*ee546289SJens Wiklander free(rop->hashes); 228*ee546289SJens Wiklander free(rop); 229*ee546289SJens Wiklander } 230*ee546289SJens Wiklander 231*ee546289SJens Wiklander static TEE_Result rop_load_page(struct fobj *fobj, unsigned int page_idx, 232*ee546289SJens Wiklander void *va) 233*ee546289SJens Wiklander { 234*ee546289SJens Wiklander struct fobj_rop *rop = to_rop(fobj); 235*ee546289SJens Wiklander const uint8_t *hash = rop->hashes + page_idx * TEE_SHA256_HASH_SIZE; 236*ee546289SJens Wiklander const uint8_t *src = rop->store + page_idx * SMALL_PAGE_SIZE; 237*ee546289SJens Wiklander 238*ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 239*ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 240*ee546289SJens Wiklander memcpy(va, src, SMALL_PAGE_SIZE); 241*ee546289SJens Wiklander 242*ee546289SJens Wiklander return hash_sha256_check(hash, va, SMALL_PAGE_SIZE); 243*ee546289SJens Wiklander } 244*ee546289SJens Wiklander KEEP_PAGER(rop_load_page); 245*ee546289SJens Wiklander 246*ee546289SJens Wiklander static TEE_Result rop_save_page(struct fobj *fobj __unused, 247*ee546289SJens Wiklander unsigned int page_idx __unused, 248*ee546289SJens Wiklander const void *va __unused) 249*ee546289SJens Wiklander { 250*ee546289SJens Wiklander return TEE_ERROR_GENERIC; 251*ee546289SJens Wiklander } 252*ee546289SJens Wiklander KEEP_PAGER(rop_save_page); 253*ee546289SJens Wiklander 254*ee546289SJens Wiklander static struct fobj_ops ops_ro_paged __rodata_unpaged = { 255*ee546289SJens Wiklander .free = rop_free, 256*ee546289SJens Wiklander .load_page = rop_load_page, 257*ee546289SJens Wiklander .save_page = rop_save_page, 258*ee546289SJens Wiklander }; 259*ee546289SJens Wiklander 260*ee546289SJens Wiklander static struct fobj_ops ops_locked_paged; 261*ee546289SJens Wiklander 262*ee546289SJens Wiklander struct fobj *fobj_locked_paged_alloc(unsigned int num_pages) 263*ee546289SJens Wiklander { 264*ee546289SJens Wiklander struct fobj *f = NULL; 265*ee546289SJens Wiklander 266*ee546289SJens Wiklander assert(num_pages); 267*ee546289SJens Wiklander 268*ee546289SJens Wiklander f = calloc(1, sizeof(*f)); 269*ee546289SJens Wiklander if (!f) 270*ee546289SJens Wiklander return NULL; 271*ee546289SJens Wiklander 272*ee546289SJens Wiklander fobj_init(f, &ops_locked_paged, num_pages); 273*ee546289SJens Wiklander 274*ee546289SJens Wiklander return f; 275*ee546289SJens Wiklander } 276*ee546289SJens Wiklander 277*ee546289SJens Wiklander static void lop_free(struct fobj *fobj) 278*ee546289SJens Wiklander { 279*ee546289SJens Wiklander assert(fobj->ops == &ops_locked_paged); 280*ee546289SJens Wiklander fobj_uninit(fobj); 281*ee546289SJens Wiklander free(fobj); 282*ee546289SJens Wiklander } 283*ee546289SJens Wiklander 284*ee546289SJens Wiklander static TEE_Result lop_load_page(struct fobj *fobj __maybe_unused, 285*ee546289SJens Wiklander unsigned int page_idx __maybe_unused, 286*ee546289SJens Wiklander void *va) 287*ee546289SJens Wiklander { 288*ee546289SJens Wiklander assert(fobj->ops == &ops_locked_paged); 289*ee546289SJens Wiklander assert(refcount_val(&fobj->refc)); 290*ee546289SJens Wiklander assert(page_idx < fobj->num_pages); 291*ee546289SJens Wiklander 292*ee546289SJens Wiklander memset(va, 0, SMALL_PAGE_SIZE); 293*ee546289SJens Wiklander 294*ee546289SJens Wiklander return TEE_SUCCESS; 295*ee546289SJens Wiklander } 296*ee546289SJens Wiklander KEEP_PAGER(lop_load_page); 297*ee546289SJens Wiklander 298*ee546289SJens Wiklander static TEE_Result lop_save_page(struct fobj *fobj __unused, 299*ee546289SJens Wiklander unsigned int page_idx __unused, 300*ee546289SJens Wiklander const void *va __unused) 301*ee546289SJens Wiklander { 302*ee546289SJens Wiklander return TEE_ERROR_GENERIC; 303*ee546289SJens Wiklander } 304*ee546289SJens Wiklander KEEP_PAGER(lop_save_page); 305*ee546289SJens Wiklander 306*ee546289SJens Wiklander static struct fobj_ops ops_locked_paged __rodata_unpaged = { 307*ee546289SJens Wiklander .free = lop_free, 308*ee546289SJens Wiklander .load_page = lop_load_page, 309*ee546289SJens Wiklander .save_page = lop_save_page, 310*ee546289SJens Wiklander }; 311*ee546289SJens Wiklander #endif /*CFG_WITH_PAGER*/ 312