xref: /base/startup/hvb/libhvb/src/footer/hvb_footer.c (revision 7310c0d0)
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