Siew Chin Lim | 2492d59 | 2021-03-01 20:04:11 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) 2020 Intel Corporation <www.intel.com> |
| 4 | * |
| 5 | */ |
| 6 | |
| 7 | #include <asm/arch/mailbox_s10.h> |
| 8 | #include <asm/arch/secure_vab.h> |
| 9 | #include <asm/arch/smc_api.h> |
| 10 | #include <asm/unaligned.h> |
Siew Chin Lim | 2492d59 | 2021-03-01 20:04:11 +0800 | [diff] [blame] | 11 | #include <exports.h> |
| 12 | #include <linux/errno.h> |
| 13 | #include <linux/intel-smc.h> |
| 14 | #include <log.h> |
| 15 | |
| 16 | #define CHUNKSZ_PER_WD_RESET (256 * SZ_1K) |
| 17 | |
| 18 | /* |
| 19 | * Read the length of the VAB certificate from the end of image |
| 20 | * and calculate the actual image size (excluding the VAB certificate). |
| 21 | */ |
| 22 | static size_t get_img_size(u8 *img_buf, size_t img_buf_sz) |
| 23 | { |
| 24 | u8 *img_buf_end = img_buf + img_buf_sz; |
| 25 | u32 cert_sz = get_unaligned_le32(img_buf_end - sizeof(u32)); |
| 26 | u8 *p = img_buf_end - cert_sz - sizeof(u32); |
| 27 | |
| 28 | /* Ensure p is pointing within the img_buf */ |
| 29 | if (p < img_buf || p > (img_buf_end - VAB_CERT_HEADER_SIZE)) |
| 30 | return 0; |
| 31 | |
| 32 | if (get_unaligned_le32(p) == SDM_CERT_MAGIC_NUM) |
| 33 | return (size_t)(p - img_buf); |
| 34 | |
| 35 | return 0; |
| 36 | } |
| 37 | |
| 38 | /* |
| 39 | * Vendor Authorized Boot (VAB) is a security feature for authenticating |
| 40 | * the images such as U-Boot, ARM trusted Firmware, Linux kernel, |
| 41 | * device tree blob and etc loaded from FIT. User can also trigger |
| 42 | * the VAB authentication from U-Boot command. |
| 43 | * |
| 44 | * This function extracts the VAB certificate and signature block |
| 45 | * appended at the end of the image, then send to Secure Device Manager |
| 46 | * (SDM) for authentication. This function will validate the SHA384 |
| 47 | * of the image against the SHA384 hash stored in the VAB certificate |
| 48 | * before sending the VAB certificate to SDM for authentication. |
| 49 | * |
| 50 | * RETURN |
| 51 | * 0 if authentication success or |
| 52 | * if authentication is not required and bypassed on a non-secure device |
| 53 | * negative error code if authentication fail |
| 54 | */ |
| 55 | int socfpga_vendor_authentication(void **p_image, size_t *p_size) |
| 56 | { |
| 57 | int retry_count = 20; |
| 58 | u8 hash384[SHA384_SUM_LEN]; |
| 59 | u64 img_addr, mbox_data_addr; |
| 60 | size_t img_sz, mbox_data_sz; |
| 61 | u8 *cert_hash_ptr, *mbox_relocate_data_addr; |
| 62 | u32 resp = 0, resp_len = 1; |
| 63 | int ret; |
| 64 | |
| 65 | img_addr = (uintptr_t)*p_image; |
| 66 | |
| 67 | debug("Authenticating image at address 0x%016llx (%ld bytes)\n", |
| 68 | img_addr, *p_size); |
| 69 | |
| 70 | img_sz = get_img_size((u8 *)img_addr, *p_size); |
| 71 | debug("img_sz = %ld\n", img_sz); |
| 72 | |
| 73 | if (!img_sz) { |
| 74 | puts("VAB certificate not found in image!\n"); |
| 75 | return -ENOKEY; |
| 76 | } |
| 77 | |
| 78 | if (!IS_ALIGNED(img_sz, sizeof(u32))) { |
| 79 | printf("Image size (%ld bytes) not aliged to 4 bytes!\n", |
| 80 | img_sz); |
| 81 | return -EBFONT; |
| 82 | } |
| 83 | |
| 84 | /* Generate HASH384 from the image */ |
| 85 | sha384_csum_wd((u8 *)img_addr, img_sz, hash384, CHUNKSZ_PER_WD_RESET); |
| 86 | |
| 87 | cert_hash_ptr = (u8 *)(img_addr + img_sz + VAB_CERT_MAGIC_OFFSET + |
| 88 | VAB_CERT_FIT_SHA384_OFFSET); |
| 89 | |
| 90 | /* |
| 91 | * Compare the SHA384 found in certificate against the SHA384 |
| 92 | * calculated from image |
| 93 | */ |
| 94 | if (memcmp(hash384, cert_hash_ptr, SHA384_SUM_LEN)) { |
| 95 | puts("SHA384 not match!\n"); |
| 96 | return -EKEYREJECTED; |
| 97 | } |
| 98 | |
| 99 | mbox_data_addr = img_addr + img_sz - sizeof(u32); |
| 100 | /* Size in word (32bits) */ |
| 101 | mbox_data_sz = (ALIGN(*p_size - img_sz, sizeof(u32))) >> 2; |
| 102 | |
| 103 | debug("mbox_data_addr = 0x%016llx\n", mbox_data_addr); |
| 104 | debug("mbox_data_sz = %ld words\n", mbox_data_sz); |
| 105 | |
| 106 | /* |
| 107 | * Relocate certificate to first memory block before trigger SMC call |
| 108 | * to send mailbox command because ATF only able to access first |
| 109 | * memory block. |
| 110 | */ |
| 111 | mbox_relocate_data_addr = (u8 *)malloc(mbox_data_sz * sizeof(u32)); |
| 112 | if (!mbox_relocate_data_addr) { |
| 113 | puts("Out of memory for VAB certificate relocation!\n"); |
| 114 | return -ENOMEM; |
| 115 | } |
| 116 | |
| 117 | memcpy(mbox_relocate_data_addr, (u8 *)mbox_data_addr, mbox_data_sz * sizeof(u32)); |
| 118 | *(u32 *)mbox_relocate_data_addr = 0; |
| 119 | |
| 120 | debug("mbox_relocate_data_addr = 0x%p\n", mbox_relocate_data_addr); |
| 121 | |
| 122 | do { |
| 123 | if (!IS_ENABLED(CONFIG_SPL_BUILD) && IS_ENABLED(CONFIG_SPL_ATF)) { |
| 124 | /* Invoke SMC call to ATF to send the VAB certificate to SDM */ |
| 125 | ret = smc_send_mailbox(MBOX_VAB_SRC_CERT, mbox_data_sz, |
| 126 | (u32 *)mbox_relocate_data_addr, 0, &resp_len, |
| 127 | &resp); |
| 128 | } else { |
| 129 | /* Send the VAB certficate to SDM for authentication */ |
| 130 | ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_VAB_SRC_CERT, |
| 131 | MBOX_CMD_DIRECT, mbox_data_sz, |
| 132 | (u32 *)mbox_relocate_data_addr, 0, &resp_len, |
| 133 | &resp); |
| 134 | } |
| 135 | /* If SDM is not available, just delay 50ms and retry again */ |
| 136 | if (ret == MBOX_RESP_DEVICE_BUSY) |
| 137 | mdelay(50); |
| 138 | else |
| 139 | break; |
| 140 | } while (--retry_count); |
| 141 | |
| 142 | /* Free the relocate certificate memory space */ |
| 143 | free(mbox_relocate_data_addr); |
| 144 | |
| 145 | /* Exclude the size of the VAB certificate from image size */ |
| 146 | *p_size = img_sz; |
| 147 | |
| 148 | debug("ret = 0x%08x, resp = 0x%08x, resp_len = %d\n", ret, resp, |
| 149 | resp_len); |
| 150 | |
| 151 | if (ret) { |
| 152 | /* |
| 153 | * Unsupported mailbox command or device not in the |
| 154 | * owned/secure state |
| 155 | */ |
| 156 | if (ret == MBOX_RESP_NOT_ALLOWED_UNDER_SECURITY_SETTINGS) { |
| 157 | /* SDM bypass authentication */ |
| 158 | printf("%s 0x%016llx (%ld bytes)\n", |
| 159 | "Image Authentication bypassed at address", |
| 160 | img_addr, img_sz); |
| 161 | return 0; |
| 162 | } |
| 163 | puts("VAB certificate authentication failed in SDM"); |
| 164 | if (ret == MBOX_RESP_DEVICE_BUSY) { |
| 165 | puts(" (SDM busy timeout)\n"); |
| 166 | return -ETIMEDOUT; |
| 167 | } else if (ret == MBOX_RESP_UNKNOWN) { |
| 168 | puts(" (Not supported)\n"); |
| 169 | return -ESRCH; |
| 170 | } |
| 171 | puts("\n"); |
| 172 | return -EKEYREJECTED; |
| 173 | } else { |
| 174 | /* If Certificate Process Status has error */ |
| 175 | if (resp) { |
| 176 | puts("VAB certificate process failed\n"); |
| 177 | return -ENOEXEC; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | printf("%s 0x%016llx (%ld bytes)\n", |
| 182 | "Image Authentication passed at address", img_addr, img_sz); |
| 183 | |
| 184 | return 0; |
| 185 | } |