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, &param)) {
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