uboot/cmd/zynq_rsa.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Xilinx, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <asm/io.h>
   9#include <asm/arch/hardware.h>
  10#include <asm/arch/sys_proto.h>
  11#include <u-boot/md5.h>
  12#include <u-boot/rsa.h>
  13#include <u-boot/rsa-mod-exp.h>
  14#include <u-boot/sha256.h>
  15#include <spi_flash.h>
  16#include <zynqpl.h>
  17#include <fpga.h>
  18
  19DECLARE_GLOBAL_DATA_PTR;
  20
  21#define ZYNQ_IMAGE_PHDR_OFFSET          0x09C
  22#define ZYNQ_IMAGE_FSBL_LEN_OFFSET      0x040
  23
  24#define ZYNQ_PART_HDR_CHKSUM_WORD_COUNT 0x0F
  25#define ZYNQ_PART_HDR_WORD_COUNT        0x10
  26
  27#define ZYNQ_EFUSE_RSA_ENABLE_MASK      0x400
  28
  29#define ZYNQ_ATTRIBUTE_PL_IMAGE_MASK            0x20
  30#define ZYNQ_ATTRIBUTE_CHECKSUM_TYPE_MASK       0x7000
  31#define ZYNQ_ATTRIBUTE_RSA_PRESENT_MASK         0x8000
  32#define ZYNQ_ATTRIBUTE_RSA_PART_OWNER_MASK      0x30000
  33
  34#define ZYNQ_MAX_PARTITION_NUMBER       0xE
  35
  36#define ZYNQ_RSA_MODULAR_SIZE                   256
  37#define ZYNQ_RSA_MODULAR_EXT_SIZE               256
  38#define ZYNQ_RSA_EXPO_SIZE                      64
  39#define ZYNQ_RSA_SPK_SIGNATURE_SIZE             256
  40#define ZYNQ_RSA_PARTITION_SIGNATURE_SIZE       256
  41#define ZYNQ_RSA_SIGNATURE_SIZE                 0x6C0
  42#define ZYNQ_RSA_HEADER_SIZE                    4
  43#define ZYNQ_RSA_MAGIC_WORD_SIZE                60
  44#define ZYNQ_RSA_PART_OWNER_UBOOT               1
  45#define ZYNQ_RSA_ALIGN_PPK_START                64
  46
  47#define WORD_LENGTH_SHIFT       2
  48#define ZYNQ_MAXIMUM_IMAGE_WORD_LEN     0x40000000
  49
  50#define MD5_CHECKSUM_SIZE       16
  51
  52static u8 *ppkmodular;
  53static u8 *ppkmodularex;
  54static u32 ppkexp;
  55
  56struct partition_hdr {
  57        u32 imagewordlen;       /* 0x0 */
  58        u32 datawordlen;        /* 0x4 */
  59        u32 partitionwordlen;   /* 0x8 */
  60        u32 loadaddr;           /* 0xC */
  61        u32 execaddr;           /* 0x10 */
  62        u32 partitionstart;     /* 0x14 */
  63        u32 partitionattr;      /* 0x18 */
  64        u32 sectioncount;       /* 0x1C */
  65        u32 checksumoffset;     /* 0x20 */
  66        u32 pads1[1];
  67        u32 acoffset;   /* 0x28 */
  68        u32 pads2[4];
  69        u32 checksum;           /* 0x3C */
  70};
  71
  72struct zynq_rsa_public_key {
  73        uint len;               /* Length of modulus[] in number of uint32_t */
  74        uint32_t n0inv;         /* -1 / modulus[0] mod 2^32 */
  75        uint32_t *modulus;      /* modulus as little endian array */
  76        uint32_t *rr;           /* R^2 as little endian array */
  77};
  78
  79struct partition_hdr part_hdr[ZYNQ_MAX_PARTITION_NUMBER];
  80
  81struct headerarray {
  82        u32 fields[16];
  83};
  84
  85struct zynq_rsa_public_key public_key;
  86
  87static u32 fsbl_len;
  88
  89/*
  90 * Check whether the given partition is last partition or not
  91 */
  92static int zynq_islastpartition(struct headerarray *head)
  93{
  94        int index;
  95
  96        debug("zynq_islastpartition\n");
  97        if (head->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != 0xFFFFFFFF)
  98                return -1;
  99
 100        for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT - 1; index++) {
 101                if (head->fields[index] != 0x0)
 102                        return -1;
 103        }
 104
 105        return 0;
 106}
 107
 108/*
 109 * Get the partition count from the partition header
 110 */
 111static int zynq_get_part_count(struct partition_hdr *part_hdr_info)
 112{
 113        u32 count = 0;
 114        struct headerarray *hap;
 115
 116        debug("zynq_get_part_count\n");
 117
 118        for (count = 0; count < ZYNQ_MAX_PARTITION_NUMBER; count++) {
 119                hap = (struct headerarray *)&part_hdr_info[count];
 120                if (zynq_islastpartition(hap) != -1)
 121                        break;
 122        }
 123
 124        return count;
 125}
 126
 127/*
 128 * Get the partition info of all the partitions available.
 129 */
 130static int zynq_get_partition_info(u32 image_base_addr)
 131{
 132        u32 parthdroffset;
 133
 134        fsbl_len = *((u32 *)(image_base_addr + ZYNQ_IMAGE_FSBL_LEN_OFFSET));
 135
 136        parthdroffset = *((u32 *)(image_base_addr + ZYNQ_IMAGE_PHDR_OFFSET));
 137
 138        parthdroffset  += image_base_addr;
 139
 140        memcpy(&part_hdr[0], (u32 *)parthdroffset,
 141               (sizeof(struct partition_hdr) * ZYNQ_MAX_PARTITION_NUMBER));
 142
 143        return 0;
 144}
 145
 146/*
 147 * Check whether the partition header is valid or not
 148 */
 149static int zynq_validate_hdr(struct partition_hdr *header)
 150{
 151        struct headerarray *hap;
 152        u32 index;
 153        u32 checksum;
 154
 155        debug("zynq_validate_hdr\n");
 156
 157        hap = (struct headerarray *)header;
 158
 159        for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT; index++) {
 160                if (hap->fields[index] != 0x0)
 161                        break;
 162        }
 163        if (index  == ZYNQ_PART_HDR_WORD_COUNT)
 164                return -1;
 165
 166        checksum = 0;
 167        for (index = 0; index < ZYNQ_PART_HDR_CHKSUM_WORD_COUNT; index++)
 168                checksum += hap->fields[index];
 169
 170        checksum ^= 0xFFFFFFFF;
 171
 172        if (hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != checksum) {
 173                printf("Error: Checksum 0x%8.8x != 0x%8.8x\r\n",
 174                       checksum, hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT]);
 175                return -1;
 176        }
 177
 178        if (header->imagewordlen > ZYNQ_MAXIMUM_IMAGE_WORD_LEN) {
 179                printf("INVALID_PARTITION_LENGTH\r\n");
 180                return -1;
 181        }
 182
 183        return 0;
 184}
 185
 186/*
 187 * Validate the partition by calculationg the md5 checksum for the
 188 * partition and compare with checksum present in checksum offset of
 189 * partition
 190 */
 191static int zynq_validate_partition(u32 start_addr, u32 len, u32 chksum_off)
 192{
 193        u8 checksum[MD5_CHECKSUM_SIZE];
 194        u8 calchecksum[MD5_CHECKSUM_SIZE];
 195
 196        memcpy(&checksum[0], (u32 *)chksum_off, MD5_CHECKSUM_SIZE);
 197
 198        md5_wd((u8 *)start_addr, len, &calchecksum[0], 0x10000);
 199
 200        if ((memcmp(checksum, calchecksum, MD5_CHECKSUM_SIZE)) != 0) {
 201                printf("Error: Partition DataChecksum \r\n");
 202                return -1;
 203        }
 204        return 0;
 205}
 206
 207/*
 208 * Extract the primary public key components from already autheticated FSBL
 209 */
 210static void zynq_extract_ppk(void)
 211{
 212        u32 padsize;
 213        u8 *ppkptr;
 214
 215        debug("zynq_extract_ppk\n");
 216
 217        ppkptr = (u8 *)(fsbl_len + 0xFFFC0000);
 218        padsize = ((u32)ppkptr % ZYNQ_RSA_ALIGN_PPK_START);
 219        if (padsize != 0)
 220                ppkptr += (ZYNQ_RSA_ALIGN_PPK_START - padsize);
 221
 222        ppkptr += ZYNQ_RSA_HEADER_SIZE;
 223
 224        ppkptr += ZYNQ_RSA_MAGIC_WORD_SIZE;
 225
 226        ppkmodular = (u8 *)ppkptr;
 227        ppkptr += ZYNQ_RSA_MODULAR_SIZE;
 228        ppkmodularex = (u8 *)ppkptr;
 229        ppkptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
 230        ppkexp = *(u32 *)ppkptr;
 231}
 232
 233/*
 234 * Calculate the inverse(-1 / modulus[0] mod 2^32 ) for the PPK
 235 */
 236static u32 zynq_calc_inv(void)
 237{
 238        u32 modulus = public_key.modulus[0];
 239        u32 tmp = 2;
 240        u32 inverse;
 241
 242        inverse = modulus & 0x1;
 243
 244        while (tmp) {
 245                inverse *= 2-modulus*inverse;
 246                tmp *= tmp;
 247        }
 248
 249        return -inverse;
 250}
 251
 252/*
 253 * Recreate the signature by padding the bytes and verify with hash value
 254 */
 255static int zynq_pad_and_check(u8 *signature, u8 *hash)
 256{
 257        u8 padding[] = {0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
 258                        0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
 259                        0x20 };
 260        u8 *pad_ptr = signature + 256;
 261        u32 pad = 256 - 3 - 19 - 32;
 262        u32 ii;
 263
 264        /* Re-Create PKCS#1v1.5 Padding */
 265        if (*--pad_ptr != 0x00 || *--pad_ptr != 0x01)
 266                return -1;
 267
 268        for (ii = 0; ii < pad; ii++) {
 269                if (*--pad_ptr != 0xFF)
 270                        return -1;
 271        }
 272
 273        if (*--pad_ptr != 0x00)
 274                return -1;
 275
 276        for (ii = 0; ii < sizeof(padding); ii++) {
 277                if (*--pad_ptr != padding[ii])
 278                        return -1;
 279        }
 280
 281        for (ii = 0; ii < 32; ii++) {
 282                if (*--pad_ptr != hash[ii])
 283                        return -1;
 284        }
 285        return 0;
 286}
 287
 288/*
 289 * Verify and extract the hash value from signature using the public key
 290 * and compare it with calculated hash value.
 291 */
 292static int zynq_rsa_verify_key(const struct zynq_rsa_public_key *key,
 293                               const u8 *sig, const u32 sig_len, const u8 *hash)
 294{
 295        int status;
 296
 297        if ((!key) || (!sig) || (!hash))
 298                return -1;
 299
 300        if (sig_len != (key->len * sizeof(uint32_t))) {
 301                printf("Signature is of incorrect length %d\n", sig_len);
 302                return -1;
 303        }
 304
 305        /* Sanity check for stack size */
 306        if (sig_len > ZYNQ_RSA_SPK_SIGNATURE_SIZE) {
 307                printf("Signature length %u exceeds maximum %d\n", sig_len,
 308                       ZYNQ_RSA_SPK_SIGNATURE_SIZE);
 309                return -1;
 310        }
 311
 312        u32 buf[sig_len / sizeof(uint32_t)];
 313
 314        memcpy(buf, sig, sig_len);
 315
 316        status = zynq_pow_mod((u32 *)key, buf);
 317        if (status == -1)
 318                return status;
 319
 320        status = zynq_pad_and_check((u8 *)buf, (u8 *)hash);
 321        if (status == -1)
 322                return status;
 323        return 0;
 324}
 325
 326/*
 327 * Authenticate the partition
 328 */
 329static int zynq_authenticate_part(u8 *buffer, u32 size)
 330{
 331        u8 hash_signature[32];
 332        u8 *spk_modular;
 333        u8 *spk_modular_ex;
 334        u8 *signature_ptr;
 335        u32 status;
 336
 337        debug("zynq_authenticate_part\n");
 338
 339        signature_ptr = (u8 *)(buffer + size - ZYNQ_RSA_SIGNATURE_SIZE);
 340
 341        signature_ptr += ZYNQ_RSA_HEADER_SIZE;
 342
 343        signature_ptr += ZYNQ_RSA_MAGIC_WORD_SIZE;
 344
 345        ppkmodular = (u8 *)signature_ptr;
 346        signature_ptr += ZYNQ_RSA_MODULAR_SIZE;
 347        ppkmodularex = signature_ptr;
 348        signature_ptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
 349        signature_ptr += ZYNQ_RSA_EXPO_SIZE;
 350
 351        sha256_csum_wd((const unsigned char *)signature_ptr,
 352                       (ZYNQ_RSA_MODULAR_EXT_SIZE + ZYNQ_RSA_EXPO_SIZE +
 353                       ZYNQ_RSA_MODULAR_SIZE),
 354                       (unsigned char *)hash_signature, 0x1000);
 355
 356        spk_modular = (u8 *)signature_ptr;
 357        signature_ptr += ZYNQ_RSA_MODULAR_SIZE;
 358        spk_modular_ex = (u8 *)signature_ptr;
 359        signature_ptr += ZYNQ_RSA_MODULAR_EXT_SIZE;
 360        signature_ptr += ZYNQ_RSA_EXPO_SIZE;
 361
 362        public_key.len = ZYNQ_RSA_MODULAR_SIZE/sizeof(u32);
 363        public_key.modulus = (u32 *)ppkmodular;
 364        public_key.rr = (u32 *)ppkmodularex;
 365        public_key.n0inv = zynq_calc_inv();
 366
 367        status = zynq_rsa_verify_key(&public_key, signature_ptr,
 368                                ZYNQ_RSA_SPK_SIGNATURE_SIZE, hash_signature);
 369
 370        if (status)
 371                return status;
 372
 373        signature_ptr += ZYNQ_RSA_SPK_SIGNATURE_SIZE;
 374
 375        sha256_csum_wd((const unsigned char *)buffer,
 376                       (size - ZYNQ_RSA_PARTITION_SIGNATURE_SIZE),
 377                       (unsigned char *)hash_signature, 0x1000);
 378
 379        public_key.len = ZYNQ_RSA_MODULAR_SIZE/sizeof(u32);
 380        public_key.modulus = (u32 *)spk_modular;
 381        public_key.rr = (u32 *)spk_modular_ex;
 382        public_key.n0inv = zynq_calc_inv();
 383
 384        status = zynq_rsa_verify_key(&public_key, (u8 *)signature_ptr,
 385                                     ZYNQ_RSA_PARTITION_SIGNATURE_SIZE,
 386                                     (u8 *)hash_signature);
 387
 388        if (status)
 389                return status;
 390
 391        return 0;
 392}
 393
 394/*
 395 * Parses the partition header and verfies the authenticated and
 396 * encrypted image.
 397 */
 398static int do_zynq_verify_image(cmd_tbl_t *cmdtp, int flag, int argc,
 399                                char * const argv[])
 400{
 401        u32 silicon_ver;
 402        u32 image_base_addr;
 403        u32 status;
 404        u32 partition_num;
 405        u32 efuseval;
 406        u32 srcaddr;
 407        u32 size;
 408        struct partition_hdr *hdr_ptr;
 409        u32 part_data_len;
 410        u32 part_img_len;
 411        u32 part_attr;
 412        u32 part_load_addr;
 413        u32 part_dst_addr;
 414        u32 part_chksum_offset;
 415        u32 part_start_addr;
 416        u32 part_total_size;
 417        u32 partitioncount;
 418        u8 encrypt_part_flag;
 419        u8 part_chksum_flag;
 420        u8 signed_part_flag;
 421        char *endp;
 422
 423        if (argc < 2)
 424                goto usage;
 425
 426        image_base_addr = simple_strtoul(argv[1], &endp, 16);
 427        if (*argv[1] == 0 || *endp != 0)
 428                return -1;
 429
 430        silicon_ver = zynq_get_silicon_version();
 431
 432        /* RSA not supported in silicon versions 1.0 and 2.0 */
 433        if (silicon_ver == 0 || silicon_ver == 1)
 434                return -1;
 435
 436        status = zynq_get_partition_info(image_base_addr);
 437        if (status == -1) {
 438                printf("Get Partition Info Failed\n");
 439                return status;
 440        }
 441
 442        /* Extract ppk if efuse was blown Otherwise return error */
 443        efuseval = readl(&efuse_base->status);
 444        if (efuseval & ZYNQ_EFUSE_RSA_ENABLE_MASK)
 445                zynq_extract_ppk();
 446        else
 447                return -1;
 448
 449        partitioncount = zynq_get_part_count(&part_hdr[0]);
 450
 451        if ((partitioncount <= 2) ||
 452            (partitioncount > ZYNQ_MAX_PARTITION_NUMBER))
 453                return -1;
 454
 455        partition_num = 0;
 456
 457        while (partition_num < partitioncount) {
 458                if (((part_hdr[partition_num].partitionattr &
 459                   ZYNQ_ATTRIBUTE_RSA_PART_OWNER_MASK) >> 16) !=
 460                   ZYNQ_RSA_PART_OWNER_UBOOT) {
 461                        printf("UBOOT is not Owner for partition %d\r\n",
 462                               partition_num);
 463                } else {
 464                        hdr_ptr = &part_hdr[partition_num];
 465                        status = zynq_validate_hdr(hdr_ptr);
 466                        if (status == -1)
 467                                return status;
 468
 469                        part_data_len = hdr_ptr->datawordlen;
 470                        part_img_len = hdr_ptr->imagewordlen;
 471                        part_attr = hdr_ptr->partitionattr;
 472                        part_load_addr = hdr_ptr->loadaddr;
 473                        part_chksum_offset = hdr_ptr->checksumoffset;
 474                        part_start_addr = hdr_ptr->partitionstart;
 475                        part_total_size = hdr_ptr->partitionwordlen;
 476
 477                        if (part_data_len != part_img_len) {
 478                                debug("Encrypted\r\n");
 479                                encrypt_part_flag = 1;
 480                        } else {
 481                                encrypt_part_flag = 0;
 482                        }
 483
 484                        if (part_attr & ZYNQ_ATTRIBUTE_CHECKSUM_TYPE_MASK)
 485                                part_chksum_flag = 1;
 486                        else
 487                                part_chksum_flag = 0;
 488
 489                        if (part_attr & ZYNQ_ATTRIBUTE_RSA_PRESENT_MASK) {
 490                                debug("RSA Signed\r\n");
 491                                signed_part_flag = 1;
 492                        } else {
 493                                signed_part_flag = 0;
 494                        }
 495
 496                        srcaddr = image_base_addr +
 497                                  (part_start_addr << WORD_LENGTH_SHIFT);
 498
 499                        if (part_attr & ZYNQ_ATTRIBUTE_RSA_PRESENT_MASK) {
 500                                signed_part_flag = 1;
 501                                size = part_total_size << WORD_LENGTH_SHIFT;
 502                        } else {
 503                                signed_part_flag = 0;
 504                                size = part_img_len;
 505                        }
 506
 507                        if ((part_load_addr < gd->bd->bi_dram[0].start) &&
 508                            ((part_load_addr + part_data_len) >
 509                            (gd->bd->bi_dram[0].start +
 510                             gd->bd->bi_dram[0].size))) {
 511                                printf("INVALID_LOAD_ADDRESS_FAIL\r\n");
 512                                return -1;
 513                        }
 514
 515                        if (part_attr & ZYNQ_ATTRIBUTE_PL_IMAGE_MASK)
 516                                part_load_addr = srcaddr;
 517                        else
 518                                memcpy((u32 *)part_load_addr, (u32 *)srcaddr,
 519                                       size);
 520
 521                        if (!signed_part_flag && !part_chksum_flag) {
 522                                printf("Partition not signed & no chksum\n");
 523                                continue;
 524                        }
 525
 526                        if (part_chksum_flag) {
 527                                part_chksum_offset = image_base_addr +
 528                                                     (part_chksum_offset <<
 529                                                     WORD_LENGTH_SHIFT);
 530                                status = zynq_validate_partition(part_load_addr,
 531                                                        (part_total_size <<
 532                                                        WORD_LENGTH_SHIFT),
 533                                                        part_chksum_offset);
 534                                if (status != 0) {
 535                                        printf("PART_CHKSUM_FAIL\r\n");
 536                                        return -1;
 537                                }
 538                                debug("Partition Validation Done\r\n");
 539                        }
 540
 541                        if (signed_part_flag == 1) {
 542                                status = zynq_authenticate_part(
 543                                                           (u8 *)part_load_addr,
 544                                                           size);
 545                                if (status != 0) {
 546                                        printf("AUTHENTICATION_FAIL\r\n");
 547                                        return -1;
 548                                }
 549                                debug("Authentication Done\r\n");
 550                        }
 551
 552                        if (encrypt_part_flag) {
 553                                debug("DECRYPTION \r\n");
 554
 555                                part_dst_addr = part_load_addr;
 556
 557                                if (part_attr & ZYNQ_ATTRIBUTE_PL_IMAGE_MASK)
 558                                        part_dst_addr = 0xFFFFFFFF;
 559
 560                                status = zynq_decrypt_load(part_load_addr,
 561                                                           part_img_len,
 562                                                           part_dst_addr,
 563                                                           part_data_len,
 564                                                           BIT_NONE);
 565                                if (status != 0) {
 566                                        printf("DECRYPTION_FAIL\r\n");
 567                                        return -1;
 568                                }
 569                        }
 570                }
 571                partition_num++;
 572        }
 573
 574        return 0;
 575
 576usage:
 577        return CMD_RET_USAGE;
 578}
 579
 580#ifdef CONFIG_SYS_LONGHELP
 581static char zynqrsa_help_text[] =
 582"zynqrsa <baseaddr>  - Verifies the authenticated and encrypted zynq images\n";
 583#endif
 584
 585U_BOOT_CMD(
 586        zynqrsa,        2,      0,      do_zynq_verify_image,
 587        "Zynq RSA verfication ", zynqrsa_help_text
 588);
 589