From ca4258ca0702e082ad975e08ee33fd05d518b690 Mon Sep 17 00:00:00 2001 From: Ji Luo Date: Fri, 5 Feb 2021 08:43:13 +0800 Subject: [PATCH] MA-18680-2 Support derive rpmb key from BKEK The BKEK will bind to the soc chip and we don't need to store the encapsulated keyslot after using BKEK as the rpmb key, which reduces the risk of losing the rpmb key. This commit adds two commands to support derive the rpmb key from BKEK and erase the rpmb storage (for debug purpose, need support from trusty): $ fastboot oem set-rpmb-hardware-key $ fastboot oem erase-rpmb Legacy keyslot way is still supported and boards programed with keyslot can still work in compatible way. Command to set provisioned rpmb key is changed to: $ fastboot stage $ fastboot oem set-rpmb-staged-key Test: Key set and boot on imx8mn/imx8qxp. Change-Id: Ifc88010fe8802d3550e42dff0bbd5a5e5ad922a3 Signed-off-by: Ji Luo (cherry picked from commit 0fd1b5e41645ac3f5c05ad82258df1645c59fb5a) (cherry picked from commit 6a5125b9caf4c2e036853d8f53f8398c147758b3) --- drivers/fastboot/fb_fsl/fb_fsl_command.c | 25 ++-- include/fb_fsl.h | 5 +- include/fsl_avb.h | 6 +- include/interface/storage/storage.h | 3 + include/trusty/rpmb.h | 10 ++ lib/avb/fsl/fsl_avbkey.c | 57 +++++----- lib/avb/fsl/fsl_bootctrl.c | 8 +- lib/trusty/ql-tipc/ipc.c | 12 +- lib/trusty/ql-tipc/libtipc.c | 32 ++++-- lib/trusty/ql-tipc/rpmb_proxy.c | 138 +++++++++++++++++++++++ 10 files changed, 238 insertions(+), 58 deletions(-) diff --git a/drivers/fastboot/fb_fsl/fb_fsl_command.c b/drivers/fastboot/fb_fsl/fb_fsl_command.c index b5ec0ff696..d2eee5e6ed 100644 --- a/drivers/fastboot/fb_fsl/fb_fsl_command.c +++ b/drivers/fastboot/fb_fsl/fb_fsl_command.c @@ -45,6 +45,7 @@ #ifdef CONFIG_IMX_TRUSTY_OS #include "u-boot/sha256.h" +#include "trusty/rpmb.h" #include #endif @@ -696,18 +697,26 @@ static void flashing(char *cmd, char *response) } #endif #ifndef CONFIG_AVB_ATX - else if (endswith(cmd, FASTBOOT_SET_RPMB_KEY)) { - if (fastboot_set_rpmb_key(fastboot_buf_addr, fastboot_bytes_received)) { - printf("ERROR set rpmb key failed!\n"); - strcpy(response, "FAILset rpmb key failed!"); + else if (endswith(cmd, FASTBOOT_SET_RPMB_STAGED_KEY)) { + if (fastboot_set_rpmb_staged_key(fastboot_buf_addr, fastboot_bytes_received)) { + printf("ERROR set rpmb staged key failed!\n"); + strcpy(response, "FAILset rpmb staged key failed!"); } else strcpy(response, "OKAY"); - } else if (endswith(cmd, FASTBOOT_SET_RPMB_RANDOM_KEY)) { - if (fastboot_set_rpmb_random_key()) { - printf("ERROR set rpmb random key failed!\n"); - strcpy(response, "FAILset rpmb random key failed!"); + } else if (endswith(cmd, FASTBOOT_SET_RPMB_HARDWARE_KEY)) { + if (fastboot_set_rpmb_hardware_key()) { + printf("ERROR set rpmb hardware key failed!\n"); + strcpy(response, "FAILset rpmb hardware key failed!"); } else strcpy(response, "OKAY"); + } else if (endswith(cmd, FASTBOOT_ERASE_RPMB)) { + if (storage_erase_rpmb()) { + printf("ERROR erase rpmb storage failed!\n"); + strcpy(response, "FAILerase rpmb storage failed!"); + } else { + printf("erase rpmb storage succeed!\n"); + strcpy(response, "OKAY"); + } } else if (endswith(cmd, FASTBOOT_SET_VBMETA_PUBLIC_KEY)) { if (avb_set_public_key(fastboot_buf_addr, fastboot_bytes_received)) diff --git a/include/fb_fsl.h b/include/fb_fsl.h index 8e2f1c487a..a0018169ef 100644 --- a/include/fb_fsl.h +++ b/include/fb_fsl.h @@ -86,9 +86,10 @@ #ifdef CONFIG_IMX_TRUSTY_OS #ifndef CONFIG_AVB_ATX -#define FASTBOOT_SET_RPMB_KEY "set-rpmb-key" -#define FASTBOOT_SET_RPMB_RANDOM_KEY "set-rpmb-random-key" +#define FASTBOOT_SET_RPMB_STAGED_KEY "set-rpmb-staged-key" +#define FASTBOOT_SET_RPMB_HARDWARE_KEY "set-rpmb-hardware-key" #define FASTBOOT_SET_VBMETA_PUBLIC_KEY "set-public-key" +#define FASTBOOT_ERASE_RPMB "erase-rpmb" #endif #define FASTBOOT_SET_CA_RESP "at-set-ca-response" diff --git a/include/fsl_avb.h b/include/fsl_avb.h index 0eaa842cf1..9c7cfe059d 100644 --- a/include/fsl_avb.h +++ b/include/fsl_avb.h @@ -172,10 +172,10 @@ AvbIOResult fsl_get_random(AvbAtxOps* atx_ops, int avb_atx_fuse_perm_attr(uint8_t *staged_buffer, uint32_t size); /* Initialize rpmb key with the staged key */ -int fastboot_set_rpmb_key(uint8_t *staged_buf, uint32_t key_size); +int fastboot_set_rpmb_staged_key(uint8_t *staged_buf, uint32_t key_size); -/* Initialize rpmb key with random key which is generated by caam rng */ -int fastboot_set_rpmb_random_key(void); +/* Initialize rpmb key with hardware key which is derived from BKEK */ +int fastboot_set_rpmb_hardware_key(void); /* Generate ATX unlock challenge */ int avb_atx_get_unlock_challenge(struct AvbAtxOps* atx_ops, diff --git a/include/interface/storage/storage.h b/include/interface/storage/storage.h index e4f7f83656..4d524984e6 100644 --- a/include/interface/storage/storage.h +++ b/include/interface/storage/storage.h @@ -56,6 +56,9 @@ enum storage_cmd { /* transaction support */ STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT, + + STORAGE_RPMB_KEY_SET = 12 << STORAGE_REQ_SHIFT, + STORAGE_RPMB_ERASE_ALL = 13 << STORAGE_REQ_SHIFT, }; /** diff --git a/include/trusty/rpmb.h b/include/trusty/rpmb.h index e29a608a4b..810b8a1d7f 100644 --- a/include/trusty/rpmb.h +++ b/include/trusty/rpmb.h @@ -75,4 +75,14 @@ void *rpmb_storage_get_ctx(void); */ void rpmb_storage_put_ctx(void *dev); +/* + * Set rpmb key by secure side. + */ +int storage_set_rpmb_key(void); + +/* + * Erase rpmb storage by secure side. + */ +int storage_erase_rpmb(void); + #endif /* TRUSTY_RPMB_H_ */ diff --git a/lib/avb/fsl/fsl_avbkey.c b/lib/avb/fsl/fsl_avbkey.c index 8d34b505b1..7cabfc8ab8 100644 --- a/lib/avb/fsl/fsl_avbkey.c +++ b/lib/avb/fsl/fsl_avbkey.c @@ -26,6 +26,7 @@ #include "debug.h" #include #include "trusty/hwcrypto.h" +#include "trusty/rpmb.h" #include "fsl_atx_attributes.h" #include #include @@ -302,12 +303,18 @@ int rpmb_read(struct mmc *mmc, uint8_t *buffer, size_t num_bytes, int64_t offset ret = -1; goto fail; } - /* copy rpmb key to blob */ - memcpy(blob, kp.rpmb_keyblob, RPMBKEY_BLOB_LEN); caam_open(); - if (caam_decap_blob((ulong)extract_key, (ulong)blob, - RPMBKEY_LENGTH)) { - ERR("decap rpmb key error\n"); + if (!strcmp(kp.magic, KEYPACK_MAGIC)) { + /* Use the key from keyslot. */ + memcpy(blob, kp.rpmb_keyblob, RPMBKEY_BLOB_LEN); + if (caam_decap_blob((ulong)extract_key, (ulong)blob, + RPMBKEY_LENGTH)) { + ERR("decap rpmb key error\n"); + ret = -1; + goto fail; + } + } else if (caam_derive_bkek(extract_key)) { + ERR("get rpmb key error\n"); ret = -1; goto fail; } @@ -336,6 +343,7 @@ int rpmb_read(struct mmc *mmc, uint8_t *buffer, size_t num_bytes, int64_t offset out_buf += cnt; s = 0; } + memset(extract_key, 0, RPMBKEY_LENGTH); ret = 0; fail: @@ -402,12 +410,18 @@ int rpmb_write(struct mmc *mmc, uint8_t *buffer, size_t num_bytes, int64_t offse ret = -1; goto fail; } - /* copy rpmb key to blob */ - memcpy(blob, kp.rpmb_keyblob, RPMBKEY_BLOB_LEN); caam_open(); - if (caam_decap_blob((ulong)extract_key, (ulong)blob, - RPMBKEY_LENGTH)) { - ERR("decap rpmb key error\n"); + if (!strcmp(kp.magic, KEYPACK_MAGIC)) { + /* Use the key from keyslot. */ + memcpy(blob, kp.rpmb_keyblob, RPMBKEY_BLOB_LEN); + if (caam_decap_blob((ulong)extract_key, (ulong)blob, + RPMBKEY_LENGTH)) { + ERR("decap rpmb key error\n"); + ret = -1; + goto fail; + } + } else if (caam_derive_bkek(extract_key)) { + ERR("get rpmb key error\n"); ret = -1; goto fail; } @@ -441,6 +455,7 @@ int rpmb_write(struct mmc *mmc, uint8_t *buffer, size_t num_bytes, int64_t offse if (s != 0) s = 0; } + memset(extract_key, 0, RPMBKEY_LENGTH); ret = 0; fail: @@ -801,13 +816,8 @@ int check_rpmb_blob(struct mmc *mmc) read_keyslot_package(&kp); if (strcmp(kp.magic, KEYPACK_MAGIC)) { - if (rpmbkey_is_set()) { - printf("\nFATAL - RPMB key was destroyed!\n"); - hang(); - } else { - printf("keyslot package magic error, do nothing here!\n"); - return 0; - } + /* Return if the magic doesn't match */ + return 0; } /* If keyslot package valid, copy it to secure memory */ fill_secure_keyslot_package(&kp); @@ -1278,7 +1288,7 @@ fail: return ret; } -int fastboot_set_rpmb_key(uint8_t *staged_buf, uint32_t key_size) +int fastboot_set_rpmb_staged_key(uint8_t *staged_buf, uint32_t key_size) { if (memcmp(staged_buf, RPMB_KEY_MAGIC, strlen(RPMB_KEY_MAGIC))) { @@ -1290,16 +1300,9 @@ int fastboot_set_rpmb_key(uint8_t *staged_buf, uint32_t key_size) RPMBKEY_LENGTH); } -int fastboot_set_rpmb_random_key(void) +int fastboot_set_rpmb_hardware_key(void) { - ALLOC_CACHE_ALIGN_BUFFER(uint8_t, rpmb_key, RPMBKEY_LENGTH); - - if (hwcrypto_gen_rng((ulong)rpmb_key, RPMBKEY_LENGTH)) { - printf("error - can't generate random key!\n"); - return -1; - } - - return do_rpmb_key_set(rpmb_key, RPMBKEY_LENGTH); + return storage_set_rpmb_key(); } int avb_set_public_key(uint8_t *staged_buffer, uint32_t size) { diff --git a/lib/avb/fsl/fsl_bootctrl.c b/lib/avb/fsl/fsl_bootctrl.c index b10ccdaeb9..abb6a12536 100755 --- a/lib/avb/fsl/fsl_bootctrl.c +++ b/lib/avb/fsl/fsl_bootctrl.c @@ -643,13 +643,7 @@ int mmc_load_image_raw_sector_dual_uboot(struct spl_image_info *spl_image, #if !defined(CONFIG_XEN) && defined(CONFIG_IMX_TRUSTY_OS) read_keyslot_package(&kp); - if (strcmp(kp.magic, KEYPACK_MAGIC)) { - if (rpmbkey_is_set()) { - printf("\nFATAL - RPMB key was destroyed!\n"); - hang(); - } else - printf("keyslot package magic error, do nothing here!\n"); - } else { + if (!strcmp(kp.magic, KEYPACK_MAGIC)) { /* Set power-on write protection to boot1 partition. */ if (mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, BOOT1_PWR_WP)) { printf("Unable to set power-on write protection to boot1!\n"); diff --git a/lib/trusty/ql-tipc/ipc.c b/lib/trusty/ql-tipc/ipc.c index f488984d76..d1eb5ef456 100644 --- a/lib/trusty/ql-tipc/ipc.c +++ b/lib/trusty/ql-tipc/ipc.c @@ -177,6 +177,8 @@ Again: return rc; } +extern bool proxy_resp_flag; + int trusty_ipc_recv(struct trusty_ipc_chan *chan, const struct trusty_ipc_iovec *iovs, size_t iovs_cnt, bool wait) @@ -194,9 +196,13 @@ int trusty_ipc_recv(struct trusty_ipc_chan *chan, } } - rc = trusty_ipc_dev_recv(chan->dev, chan->handle, iovs, iovs_cnt); - if (rc < 0) - trusty_error("%s: ipc recv failed (%d)\n", __func__, rc); + /* Return directly if the iovs have been received. */ + if (!proxy_resp_flag) { + rc = trusty_ipc_dev_recv(chan->dev, chan->handle, iovs, iovs_cnt); + if (rc < 0) + trusty_error("%s: ipc recv failed (%d)\n", __func__, rc); + } else + rc = 0; return rc; } diff --git a/lib/trusty/ql-tipc/libtipc.c b/lib/trusty/ql-tipc/libtipc.c index 92c842be2c..f3bb3c8f70 100644 --- a/lib/trusty/ql-tipc/libtipc.c +++ b/lib/trusty/ql-tipc/libtipc.c @@ -48,6 +48,14 @@ bool rpmbkey_is_set(void); void rpmb_storage_put_ctx(void *dev); void trusty_ipc_shutdown(void) { + /** + * Trusty OS is not well initialized when the rpmb + * key is not set, skip ipc shut down to avoid panic. + */ + if (!rpmbkey_is_set()) { + return; + } + (void)rpmb_storage_proxy_shutdown(_ipc_dev); (void)rpmb_storage_put_ctx(rpmb_ctx); @@ -68,6 +76,7 @@ void trusty_ipc_shutdown(void) int trusty_ipc_init(void) { int rc; + bool use_keystore = true; /* init Trusty device */ trusty_info("Initializing Trusty device\n"); rc = trusty_dev_init(&_tdev, NULL); @@ -91,8 +100,7 @@ int trusty_ipc_init(void) trusty_info("Initializing RPMB storage proxy service\n"); rc = rpmb_storage_proxy_init(_ipc_dev, rpmb_ctx); if (rc != 0) { - trusty_error("Initlializing RPMB storage proxy service failed (%d)\n", - rc); + trusty_error("Initlializing RPMB storage proxy service failed (%d)\n", rc); #ifndef CONFIG_AVB_ATX /* check if rpmb key has been fused. */ if(rpmbkey_is_set()) { @@ -101,13 +109,16 @@ int trusty_ipc_init(void) hang(); } #else - return rc; + return rc; #endif - } else { - /* secure storage service init ok, use trusty backed keystore */ - env_set("keystore", "trusty"); + } - trusty_info("Initializing Trusty AVB client\n"); + /** + * The proxy service can return success even the storage initialization + * failed (when the rpmb key not set). Init the avb and keymaster service + * only when the rpmb key has been set. + */ + if (rpmbkey_is_set()) { rc = avb_tipc_init(_ipc_dev); if (rc != 0) { trusty_error("Initlializing Trusty AVB client failed (%d)\n", rc); @@ -120,7 +131,8 @@ int trusty_ipc_init(void) trusty_error("Initlializing Trusty Keymaster client failed (%d)\n", rc); return rc; } - } + } else + use_keystore = false; #ifndef CONFIG_AVB_ATX trusty_info("Initializing Trusty Hardware Crypto client\n"); @@ -131,5 +143,9 @@ int trusty_ipc_init(void) } #endif + /* secure storage service init ok, use trusty backed keystore */ + if (use_keystore) + env_set("keystore", "trusty"); + return TRUSTY_ERR_NONE; } diff --git a/lib/trusty/ql-tipc/rpmb_proxy.c b/lib/trusty/ql-tipc/rpmb_proxy.c index 2d5ca94f49..3c9d8ee36d 100644 --- a/lib/trusty/ql-tipc/rpmb_proxy.c +++ b/lib/trusty/ql-tipc/rpmb_proxy.c @@ -37,6 +37,8 @@ struct trusty_ipc_chan proxy_chan; struct storage_msg req_msg; static uint8_t req_buf[4096]; static uint8_t read_buf[4096]; +bool proxy_resp_flag = false; +static int req_len = 0; /* * Read RPMB request from storage service. Writes message to @msg @@ -73,6 +75,53 @@ static int proxy_read_request(struct trusty_ipc_chan *chan, return rc - sizeof(*msg); /* return payload size */ } +/* + * Read RPMB response from storage service. Writes message to @msg + * and @req. + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @cmd: cmd corresponding to the request + * @resp: address of storage message response + * @resp_len: length of resp in bytes + */ +static int proxy_read_response(struct trusty_ipc_chan *chan, struct storage_msg *msg, + uint32_t cmd, void *resp, size_t resp_len) +{ + int rc; + + struct trusty_ipc_iovec resp_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = resp, .len = resp_len }, + }; + rc = trusty_ipc_recv(chan, resp_iovs, resp ? 2 : 1, true); + if (rc < 0) { + /* recv message failed */ + trusty_error("%s: failed (%d) to recv response\n", __func__, rc); + return rc; + } + if (proxy_resp_flag) { + memcpy(msg, &req_msg, sizeof(struct storage_msg)); + if (resp) + memcpy(resp, req_buf, req_len); + rc = req_len + sizeof(struct storage_msg); + proxy_resp_flag = false; + } + + if ((size_t)rc < sizeof(*msg)) { + /* malformed message */ + trusty_error("%s: malformed request (%zu)\n", __func__, (size_t)rc); + return TRUSTY_ERR_GENERIC; + } + + if (msg->cmd != (cmd | STORAGE_RESP_BIT)) { + trusty_error("malformed response, cmd: 0x%x\n", msg->cmd); + return TRUSTY_ERR_GENERIC; + } + + return rc - sizeof(*msg); /* return payload size */ +} + /* * Send RPMB response to storage service * @@ -94,6 +143,71 @@ static int proxy_send_response(struct trusty_ipc_chan *chan, return trusty_ipc_send(chan, resp_iovs, resp ? 2 : 1, false); } +/* + * Send RPMB request to storage service + * + * @chan: proxy ipc channel + * @msg: address of storage message header + * @req: address of storage message request + * @req_len: length of request in bytes + */ +static int proxy_send_request(struct trusty_ipc_chan *chan, + struct storage_msg *msg, void *req, + size_t req_len) +{ + struct trusty_ipc_iovec req_iovs[2] = { + { .base = msg, .len = sizeof(*msg) }, + { .base = req, .len = req_len } + }; + + return trusty_ipc_send(chan, req_iovs, req ? 2 : 1, false); +} + +/* + * Convenience function to send a request to the storage service and read the + * response. + * + * @cmd: the command + * @req: the request buffer + * @req_size: size of the request buffer + * @resp: the response buffer + * @resp_size_p: pointer to the size of the response buffer. changed to the + actual size of the response read from the secure side + */ +static int storage_do_tipc(uint32_t cmd, void *req, uint32_t req_size, void *resp, + uint32_t *resp_size_p) +{ + int rc; + struct storage_msg msg = { .cmd = cmd }; + + if (!initialized) { + trusty_error("%s: Secure storage TIPC client not initialized\n", __func__); + return TRUSTY_ERR_GENERIC; + } + rc = proxy_send_request(&proxy_chan, &msg, req, req_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to send storage request\n", __func__, rc); + return rc; + } + + uint32_t resp_size = resp_size_p ? *resp_size_p : 0; + rc = proxy_read_response(&proxy_chan, &msg, cmd, resp, resp_size); + if (rc < 0) { + trusty_error("%s: failed (%d) to read secure storage response\n", __func__, rc); + return rc; + } + /* change response size to actual response size */ + if (resp_size_p && rc != *resp_size_p) { + *resp_size_p = rc; + } + if (msg.result != STORAGE_NO_ERROR) { + trusty_error("%s: secure storage service returned error (%d)\n", __func__, + msg.result); + return TRUSTY_ERR_GENERIC; + } + return TRUSTY_ERR_NONE; +} + /* * Executes the RPMB request at @r, sends response to storage service. * @@ -257,6 +371,18 @@ static int proxy_on_message(struct trusty_ipc_chan *chan) return rc; } + /** + * The response of proxy will also be routed to here but we should + * not handle them, just return and set "proxy_resp_flag" to indicate + * func trusty_ipc_dev_recv() not try to receive the msg again. + */ + if (req_msg.cmd & STORAGE_RESP_BIT) { + chan->complete = 1; + proxy_resp_flag = 1; + req_len = rc; + return TRUSTY_EVENT_HANDLED; + } + /* handle it and send reply */ rc = proxy_handle_req(chan, &req_msg, req_buf, rc); if (rc < 0) { @@ -330,3 +456,15 @@ void rpmb_storage_proxy_shutdown(struct trusty_ipc_dev *dev) initialized = false; } + +int storage_set_rpmb_key(void) +{ + uint32_t size = 0; + return storage_do_tipc(STORAGE_RPMB_KEY_SET, NULL, 0, NULL, &size); +} + +int storage_erase_rpmb(void) +{ + uint32_t size = 0; + return storage_do_tipc(STORAGE_RPMB_ERASE_ALL, NULL, 0, NULL, &size); +} -- 2.17.1