xref: /base/startup/hvb/libhvb/src/auth/hvb.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 <stdio.h>
16#include <stdlib.h>
17#include "hvb_footer.h"
18#include "hvb_crypto.h"
19#include "hvb_ops.h"
20#include "hvb_rvt.h"
21#include "hvb_cert.h"
22#include "hvb_sysdeps.h"
23#include "hvb_util.h"
24#include "hvb_cmdline.h"
25#include "hvb.h"
26
27struct hvb_verified_data *hvb_init_verified_data(void)
28{
29    struct hvb_verified_data *vd = NULL;
30
31    vd = hvb_calloc(sizeof(*vd));
32    if (!vd) {
33        hvb_print("malloc verified_data fail\n");
34        return NULL;
35    }
36
37    vd->certs = hvb_calloc(sizeof(struct hvb_cert_data) * HVB_MAX_NUMBER_OF_LOADED_CERTS);
38    if (!vd->certs) {
39        hvb_print("malloc certs fail\n");
40        goto fail;
41    }
42
43    vd->images = hvb_calloc(sizeof(struct hvb_image_data) * HVB_MAX_NUMBER_OF_LOADED_IMAGES);
44    if (!vd->images) {
45        hvb_print("malloc images fail\n");
46        goto fail;
47    }
48
49    vd->num_loaded_certs = 0;
50    vd->num_loaded_images = 0;
51
52    vd->cmdline.buf = hvb_calloc(CMD_LINE_SIZE);
53    if (!vd->cmdline.buf) {
54        hvb_print("malloc cmdline fail\n");
55        goto fail;
56    }
57
58    vd->cmdline.cur_pos = 0;
59    vd->cmdline.max_size = CMD_LINE_SIZE;
60
61    vd->key_len = 0;
62
63    return vd;
64
65fail:
66    hvb_chain_verify_data_free(vd);
67    hvb_free(vd);
68    vd = NULL;
69    return vd;
70}
71
72static enum hvb_errno hvb_rvt_verify_root(struct hvb_ops *ops, const char *ptn,
73                                          const char *const *ptn_list,
74                                          struct hvb_verified_data *vd)
75{
76    enum hvb_errno ret = HVB_OK;
77    enum hvb_io_errno io_ret = HVB_IO_OK;
78    bool is_trusted = false;
79    struct hvb_buf cert_pubk = {0};
80
81    ret = footer_init_desc(ops, ptn, ptn_list, &cert_pubk, vd);
82    if (ret != HVB_OK) {
83        hvb_printv("error verity partition: ", ptn, "\n", NULL);
84        goto fail;
85    }
86
87    io_ret = ops->valid_rvt_key(ops, cert_pubk.addr, cert_pubk.size, NULL, 0, &is_trusted);
88    if (io_ret != HVB_IO_OK) {
89        ret = HVB_ERROR_PUBLIC_KEY_REJECTED;
90        hvb_print("error, rvt public key invalid\n");
91        goto fail;
92    }
93
94    if (is_trusted == false) {
95        ret = HVB_ERROR_PUBLIC_KEY_REJECTED;
96        hvb_print("error, rvt public key rejected\n");
97        goto fail;
98    }
99
100fail:
101    return ret;
102}
103
104static struct hvb_buf *hvb_get_partition_image(struct hvb_verified_data *vd, const char *ptn)
105{
106    struct hvb_image_data *p = vd->images;
107    struct hvb_image_data *end = p + vd->num_loaded_images;
108    size_t name_len = hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN);
109    if (name_len >= HVB_MAX_PARTITION_NAME_LEN) {
110        hvb_print("invalid ptn name len\n");
111        return NULL;
112    }
113
114    for (; p < end; p++) {
115        if (hvb_strnlen(p->partition_name, HVB_MAX_PARTITION_NAME_LEN) == name_len &&
116            hvb_strncmp(ptn, p->partition_name, HVB_MAX_PARTITION_NAME_LEN) == 0) {
117            return &p->data;
118        }
119    }
120
121    return NULL;
122}
123
124static bool hvb_buf_equal(const struct hvb_buf *buf1, const struct hvb_buf *buf2)
125{
126    return buf1->size == buf2->size && hvb_memcmp(buf1->addr, buf2->addr, buf1->size) == 0;
127}
128
129static enum hvb_errno hvb_walk_verify_nodes(struct hvb_ops *ops, const char *const *ptn_list,
130                                            struct hvb_buf *rvt, struct hvb_verified_data *vd)
131{
132    enum hvb_errno ret = HVB_OK;
133    uint32_t i, nodes_num;
134    struct hvb_buf pubk_descs;
135    struct rvt_pubk_desc desc;
136    struct hvb_buf expected_pubk;
137    struct hvb_buf cert_pubk;
138    struct rvt_image_header header;
139    uint64_t desc_size;
140
141    desc_size = sizeof(desc) - (PUBKEY_LEN - vd->key_len);
142    ret = hvb_rvt_head_parser(rvt, &header, desc_size);
143    if (ret != HVB_OK) {
144        hvb_print("error, parse rvt header.\n");
145        goto fail;
146    }
147
148    nodes_num = header.verity_num;
149    ret = hvb_rvt_get_pubk_desc(rvt, &pubk_descs);
150    if (ret != HVB_OK) {
151        hvb_print("error, pubk descs.\n");
152        goto fail;
153    }
154
155    for (i = 0; i < nodes_num; i++) {
156        ret = hvb_rvt_pubk_desc_parser(&pubk_descs, &desc, desc_size);
157        if (ret != HVB_OK) {
158            hvb_print("errror, parser rvt k descs\n");
159            goto fail;
160        }
161
162        ret = hvb_rvt_get_pubk_buf(&expected_pubk, rvt, &desc);
163        if (ret != HVB_OK) {
164            hvb_print("errror, get pubk buf\n");
165            goto fail;
166        }
167
168        ret = footer_init_desc(ops, &desc.name[0], ptn_list, &cert_pubk, vd);
169        if (ret != HVB_OK) {
170            hvb_printv("error, verity partition: ", desc.name, "\n", NULL);
171            goto fail;
172        }
173
174        if (hvb_buf_equal(&expected_pubk, &cert_pubk) != true) {
175            ret = HVB_ERROR_PUBLIC_KEY_REJECTED;
176            hvb_printv("error, compare public key: ", desc.name, "\n", NULL);
177            goto fail;
178        }
179
180        pubk_descs.addr += desc_size;
181    }
182
183fail:
184    return ret;
185}
186
187static char const **hash_ptn_list_add_rvt(const char *const *hash_ptn_list, const char *rvt_ptn)
188{
189    size_t n;
190    bool need_add_rvt = true;
191    char const **ptn = NULL;
192    size_t num_parttions = 0;
193
194    if (hash_ptn_list != NULL) {
195        while (hash_ptn_list[num_parttions] != NULL) {
196            num_parttions++;
197        }
198    }
199
200    num_parttions += REQUEST_LIST_LEN;
201
202    ptn = (char const **)hvb_calloc(num_parttions * sizeof(char *));
203    if (ptn == NULL) {
204        hvb_print("error, alloc ptn\n");
205        return NULL;
206    }
207
208    for (n = 0; n < num_parttions - REQUEST_LIST_LEN; n++) {
209        ptn[n] = hash_ptn_list[n];
210        if (hvb_strncmp(ptn[n], rvt_ptn, HVB_MAX_PARTITION_NAME_LEN) == 0) {
211            need_add_rvt = false;
212        }
213    }
214
215    if (need_add_rvt) {
216        ptn[num_parttions - REQUEST_LIST_LEN] = rvt_ptn;
217    }
218
219    return ptn;
220}
221
222enum hvb_errno hvb_chain_verify(struct hvb_ops *ops,
223                                const char *rvt_ptn,
224                                const char *const *hash_ptn_list,
225                                struct hvb_verified_data **out_vd)
226{
227    enum hvb_errno ret = HVB_OK;
228    struct hvb_buf *rvt_image = NULL;
229    struct hvb_verified_data *vd = NULL;
230    char const **ptn_list = NULL;
231
232    hvb_return_hvb_err_if_null(ops);
233    hvb_return_hvb_err_if_null(rvt_ptn);
234    hvb_return_hvb_err_if_null(out_vd);
235    ret = check_hvb_ops(ops);
236    if (ret != HVB_OK) {
237        hvb_print("error, check ops\n");
238        return HVB_ERROR_INVALID_ARGUMENT;
239    }
240
241    if (hvb_strnlen(rvt_ptn, HVB_MAX_PARTITION_NAME_LEN) >= HVB_MAX_PARTITION_NAME_LEN) {
242        hvb_print("error, check rvt partition name\n");
243        return HVB_ERROR_INVALID_ARGUMENT;
244    }
245
246    ptn_list = hash_ptn_list_add_rvt(hash_ptn_list, rvt_ptn);
247    if (ptn_list == NULL) {
248        hvb_print("error, add rvt\n");
249        return HVB_ERROR_OOM;
250    }
251
252    vd = hvb_init_verified_data();
253    if (!vd) {
254        hvb_print("malloc verified_data fail\n");
255        ret = HVB_ERROR_OOM;
256        goto fail;
257    }
258
259    /* verity rvt cert */
260    ret = hvb_rvt_verify_root(ops, rvt_ptn, ptn_list, vd);
261    if (ret != HVB_OK) {
262        hvb_print("error, verity rvt partition.\n");
263        goto fail;
264    }
265
266    /* get rvt image */
267    rvt_image = hvb_get_partition_image(vd, rvt_ptn);
268    if (!rvt_image) {
269        hvb_print("error, get rvt ptn.\n");
270        ret = HVB_ERROR_OOM;
271        goto fail;
272    }
273
274    /* walk verify all nodes from rvt */
275    ret = hvb_walk_verify_nodes(ops, ptn_list, rvt_image, vd);
276    if (ret != HVB_OK) {
277        hvb_print("error, walk nodes.\n");
278        goto fail;
279    }
280
281    /* creat cmdline info */
282    ret = hvb_creat_cmdline(ops, vd);
283    if (ret != HVB_OK) {
284        hvb_print("error, create cmdline.\n");
285        goto fail;
286    }
287
288    *out_vd = vd;
289
290fail:
291    if (vd != NULL && ret != HVB_OK) {
292        hvb_chain_verify_data_free(vd);
293        hvb_free(vd);
294    }
295
296    hvb_free(ptn_list);
297
298    return ret;
299}
300
301void hvb_chain_verify_data_free(struct hvb_verified_data *vd)
302{
303    uint64_t n;
304
305    if (vd == NULL) {
306        hvb_print("vd is NULL, do nothing\n");
307        return;
308    }
309
310    for (n = 0; n < vd->num_loaded_certs && vd->certs; n++) {
311        if (vd->certs[n].data.addr != NULL)
312            hvb_free(vd->certs[n].data.addr);
313
314        if (vd->certs[n].partition_name != NULL) {
315            hvb_free(vd->certs[n].partition_name);
316        }
317    }
318
319    if (vd->certs != NULL) {
320        hvb_free(vd->certs);
321    }
322
323    for (n = 0; n < vd->num_loaded_images && vd->images; n++) {
324        if (vd->images[n].data.addr != NULL)
325            hvb_free(vd->images[n].data.addr);
326
327        if (vd->images[n].partition_name != NULL)
328            hvb_free(vd->images[n].partition_name);
329    }
330
331    if (vd->images != NULL) {
332        hvb_free(vd->images);
333    }
334
335    if (vd->cmdline.buf != NULL) {
336        hvb_free(vd->cmdline.buf);
337    }
338
339    hvb_memset((uint8_t *)vd, 0, sizeof(*vd));
340}
341