xref: /base/startup/hvb/libhvb/src/cert/hvb_cert.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 <string.h>
18#include "hvb.h"
19#include "hvb_util.h"
20#include "hvb_crypto.h"
21#include "hvb_sysdeps.h"
22#include "hvb_cert.h"
23
24
25static bool hvb_need_verify_hash(const char *const *hash_ptn_list, const char *ptn)
26{
27    size_t n;
28    size_t ptn_len = hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN);
29    if (ptn_len >= HVB_MAX_PARTITION_NAME_LEN) {
30        hvb_print("invalid ptn name len\n");
31        return false;
32    }
33
34    if (hash_ptn_list == NULL)
35        return false;
36
37    for (n = 0; hash_ptn_list[n] != NULL; n++) {
38        if (hvb_strnlen(hash_ptn_list[n], HVB_MAX_PARTITION_NAME_LEN) == ptn_len &&
39            hvb_strncmp(hash_ptn_list[n], ptn, HVB_MAX_PARTITION_NAME_LEN) == 0) {
40            return true;
41        }
42    }
43
44    return false;
45}
46
47static uint64_t get_hash_size(uint32_t algo)
48{
49    switch (algo) {
50        case 0: // SHA256_RSA3072
51        case 1: // SHA256_RSA4096
52        case 2: // SHA256_RSA2048
53            return 32;
54        default:
55            return 0;
56    }
57
58    return 0;
59}
60
61static enum hvb_errno hvb_compare_hash(struct hvb_buf *digest_buf, struct hvb_buf *msg_buf,
62                                       struct hvb_buf *salt_buf, uint32_t hash_algo)
63{
64    int hash_err;
65    struct hash_ctx_t ctx = {0};
66    uint8_t computed_hash[HVB_HASH_MAX_BYTES] = {0};
67
68    uint32_t computed_hash_size = get_hash_size(hash_algo);
69    if (computed_hash_size != digest_buf->size) {
70        hvb_print("computed_hash_size error\n");
71        return HVB_ERROR_INVALID_ARGUMENT;
72    }
73
74    hash_err = hash_ctx_init(&ctx, hash_algo);
75    if (hash_err != HASH_OK) {
76        hvb_print("hash init error\n");
77        return HVB_ERROR_VERIFY_HASH;
78    }
79
80    hash_err = hash_calc_update(&ctx, salt_buf->addr, salt_buf->size);
81    if (hash_err != HASH_OK) {
82        hvb_print("hash updata salt error\n");
83        return HVB_ERROR_VERIFY_HASH;
84    }
85
86    hash_err = hash_calc_do_final(&ctx, msg_buf->addr, msg_buf->size, &computed_hash[0], digest_buf->size);
87    if (hash_err != HASH_OK) {
88        hvb_print("hash updata msg error\n");
89        return HVB_ERROR_VERIFY_HASH;
90    }
91
92    if (hvb_memcmp(&computed_hash[0], digest_buf->addr, computed_hash_size) != 0) {
93        hvb_print("compare fail\n");
94        return HVB_ERROR_VERIFY_HASH;
95    }
96
97    return HVB_OK;
98}
99
100static enum hvb_errno hash_image_init_desc(struct hvb_ops *ops, const char *ptn,
101                                           struct hvb_cert *cert, const char *const *hash_ptn_list,
102                                           struct hvb_verified_data *vd)
103{
104    enum hvb_io_errno io_ret = HVB_IO_OK;
105    enum hvb_errno ret = HVB_OK;
106    struct hvb_buf image_buf = {NULL, 0};
107    struct hvb_buf salt_buf = {cert->hash_payload.salt, cert->salt_size};
108    struct hvb_buf digest_buf = {cert->hash_payload.digest, cert->digest_size};
109    uint64_t read_bytes = 0;
110    struct hvb_image_data *image = NULL;
111    enum hvb_image_type image_type = (enum hvb_image_type)cert->verity_type;
112
113    if (image_type != HVB_IMAGE_TYPE_HASH || !hvb_need_verify_hash(hash_ptn_list, ptn)) {
114        hvb_printv(ptn, ": no need verify hash image.\n", NULL);
115        return HVB_OK;
116    }
117
118    image_buf.size = cert->image_original_len;
119    image_buf.addr = hvb_malloc(image_buf.size);
120    if (image_buf.addr == NULL) {
121        hvb_print("malloc image_buf fail\n");
122        return HVB_ERROR_OOM;
123    }
124
125    io_ret = ops->read_partition(ops, ptn, 0, image_buf.size, image_buf.addr, &read_bytes);
126    if (io_ret != HVB_IO_OK) {
127        hvb_printv(ptn, ": Error loading data.\n", NULL);
128        ret = HVB_ERROR_IO;
129        goto out;
130    }
131    if (read_bytes != image_buf.size) {
132        hvb_printv(ptn, ": Read incorrect number of bytes from.\n", NULL);
133        ret = HVB_ERROR_IO;
134        goto out;
135    }
136
137    ret = hvb_compare_hash(&digest_buf, &image_buf, &salt_buf, cert->hash_algo);
138    if (ret != HVB_OK) {
139        hvb_printv(ptn, ": compare hash error.\n", NULL);
140        goto out;
141    }
142
143    if (vd->num_loaded_images >= HVB_MAX_NUMBER_OF_LOADED_IMAGES) {
144        hvb_print("error, too many images\n");
145        ret = HVB_ERROR_OOM;
146        goto out;
147    }
148
149    image = &vd->images[vd->num_loaded_images++];
150    image->partition_name = hvb_strdup(ptn);
151    image->data = image_buf;
152    image->preloaded = true;
153
154    return HVB_OK;
155
156out:
157    if (image_buf.addr != NULL)
158        hvb_free(image_buf.addr);
159
160    return ret;
161}
162
163static bool _decode_octets(struct hvb_buf *buf, size_t size, uint8_t **p, uint8_t *end)
164{
165    /* check range */
166    if (*p + size > end || *p + size < *p)
167        return false;
168
169    buf->addr = *p;
170    buf->size = size;
171
172    /* forward move */
173    *p += size;
174
175    return true;
176}
177
178static enum hvb_errno _hvb_cert_payload_parser(struct hvb_cert *cert, uint8_t **p, uint8_t *end)
179{
180    struct hvb_buf buf;
181    struct hash_payload *payload = &cert->hash_payload;
182
183    if (!_decode_octets(&buf, cert->salt_size, p, end)) {
184        hvb_print("error, dc salt.\n");
185        return HVB_ERROR_INVALID_CERT_FORMAT;
186    }
187    payload->salt = buf.addr;
188
189    if (!_decode_octets(&buf, cert->digest_size, p, end)) {
190        hvb_print("error, dc digest.\n");
191        return HVB_ERROR_INVALID_CERT_FORMAT;
192    }
193    payload->digest = buf.addr;
194
195    return HVB_OK;
196}
197
198static enum hvb_errno _hvb_cert_payload_parser_v2(struct hvb_cert *cert, uint8_t **p, uint8_t *end, uint8_t *header)
199{
200    struct hash_payload *payload = &cert->hash_payload;
201    uint8_t *cur_header;
202
203    if (header + cert->salt_offset > end || header + cert->salt_offset <= header) {
204        hvb_print("error, illegal salt offset.\n");
205        return HVB_ERROR_INVALID_CERT_FORMAT;
206    }
207    cur_header = header + cert->salt_offset;
208
209    if (cur_header + cert->salt_size > end || cur_header + cert->salt_size <= cur_header) {
210        hvb_print("error, dc salt.\n");
211        return HVB_ERROR_INVALID_CERT_FORMAT;
212    }
213    payload->salt = cur_header;
214
215    if (header + cert->digest_offset > end || header + cert->digest_offset <= header) {
216        hvb_print("error, illegal digest offset.\n");
217        return HVB_ERROR_INVALID_CERT_FORMAT;
218    }
219    cur_header = header + cert->digest_offset;
220
221    if (cur_header + cert->digest_size > end || cur_header + cert->digest_size <= cur_header) {
222        hvb_print("error, dc digest.\n");
223        return HVB_ERROR_INVALID_CERT_FORMAT;
224    }
225    payload->digest = cur_header;
226    *p = cur_header + cert->digest_size;
227
228    return HVB_OK;
229}
230
231static enum hvb_errno _hvb_cert_signature_parser(struct hvb_cert *cert, uint8_t **p, uint8_t *end)
232{
233    struct hvb_buf buf;
234    struct hvb_sign_info *sign_info = &cert->signature_info;
235    size_t cp_size = hvb_offsetof(struct hvb_sign_info, pubk);
236
237    if (!_decode_octets(&buf, cp_size, p, end)) {
238        hvb_print("error, dc sign info const.\n");
239        return HVB_ERROR_INVALID_CERT_FORMAT;
240    }
241    if (hvb_memcpy_s(&cert->signature_info, sizeof(cert->signature_info), buf.addr, cp_size) != 0) {
242        hvb_print("error, copy dc sign info const.\n");
243        return HVB_ERROR_OOM;
244    }
245
246    if (!_decode_octets(&buf, sign_info->pubkey_len, p, end)) {
247        hvb_print("error, dc pubk.\n");
248        return HVB_ERROR_INVALID_CERT_FORMAT;
249    }
250    if (hvb_memcpy_s(&sign_info->pubk, sizeof(sign_info->pubk), &buf, sizeof(buf)) != 0) {
251        hvb_print("error, copy dc pubk.\n");
252        return HVB_ERROR_OOM;
253    }
254
255    if (!_decode_octets(&buf, sign_info->signature_len, p, end)) {
256        hvb_print("error, dc sign.\n");
257        return HVB_ERROR_INVALID_CERT_FORMAT;
258    }
259    if (hvb_memcpy_s(&sign_info->sign, sizeof(sign_info->sign), &buf, sizeof(buf)) != 0) {
260        hvb_print("error, copy dc sign.\n");
261        return HVB_ERROR_OOM;
262    }
263
264    return HVB_OK;
265}
266
267static enum hvb_errno _hvb_cert_signature_parser_v2(struct hvb_cert *cert, uint8_t **p, uint8_t *end, uint8_t *header)
268{
269    struct hvb_buf buf;
270    struct hvb_sign_info *sign_info = &cert->signature_info;
271    size_t cp_size = hvb_offsetof(struct hvb_sign_info, pubk);
272    uint8_t *cur_header;
273
274    if (!_decode_octets(&buf, cp_size, p, end)) {
275        hvb_print("error, dc sign info const.\n");
276        return HVB_ERROR_INVALID_CERT_FORMAT;
277    }
278    if (hvb_memcpy_s(&cert->signature_info, sizeof(cert->signature_info), buf.addr, cp_size) != 0) {
279        hvb_print("error, copy dc sign info const.\n");
280        return HVB_ERROR_OOM;
281    }
282
283    if (header + sign_info->pubkey_offset > end || header + sign_info->pubkey_offset <= header) {
284        hvb_print("error, illegal pubkey offset.\n");
285        return HVB_ERROR_INVALID_CERT_FORMAT;
286    }
287    cur_header = header + sign_info->pubkey_offset;
288
289    if (cur_header + sign_info->pubkey_len > end || cur_header + sign_info->pubkey_len <= cur_header) {
290        hvb_print("error, dc pubkey.\n");
291        return HVB_ERROR_INVALID_CERT_FORMAT;
292    }
293    sign_info->pubk.addr = cur_header;
294    sign_info->pubk.size = sign_info->pubkey_len;
295
296    if (header + sign_info->signature_offset > end || header + sign_info->signature_offset <= header) {
297        hvb_print("error, illegal signature offset.\n");
298        return HVB_ERROR_INVALID_CERT_FORMAT;
299    }
300    cur_header = header + sign_info->signature_offset;
301
302    if (cur_header + sign_info->signature_len > end || cur_header + sign_info->signature_len <= cur_header) {
303        hvb_print("error, dc pubkey.\n");
304        return HVB_ERROR_INVALID_CERT_FORMAT;
305    }
306    sign_info->sign.addr = cur_header;
307    sign_info->sign.size = sign_info->signature_len;
308
309    return HVB_OK;
310}
311
312enum hvb_errno hvb_cert_parser(struct hvb_cert *cert, struct hvb_buf *cert_buf)
313{
314    hvb_return_hvb_err_if_null(cert);
315    hvb_return_hvb_err_if_null(cert_buf);
316    hvb_return_hvb_err_if_null(cert_buf->addr);
317
318    if (cert_buf->size > HVB_CERT_MAX_SIZE) {
319        hvb_print("invalid cert size.\n");
320        return HVB_ERROR_INVALID_ARGUMENT;
321    }
322
323    enum hvb_errno ret = HVB_OK;
324    struct hvb_buf buf;
325    uint8_t *p = cert_buf->addr;
326    uint8_t *end = p + cert_buf->size;
327    uint8_t *header = p;
328    size_t header_size = hvb_offsetof(struct hvb_cert, hash_payload);
329
330    /* parse header */
331    if (!_decode_octets(&buf, header_size, &p, end)) {
332        hvb_print("error, dc cert const.\n");
333        return HVB_ERROR_INVALID_CERT_FORMAT;
334    }
335    if (hvb_memcpy_s(cert, sizeof(*cert), buf.addr, buf.size) != 0) {
336        hvb_print("error, copy dc cert const.\n");
337        return HVB_ERROR_OOM;
338    }
339
340    if (cert->version_minor == 0) {
341        /* parse hash payload */
342        ret = _hvb_cert_payload_parser(cert, &p, end);
343        if (ret != HVB_OK) {
344            hvb_print("error, pr hash payload.\n");
345            return ret;
346        }
347
348        /* parse signature info */
349        ret = _hvb_cert_signature_parser(cert, &p, end);
350        if (ret != HVB_OK) {
351            hvb_print("error, pr sign.\n");
352            return ret;
353        }
354    } else if (cert->version_minor == 1) {
355        /* parse hash payload v2 */
356        ret = _hvb_cert_payload_parser_v2(cert, &p, end, header);
357        if (ret != HVB_OK) {
358            hvb_print("error, pr hash payload.\n");
359            return ret;
360        }
361
362        /* parse signature info v2 */
363        ret = _hvb_cert_signature_parser_v2(cert, &p, end, header);
364        if (ret != HVB_OK) {
365            hvb_print("error, pr sign.\n");
366            return ret;
367        }
368    } else {
369        hvb_print("error minor version\n");
370        return HVB_ERROR_INVALID_ARGUMENT;
371    }
372
373    return HVB_OK;
374}
375
376static uint64_t hvb_buftouint64(uint8_t *p)
377{
378    uint32_t i;
379    uint64_t val = 0;
380
381    for (i = 0; i < 8; i++, p++) {
382        val |= (((uint64_t)(*p)) << (i * 8));
383    }
384
385    return val;
386}
387
388/*
389 * raw_pubk: |bit_length|n0|mod|p_rr|
390 */
391static enum hvb_errno hvb_cert_pubk_parser(struct hvb_rsa_pubkey *pubk, struct hvb_buf *raw_pubk)
392{
393    uint64_t bit_length = 0;
394    uint64_t n0 = 0;
395    struct hvb_buf mod;
396    struct hvb_buf p_rr;
397    struct hvb_buf buf;
398
399    uint8_t *p = raw_pubk->addr;
400    uint8_t *end = p + raw_pubk->size;
401
402    if (!_decode_octets(&buf, sizeof(uint64_t), &p, end)) {
403        hvb_print("error, dc bit_length.\n");
404        return 1;
405    }
406    bit_length = hvb_buftouint64(buf.addr);
407    bit_length = hvb_be64toh(bit_length);
408
409    if (!_decode_octets(&buf, sizeof(uint64_t), &p, end)) {
410        hvb_print("error, dc n0.\n");
411        return 1;
412    }
413    n0 = hvb_buftouint64(buf.addr);
414    n0 = hvb_be64toh(n0);
415
416    if (!_decode_octets(&mod, bit_length / 8, &p, end)) {
417        hvb_print("error, dc mod.\n");
418        return 1;
419    }
420
421    if (!_decode_octets(&p_rr, bit_length / 8, &p, end)) {
422        hvb_print("error, dc p_rr\n");
423        return 1;
424    }
425
426    pubk->width = bit_length;
427    pubk->e = 65537;
428    pubk->pn = mod.addr;
429    pubk->nlen = mod.size;
430    pubk->p_rr = p_rr.addr;
431    pubk->rlen = p_rr.size;
432    pubk->n_n0_i = n0;
433
434    return 0;
435}
436
437static enum hvb_errno hvb_verify_cert(struct hvb_buf *tbs, struct hvb_sign_info *sign_info, uint32_t salt_size)
438{
439    int cry_err;
440    enum hvb_errno ret = HVB_OK;
441    uint32_t hash_len;
442    struct hvb_buf temp_buf;
443    uint8_t *hash = NULL;
444    struct hvb_rsa_pubkey pubk;
445
446    temp_buf = sign_info->pubk;
447    ret = hvb_cert_pubk_parser(&pubk, &temp_buf);
448    if (ret != HVB_OK) {
449        hvb_print("error, hvb cert pubk parser.\n");
450        return ret;
451    }
452
453    hash_len = get_hash_size(sign_info->algorithm);
454    hash = hvb_malloc(hash_len);
455    if (!hash) {
456        hvb_print("hash malloc error:");
457        return HVB_ERROR_OOM;
458    }
459
460    cry_err = hash_sha256_single(tbs->addr, tbs->size, hash, hash_len);
461    if (cry_err != 0) {
462        hvb_print("Error computed hash.\n");
463        return HVB_ERROR_INVALID_ARGUMENT;
464    }
465
466    cry_err = hvb_rsa_verify_pss(&pubk, hash, hash_len, sign_info->sign.addr, sign_info->sign.size, salt_size);
467    if (cry_err != VERIFY_OK) {
468        hvb_print("hvb_rsa_verify_pss result error, signature mismatch\n");
469        return HVB_ERROR_VERIFY_SIGN;
470    }
471
472    return HVB_OK;
473}
474
475static enum hvb_errno _check_rollback_index(struct hvb_ops *ops, struct hvb_cert *cert, struct hvb_verified_data *vd)
476{
477    enum hvb_io_errno io_ret = HVB_IO_OK;
478    uint64_t stored_rollback_index = 0;
479    uint64_t cert_rollback_index = cert->rollback_index;
480    uint64_t rollback_location = cert->rollback_location;
481
482    if (rollback_location >= HVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
483        hvb_print("error, rollback_location too big\n");
484        return HVB_ERROR_INVALID_CERT_FORMAT;
485    }
486
487    io_ret = ops->read_rollback(ops, rollback_location, &stored_rollback_index);
488    if (io_ret != HVB_IO_OK) {
489        hvb_print("error, read rollback idnex\n");
490        return HVB_ERROR_IO;
491    }
492
493    if (cert_rollback_index < stored_rollback_index) {
494        hvb_print("error, cert rollback index is less than the stored\n");
495        return HVB_ERROR_ROLLBACK_INDEX;
496    }
497
498    vd->rollback_indexes[rollback_location] = cert_rollback_index;
499
500    return HVB_OK;
501}
502
503enum hvb_errno cert_init_desc(struct hvb_ops *ops, const char *ptn, struct hvb_buf *cert_buf,
504                              const char *const *hash_ptn_list, struct hvb_buf *out_pubk,
505                              struct hvb_verified_data *vd)
506{
507    hvb_return_hvb_err_if_null(ops);
508    hvb_return_hvb_err_if_null(ptn);
509    hvb_return_hvb_err_if_null(cert_buf);
510    hvb_return_hvb_err_if_null(cert_buf->addr);
511    hvb_return_hvb_err_if_null(out_pubk);
512    hvb_return_hvb_err_if_null(vd);
513
514    enum hvb_errno ret = HVB_OK;
515    ret = check_hvb_ops(ops);
516    if (ret != HVB_OK) {
517        hvb_print("error, check ops\n");
518        return HVB_ERROR_INVALID_ARGUMENT;
519    }
520    if (hvb_strnlen(ptn, HVB_MAX_PARTITION_NAME_LEN) >= HVB_MAX_PARTITION_NAME_LEN) {
521        hvb_print("error, check partition name\n");
522        return HVB_ERROR_INVALID_ARGUMENT;
523    }
524
525    struct hvb_cert cert = {0};
526    struct hvb_buf tbs = {0};
527    struct hvb_sign_info *sign_info = &cert.signature_info;
528
529    ret = hvb_cert_parser(&cert, cert_buf);
530    if (ret != HVB_OK) {
531        hvb_print("error, hvb cert parser.\n");
532        return ret;
533    }
534
535    tbs.addr = cert_buf->addr;
536    tbs.size = sign_info->sign.addr - cert_buf->addr;
537    ret = hvb_verify_cert(&tbs, sign_info, cert.salt_size);
538    if (ret != HVB_OK) {
539        hvb_print("error, verify cert.\n");
540        return ret;
541    }
542
543    ret = _check_rollback_index(ops, &cert, vd);
544    if (ret != HVB_OK) {
545        hvb_print("error, checkout index.\n");
546        return ret;
547    }
548
549    ret = hash_image_init_desc(ops, ptn, &cert, hash_ptn_list, vd);
550    if (ret != HVB_OK) {
551        hvb_print("hash_image_init_desc result error\n");
552        return ret;
553    }
554
555    *out_pubk = sign_info->pubk;
556    vd->key_len = out_pubk->size;
557
558    return ret;
559}
560