1/* 2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "hvb_footer.h" 16#include "hvb_util.h" 17#include "hvb_cert.h" 18#include "hvb_sysdeps.h" 19 20static enum hvb_errno _footer_parser(struct hvb_footer *footer, struct hvb_buf *footer_buf) 21{ 22 uint64_t size; 23 24 if (footer_buf->size < sizeof(*footer)) { 25 hvb_print("footer src size error.\n"); 26 return HVB_ERROR_INVALID_FOOTER_FORMAT; 27 } 28 if (hvb_memcpy_s(footer, sizeof(*footer), footer_buf->addr, sizeof(*footer)) != 0) { 29 hvb_print("error, copy footer.\n"); 30 return HVB_ERROR_OOM; 31 } 32 33 /* Check that magic is correct. */ 34 if (hvb_memcmp(footer->magic, HVB_FOOTER_MAGIC, sizeof(footer->magic)) != 0) { 35 hvb_print("Footer magic is incorrect.\n"); 36 return HVB_ERROR_INVALID_FOOTER_FORMAT; 37 } 38 39 /* check these size is correct */ 40 if (footer->partition_size > HVB_MAX_PARTITION_SIZE || 41 footer->partition_size < HVB_MIN_PARTITION_SIZE) { 42 hvb_print("Invalid partition_size in footer.\n"); 43 return HVB_ERROR_INVALID_FOOTER_FORMAT; 44 } 45 46 size = footer->image_size + footer->cert_size + HVB_FOOTER_SIZE; 47 if (footer->image_size >= footer->partition_size || 48 size < footer->image_size + HVB_FOOTER_SIZE || 49 size > footer->partition_size) { 50 hvb_print("Invalid image_size in footer.\n"); 51 return HVB_ERROR_INVALID_FOOTER_FORMAT; 52 } 53 54 size = footer->cert_offset + footer->cert_size + HVB_FOOTER_SIZE; 55 if (footer->cert_offset < footer->image_size || 56 size < footer->cert_offset + HVB_FOOTER_SIZE || 57 size > footer->partition_size) { 58 hvb_print("Invalid cert info in footer.\n"); 59 return HVB_ERROR_INVALID_FOOTER_FORMAT; 60 } 61 62 return HVB_OK; 63} 64 65static enum hvb_errno _load_and_parse_footer(struct hvb_ops *ops, struct hvb_footer *footer, const char *ptn) 66{ 67 enum hvb_errno ret = HVB_OK; 68 uint64_t read_bytes = 0; 69 enum hvb_io_errno io_ret = HVB_IO_OK; 70 uint8_t buf[HVB_FOOTER_SIZE] = {0}; 71 struct hvb_buf footer_buf = {&buf[0], sizeof(buf)}; 72 73 io_ret = ops->read_partition(ops, ptn, -HVB_FOOTER_SIZE, HVB_FOOTER_SIZE, footer_buf.addr, &read_bytes); 74 if (io_ret != HVB_IO_OK) { 75 hvb_printv(ptn, ": error, loading data.\n", NULL); 76 return HVB_ERROR_IO; 77 } 78 79 if (read_bytes != footer_buf.size) { 80 hvb_printv(ptn, ": Read incorrect number of bytes.\n", NULL); 81 return HVB_ERROR_IO; 82 } 83 84 ret = _footer_parser(footer, &footer_buf); 85 if (ret != HVB_OK) { 86 hvb_printv(ptn, ": No footer detected,.\n", NULL); 87 return ret; 88 } 89 90 return HVB_OK; 91} 92 93static enum hvb_errno _load_cert(struct hvb_ops *ops, struct hvb_buf *cert, const char *ptn, struct hvb_footer *footer) 94{ 95 enum hvb_io_errno io_ret = HVB_IO_OK; 96 uint64_t read_bytes = 0; 97 uint64_t offset = footer->cert_offset; 98 99 io_ret = ops->read_partition(ops, ptn, offset, cert->size, cert->addr, &read_bytes); 100 if (io_ret != HVB_IO_OK) { 101 hvb_printv(ptn, ": error loading signature data.\n", NULL); 102 return HVB_ERROR_IO; 103 } 104 105 if (cert->size != read_bytes) { 106 hvb_printv(ptn, ": Read incorrect number of bytes from.\n", NULL); 107 return HVB_ERROR_IO; 108 } 109 110 return HVB_OK; 111} 112 113enum hvb_errno footer_init_desc(struct hvb_ops *ops, const char *ptn, const char *const *hash_ptn_list, 114 struct hvb_buf *out_pubk, struct hvb_verified_data *vd) 115{ 116 hvb_return_hvb_err_if_null(ops); 117 hvb_return_hvb_err_if_null(ptn); 118 hvb_return_hvb_err_if_null(out_pubk); 119 hvb_return_hvb_err_if_null(vd); 120 121 enum hvb_errno ret = HVB_OK; 122 struct hvb_buf cert_buf = {NULL, 0}; 123 struct hvb_footer footer = {0}; 124 struct hvb_cert_data *cert_info = NULL; 125 126 ret = check_hvb_ops(ops); 127 if (ret != HVB_OK) { 128 hvb_print("error, check ops\n"); 129 return HVB_ERROR_INVALID_ARGUMENT; 130 } 131 if (hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN) >= HVB_MAX_PARTITION_NAME_LEN) { 132 hvb_print("error, check partition name\n"); 133 return HVB_ERROR_INVALID_ARGUMENT; 134 } 135 136 ret = _load_and_parse_footer(ops, &footer, ptn); 137 if (ret != HVB_OK) 138 return ret; 139 140 cert_buf.size = footer.cert_size; 141 cert_buf.addr = hvb_malloc(cert_buf.size); 142 if (!cert_buf.addr) { 143 hvb_print("error, alloc cert buf\n"); 144 return HVB_ERROR_OOM; 145 } 146 147 ret = _load_cert(ops, &cert_buf, ptn, &footer); 148 if (ret != HVB_OK) 149 goto out; 150 151 ret = cert_init_desc(ops, ptn, &cert_buf, hash_ptn_list, out_pubk, vd); 152 if (ret != HVB_OK) 153 goto out; 154 155 if (vd->num_loaded_certs >= HVB_MAX_NUMBER_OF_LOADED_CERTS) { 156 hvb_print("error, too many certs\n"); 157 ret = HVB_ERROR_OOM; 158 goto out; 159 } 160 161 cert_info = &vd->certs[vd->num_loaded_certs++]; 162 cert_info->partition_name = hvb_strdup(ptn); 163 cert_info->data = cert_buf; 164 cert_info->verify_result = ret; 165 166 return ret; 167 168out: 169 if (cert_buf.addr != NULL) 170 hvb_free(cert_buf.addr); 171 172 return ret; 173} 174