uboot/drivers/mmc/rpmb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2014, Staubli Faverges
   4 * Pierre Aubert
   5 *
   6 * eMMC- Replay Protected Memory Block
   7 * According to JEDEC Standard No. 84-A441
   8 */
   9
  10#include <config.h>
  11#include <common.h>
  12#include <memalign.h>
  13#include <mmc.h>
  14#include <u-boot/sha256.h>
  15#include "mmc_private.h"
  16
  17/* Request codes */
  18#define RPMB_REQ_KEY            1
  19#define RPMB_REQ_WCOUNTER       2
  20#define RPMB_REQ_WRITE_DATA     3
  21#define RPMB_REQ_READ_DATA      4
  22#define RPMB_REQ_STATUS         5
  23
  24/* Response code */
  25#define RPMB_RESP_KEY           0x0100
  26#define RPMB_RESP_WCOUNTER      0x0200
  27#define RPMB_RESP_WRITE_DATA    0x0300
  28#define RPMB_RESP_READ_DATA     0x0400
  29
  30/* Error codes */
  31#define RPMB_OK                 0
  32#define RPMB_ERR_GENERAL        1
  33#define RPMB_ERR_AUTH   2
  34#define RPMB_ERR_COUNTER        3
  35#define RPMB_ERR_ADDRESS        4
  36#define RPMB_ERR_WRITE          5
  37#define RPMB_ERR_READ           6
  38#define RPMB_ERR_KEY            7
  39#define RPMB_ERR_CNT_EXPIRED    0x80
  40#define RPMB_ERR_MSK            0x7
  41
  42/* Sizes of RPMB data frame */
  43#define RPMB_SZ_STUFF           196
  44#define RPMB_SZ_MAC             32
  45#define RPMB_SZ_DATA            256
  46#define RPMB_SZ_NONCE           16
  47
  48#define SHA256_BLOCK_SIZE       64
  49
  50/* Error messages */
  51static const char * const rpmb_err_msg[] = {
  52        "",
  53        "General failure",
  54        "Authentication failure",
  55        "Counter failure",
  56        "Address failure",
  57        "Write failure",
  58        "Read failure",
  59        "Authentication key not yet programmed",
  60};
  61
  62
  63/* Structure of RPMB data frame. */
  64struct s_rpmb {
  65        unsigned char stuff[RPMB_SZ_STUFF];
  66        unsigned char mac[RPMB_SZ_MAC];
  67        unsigned char data[RPMB_SZ_DATA];
  68        unsigned char nonce[RPMB_SZ_NONCE];
  69        unsigned int write_counter;
  70        unsigned short address;
  71        unsigned short block_count;
  72        unsigned short result;
  73        unsigned short request;
  74};
  75
  76static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount,
  77                              bool is_rel_write)
  78{
  79        struct mmc_cmd cmd = {0};
  80
  81        cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
  82        cmd.cmdarg = blockcount & 0x0000FFFF;
  83        if (is_rel_write)
  84                cmd.cmdarg |= 1 << 31;
  85        cmd.resp_type = MMC_RSP_R1;
  86
  87        return mmc_send_cmd(mmc, &cmd, NULL);
  88}
  89static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
  90                            unsigned int count, bool is_rel_write)
  91{
  92        struct mmc_cmd cmd = {0};
  93        struct mmc_data data;
  94        int ret;
  95
  96        ret = mmc_set_blockcount(mmc, count, is_rel_write);
  97        if (ret) {
  98#ifdef CONFIG_MMC_RPMB_TRACE
  99                printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
 100#endif
 101                return 1;
 102        }
 103
 104        cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
 105        cmd.cmdarg = 0;
 106        cmd.resp_type = MMC_RSP_R1b;
 107
 108        data.src = (const char *)s;
 109        data.blocks = 1;
 110        data.blocksize = MMC_MAX_BLOCK_LEN;
 111        data.flags = MMC_DATA_WRITE;
 112
 113        ret = mmc_send_cmd(mmc, &cmd, &data);
 114        if (ret) {
 115#ifdef CONFIG_MMC_RPMB_TRACE
 116                printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
 117#endif
 118                return 1;
 119        }
 120        return 0;
 121}
 122static int mmc_rpmb_response(struct mmc *mmc, struct s_rpmb *s,
 123                             unsigned short expected)
 124{
 125        struct mmc_cmd cmd = {0};
 126        struct mmc_data data;
 127        int ret;
 128
 129        ret = mmc_set_blockcount(mmc, 1, false);
 130        if (ret) {
 131#ifdef CONFIG_MMC_RPMB_TRACE
 132                printf("%s:mmc_set_blockcount-> %d\n", __func__, ret);
 133#endif
 134                return -1;
 135        }
 136        cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
 137        cmd.cmdarg = 0;
 138        cmd.resp_type = MMC_RSP_R1;
 139
 140        data.dest = (char *)s;
 141        data.blocks = 1;
 142        data.blocksize = MMC_MAX_BLOCK_LEN;
 143        data.flags = MMC_DATA_READ;
 144
 145        ret = mmc_send_cmd(mmc, &cmd, &data);
 146        if (ret) {
 147#ifdef CONFIG_MMC_RPMB_TRACE
 148                printf("%s:mmc_send_cmd-> %d\n", __func__, ret);
 149#endif
 150                return -1;
 151        }
 152        /* Check the response and the status */
 153        if (be16_to_cpu(s->request) != expected) {
 154#ifdef CONFIG_MMC_RPMB_TRACE
 155                printf("%s:response= %x\n", __func__,
 156                       be16_to_cpu(s->request));
 157#endif
 158                return -1;
 159        }
 160        ret = be16_to_cpu(s->result);
 161        if (ret) {
 162                printf("%s %s\n", rpmb_err_msg[ret & RPMB_ERR_MSK],
 163                       (ret & RPMB_ERR_CNT_EXPIRED) ?
 164                       "Write counter has expired" : "");
 165        }
 166
 167        /* Return the status of the command */
 168        return ret;
 169}
 170static int mmc_rpmb_status(struct mmc *mmc, unsigned short expected)
 171{
 172        ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
 173
 174        memset(rpmb_frame, 0, sizeof(struct s_rpmb));
 175        rpmb_frame->request = cpu_to_be16(RPMB_REQ_STATUS);
 176        if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
 177                return -1;
 178
 179        /* Read the result */
 180        return mmc_rpmb_response(mmc, rpmb_frame, expected);
 181}
 182static void rpmb_hmac(unsigned char *key, unsigned char *buff, int len,
 183                      unsigned char *output)
 184{
 185        sha256_context ctx;
 186        int i;
 187        unsigned char k_ipad[SHA256_BLOCK_SIZE];
 188        unsigned char k_opad[SHA256_BLOCK_SIZE];
 189
 190        sha256_starts(&ctx);
 191
 192        /* According to RFC 4634, the HMAC transform looks like:
 193           SHA(K XOR opad, SHA(K XOR ipad, text))
 194
 195           where K is an n byte key.
 196           ipad is the byte 0x36 repeated blocksize times
 197           opad is the byte 0x5c repeated blocksize times
 198           and text is the data being protected.
 199        */
 200
 201        for (i = 0; i < RPMB_SZ_MAC; i++) {
 202                k_ipad[i] = key[i] ^ 0x36;
 203                k_opad[i] = key[i] ^ 0x5c;
 204        }
 205        /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
 206        for ( ; i < SHA256_BLOCK_SIZE; i++) {
 207                k_ipad[i] = 0x36;
 208                k_opad[i] = 0x5c;
 209        }
 210        sha256_update(&ctx, k_ipad, SHA256_BLOCK_SIZE);
 211        sha256_update(&ctx, buff, len);
 212        sha256_finish(&ctx, output);
 213
 214        /* Init context for second pass */
 215        sha256_starts(&ctx);
 216
 217        /* start with outer pad */
 218        sha256_update(&ctx, k_opad, SHA256_BLOCK_SIZE);
 219
 220        /* then results of 1st hash */
 221        sha256_update(&ctx, output, RPMB_SZ_MAC);
 222
 223        /* finish up 2nd pass */
 224        sha256_finish(&ctx, output);
 225}
 226int mmc_rpmb_get_counter(struct mmc *mmc, unsigned long *pcounter)
 227{
 228        int ret;
 229        ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
 230
 231        /* Fill the request */
 232        memset(rpmb_frame, 0, sizeof(struct s_rpmb));
 233        rpmb_frame->request = cpu_to_be16(RPMB_REQ_WCOUNTER);
 234        if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
 235                return -1;
 236
 237        /* Read the result */
 238        ret = mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_WCOUNTER);
 239        if (ret)
 240                return ret;
 241
 242        *pcounter = be32_to_cpu(rpmb_frame->write_counter);
 243        return 0;
 244}
 245int mmc_rpmb_set_key(struct mmc *mmc, void *key)
 246{
 247        ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
 248        /* Fill the request */
 249        memset(rpmb_frame, 0, sizeof(struct s_rpmb));
 250        rpmb_frame->request = cpu_to_be16(RPMB_REQ_KEY);
 251        memcpy(rpmb_frame->mac, key, RPMB_SZ_MAC);
 252
 253        if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
 254                return -1;
 255
 256        /* read the operation status */
 257        return mmc_rpmb_status(mmc, RPMB_RESP_KEY);
 258}
 259int mmc_rpmb_read(struct mmc *mmc, void *addr, unsigned short blk,
 260                  unsigned short cnt, unsigned char *key)
 261{
 262        ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
 263        int i;
 264
 265        for (i = 0; i < cnt; i++) {
 266                /* Fill the request */
 267                memset(rpmb_frame, 0, sizeof(struct s_rpmb));
 268                rpmb_frame->address = cpu_to_be16(blk + i);
 269                rpmb_frame->request = cpu_to_be16(RPMB_REQ_READ_DATA);
 270                if (mmc_rpmb_request(mmc, rpmb_frame, 1, false))
 271                        break;
 272
 273                /* Read the result */
 274                if (mmc_rpmb_response(mmc, rpmb_frame, RPMB_RESP_READ_DATA))
 275                        break;
 276
 277                /* Check the HMAC if key is provided */
 278                if (key) {
 279                        unsigned char ret_hmac[RPMB_SZ_MAC];
 280
 281                        rpmb_hmac(key, rpmb_frame->data, 284, ret_hmac);
 282                        if (memcmp(ret_hmac, rpmb_frame->mac, RPMB_SZ_MAC)) {
 283                                printf("MAC error on block #%d\n", i);
 284                                break;
 285                        }
 286                }
 287                /* Copy data */
 288                memcpy(addr + i * RPMB_SZ_DATA, rpmb_frame->data, RPMB_SZ_DATA);
 289        }
 290        return i;
 291}
 292int mmc_rpmb_write(struct mmc *mmc, void *addr, unsigned short blk,
 293                  unsigned short cnt, unsigned char *key)
 294{
 295        ALLOC_CACHE_ALIGN_BUFFER(struct s_rpmb, rpmb_frame, 1);
 296        unsigned long wcount;
 297        int i;
 298
 299        for (i = 0; i < cnt; i++) {
 300                if (mmc_rpmb_get_counter(mmc, &wcount)) {
 301                        printf("Cannot read RPMB write counter\n");
 302                        break;
 303                }
 304
 305                /* Fill the request */
 306                memset(rpmb_frame, 0, sizeof(struct s_rpmb));
 307                memcpy(rpmb_frame->data, addr + i * RPMB_SZ_DATA, RPMB_SZ_DATA);
 308                rpmb_frame->address = cpu_to_be16(blk + i);
 309                rpmb_frame->block_count = cpu_to_be16(1);
 310                rpmb_frame->write_counter = cpu_to_be32(wcount);
 311                rpmb_frame->request = cpu_to_be16(RPMB_REQ_WRITE_DATA);
 312                /* Computes HMAC */
 313                rpmb_hmac(key, rpmb_frame->data, 284, rpmb_frame->mac);
 314
 315                if (mmc_rpmb_request(mmc, rpmb_frame, 1, true))
 316                        break;
 317
 318                /* Get status */
 319                if (mmc_rpmb_status(mmc, RPMB_RESP_WRITE_DATA))
 320                        break;
 321        }
 322        return i;
 323}
 324
 325static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm,
 326                                 unsigned short cnt)
 327{
 328        struct mmc_cmd cmd = {
 329                .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK,
 330                .resp_type = MMC_RSP_R1b,
 331        };
 332        struct mmc_data data = {
 333                .src = (const void *)frm,
 334                .blocks = cnt,
 335                .blocksize = sizeof(*frm),
 336                .flags = MMC_DATA_WRITE,
 337        };
 338
 339        return mmc_send_cmd(mmc, &cmd, &data);
 340}
 341
 342static int send_read_mult_block(struct mmc *mmc, struct s_rpmb *frm,
 343                                unsigned short cnt)
 344{
 345        struct mmc_cmd cmd = {
 346                .cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
 347                .resp_type = MMC_RSP_R1,
 348        };
 349        struct mmc_data data = {
 350                .dest = (void *)frm,
 351                .blocks = cnt,
 352                .blocksize = sizeof(*frm),
 353                .flags = MMC_DATA_READ,
 354        };
 355
 356        return mmc_send_cmd(mmc, &cmd, &data);
 357}
 358
 359static int rpmb_route_write_req(struct mmc *mmc, struct s_rpmb *req,
 360                                unsigned short req_cnt, struct s_rpmb *rsp,
 361                                unsigned short rsp_cnt)
 362{
 363        int ret;
 364
 365        /*
 366         * Send the write request.
 367         */
 368        ret = mmc_set_blockcount(mmc, req_cnt, true);
 369        if (ret)
 370                return ret;
 371
 372        ret = send_write_mult_block(mmc, req, req_cnt);
 373        if (ret)
 374                return ret;
 375
 376        /*
 377         * Read the result of the request.
 378         */
 379        ret = mmc_set_blockcount(mmc, 1, false);
 380        if (ret)
 381                return ret;
 382
 383        memset(rsp, 0, sizeof(*rsp));
 384        rsp->request = cpu_to_be16(RPMB_REQ_STATUS);
 385        ret = send_write_mult_block(mmc, rsp, 1);
 386        if (ret)
 387                return ret;
 388
 389        ret = mmc_set_blockcount(mmc, 1, false);
 390        if (ret)
 391                return ret;
 392
 393        return send_read_mult_block(mmc, rsp, 1);
 394}
 395
 396static int rpmb_route_read_req(struct mmc *mmc, struct s_rpmb *req,
 397                               unsigned short req_cnt, struct s_rpmb *rsp,
 398                               unsigned short rsp_cnt)
 399{
 400        int ret;
 401
 402        /*
 403         * Send the read request.
 404         */
 405        ret = mmc_set_blockcount(mmc, 1, false);
 406        if (ret)
 407                return ret;
 408
 409        ret = send_write_mult_block(mmc, req, 1);
 410        if (ret)
 411                return ret;
 412
 413        /*
 414         * Read the result of the request.
 415         */
 416
 417        ret = mmc_set_blockcount(mmc, rsp_cnt, false);
 418        if (ret)
 419                return ret;
 420
 421        return send_read_mult_block(mmc, rsp, rsp_cnt);
 422}
 423
 424static int rpmb_route_frames(struct mmc *mmc, struct s_rpmb *req,
 425                             unsigned short req_cnt, struct s_rpmb *rsp,
 426                             unsigned short rsp_cnt)
 427{
 428        unsigned short n;
 429
 430        /*
 431         * If multiple request frames are provided, make sure that all are
 432         * of the same type.
 433         */
 434        for (n = 1; n < req_cnt; n++)
 435                if (req[n].request != req->request)
 436                        return -EINVAL;
 437
 438        switch (be16_to_cpu(req->request)) {
 439        case RPMB_REQ_KEY:
 440                if (req_cnt != 1 || rsp_cnt != 1)
 441                        return -EINVAL;
 442                return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
 443
 444        case RPMB_REQ_WRITE_DATA:
 445                if (!req_cnt || rsp_cnt != 1)
 446                        return -EINVAL;
 447                return rpmb_route_write_req(mmc, req, req_cnt, rsp, rsp_cnt);
 448
 449        case RPMB_REQ_WCOUNTER:
 450                if (req_cnt != 1 || rsp_cnt != 1)
 451                        return -EINVAL;
 452                return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
 453
 454        case RPMB_REQ_READ_DATA:
 455                if (req_cnt != 1 || !req_cnt)
 456                        return -EINVAL;
 457                return rpmb_route_read_req(mmc, req, req_cnt, rsp, rsp_cnt);
 458
 459        default:
 460                debug("Unsupported message type: %d\n",
 461                      be16_to_cpu(req->request));
 462                return -EINVAL;
 463        }
 464}
 465
 466int mmc_rpmb_route_frames(struct mmc *mmc, void *req, unsigned long reqlen,
 467                          void *rsp, unsigned long rsplen)
 468{
 469        /*
 470         * Whoever crafted the data supplied to this function knows how to
 471         * format the PRMB frames and which response is expected. If
 472         * there's some unexpected mismatch it's more helpful to report an
 473         * error immediately than trying to guess what was the intention
 474         * and possibly just delay an eventual error which will be harder
 475         * to track down.
 476         */
 477
 478        if (reqlen % sizeof(struct s_rpmb) || rsplen % sizeof(struct s_rpmb))
 479                return -EINVAL;
 480
 481        return rpmb_route_frames(mmc, req, reqlen / sizeof(struct s_rpmb),
 482                                 rsp, rsplen / sizeof(struct s_rpmb));
 483}
 484