191fdabc6SPierre Aubert /* 291fdabc6SPierre Aubert * Copyright 2014, Staubli Faverges 391fdabc6SPierre Aubert * Pierre Aubert 491fdabc6SPierre Aubert * 591fdabc6SPierre Aubert * eMMC- Replay Protected Memory Block 691fdabc6SPierre Aubert * According to JEDEC Standard No. 84-A441 791fdabc6SPierre Aubert * 891fdabc6SPierre Aubert * SPDX-License-Identifier: GPL-2.0+ 991fdabc6SPierre Aubert */ 1091fdabc6SPierre Aubert 1191fdabc6SPierre Aubert #include <config.h> 1291fdabc6SPierre Aubert #include <common.h> 1391fdabc6SPierre Aubert #include <mmc.h> 14*2b9912e6SJeroen Hofstee #include <u-boot/sha256.h> 1591fdabc6SPierre Aubert #include "mmc_private.h" 1691fdabc6SPierre Aubert 1791fdabc6SPierre Aubert /* Request codes */ 1891fdabc6SPierre Aubert #define RPMB_REQ_KEY 1 1991fdabc6SPierre Aubert #define RPMB_REQ_WCOUNTER 2 2091fdabc6SPierre Aubert #define RPMB_REQ_WRITE_DATA 3 2191fdabc6SPierre Aubert #define RPMB_REQ_READ_DATA 4 2291fdabc6SPierre Aubert #define RPMB_REQ_STATUS 5 2391fdabc6SPierre Aubert 2491fdabc6SPierre Aubert /* Response code */ 2591fdabc6SPierre Aubert #define RPMB_RESP_KEY 0x0100 2691fdabc6SPierre Aubert #define RPMB_RESP_WCOUNTER 0x0200 2791fdabc6SPierre Aubert #define RPMB_RESP_WRITE_DATA 0x0300 2891fdabc6SPierre Aubert #define RPMB_RESP_READ_DATA 0x0400 2991fdabc6SPierre Aubert 3091fdabc6SPierre Aubert /* Error codes */ 3191fdabc6SPierre Aubert #define RPMB_OK 0 3291fdabc6SPierre Aubert #define RPMB_ERR_GENERAL 1 3391fdabc6SPierre Aubert #define RPMB_ERR_AUTH 2 3491fdabc6SPierre Aubert #define RPMB_ERR_COUNTER 3 3591fdabc6SPierre Aubert #define RPMB_ERR_ADDRESS 4 3691fdabc6SPierre Aubert #define RPMB_ERR_WRITE 5 3791fdabc6SPierre Aubert #define RPMB_ERR_READ 6 3891fdabc6SPierre Aubert #define RPMB_ERR_KEY 7 3991fdabc6SPierre Aubert #define RPMB_ERR_CNT_EXPIRED 0x80 4091fdabc6SPierre Aubert #define RPMB_ERR_MSK 0x7 4191fdabc6SPierre Aubert 4291fdabc6SPierre Aubert /* Sizes of RPMB data frame */ 4391fdabc6SPierre Aubert #define RPMB_SZ_STUFF 196 4491fdabc6SPierre Aubert #define RPMB_SZ_MAC 32 4591fdabc6SPierre Aubert #define RPMB_SZ_DATA 256 4691fdabc6SPierre Aubert #define RPMB_SZ_NONCE 16 4791fdabc6SPierre Aubert 4891fdabc6SPierre Aubert #define SHA256_BLOCK_SIZE 64 4991fdabc6SPierre Aubert 5091fdabc6SPierre Aubert /* Error messages */ 5191fdabc6SPierre Aubert static const char * const rpmb_err_msg[] = { 5291fdabc6SPierre Aubert "", 5391fdabc6SPierre Aubert "General failure", 5491fdabc6SPierre Aubert "Authentication failure", 5591fdabc6SPierre Aubert "Counter failure", 5691fdabc6SPierre Aubert "Address failure", 5791fdabc6SPierre Aubert "Write failure", 5891fdabc6SPierre Aubert "Read failure", 5991fdabc6SPierre Aubert "Authentication key not yet programmed", 6091fdabc6SPierre Aubert }; 6191fdabc6SPierre Aubert 6291fdabc6SPierre Aubert 6391fdabc6SPierre Aubert /* Structure of RPMB data frame. */ 6491fdabc6SPierre Aubert struct s_rpmb { 6591fdabc6SPierre Aubert unsigned char stuff[RPMB_SZ_STUFF]; 6691fdabc6SPierre Aubert unsigned char mac[RPMB_SZ_MAC]; 6791fdabc6SPierre Aubert unsigned char data[RPMB_SZ_DATA]; 6891fdabc6SPierre Aubert unsigned char nonce[RPMB_SZ_NONCE]; 6991fdabc6SPierre Aubert unsigned long write_counter; 7091fdabc6SPierre Aubert unsigned short address; 7191fdabc6SPierre Aubert unsigned short block_count; 7291fdabc6SPierre Aubert unsigned short result; 7391fdabc6SPierre Aubert unsigned short request; 7491fdabc6SPierre Aubert }; 7591fdabc6SPierre Aubert 7691fdabc6SPierre Aubert static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount, 7791fdabc6SPierre Aubert bool is_rel_write) 7891fdabc6SPierre Aubert { 7991fdabc6SPierre Aubert struct mmc_cmd cmd = {0}; 8091fdabc6SPierre Aubert 8191fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT; 8291fdabc6SPierre Aubert cmd.cmdarg = blockcount & 0x0000FFFF; 8391fdabc6SPierre Aubert if (is_rel_write) 8491fdabc6SPierre Aubert cmd.cmdarg |= 1 << 31; 8591fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1; 8691fdabc6SPierre Aubert 8791fdabc6SPierre Aubert return mmc_send_cmd(mmc, &cmd, NULL); 8891fdabc6SPierre Aubert } 8991fdabc6SPierre Aubert static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, 9091fdabc6SPierre Aubert unsigned int count, bool is_rel_write) 9191fdabc6SPierre Aubert { 9291fdabc6SPierre Aubert struct mmc_cmd cmd = {0}; 9391fdabc6SPierre Aubert struct mmc_data data; 9491fdabc6SPierre Aubert int ret; 9591fdabc6SPierre Aubert 9691fdabc6SPierre Aubert ret = mmc_set_blockcount(mmc, count, is_rel_write); 9791fdabc6SPierre Aubert if (ret) { 9891fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE 9991fdabc6SPierre Aubert printf("%s:mmc_set_blockcount-> %d\n", __func__, ret); 10091fdabc6SPierre Aubert #endif 10191fdabc6SPierre Aubert return 1; 10291fdabc6SPierre Aubert } 10391fdabc6SPierre Aubert 10491fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; 10591fdabc6SPierre Aubert cmd.cmdarg = 0; 10691fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1b; 10791fdabc6SPierre Aubert 10891fdabc6SPierre Aubert data.src = (const char *)s; 10991fdabc6SPierre Aubert data.blocks = 1; 11091fdabc6SPierre Aubert data.blocksize = MMC_MAX_BLOCK_LEN; 11191fdabc6SPierre Aubert data.flags = MMC_DATA_WRITE; 11291fdabc6SPierre Aubert 11391fdabc6SPierre Aubert ret = mmc_send_cmd(mmc, &cmd, &data); 11491fdabc6SPierre Aubert if (ret) { 11591fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE 11691fdabc6SPierre Aubert printf("%s:mmc_send_cmd-> %d\n", __func__, ret); 11791fdabc6SPierre Aubert #endif 11891fdabc6SPierre Aubert return 1; 11991fdabc6SPierre Aubert } 12091fdabc6SPierre Aubert return 0; 12191fdabc6SPierre Aubert } 12291fdabc6SPierre Aubert static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s, 12391fdabc6SPierre Aubert unsigned short expected) 12491fdabc6SPierre Aubert { 12591fdabc6SPierre Aubert struct mmc_cmd cmd = {0}; 12691fdabc6SPierre Aubert struct mmc_data data; 12791fdabc6SPierre Aubert int ret; 12891fdabc6SPierre Aubert 12991fdabc6SPierre Aubert ret = mmc_set_blockcount(mmc, 1, false); 13091fdabc6SPierre Aubert if (ret) { 13191fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE 13291fdabc6SPierre Aubert printf("%s:mmc_set_blockcount-> %d\n", __func__, ret); 13391fdabc6SPierre Aubert #endif 13491fdabc6SPierre Aubert return -1; 13591fdabc6SPierre Aubert } 13691fdabc6SPierre Aubert cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 13791fdabc6SPierre Aubert cmd.cmdarg = 0; 13891fdabc6SPierre Aubert cmd.resp_type = MMC_RSP_R1; 13991fdabc6SPierre Aubert 14091fdabc6SPierre Aubert data.dest = (char *)s; 14191fdabc6SPierre Aubert data.blocks = 1; 14291fdabc6SPierre Aubert data.blocksize = MMC_MAX_BLOCK_LEN; 14391fdabc6SPierre Aubert data.flags = MMC_DATA_READ; 14491fdabc6SPierre Aubert 14591fdabc6SPierre Aubert ret = mmc_send_cmd(mmc, &cmd, &data); 14691fdabc6SPierre Aubert if (ret) { 14791fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE 14891fdabc6SPierre Aubert printf("%s:mmc_send_cmd-> %d\n", __func__, ret); 14991fdabc6SPierre Aubert #endif 15091fdabc6SPierre Aubert return -1; 15191fdabc6SPierre Aubert } 15291fdabc6SPierre Aubert /* Check the response and the status */ 15391fdabc6SPierre Aubert if (be16_to_cpu(s->request) != expected) { 15491fdabc6SPierre Aubert #ifdef CONFIG_MMC_RPMB_TRACE 15591fdabc6SPierre Aubert printf("%s:response= %x\n", __func__, 15691fdabc6SPierre Aubert be16_to_cpu(s->request)); 15791fdabc6SPierre Aubert #endif 15891fdabc6SPierre Aubert return -1; 15991fdabc6SPierre Aubert } 16091fdabc6SPierre Aubert ret = be16_to_cpu(s->result); 16191fdabc6SPierre Aubert if (ret) { 16291fdabc6SPierre Aubert printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK], 16391fdabc6SPierre Aubert (ret & RPMB_ERR_CNT_EXPIRED) ? 16491fdabc6SPierre Aubert "Write counter has expired" : ""); 16591fdabc6SPierre Aubert } 16691fdabc6SPierre Aubert 16791fdabc6SPierre Aubert /* Return the status of the command */ 16891fdabc6SPierre Aubert return ret; 16991fdabc6SPierre Aubert } 17091fdabc6SPierre Aubert static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected) 17191fdabc6SPierre Aubert { 17291fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); 17391fdabc6SPierre Aubert 17491fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb)); 17591fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS); 17691fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) 17791fdabc6SPierre Aubert return -1; 17891fdabc6SPierre Aubert 17991fdabc6SPierre Aubert /* Read the result */ 18091fdabc6SPierre Aubert return mmc_rpmb_response(mmc, rpmb_frame, expected); 18191fdabc6SPierre Aubert } 18291fdabc6SPierre Aubert static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len, 18391fdabc6SPierre Aubert unsigned char *output) 18491fdabc6SPierre Aubert { 18591fdabc6SPierre Aubert sha256_context ctx; 18691fdabc6SPierre Aubert int i; 18791fdabc6SPierre Aubert unsigned char k_ipad[SHA256_BLOCK_SIZE]; 18891fdabc6SPierre Aubert unsigned char k_opad[SHA256_BLOCK_SIZE]; 18991fdabc6SPierre Aubert 19091fdabc6SPierre Aubert sha256_starts(&ctx); 19191fdabc6SPierre Aubert 19291fdabc6SPierre Aubert /* According to RFC 4634, the HMAC transform looks like: 19391fdabc6SPierre Aubert SHA(K XOR opad, SHA(K XOR ipad, text)) 19491fdabc6SPierre Aubert 19591fdabc6SPierre Aubert where K is an n byte key. 19691fdabc6SPierre Aubert ipad is the byte 0x36 repeated blocksize times 19791fdabc6SPierre Aubert opad is the byte 0x5c repeated blocksize times 19891fdabc6SPierre Aubert and text is the data being protected. 19991fdabc6SPierre Aubert */ 20091fdabc6SPierre Aubert 20191fdabc6SPierre Aubert for (i = 0; i < RPMB_SZ_MAC; i++) { 20291fdabc6SPierre Aubert k_ipad[i] = key[i] ^ 0x36; 20391fdabc6SPierre Aubert k_opad[i] = key[i] ^ 0x5c; 20491fdabc6SPierre Aubert } 20591fdabc6SPierre Aubert /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ 20691fdabc6SPierre Aubert for ( ; i < SHA256_BLOCK_SIZE; i++) { 20791fdabc6SPierre Aubert k_ipad[i] = 0x36; 20891fdabc6SPierre Aubert k_opad[i] = 0x5c; 20991fdabc6SPierre Aubert } 21091fdabc6SPierre Aubert sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE); 21191fdabc6SPierre Aubert sha256_update(&ctx, buff, len); 21291fdabc6SPierre Aubert sha256_finish(&ctx, output); 21391fdabc6SPierre Aubert 21491fdabc6SPierre Aubert /* Init context for second pass */ 21591fdabc6SPierre Aubert sha256_starts(&ctx); 21691fdabc6SPierre Aubert 21791fdabc6SPierre Aubert /* start with outer pad */ 21891fdabc6SPierre Aubert sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE); 21991fdabc6SPierre Aubert 22091fdabc6SPierre Aubert /* then results of 1st hash */ 22191fdabc6SPierre Aubert sha256_update(&ctx, output, RPMB_SZ_MAC); 22291fdabc6SPierre Aubert 22391fdabc6SPierre Aubert /* finish up 2nd pass */ 22491fdabc6SPierre Aubert sha256_finish(&ctx, output); 22591fdabc6SPierre Aubert } 22691fdabc6SPierre Aubert int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter) 22791fdabc6SPierre Aubert { 22891fdabc6SPierre Aubert int ret; 22991fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); 23091fdabc6SPierre Aubert 23191fdabc6SPierre Aubert /* Fill the request */ 23291fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb)); 23391fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER); 23491fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) 23591fdabc6SPierre Aubert return -1; 23691fdabc6SPierre Aubert 23791fdabc6SPierre Aubert /* Read the result */ 23891fdabc6SPierre Aubert ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER); 23991fdabc6SPierre Aubert if (ret) 24091fdabc6SPierre Aubert return ret; 24191fdabc6SPierre Aubert 24291fdabc6SPierre Aubert *pcounter = be32_to_cpu(rpmb_frame->write_counter); 24391fdabc6SPierre Aubert return 0; 24491fdabc6SPierre Aubert } 24591fdabc6SPierre Aubert int mmc_rpmb_set_key(struct mmc *mmc, void *key) 24691fdabc6SPierre Aubert { 24791fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); 24891fdabc6SPierre Aubert /* Fill the request */ 24991fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb)); 25091fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY); 25191fdabc6SPierre Aubert memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC); 25291fdabc6SPierre Aubert 25391fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, true)) 25491fdabc6SPierre Aubert return -1; 25591fdabc6SPierre Aubert 25691fdabc6SPierre Aubert /* read the operation status */ 25791fdabc6SPierre Aubert return mmc_rpmb_status(mmc, RPMB_RESP_KEY); 25891fdabc6SPierre Aubert } 25991fdabc6SPierre Aubert int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk, 26091fdabc6SPierre Aubert unsigned short cnt, unsigned char *key) 26191fdabc6SPierre Aubert { 26291fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); 26391fdabc6SPierre Aubert int i; 26491fdabc6SPierre Aubert 26591fdabc6SPierre Aubert for (i = 0; i < cnt; i++) { 26691fdabc6SPierre Aubert /* Fill the request */ 26791fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb)); 26891fdabc6SPierre Aubert rpmb_frame->address = cpu_to_be16(blk + i); 26991fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA); 27091fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, false)) 27191fdabc6SPierre Aubert break; 27291fdabc6SPierre Aubert 27391fdabc6SPierre Aubert /* Read the result */ 27491fdabc6SPierre Aubert if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA)) 27591fdabc6SPierre Aubert break; 27691fdabc6SPierre Aubert 27791fdabc6SPierre Aubert /* Check the HMAC if key is provided */ 27891fdabc6SPierre Aubert if (key) { 27991fdabc6SPierre Aubert unsigned char ret_hmac[RPMB_SZ_MAC]; 28091fdabc6SPierre Aubert 28191fdabc6SPierre Aubert rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac); 28291fdabc6SPierre Aubert if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) { 28391fdabc6SPierre Aubert printf("MAC error on block #%d\n", i); 28491fdabc6SPierre Aubert break; 28591fdabc6SPierre Aubert } 28691fdabc6SPierre Aubert } 28791fdabc6SPierre Aubert /* Copy data */ 28891fdabc6SPierre Aubert memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA); 28991fdabc6SPierre Aubert } 29091fdabc6SPierre Aubert return i; 29191fdabc6SPierre Aubert } 29291fdabc6SPierre Aubert int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk, 29391fdabc6SPierre Aubert unsigned short cnt, unsigned char *key) 29491fdabc6SPierre Aubert { 29591fdabc6SPierre Aubert ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1); 29691fdabc6SPierre Aubert unsigned long wcount; 29791fdabc6SPierre Aubert int i; 29891fdabc6SPierre Aubert 29991fdabc6SPierre Aubert for (i = 0; i < cnt; i++) { 30091fdabc6SPierre Aubert if (mmc_rpmb_get_counter(mmc, &wcount)) { 30191fdabc6SPierre Aubert printf("Cannot read RPMB write counter\n"); 30291fdabc6SPierre Aubert break; 30391fdabc6SPierre Aubert } 30491fdabc6SPierre Aubert 30591fdabc6SPierre Aubert /* Fill the request */ 30691fdabc6SPierre Aubert memset(rpmb_frame, 0, sizeof(struct s_rpmb)); 30791fdabc6SPierre Aubert memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA); 30891fdabc6SPierre Aubert rpmb_frame->address = cpu_to_be16(blk + i); 30991fdabc6SPierre Aubert rpmb_frame->block_count = cpu_to_be16(1); 31091fdabc6SPierre Aubert rpmb_frame->write_counter = cpu_to_be32(wcount); 31191fdabc6SPierre Aubert rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA); 31291fdabc6SPierre Aubert /* Computes HMAC */ 31391fdabc6SPierre Aubert rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac); 31491fdabc6SPierre Aubert 31591fdabc6SPierre Aubert if (mmc_rpmb_request(mmc, rpmb_frame, 1, true)) 31691fdabc6SPierre Aubert break; 31791fdabc6SPierre Aubert 31891fdabc6SPierre Aubert /* Get status */ 31991fdabc6SPierre Aubert if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA)) 32091fdabc6SPierre Aubert break; 32191fdabc6SPierre Aubert } 32291fdabc6SPierre Aubert return i; 32391fdabc6SPierre Aubert } 324