1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 *
4 * Copyright (c) 2019 JUUL Labs
5 * Copyright (c) 2021-2023 Arm Limited
6 */
7
8 #include <string.h>
9
10 #include "mcuboot_config/mcuboot_config.h"
11
12 #ifdef MCUBOOT_SIGN_ED25519
13 #include "bootutil/sign_key.h"
14
15 /* We are not really using the MBEDTLS but need the ASN.1 parsing functions */
16 #define MBEDTLS_ASN1_PARSE_C
17 #include "mbedtls/oid.h"
18 #include "mbedtls/asn1.h"
19
20 #include "bootutil_priv.h"
21 #include "bootutil/crypto/common.h"
22 #include "bootutil/crypto/sha.h"
23
24 #define EDDSA_SIGNATURE_LENGTH 64
25
26 static const uint8_t ed25519_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x65\x70";
27 #define NUM_ED25519_BYTES 32
28
29 extern int ED25519_verify(const uint8_t *message, size_t message_len,
30 const uint8_t signature[EDDSA_SIGNATURE_LENGTH],
31 const uint8_t public_key[NUM_ED25519_BYTES]);
32
33 /*
34 * Parse the public key used for signing.
35 */
36 static int
bootutil_import_key(uint8_t ** cp,uint8_t * end)37 bootutil_import_key(uint8_t **cp, uint8_t *end)
38 {
39 size_t len;
40 mbedtls_asn1_buf alg;
41 mbedtls_asn1_buf param;
42
43 if (mbedtls_asn1_get_tag(cp, end, &len,
44 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
45 return -1;
46 }
47 end = *cp + len;
48
49 if (mbedtls_asn1_get_alg(cp, end, &alg, ¶m)) {
50 return -2;
51 }
52
53 if (alg.ASN1_CONTEXT_MEMBER(len) != sizeof(ed25519_pubkey_oid) - 1 ||
54 memcmp(alg.ASN1_CONTEXT_MEMBER(p), ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) {
55 return -3;
56 }
57
58 if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
59 return -4;
60 }
61 if (*cp + len != end) {
62 return -5;
63 }
64
65 if (len != NUM_ED25519_BYTES) {
66 return -6;
67 }
68
69 return 0;
70 }
71
72 /* Signature verification base function.
73 * The function takes buffer of specified length and tries to verify
74 * it against provided signature.
75 * The function does key import and checks whether signature is
76 * of expected length.
77 */
78 static fih_ret
bootutil_verify(uint8_t * buf,uint32_t blen,uint8_t * sig,size_t slen,uint8_t key_id)79 bootutil_verify(uint8_t *buf, uint32_t blen,
80 uint8_t *sig, size_t slen,
81 uint8_t key_id)
82 {
83 int rc;
84 FIH_DECLARE(fih_rc, FIH_FAILURE);
85 uint8_t *pubkey;
86 uint8_t *end;
87
88 if (slen != EDDSA_SIGNATURE_LENGTH) {
89 FIH_SET(fih_rc, FIH_FAILURE);
90 goto out;
91 }
92
93 pubkey = (uint8_t *)bootutil_keys[key_id].key;
94 end = pubkey + *bootutil_keys[key_id].len;
95
96 rc = bootutil_import_key(&pubkey, end);
97 if (rc) {
98 FIH_SET(fih_rc, FIH_FAILURE);
99 goto out;
100 }
101
102 rc = ED25519_verify(buf, blen, sig, pubkey);
103
104 if (rc == 0) {
105 /* if verify returns 0, there was an error. */
106 FIH_SET(fih_rc, FIH_FAILURE);
107 goto out;
108 }
109
110 FIH_SET(fih_rc, FIH_SUCCESS);
111 out:
112
113 FIH_RET(fih_rc);
114 }
115
116 /* Hash signature verification function.
117 * Verifies hash against provided signature.
118 * The function verifies that hash is of expected size and then
119 * calls bootutil_verify to do the signature verification.
120 */
121 fih_ret
bootutil_verify_sig(uint8_t * hash,uint32_t hlen,uint8_t * sig,size_t slen,uint8_t key_id)122 bootutil_verify_sig(uint8_t *hash, uint32_t hlen,
123 uint8_t *sig, size_t slen,
124 uint8_t key_id)
125 {
126 FIH_DECLARE(fih_rc, FIH_FAILURE);
127
128 if (hlen != IMAGE_HASH_SIZE) {
129 FIH_SET(fih_rc, FIH_FAILURE);
130 goto out;
131 }
132
133 FIH_CALL(bootutil_verify, fih_rc, hash, IMAGE_HASH_SIZE, sig,
134 slen, key_id);
135
136 out:
137 FIH_RET(fih_rc);
138 }
139
140 /* Image verification function.
141 * The function directly calls bootutil_verify to verify signature
142 * of image.
143 */
144 fih_ret
bootutil_verify_img(uint8_t * img,uint32_t size,uint8_t * sig,size_t slen,uint8_t key_id)145 bootutil_verify_img(uint8_t *img, uint32_t size,
146 uint8_t *sig, size_t slen,
147 uint8_t key_id)
148 {
149 FIH_DECLARE(fih_rc, FIH_FAILURE);
150
151 FIH_CALL(bootutil_verify, fih_rc, img, size, sig,
152 slen, key_id);
153
154 FIH_RET(fih_rc);
155 }
156
157 #endif /* MCUBOOT_SIGN_ED25519 */
158