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_cmdline.h"
167310c0d0Sopenharmony_ci#include "hvb_util.h"
177310c0d0Sopenharmony_ci#include "hvb_cert.h"
187310c0d0Sopenharmony_ci#include "hvb_rvt.h"
197310c0d0Sopenharmony_ci#include "hvb_ops.h"
207310c0d0Sopenharmony_ci#include "hvb.h"
217310c0d0Sopenharmony_ci#include "hvb_sysdeps.h"
227310c0d0Sopenharmony_ci#include "hvb_crypto.h"
237310c0d0Sopenharmony_ci
247310c0d0Sopenharmony_cistatic int cmdline_append_option(struct hvb_verified_data *vd, const char *key, const char *value)
257310c0d0Sopenharmony_ci{
267310c0d0Sopenharmony_ci    uint64_t option_len = 0;
277310c0d0Sopenharmony_ci    uint64_t key_len, value_len;
287310c0d0Sopenharmony_ci    struct hvb_cmdline_data *cmdline = NULL;
297310c0d0Sopenharmony_ci
307310c0d0Sopenharmony_ci    if (vd == NULL || vd->cmdline.buf == NULL)
317310c0d0Sopenharmony_ci        return 0;
327310c0d0Sopenharmony_ci
337310c0d0Sopenharmony_ci    cmdline = &vd->cmdline;
347310c0d0Sopenharmony_ci
357310c0d0Sopenharmony_ci    key_len = hvb_strlen(key);
367310c0d0Sopenharmony_ci    value_len = hvb_strlen(value);
377310c0d0Sopenharmony_ci    /* 2 for blank space and = */
387310c0d0Sopenharmony_ci    option_len = key_len + value_len + 2;
397310c0d0Sopenharmony_ci    if (option_len > cmdline->max_size - cmdline->cur_pos - 1)
407310c0d0Sopenharmony_ci        return 0;
417310c0d0Sopenharmony_ci
427310c0d0Sopenharmony_ci    /* append blank space */
437310c0d0Sopenharmony_ci    cmdline->buf[cmdline->cur_pos] = ' ';
447310c0d0Sopenharmony_ci    cmdline->cur_pos++;
457310c0d0Sopenharmony_ci    /* append key */
467310c0d0Sopenharmony_ci    hvb_memcpy(cmdline->buf + cmdline->cur_pos, key, key_len);
477310c0d0Sopenharmony_ci    cmdline->cur_pos += key_len;
487310c0d0Sopenharmony_ci    /* append = */
497310c0d0Sopenharmony_ci    cmdline->buf[cmdline->cur_pos] = '=';
507310c0d0Sopenharmony_ci    cmdline->cur_pos++;
517310c0d0Sopenharmony_ci    /* append value */
527310c0d0Sopenharmony_ci    hvb_memcpy(cmdline->buf + cmdline->cur_pos, value, value_len);
537310c0d0Sopenharmony_ci    cmdline->cur_pos += value_len;
547310c0d0Sopenharmony_ci
557310c0d0Sopenharmony_ci    return 1;
567310c0d0Sopenharmony_ci}
577310c0d0Sopenharmony_ci
587310c0d0Sopenharmony_cistatic int hvb_append_version_cmdline(struct hvb_verified_data *vd, const char *key_value,
597310c0d0Sopenharmony_ci                                      uint64_t version_major, uint64_t version_minor)
607310c0d0Sopenharmony_ci{
617310c0d0Sopenharmony_ci    char major_digits[HVB_MAX_DIGITS_UINT64];
627310c0d0Sopenharmony_ci    char minor_digits[HVB_MAX_DIGITS_UINT64];
637310c0d0Sopenharmony_ci    char combined[HVB_MAX_DIGITS_UINT64 * 2 + 1];
647310c0d0Sopenharmony_ci    uint64_t num_major_digits, num_minor_digits;
657310c0d0Sopenharmony_ci
667310c0d0Sopenharmony_ci    num_major_digits = hvb_uint64_to_base10(version_major, major_digits);
677310c0d0Sopenharmony_ci    num_minor_digits = hvb_uint64_to_base10(version_minor, minor_digits);
687310c0d0Sopenharmony_ci
697310c0d0Sopenharmony_ci    hvb_memcpy(combined, major_digits, num_major_digits);
707310c0d0Sopenharmony_ci    combined[num_major_digits] = '.';
717310c0d0Sopenharmony_ci    hvb_memcpy(combined + num_major_digits + 1, minor_digits, num_minor_digits);
727310c0d0Sopenharmony_ci    combined[num_major_digits + 1 + num_minor_digits] = '\0';
737310c0d0Sopenharmony_ci
747310c0d0Sopenharmony_ci    return cmdline_append_option(vd, key_value, combined);
757310c0d0Sopenharmony_ci}
767310c0d0Sopenharmony_ci
777310c0d0Sopenharmony_cistatic int cmdline_append_uint64_base10(struct hvb_verified_data *vd, const char *key, uint64_t value)
787310c0d0Sopenharmony_ci{
797310c0d0Sopenharmony_ci    char digits[HVB_MAX_DIGITS_UINT64];
807310c0d0Sopenharmony_ci
817310c0d0Sopenharmony_ci    hvb_uint64_to_base10(value, digits);
827310c0d0Sopenharmony_ci
837310c0d0Sopenharmony_ci    return cmdline_append_option(vd, key, digits);
847310c0d0Sopenharmony_ci}
857310c0d0Sopenharmony_ci
867310c0d0Sopenharmony_cistatic int cmdline_append_hex(struct hvb_verified_data *vd, const char* key,
877310c0d0Sopenharmony_ci                              const uint8_t *data, uint64_t data_len)
887310c0d0Sopenharmony_ci{
897310c0d0Sopenharmony_ci    int ret;
907310c0d0Sopenharmony_ci    char *hex_data = hvb_bin2hex(data, data_len);
917310c0d0Sopenharmony_ci
927310c0d0Sopenharmony_ci    if (hex_data == NULL) {
937310c0d0Sopenharmony_ci        return 0;
947310c0d0Sopenharmony_ci    }
957310c0d0Sopenharmony_ci
967310c0d0Sopenharmony_ci    ret = cmdline_append_option(vd, key, hex_data);
977310c0d0Sopenharmony_ci    hvb_free(hex_data);
987310c0d0Sopenharmony_ci
997310c0d0Sopenharmony_ci    return ret;
1007310c0d0Sopenharmony_ci}
1017310c0d0Sopenharmony_ci
1027310c0d0Sopenharmony_cienum hvb_errno hvb_creat_cmdline(struct hvb_ops *ops, struct hvb_verified_data *vd)
1037310c0d0Sopenharmony_ci{
1047310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(ops);
1057310c0d0Sopenharmony_ci    hvb_return_hvb_err_if_null(vd);
1067310c0d0Sopenharmony_ci
1077310c0d0Sopenharmony_ci    enum hvb_errno ret = HVB_OK;
1087310c0d0Sopenharmony_ci    enum hvb_io_errno io_ret = HVB_IO_OK;
1097310c0d0Sopenharmony_ci    bool device_locked = false;
1107310c0d0Sopenharmony_ci    ret = check_hvb_ops(ops);
1117310c0d0Sopenharmony_ci    if (ret != HVB_OK) {
1127310c0d0Sopenharmony_ci        hvb_print("error, check ops\n");
1137310c0d0Sopenharmony_ci        return HVB_ERROR_INVALID_ARGUMENT;
1147310c0d0Sopenharmony_ci    }
1157310c0d0Sopenharmony_ci
1167310c0d0Sopenharmony_ci    /* set ohos.boot.hvb.version. */
1177310c0d0Sopenharmony_ci    if (!hvb_append_version_cmdline(vd, HVB_CMDLINE_VERSION,
1187310c0d0Sopenharmony_ci                                    HVB_VERSION_MAJOR, HVB_VERSION_MINOR)) {
1197310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1207310c0d0Sopenharmony_ci        goto fail;
1217310c0d0Sopenharmony_ci    }
1227310c0d0Sopenharmony_ci
1237310c0d0Sopenharmony_ci    /* set ohos.boot.device_state to "locked" or "unlocked". */
1247310c0d0Sopenharmony_ci    io_ret = ops->read_lock_state(ops, &device_locked);
1257310c0d0Sopenharmony_ci    if (io_ret == HVB_IO_ERROR_OOM) {
1267310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1277310c0d0Sopenharmony_ci        goto fail;
1287310c0d0Sopenharmony_ci    } else if (io_ret != HVB_IO_OK) {
1297310c0d0Sopenharmony_ci        hvb_print("Error getting device state.\n");
1307310c0d0Sopenharmony_ci        ret = HVB_ERROR_IO;
1317310c0d0Sopenharmony_ci        goto fail;
1327310c0d0Sopenharmony_ci    }
1337310c0d0Sopenharmony_ci
1347310c0d0Sopenharmony_ci    if (!cmdline_append_option(vd, HVB_CMDLINE_DEV_STATE,
1357310c0d0Sopenharmony_ci                               device_locked ? "locked" : "unlocked")) {
1367310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1377310c0d0Sopenharmony_ci        goto fail;
1387310c0d0Sopenharmony_ci    }
1397310c0d0Sopenharmony_ci
1407310c0d0Sopenharmony_ci    /*
1417310c0d0Sopenharmony_ci     * set ohos.boot.hvb.{hash_algo, size, digest} - use same hash
1427310c0d0Sopenharmony_ci     * function as is used to sign rvt.
1437310c0d0Sopenharmony_ci     */
1447310c0d0Sopenharmony_ci    uint8_t rvt_digest[HVB_SHA256_DIGEST_BYTES] = {0};
1457310c0d0Sopenharmony_ci    uint64_t rvt_size = 0;
1467310c0d0Sopenharmony_ci    for (uint64_t n = 0; n < vd->num_loaded_certs; n++) {
1477310c0d0Sopenharmony_ci        rvt_size += vd->certs[n].data.size;
1487310c0d0Sopenharmony_ci    }
1497310c0d0Sopenharmony_ci
1507310c0d0Sopenharmony_ci    if (hvb_calculate_certs_digest(vd, rvt_digest) != HVB_OK) {
1517310c0d0Sopenharmony_ci        hvb_print("Error calculate rvt digest.\n");
1527310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1537310c0d0Sopenharmony_ci        goto fail;
1547310c0d0Sopenharmony_ci    }
1557310c0d0Sopenharmony_ci
1567310c0d0Sopenharmony_ci    if (!cmdline_append_option(vd, HVB_CMDLINE_HASH_ALG, "sha256") ||
1577310c0d0Sopenharmony_ci        !cmdline_append_uint64_base10(vd, HVB_CMDLINE_RVT_SIZE, rvt_size) ||
1587310c0d0Sopenharmony_ci        !cmdline_append_hex(vd, HVB_CMDLINE_CERT_DIGEST, rvt_digest, HVB_SHA256_DIGEST_BYTES)) {
1597310c0d0Sopenharmony_ci        ret = HVB_ERROR_OOM;
1607310c0d0Sopenharmony_ci        goto fail;
1617310c0d0Sopenharmony_ci    }
1627310c0d0Sopenharmony_ci
1637310c0d0Sopenharmony_cifail:
1647310c0d0Sopenharmony_ci    return ret;
1657310c0d0Sopenharmony_ci}
166