xref: /base/startup/hvb/libhvb/src/footer/hvb_footer.c (revision 7310c0d0)
17310c0d0Sopenharmony_ci/*
27310c0d0Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
37310c0d0Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
47310c0d0Sopenharmony_ci * you may not use this file except in compliance with the License.
57310c0d0Sopenharmony_ci * You may obtain a copy of the License at
67310c0d0Sopenharmony_ci *
77310c0d0Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
87310c0d0Sopenharmony_ci *
97310c0d0Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
107310c0d0Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
117310c0d0Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127310c0d0Sopenharmony_ci * See the License for the specific language governing permissions and
137310c0d0Sopenharmony_ci * limitations under the License.
147310c0d0Sopenharmony_ci */
157310c0d0Sopenharmony_ci#include "hvb_footer.h"
167310c0d0Sopenharmony_ci#include "hvb_util.h"
177310c0d0Sopenharmony_ci#include "hvb_cert.h"
187310c0d0Sopenharmony_ci#include "hvb_sysdeps.h"
197310c0d0Sopenharmony_ci
207310c0d0Sopenharmony_cistatic enum hvb_errno _footer_parser(struct hvb_footer *footer, struct hvb_buf *footer_buf)
217310c0d0Sopenharmony_ci{
227310c0d0Sopenharmony_ci    uint64_t size;
237310c0d0Sopenharmony_ci
247310c0d0Sopenharmony_ci    if (footer_buf->size < sizeof(*footer)) {
257310c0d0Sopenharmony_ci        hvb_print("footer src size error.\n");
267310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_FOOTER_FORMAT;
277310c0d0Sopenharmony_ci    }
287310c0d0Sopenharmony_ci    if (hvb_memcpy_s(footer, sizeof(*footer), footer_buf->addr, sizeof(*footer)) != 0) {
297310c0d0Sopenharmony_ci        hvb_print("error, copy footer.\n");
307310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
317310c0d0Sopenharmony_ci    }
327310c0d0Sopenharmony_ci
337310c0d0Sopenharmony_ci    /* Check that magic is correct. */
347310c0d0Sopenharmony_ci    if (hvb_memcmp(footer->magic, HVB_FOOTER_MAGIC, sizeof(footer->magic)) != 0) {
357310c0d0Sopenharmony_ci        hvb_print("Footer magic is incorrect.\n");
367310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_FOOTER_FORMAT;
377310c0d0Sopenharmony_ci    }
387310c0d0Sopenharmony_ci
397310c0d0Sopenharmony_ci    /* check these size is correct */
407310c0d0Sopenharmony_ci    if (footer->partition_size > HVB_MAX_PARTITION_SIZE ||
417310c0d0Sopenharmony_ci        footer->partition_size < HVB_MIN_PARTITION_SIZE) {
427310c0d0Sopenharmony_ci        hvb_print("Invalid partition_size in footer.\n");
437310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_FOOTER_FORMAT;
447310c0d0Sopenharmony_ci    }
457310c0d0Sopenharmony_ci
467310c0d0Sopenharmony_ci    size = footer->image_size + footer->cert_size + HVB_FOOTER_SIZE;
477310c0d0Sopenharmony_ci    if (footer->image_size >= footer->partition_size ||
487310c0d0Sopenharmony_ci        size < footer->image_size + HVB_FOOTER_SIZE ||
497310c0d0Sopenharmony_ci        size > footer->partition_size) {
507310c0d0Sopenharmony_ci        hvb_print("Invalid image_size in footer.\n");
517310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_FOOTER_FORMAT;
527310c0d0Sopenharmony_ci    }
537310c0d0Sopenharmony_ci
547310c0d0Sopenharmony_ci    size = footer->cert_offset + footer->cert_size + HVB_FOOTER_SIZE;
557310c0d0Sopenharmony_ci    if (footer->cert_offset < footer->image_size ||
567310c0d0Sopenharmony_ci        size < footer->cert_offset + HVB_FOOTER_SIZE ||
577310c0d0Sopenharmony_ci        size > footer->partition_size) {
587310c0d0Sopenharmony_ci        hvb_print("Invalid cert info in footer.\n");
597310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_FOOTER_FORMAT;
607310c0d0Sopenharmony_ci    }
617310c0d0Sopenharmony_ci
627310c0d0Sopenharmony_ci    return HVB_OK;
637310c0d0Sopenharmony_ci}
647310c0d0Sopenharmony_ci
657310c0d0Sopenharmony_cistatic enum hvb_errno _load_and_parse_footer(struct hvb_ops *ops, struct hvb_footer *footer, const char *ptn)
667310c0d0Sopenharmony_ci{
677310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
687310c0d0Sopenharmony_ci    uint64_t read_bytes = 0;
697310c0d0Sopenharmony_ci    enum hvb_io_errno io_ret = HVB_IO_OK;
707310c0d0Sopenharmony_ci    uint8_t buf[HVB_FOOTER_SIZE] = {0};
717310c0d0Sopenharmony_ci    struct hvb_buf footer_buf = {&buf[0], sizeof(buf)};
727310c0d0Sopenharmony_ci
737310c0d0Sopenharmony_ci    io_ret = ops->read_partition(ops, ptn, -HVB_FOOTER_SIZE, HVB_FOOTER_SIZE, footer_buf.addr, &read_bytes);
747310c0d0Sopenharmony_ci    if (io_ret != HVB_IO_OK) {
757310c0d0Sopenharmony_ci        hvb_printv(ptn, ": error, loading data.\n", NULL);
767310c0d0Sopenharmony_ci        return HVB_ERROR_IO;
777310c0d0Sopenharmony_ci    }
787310c0d0Sopenharmony_ci
797310c0d0Sopenharmony_ci    if (read_bytes != footer_buf.size) {
807310c0d0Sopenharmony_ci        hvb_printv(ptn, ": Read incorrect number of bytes.\n", NULL);
817310c0d0Sopenharmony_ci        return HVB_ERROR_IO;
827310c0d0Sopenharmony_ci    }
837310c0d0Sopenharmony_ci
847310c0d0Sopenharmony_ci    ret = _footer_parser(footer, &footer_buf);
857310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
867310c0d0Sopenharmony_ci        hvb_printv(ptn, ": No footer detected,.\n", NULL);
877310c0d0Sopenharmony_ci        return ret;
887310c0d0Sopenharmony_ci    }
897310c0d0Sopenharmony_ci
907310c0d0Sopenharmony_ci    return HVB_OK;
917310c0d0Sopenharmony_ci}
927310c0d0Sopenharmony_ci
937310c0d0Sopenharmony_cistatic enum hvb_errno _load_cert(struct hvb_ops *ops, struct hvb_buf *cert, const char *ptn, struct hvb_footer *footer)
947310c0d0Sopenharmony_ci{
957310c0d0Sopenharmony_ci    enum hvb_io_errno io_ret = HVB_IO_OK;
967310c0d0Sopenharmony_ci    uint64_t read_bytes = 0;
977310c0d0Sopenharmony_ci    uint64_t offset = footer->cert_offset;
987310c0d0Sopenharmony_ci
997310c0d0Sopenharmony_ci    io_ret = ops->read_partition(ops, ptn, offset, cert->size, cert->addr, &read_bytes);
1007310c0d0Sopenharmony_ci    if (io_ret != HVB_IO_OK) {
1017310c0d0Sopenharmony_ci        hvb_printv(ptn, ": error loading signature data.\n", NULL);
1027310c0d0Sopenharmony_ci        return HVB_ERROR_IO;
1037310c0d0Sopenharmony_ci    }
1047310c0d0Sopenharmony_ci
1057310c0d0Sopenharmony_ci    if (cert->size != read_bytes) {
1067310c0d0Sopenharmony_ci        hvb_printv(ptn, ": Read incorrect number of bytes from.\n", NULL);
1077310c0d0Sopenharmony_ci        return HVB_ERROR_IO;
1087310c0d0Sopenharmony_ci    }
1097310c0d0Sopenharmony_ci
1107310c0d0Sopenharmony_ci    return HVB_OK;
1117310c0d0Sopenharmony_ci}
1127310c0d0Sopenharmony_ci
1137310c0d0Sopenharmony_cienum hvb_errno footer_init_desc(struct hvb_ops *ops, const char *ptn, const char *const *hash_ptn_list,
1147310c0d0Sopenharmony_ci                                struct hvb_buf *out_pubk, struct hvb_verified_data *vd)
1157310c0d0Sopenharmony_ci{
1167310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(ops);
1177310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(ptn);
1187310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(out_pubk);
1197310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(vd);
1207310c0d0Sopenharmony_ci
1217310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
1227310c0d0Sopenharmony_ci    struct hvb_buf cert_buf = {NULL, 0};
1237310c0d0Sopenharmony_ci    struct hvb_footer footer = {0};
1247310c0d0Sopenharmony_ci    struct hvb_cert_data *cert_info = NULL;
1257310c0d0Sopenharmony_ci
1267310c0d0Sopenharmony_ci    ret = check_hvb_ops(ops);
1277310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
1287310c0d0Sopenharmony_ci        hvb_print("error, check ops\n");
1297310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
1307310c0d0Sopenharmony_ci    }
1317310c0d0Sopenharmony_ci    if (hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN) >= HVB_MAX_PARTITION_NAME_LEN) {
1327310c0d0Sopenharmony_ci        hvb_print("error, check partition name\n");
1337310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
1347310c0d0Sopenharmony_ci    }
1357310c0d0Sopenharmony_ci
1367310c0d0Sopenharmony_ci    ret = _load_and_parse_footer(ops, &footer, ptn);
1377310c0d0Sopenharmony_ci    if (ret != HVB_OK)
1387310c0d0Sopenharmony_ci        return ret;
1397310c0d0Sopenharmony_ci
1407310c0d0Sopenharmony_ci    cert_buf.size = footer.cert_size;
1417310c0d0Sopenharmony_ci    cert_buf.addr = hvb_malloc(cert_buf.size);
1427310c0d0Sopenharmony_ci    if (!cert_buf.addr) {
1437310c0d0Sopenharmony_ci        hvb_print("error, alloc cert buf\n");
1447310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
1457310c0d0Sopenharmony_ci    }
1467310c0d0Sopenharmony_ci
1477310c0d0Sopenharmony_ci    ret = _load_cert(ops, &cert_buf, ptn, &footer);
1487310c0d0Sopenharmony_ci    if (ret != HVB_OK)
1497310c0d0Sopenharmony_ci        goto out;
1507310c0d0Sopenharmony_ci
1517310c0d0Sopenharmony_ci    ret = cert_init_desc(ops, ptn, &cert_buf, hash_ptn_list, out_pubk, vd);
1527310c0d0Sopenharmony_ci    if (ret != HVB_OK)
1537310c0d0Sopenharmony_ci        goto out;
1547310c0d0Sopenharmony_ci
1557310c0d0Sopenharmony_ci    if (vd->num_loaded_certs >= HVB_MAX_NUMBER_OF_LOADED_CERTS) {
1567310c0d0Sopenharmony_ci        hvb_print("error, too many certs\n");
1577310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1587310c0d0Sopenharmony_ci        goto out;
1597310c0d0Sopenharmony_ci    }
1607310c0d0Sopenharmony_ci
1617310c0d0Sopenharmony_ci    cert_info = &vd->certs[vd->num_loaded_certs++];
1627310c0d0Sopenharmony_ci    cert_info->partition_name = hvb_strdup(ptn);
1637310c0d0Sopenharmony_ci    cert_info->data = cert_buf;
1647310c0d0Sopenharmony_ci    cert_info->verify_result = ret;
1657310c0d0Sopenharmony_ci
1667310c0d0Sopenharmony_ci    return ret;
1677310c0d0Sopenharmony_ci
1687310c0d0Sopenharmony_ciout:
1697310c0d0Sopenharmony_ci    if (cert_buf.addr != NULL)
1707310c0d0Sopenharmony_ci        hvb_free(cert_buf.addr);
1717310c0d0Sopenharmony_ci
1727310c0d0Sopenharmony_ci    return ret;
1737310c0d0Sopenharmony_ci}
174