xref: /base/startup/hvb/libhvb/src/cert/hvb_cert.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 <stdio.h>
167310c0d0Sopenharmony_ci#include <stdlib.h>
177310c0d0Sopenharmony_ci#include <string.h>
187310c0d0Sopenharmony_ci#include "hvb.h"
197310c0d0Sopenharmony_ci#include "hvb_util.h"
207310c0d0Sopenharmony_ci#include "hvb_crypto.h"
217310c0d0Sopenharmony_ci#include "hvb_sysdeps.h"
227310c0d0Sopenharmony_ci#include "hvb_cert.h"
237310c0d0Sopenharmony_ci
247310c0d0Sopenharmony_ci
257310c0d0Sopenharmony_cistatic bool hvb_need_verify_hash(const char *const *hash_ptn_list, const char *ptn)
267310c0d0Sopenharmony_ci{
277310c0d0Sopenharmony_ci    size_t n;
287310c0d0Sopenharmony_ci    size_t ptn_len = hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN);
297310c0d0Sopenharmony_ci    if (ptn_len >= HVB_MAX_PARTITION_NAME_LEN) {
307310c0d0Sopenharmony_ci        hvb_print("invalid ptn name len\n");
317310c0d0Sopenharmony_ci        return false;
327310c0d0Sopenharmony_ci    }
337310c0d0Sopenharmony_ci
347310c0d0Sopenharmony_ci    if (hash_ptn_list == NULL)
357310c0d0Sopenharmony_ci        return false;
367310c0d0Sopenharmony_ci
377310c0d0Sopenharmony_ci    for (n = 0; hash_ptn_list[n] != NULL; n++) {
387310c0d0Sopenharmony_ci        if (hvb_strnlen(hash_ptn_list[n], HVB_MAX_PARTITION_NAME_LEN) == ptn_len &&
397310c0d0Sopenharmony_ci            hvb_strncmp(hash_ptn_list[n], ptn, HVB_MAX_PARTITION_NAME_LEN) == 0) {
407310c0d0Sopenharmony_ci            return true;
417310c0d0Sopenharmony_ci        }
427310c0d0Sopenharmony_ci    }
437310c0d0Sopenharmony_ci
447310c0d0Sopenharmony_ci    return false;
457310c0d0Sopenharmony_ci}
467310c0d0Sopenharmony_ci
477310c0d0Sopenharmony_cistatic uint64_t get_hash_size(uint32_t algo)
487310c0d0Sopenharmony_ci{
497310c0d0Sopenharmony_ci    switch (algo) {
507310c0d0Sopenharmony_ci        case 0: // SHA256_RSA3072
517310c0d0Sopenharmony_ci        case 1: // SHA256_RSA4096
527310c0d0Sopenharmony_ci        case 2: // SHA256_RSA2048
537310c0d0Sopenharmony_ci            return 32;
547310c0d0Sopenharmony_ci        default:
557310c0d0Sopenharmony_ci            return 0;
567310c0d0Sopenharmony_ci    }
577310c0d0Sopenharmony_ci
587310c0d0Sopenharmony_ci    return 0;
597310c0d0Sopenharmony_ci}
607310c0d0Sopenharmony_ci
617310c0d0Sopenharmony_cistatic enum hvb_errno hvb_compare_hash(struct hvb_buf *digest_buf, struct hvb_buf *msg_buf,
627310c0d0Sopenharmony_ci                                       struct hvb_buf *salt_buf, uint32_t hash_algo)
637310c0d0Sopenharmony_ci{
647310c0d0Sopenharmony_ci    int hash_err;
657310c0d0Sopenharmony_ci    struct hash_ctx_t ctx = {0};
667310c0d0Sopenharmony_ci    uint8_t computed_hash[HVB_HASH_MAX_BYTES] = {0};
677310c0d0Sopenharmony_ci
687310c0d0Sopenharmony_ci    uint32_t computed_hash_size = get_hash_size(hash_algo);
697310c0d0Sopenharmony_ci    if (computed_hash_size != digest_buf->size) {
707310c0d0Sopenharmony_ci        hvb_print("computed_hash_size error\n");
717310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
727310c0d0Sopenharmony_ci    }
737310c0d0Sopenharmony_ci
747310c0d0Sopenharmony_ci    hash_err = hash_ctx_init(&ctx, hash_algo);
757310c0d0Sopenharmony_ci    if (hash_err != HASH_OK) {
767310c0d0Sopenharmony_ci        hvb_print("hash init error\n");
777310c0d0Sopenharmony_ci        return HVB_ERROR_VERIFY_HASH;
787310c0d0Sopenharmony_ci    }
797310c0d0Sopenharmony_ci
807310c0d0Sopenharmony_ci    hash_err = hash_calc_update(&ctx, salt_buf->addr, salt_buf->size);
817310c0d0Sopenharmony_ci    if (hash_err != HASH_OK) {
827310c0d0Sopenharmony_ci        hvb_print("hash updata salt error\n");
837310c0d0Sopenharmony_ci        return HVB_ERROR_VERIFY_HASH;
847310c0d0Sopenharmony_ci    }
857310c0d0Sopenharmony_ci
867310c0d0Sopenharmony_ci    hash_err = hash_calc_do_final(&ctx, msg_buf->addr, msg_buf->size, &computed_hash[0], digest_buf->size);
877310c0d0Sopenharmony_ci    if (hash_err != HASH_OK) {
887310c0d0Sopenharmony_ci        hvb_print("hash updata msg error\n");
897310c0d0Sopenharmony_ci        return HVB_ERROR_VERIFY_HASH;
907310c0d0Sopenharmony_ci    }
917310c0d0Sopenharmony_ci
927310c0d0Sopenharmony_ci    if (hvb_memcmp(&computed_hash[0], digest_buf->addr, computed_hash_size) != 0) {
937310c0d0Sopenharmony_ci        hvb_print("compare fail\n");
947310c0d0Sopenharmony_ci        return HVB_ERROR_VERIFY_HASH;
957310c0d0Sopenharmony_ci    }
967310c0d0Sopenharmony_ci
977310c0d0Sopenharmony_ci    return HVB_OK;
987310c0d0Sopenharmony_ci}
997310c0d0Sopenharmony_ci
1007310c0d0Sopenharmony_cistatic enum hvb_errno hash_image_init_desc(struct hvb_ops *ops, const char *ptn,
1017310c0d0Sopenharmony_ci                                           struct hvb_cert *cert, const char *const *hash_ptn_list,
1027310c0d0Sopenharmony_ci                                           struct hvb_verified_data *vd)
1037310c0d0Sopenharmony_ci{
1047310c0d0Sopenharmony_ci    enum hvb_io_errno io_ret = HVB_IO_OK;
1057310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
1067310c0d0Sopenharmony_ci    struct hvb_buf image_buf = {NULL, 0};
1077310c0d0Sopenharmony_ci    struct hvb_buf salt_buf = {cert->hash_payload.salt, cert->salt_size};
1087310c0d0Sopenharmony_ci    struct hvb_buf digest_buf = {cert->hash_payload.digest, cert->digest_size};
1097310c0d0Sopenharmony_ci    uint64_t read_bytes = 0;
1107310c0d0Sopenharmony_ci    struct hvb_image_data *image = NULL;
1117310c0d0Sopenharmony_ci    enum hvb_image_type image_type = (enum hvb_image_type)cert->verity_type;
1127310c0d0Sopenharmony_ci
1137310c0d0Sopenharmony_ci    if (image_type != HVB_IMAGE_TYPE_HASH || !hvb_need_verify_hash(hash_ptn_list, ptn)) {
1147310c0d0Sopenharmony_ci        hvb_printv(ptn, ": no need verify hash image.\n", NULL);
1157310c0d0Sopenharmony_ci        return HVB_OK;
1167310c0d0Sopenharmony_ci    }
1177310c0d0Sopenharmony_ci
1187310c0d0Sopenharmony_ci    image_buf.size = cert->image_original_len;
1197310c0d0Sopenharmony_ci    image_buf.addr = hvb_malloc(image_buf.size);
1207310c0d0Sopenharmony_ci    if (image_buf.addr == NULL) {
1217310c0d0Sopenharmony_ci        hvb_print("malloc image_buf fail\n");
1227310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
1237310c0d0Sopenharmony_ci    }
1247310c0d0Sopenharmony_ci
1257310c0d0Sopenharmony_ci    io_ret = ops->read_partition(ops, ptn, 0, image_buf.size, image_buf.addr, &read_bytes);
1267310c0d0Sopenharmony_ci    if (io_ret != HVB_IO_OK) {
1277310c0d0Sopenharmony_ci        hvb_printv(ptn, ": Error loading data.\n", NULL);
1287310c0d0Sopenharmony_ci        ret = HVB_ERROR_IO;
1297310c0d0Sopenharmony_ci        goto out;
1307310c0d0Sopenharmony_ci    }
1317310c0d0Sopenharmony_ci    if (read_bytes != image_buf.size) {
1327310c0d0Sopenharmony_ci        hvb_printv(ptn, ": Read incorrect number of bytes from.\n", NULL);
1337310c0d0Sopenharmony_ci        ret = HVB_ERROR_IO;
1347310c0d0Sopenharmony_ci        goto out;
1357310c0d0Sopenharmony_ci    }
1367310c0d0Sopenharmony_ci
1377310c0d0Sopenharmony_ci    ret = hvb_compare_hash(&digest_buf, &image_buf, &salt_buf, cert->hash_algo);
1387310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
1397310c0d0Sopenharmony_ci        hvb_printv(ptn, ": compare hash error.\n", NULL);
1407310c0d0Sopenharmony_ci        goto out;
1417310c0d0Sopenharmony_ci    }
1427310c0d0Sopenharmony_ci
1437310c0d0Sopenharmony_ci    if (vd->num_loaded_images >= HVB_MAX_NUMBER_OF_LOADED_IMAGES) {
1447310c0d0Sopenharmony_ci        hvb_print("error, too many images\n");
1457310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1467310c0d0Sopenharmony_ci        goto out;
1477310c0d0Sopenharmony_ci    }
1487310c0d0Sopenharmony_ci
1497310c0d0Sopenharmony_ci    image = &vd->images[vd->num_loaded_images++];
1507310c0d0Sopenharmony_ci    image->partition_name = hvb_strdup(ptn);
1517310c0d0Sopenharmony_ci    image->data = image_buf;
1527310c0d0Sopenharmony_ci    image->preloaded = true;
1537310c0d0Sopenharmony_ci
1547310c0d0Sopenharmony_ci    return HVB_OK;
1557310c0d0Sopenharmony_ci
1567310c0d0Sopenharmony_ciout:
1577310c0d0Sopenharmony_ci    if (image_buf.addr != NULL)
1587310c0d0Sopenharmony_ci        hvb_free(image_buf.addr);
1597310c0d0Sopenharmony_ci
1607310c0d0Sopenharmony_ci    return ret;
1617310c0d0Sopenharmony_ci}
1627310c0d0Sopenharmony_ci
1637310c0d0Sopenharmony_cistatic bool _decode_octets(struct hvb_buf *buf, size_t size, uint8_t **p, uint8_t *end)
1647310c0d0Sopenharmony_ci{
1657310c0d0Sopenharmony_ci    /* check range */
1667310c0d0Sopenharmony_ci    if (*p + size > end || *p + size < *p)
1677310c0d0Sopenharmony_ci        return false;
1687310c0d0Sopenharmony_ci
1697310c0d0Sopenharmony_ci    buf->addr = *p;
1707310c0d0Sopenharmony_ci    buf->size = size;
1717310c0d0Sopenharmony_ci
1727310c0d0Sopenharmony_ci    /* forward move */
1737310c0d0Sopenharmony_ci    *p += size;
1747310c0d0Sopenharmony_ci
1757310c0d0Sopenharmony_ci    return true;
1767310c0d0Sopenharmony_ci}
1777310c0d0Sopenharmony_ci
1787310c0d0Sopenharmony_cistatic enum hvb_errno _hvb_cert_payload_parser(struct hvb_cert *cert, uint8_t **p, uint8_t *end)
1797310c0d0Sopenharmony_ci{
1807310c0d0Sopenharmony_ci    struct hvb_buf buf;
1817310c0d0Sopenharmony_ci    struct hash_payload *payload = &cert->hash_payload;
1827310c0d0Sopenharmony_ci
1837310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, cert->salt_size, p, end)) {
1847310c0d0Sopenharmony_ci        hvb_print("error, dc salt.\n");
1857310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
1867310c0d0Sopenharmony_ci    }
1877310c0d0Sopenharmony_ci    payload->salt = buf.addr;
1887310c0d0Sopenharmony_ci
1897310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, cert->digest_size, p, end)) {
1907310c0d0Sopenharmony_ci        hvb_print("error, dc digest.\n");
1917310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
1927310c0d0Sopenharmony_ci    }
1937310c0d0Sopenharmony_ci    payload->digest = buf.addr;
1947310c0d0Sopenharmony_ci
1957310c0d0Sopenharmony_ci    return HVB_OK;
1967310c0d0Sopenharmony_ci}
1977310c0d0Sopenharmony_ci
1987310c0d0Sopenharmony_cistatic enum hvb_errno _hvb_cert_payload_parser_v2(struct hvb_cert *cert, uint8_t **p, uint8_t *end, uint8_t *header)
1997310c0d0Sopenharmony_ci{
2007310c0d0Sopenharmony_ci    struct hash_payload *payload = &cert->hash_payload;
2017310c0d0Sopenharmony_ci    uint8_t *cur_header;
2027310c0d0Sopenharmony_ci
2037310c0d0Sopenharmony_ci    if (header + cert->salt_offset > end || header + cert->salt_offset <= header) {
2047310c0d0Sopenharmony_ci        hvb_print("error, illegal salt offset.\n");
2057310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2067310c0d0Sopenharmony_ci    }
2077310c0d0Sopenharmony_ci    cur_header = header + cert->salt_offset;
2087310c0d0Sopenharmony_ci
2097310c0d0Sopenharmony_ci    if (cur_header + cert->salt_size > end || cur_header + cert->salt_size <= cur_header) {
2107310c0d0Sopenharmony_ci        hvb_print("error, dc salt.\n");
2117310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2127310c0d0Sopenharmony_ci    }
2137310c0d0Sopenharmony_ci    payload->salt = cur_header;
2147310c0d0Sopenharmony_ci
2157310c0d0Sopenharmony_ci    if (header + cert->digest_offset > end || header + cert->digest_offset <= header) {
2167310c0d0Sopenharmony_ci        hvb_print("error, illegal digest offset.\n");
2177310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2187310c0d0Sopenharmony_ci    }
2197310c0d0Sopenharmony_ci    cur_header = header + cert->digest_offset;
2207310c0d0Sopenharmony_ci
2217310c0d0Sopenharmony_ci    if (cur_header + cert->digest_size > end || cur_header + cert->digest_size <= cur_header) {
2227310c0d0Sopenharmony_ci        hvb_print("error, dc digest.\n");
2237310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2247310c0d0Sopenharmony_ci    }
2257310c0d0Sopenharmony_ci    payload->digest = cur_header;
2267310c0d0Sopenharmony_ci    *p = cur_header + cert->digest_size;
2277310c0d0Sopenharmony_ci
2287310c0d0Sopenharmony_ci    return HVB_OK;
2297310c0d0Sopenharmony_ci}
2307310c0d0Sopenharmony_ci
2317310c0d0Sopenharmony_cistatic enum hvb_errno _hvb_cert_signature_parser(struct hvb_cert *cert, uint8_t **p, uint8_t *end)
2327310c0d0Sopenharmony_ci{
2337310c0d0Sopenharmony_ci    struct hvb_buf buf;
2347310c0d0Sopenharmony_ci    struct hvb_sign_info *sign_info = &cert->signature_info;
2357310c0d0Sopenharmony_ci    size_t cp_size = hvb_offsetof(struct hvb_sign_info, pubk);
2367310c0d0Sopenharmony_ci
2377310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, cp_size, p, end)) {
2387310c0d0Sopenharmony_ci        hvb_print("error, dc sign info const.\n");
2397310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2407310c0d0Sopenharmony_ci    }
2417310c0d0Sopenharmony_ci    if (hvb_memcpy_s(&cert->signature_info, sizeof(cert->signature_info), buf.addr, cp_size) != 0) {
2427310c0d0Sopenharmony_ci        hvb_print("error, copy dc sign info const.\n");
2437310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
2447310c0d0Sopenharmony_ci    }
2457310c0d0Sopenharmony_ci
2467310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, sign_info->pubkey_len, p, end)) {
2477310c0d0Sopenharmony_ci        hvb_print("error, dc pubk.\n");
2487310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2497310c0d0Sopenharmony_ci    }
2507310c0d0Sopenharmony_ci    if (hvb_memcpy_s(&sign_info->pubk, sizeof(sign_info->pubk), &buf, sizeof(buf)) != 0) {
2517310c0d0Sopenharmony_ci        hvb_print("error, copy dc pubk.\n");
2527310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
2537310c0d0Sopenharmony_ci    }
2547310c0d0Sopenharmony_ci
2557310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, sign_info->signature_len, p, end)) {
2567310c0d0Sopenharmony_ci        hvb_print("error, dc sign.\n");
2577310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2587310c0d0Sopenharmony_ci    }
2597310c0d0Sopenharmony_ci    if (hvb_memcpy_s(&sign_info->sign, sizeof(sign_info->sign), &buf, sizeof(buf)) != 0) {
2607310c0d0Sopenharmony_ci        hvb_print("error, copy dc sign.\n");
2617310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
2627310c0d0Sopenharmony_ci    }
2637310c0d0Sopenharmony_ci
2647310c0d0Sopenharmony_ci    return HVB_OK;
2657310c0d0Sopenharmony_ci}
2667310c0d0Sopenharmony_ci
2677310c0d0Sopenharmony_cistatic enum hvb_errno _hvb_cert_signature_parser_v2(struct hvb_cert *cert, uint8_t **p, uint8_t *end, uint8_t *header)
2687310c0d0Sopenharmony_ci{
2697310c0d0Sopenharmony_ci    struct hvb_buf buf;
2707310c0d0Sopenharmony_ci    struct hvb_sign_info *sign_info = &cert->signature_info;
2717310c0d0Sopenharmony_ci    size_t cp_size = hvb_offsetof(struct hvb_sign_info, pubk);
2727310c0d0Sopenharmony_ci    uint8_t *cur_header;
2737310c0d0Sopenharmony_ci
2747310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, cp_size, p, end)) {
2757310c0d0Sopenharmony_ci        hvb_print("error, dc sign info const.\n");
2767310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2777310c0d0Sopenharmony_ci    }
2787310c0d0Sopenharmony_ci    if (hvb_memcpy_s(&cert->signature_info, sizeof(cert->signature_info), buf.addr, cp_size) != 0) {
2797310c0d0Sopenharmony_ci        hvb_print("error, copy dc sign info const.\n");
2807310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
2817310c0d0Sopenharmony_ci    }
2827310c0d0Sopenharmony_ci
2837310c0d0Sopenharmony_ci    if (header + sign_info->pubkey_offset > end || header + sign_info->pubkey_offset <= header) {
2847310c0d0Sopenharmony_ci        hvb_print("error, illegal pubkey offset.\n");
2857310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2867310c0d0Sopenharmony_ci    }
2877310c0d0Sopenharmony_ci    cur_header = header + sign_info->pubkey_offset;
2887310c0d0Sopenharmony_ci
2897310c0d0Sopenharmony_ci    if (cur_header + sign_info->pubkey_len > end || cur_header + sign_info->pubkey_len <= cur_header) {
2907310c0d0Sopenharmony_ci        hvb_print("error, dc pubkey.\n");
2917310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2927310c0d0Sopenharmony_ci    }
2937310c0d0Sopenharmony_ci    sign_info->pubk.addr = cur_header;
2947310c0d0Sopenharmony_ci    sign_info->pubk.size = sign_info->pubkey_len;
2957310c0d0Sopenharmony_ci
2967310c0d0Sopenharmony_ci    if (header + sign_info->signature_offset > end || header + sign_info->signature_offset <= header) {
2977310c0d0Sopenharmony_ci        hvb_print("error, illegal signature offset.\n");
2987310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
2997310c0d0Sopenharmony_ci    }
3007310c0d0Sopenharmony_ci    cur_header = header + sign_info->signature_offset;
3017310c0d0Sopenharmony_ci
3027310c0d0Sopenharmony_ci    if (cur_header + sign_info->signature_len > end || cur_header + sign_info->signature_len <= cur_header) {
3037310c0d0Sopenharmony_ci        hvb_print("error, dc pubkey.\n");
3047310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
3057310c0d0Sopenharmony_ci    }
3067310c0d0Sopenharmony_ci    sign_info->sign.addr = cur_header;
3077310c0d0Sopenharmony_ci    sign_info->sign.size = sign_info->signature_len;
3087310c0d0Sopenharmony_ci
3097310c0d0Sopenharmony_ci    return HVB_OK;
3107310c0d0Sopenharmony_ci}
3117310c0d0Sopenharmony_ci
3127310c0d0Sopenharmony_cienum hvb_errno hvb_cert_parser(struct hvb_cert *cert, struct hvb_buf *cert_buf)
3137310c0d0Sopenharmony_ci{
3147310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(cert);
3157310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(cert_buf);
3167310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(cert_buf->addr);
3177310c0d0Sopenharmony_ci
3187310c0d0Sopenharmony_ci    if (cert_buf->size > HVB_CERT_MAX_SIZE) {
3197310c0d0Sopenharmony_ci        hvb_print("invalid cert size.\n");
3207310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
3217310c0d0Sopenharmony_ci    }
3227310c0d0Sopenharmony_ci
3237310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
3247310c0d0Sopenharmony_ci    struct hvb_buf buf;
3257310c0d0Sopenharmony_ci    uint8_t *p = cert_buf->addr;
3267310c0d0Sopenharmony_ci    uint8_t *end = p + cert_buf->size;
3277310c0d0Sopenharmony_ci    uint8_t *header = p;
3287310c0d0Sopenharmony_ci    size_t header_size = hvb_offsetof(struct hvb_cert, hash_payload);
3297310c0d0Sopenharmony_ci
3307310c0d0Sopenharmony_ci    /* parse header */
3317310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, header_size, &p, end)) {
3327310c0d0Sopenharmony_ci        hvb_print("error, dc cert const.\n");
3337310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
3347310c0d0Sopenharmony_ci    }
3357310c0d0Sopenharmony_ci    if (hvb_memcpy_s(cert, sizeof(*cert), buf.addr, buf.size) != 0) {
3367310c0d0Sopenharmony_ci        hvb_print("error, copy dc cert const.\n");
3377310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
3387310c0d0Sopenharmony_ci    }
3397310c0d0Sopenharmony_ci
3407310c0d0Sopenharmony_ci    if (cert->version_minor == 0) {
3417310c0d0Sopenharmony_ci        /* parse hash payload */
3427310c0d0Sopenharmony_ci        ret = _hvb_cert_payload_parser(cert, &p, end);
3437310c0d0Sopenharmony_ci        if (ret != HVB_OK) {
3447310c0d0Sopenharmony_ci            hvb_print("error, pr hash payload.\n");
3457310c0d0Sopenharmony_ci            return ret;
3467310c0d0Sopenharmony_ci        }
3477310c0d0Sopenharmony_ci
3487310c0d0Sopenharmony_ci        /* parse signature info */
3497310c0d0Sopenharmony_ci        ret = _hvb_cert_signature_parser(cert, &p, end);
3507310c0d0Sopenharmony_ci        if (ret != HVB_OK) {
3517310c0d0Sopenharmony_ci            hvb_print("error, pr sign.\n");
3527310c0d0Sopenharmony_ci            return ret;
3537310c0d0Sopenharmony_ci        }
3547310c0d0Sopenharmony_ci    } else if (cert->version_minor == 1) {
3557310c0d0Sopenharmony_ci        /* parse hash payload v2 */
3567310c0d0Sopenharmony_ci        ret = _hvb_cert_payload_parser_v2(cert, &p, end, header);
3577310c0d0Sopenharmony_ci        if (ret != HVB_OK) {
3587310c0d0Sopenharmony_ci            hvb_print("error, pr hash payload.\n");
3597310c0d0Sopenharmony_ci            return ret;
3607310c0d0Sopenharmony_ci        }
3617310c0d0Sopenharmony_ci
3627310c0d0Sopenharmony_ci        /* parse signature info v2 */
3637310c0d0Sopenharmony_ci        ret = _hvb_cert_signature_parser_v2(cert, &p, end, header);
3647310c0d0Sopenharmony_ci        if (ret != HVB_OK) {
3657310c0d0Sopenharmony_ci            hvb_print("error, pr sign.\n");
3667310c0d0Sopenharmony_ci            return ret;
3677310c0d0Sopenharmony_ci        }
3687310c0d0Sopenharmony_ci    } else {
3697310c0d0Sopenharmony_ci        hvb_print("error minor version\n");
3707310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
3717310c0d0Sopenharmony_ci    }
3727310c0d0Sopenharmony_ci
3737310c0d0Sopenharmony_ci    return HVB_OK;
3747310c0d0Sopenharmony_ci}
3757310c0d0Sopenharmony_ci
3767310c0d0Sopenharmony_cistatic uint64_t hvb_buftouint64(uint8_t *p)
3777310c0d0Sopenharmony_ci{
3787310c0d0Sopenharmony_ci    uint32_t i;
3797310c0d0Sopenharmony_ci    uint64_t val = 0;
3807310c0d0Sopenharmony_ci
3817310c0d0Sopenharmony_ci    for (i = 0; i < 8; i++, p++) {
3827310c0d0Sopenharmony_ci        val |= (((uint64_t)(*p)) << (i * 8));
3837310c0d0Sopenharmony_ci    }
3847310c0d0Sopenharmony_ci
3857310c0d0Sopenharmony_ci    return val;
3867310c0d0Sopenharmony_ci}
3877310c0d0Sopenharmony_ci
3887310c0d0Sopenharmony_ci/*
3897310c0d0Sopenharmony_ci * raw_pubk: |bit_length|n0|mod|p_rr|
3907310c0d0Sopenharmony_ci */
3917310c0d0Sopenharmony_cistatic enum hvb_errno hvb_cert_pubk_parser(struct hvb_rsa_pubkey *pubk, struct hvb_buf *raw_pubk)
3927310c0d0Sopenharmony_ci{
3937310c0d0Sopenharmony_ci    uint64_t bit_length = 0;
3947310c0d0Sopenharmony_ci    uint64_t n0 = 0;
3957310c0d0Sopenharmony_ci    struct hvb_buf mod;
3967310c0d0Sopenharmony_ci    struct hvb_buf p_rr;
3977310c0d0Sopenharmony_ci    struct hvb_buf buf;
3987310c0d0Sopenharmony_ci
3997310c0d0Sopenharmony_ci    uint8_t *p = raw_pubk->addr;
4007310c0d0Sopenharmony_ci    uint8_t *end = p + raw_pubk->size;
4017310c0d0Sopenharmony_ci
4027310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, sizeof(uint64_t), &p, end)) {
4037310c0d0Sopenharmony_ci        hvb_print("error, dc bit_length.\n");
4047310c0d0Sopenharmony_ci        return 1;
4057310c0d0Sopenharmony_ci    }
4067310c0d0Sopenharmony_ci    bit_length = hvb_buftouint64(buf.addr);
4077310c0d0Sopenharmony_ci    bit_length = hvb_be64toh(bit_length);
4087310c0d0Sopenharmony_ci
4097310c0d0Sopenharmony_ci    if (!_decode_octets(&buf, sizeof(uint64_t), &p, end)) {
4107310c0d0Sopenharmony_ci        hvb_print("error, dc n0.\n");
4117310c0d0Sopenharmony_ci        return 1;
4127310c0d0Sopenharmony_ci    }
4137310c0d0Sopenharmony_ci    n0 = hvb_buftouint64(buf.addr);
4147310c0d0Sopenharmony_ci    n0 = hvb_be64toh(n0);
4157310c0d0Sopenharmony_ci
4167310c0d0Sopenharmony_ci    if (!_decode_octets(&mod, bit_length / 8, &p, end)) {
4177310c0d0Sopenharmony_ci        hvb_print("error, dc mod.\n");
4187310c0d0Sopenharmony_ci        return 1;
4197310c0d0Sopenharmony_ci    }
4207310c0d0Sopenharmony_ci
4217310c0d0Sopenharmony_ci    if (!_decode_octets(&p_rr, bit_length / 8, &p, end)) {
4227310c0d0Sopenharmony_ci        hvb_print("error, dc p_rr\n");
4237310c0d0Sopenharmony_ci        return 1;
4247310c0d0Sopenharmony_ci    }
4257310c0d0Sopenharmony_ci
4267310c0d0Sopenharmony_ci    pubk->width = bit_length;
4277310c0d0Sopenharmony_ci    pubk->e = 65537;
4287310c0d0Sopenharmony_ci    pubk->pn = mod.addr;
4297310c0d0Sopenharmony_ci    pubk->nlen = mod.size;
4307310c0d0Sopenharmony_ci    pubk->p_rr = p_rr.addr;
4317310c0d0Sopenharmony_ci    pubk->rlen = p_rr.size;
4327310c0d0Sopenharmony_ci    pubk->n_n0_i = n0;
4337310c0d0Sopenharmony_ci
4347310c0d0Sopenharmony_ci    return 0;
4357310c0d0Sopenharmony_ci}
4367310c0d0Sopenharmony_ci
4377310c0d0Sopenharmony_cistatic enum hvb_errno hvb_verify_cert(struct hvb_buf *tbs, struct hvb_sign_info *sign_info, uint32_t salt_size)
4387310c0d0Sopenharmony_ci{
4397310c0d0Sopenharmony_ci    int cry_err;
4407310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
4417310c0d0Sopenharmony_ci    uint32_t hash_len;
4427310c0d0Sopenharmony_ci    struct hvb_buf temp_buf;
4437310c0d0Sopenharmony_ci    uint8_t *hash = NULL;
4447310c0d0Sopenharmony_ci    struct hvb_rsa_pubkey pubk;
4457310c0d0Sopenharmony_ci
4467310c0d0Sopenharmony_ci    temp_buf = sign_info->pubk;
4477310c0d0Sopenharmony_ci    ret = hvb_cert_pubk_parser(&pubk, &temp_buf);
4487310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
4497310c0d0Sopenharmony_ci        hvb_print("error, hvb cert pubk parser.\n");
4507310c0d0Sopenharmony_ci        return ret;
4517310c0d0Sopenharmony_ci    }
4527310c0d0Sopenharmony_ci
4537310c0d0Sopenharmony_ci    hash_len = get_hash_size(sign_info->algorithm);
4547310c0d0Sopenharmony_ci    hash = hvb_malloc(hash_len);
4557310c0d0Sopenharmony_ci    if (!hash) {
4567310c0d0Sopenharmony_ci        hvb_print("hash malloc error:");
4577310c0d0Sopenharmony_ci        return HVB_ERROR_OOM;
4587310c0d0Sopenharmony_ci    }
4597310c0d0Sopenharmony_ci
4607310c0d0Sopenharmony_ci    cry_err = hash_sha256_single(tbs->addr, tbs->size, hash, hash_len);
4617310c0d0Sopenharmony_ci    if (cry_err != 0) {
4627310c0d0Sopenharmony_ci        hvb_print("Error computed hash.\n");
4637310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
4647310c0d0Sopenharmony_ci    }
4657310c0d0Sopenharmony_ci
4667310c0d0Sopenharmony_ci    cry_err = hvb_rsa_verify_pss(&pubk, hash, hash_len, sign_info->sign.addr, sign_info->sign.size, salt_size);
4677310c0d0Sopenharmony_ci    if (cry_err != VERIFY_OK) {
4687310c0d0Sopenharmony_ci        hvb_print("hvb_rsa_verify_pss result error, signature mismatch\n");
4697310c0d0Sopenharmony_ci        return HVB_ERROR_VERIFY_SIGN;
4707310c0d0Sopenharmony_ci    }
4717310c0d0Sopenharmony_ci
4727310c0d0Sopenharmony_ci    return HVB_OK;
4737310c0d0Sopenharmony_ci}
4747310c0d0Sopenharmony_ci
4757310c0d0Sopenharmony_cistatic enum hvb_errno _check_rollback_index(struct hvb_ops *ops, struct hvb_cert *cert, struct hvb_verified_data *vd)
4767310c0d0Sopenharmony_ci{
4777310c0d0Sopenharmony_ci    enum hvb_io_errno io_ret = HVB_IO_OK;
4787310c0d0Sopenharmony_ci    uint64_t stored_rollback_index = 0;
4797310c0d0Sopenharmony_ci    uint64_t cert_rollback_index = cert->rollback_index;
4807310c0d0Sopenharmony_ci    uint64_t rollback_location = cert->rollback_location;
4817310c0d0Sopenharmony_ci
4827310c0d0Sopenharmony_ci    if (rollback_location >= HVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
4837310c0d0Sopenharmony_ci        hvb_print("error, rollback_location too big\n");
4847310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_CERT_FORMAT;
4857310c0d0Sopenharmony_ci    }
4867310c0d0Sopenharmony_ci
4877310c0d0Sopenharmony_ci    io_ret = ops->read_rollback(ops, rollback_location, &stored_rollback_index);
4887310c0d0Sopenharmony_ci    if (io_ret != HVB_IO_OK) {
4897310c0d0Sopenharmony_ci        hvb_print("error, read rollback idnex\n");
4907310c0d0Sopenharmony_ci        return HVB_ERROR_IO;
4917310c0d0Sopenharmony_ci    }
4927310c0d0Sopenharmony_ci
4937310c0d0Sopenharmony_ci    if (cert_rollback_index < stored_rollback_index) {
4947310c0d0Sopenharmony_ci        hvb_print("error, cert rollback index is less than the stored\n");
4957310c0d0Sopenharmony_ci        return HVB_ERROR_ROLLBACK_INDEX;
4967310c0d0Sopenharmony_ci    }
4977310c0d0Sopenharmony_ci
4987310c0d0Sopenharmony_ci    vd->rollback_indexes[rollback_location] = cert_rollback_index;
4997310c0d0Sopenharmony_ci
5007310c0d0Sopenharmony_ci    return HVB_OK;
5017310c0d0Sopenharmony_ci}
5027310c0d0Sopenharmony_ci
5037310c0d0Sopenharmony_cienum hvb_errno cert_init_desc(struct hvb_ops *ops, const char *ptn, struct hvb_buf *cert_buf,
5047310c0d0Sopenharmony_ci                              const char *const *hash_ptn_list, struct hvb_buf *out_pubk,
5057310c0d0Sopenharmony_ci                              struct hvb_verified_data *vd)
5067310c0d0Sopenharmony_ci{
5077310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(ops);
5087310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(ptn);
5097310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(cert_buf);
5107310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(cert_buf->addr);
5117310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(out_pubk);
5127310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(vd);
5137310c0d0Sopenharmony_ci
5147310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
5157310c0d0Sopenharmony_ci    ret = check_hvb_ops(ops);
5167310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
5177310c0d0Sopenharmony_ci        hvb_print("error, check ops\n");
5187310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
5197310c0d0Sopenharmony_ci    }
5207310c0d0Sopenharmony_ci    if (hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN) >= HVB_MAX_PARTITION_NAME_LEN) {
5217310c0d0Sopenharmony_ci        hvb_print("error, check partition name\n");
5227310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
5237310c0d0Sopenharmony_ci    }
5247310c0d0Sopenharmony_ci
5257310c0d0Sopenharmony_ci    struct hvb_cert cert = {0};
5267310c0d0Sopenharmony_ci    struct hvb_buf tbs = {0};
5277310c0d0Sopenharmony_ci    struct hvb_sign_info *sign_info = &cert.signature_info;
5287310c0d0Sopenharmony_ci
5297310c0d0Sopenharmony_ci    ret = hvb_cert_parser(&cert, cert_buf);
5307310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
5317310c0d0Sopenharmony_ci        hvb_print("error, hvb cert parser.\n");
5327310c0d0Sopenharmony_ci        return ret;
5337310c0d0Sopenharmony_ci    }
5347310c0d0Sopenharmony_ci
5357310c0d0Sopenharmony_ci    tbs.addr = cert_buf->addr;
5367310c0d0Sopenharmony_ci    tbs.size = sign_info->sign.addr - cert_buf->addr;
5377310c0d0Sopenharmony_ci    ret = hvb_verify_cert(&tbs, sign_info, cert.salt_size);
5387310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
5397310c0d0Sopenharmony_ci        hvb_print("error, verify cert.\n");
5407310c0d0Sopenharmony_ci        return ret;
5417310c0d0Sopenharmony_ci    }
5427310c0d0Sopenharmony_ci
5437310c0d0Sopenharmony_ci    ret = _check_rollback_index(ops, &cert, vd);
5447310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
5457310c0d0Sopenharmony_ci        hvb_print("error, checkout index.\n");
5467310c0d0Sopenharmony_ci        return ret;
5477310c0d0Sopenharmony_ci    }
5487310c0d0Sopenharmony_ci
5497310c0d0Sopenharmony_ci    ret = hash_image_init_desc(ops, ptn, &cert, hash_ptn_list, vd);
5507310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
5517310c0d0Sopenharmony_ci        hvb_print("hash_image_init_desc result error\n");
5527310c0d0Sopenharmony_ci        return ret;
5537310c0d0Sopenharmony_ci    }
5547310c0d0Sopenharmony_ci
5557310c0d0Sopenharmony_ci    *out_pubk = sign_info->pubk;
5567310c0d0Sopenharmony_ci    vd->key_len = out_pubk->size;
5577310c0d0Sopenharmony_ci
5587310c0d0Sopenharmony_ci    return ret;
5597310c0d0Sopenharmony_ci}
560