]> Git Repo - u-boot.git/blob - lib/ecdsa/ecdsa-verify.c
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sh
[u-boot.git] / lib / ecdsa / ecdsa-verify.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * ECDSA signature verification for u-boot
4  *
5  * This implements the firmware-side wrapper for ECDSA verification. It bridges
6  * the struct crypto_algo API to the ECDSA uclass implementations.
7  *
8  * Copyright (c) 2020, Alexandru Gagniuc <[email protected]>
9  */
10
11 #include <crypto/ecdsa-uclass.h>
12 #include <dm/uclass.h>
13 #include <u-boot/ecdsa.h>
14
15 /*
16  * Derive size of an ECDSA key from the curve name
17  *
18  * While it's possible to extract the key size by using string manipulation,
19  * use a list of known curves for the time being.
20  */
21 static int ecdsa_key_size(const char *curve_name)
22 {
23         if (!strcmp(curve_name, "prime256v1"))
24                 return 256;
25         else if (!strcmp(curve_name, "secp384r1"))
26                 return 384;
27
28         return 0;
29 }
30
31 static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
32 {
33         int x_len, y_len;
34
35         key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
36         if (!key->curve_name) {
37                 debug("Error: ecdsa cannot get 'ecdsa,curve' property from key. Likely not an ecdsa key.\n");
38                 return -ENOMSG;
39         }
40
41         key->size_bits = ecdsa_key_size(key->curve_name);
42         if (key->size_bits == 0) {
43                 debug("Unknown ECDSA curve '%s'", key->curve_name);
44                 return -EINVAL;
45         }
46
47         key->x = fdt_getprop(fdt, node, "ecdsa,x-point", &x_len);
48         key->y = fdt_getprop(fdt, node, "ecdsa,y-point", &y_len);
49
50         if (!key->x || !key->y)
51                 return -EINVAL;
52
53         if (x_len != (key->size_bits / 8) || y_len != (key->size_bits / 8)) {
54                 printf("%s: node=%d, curve@%p x@%p+%i y@%p+%i\n", __func__,
55                        node, key->curve_name, key->x, x_len, key->y, y_len);
56                 return -EINVAL;
57         }
58
59         return 0;
60 }
61
62 static int ecdsa_verify_hash(struct udevice *dev,
63                              const struct image_sign_info *info,
64                              const void *hash, const void *sig, uint sig_len)
65 {
66         const struct ecdsa_ops *ops = device_get_ops(dev);
67         const struct checksum_algo *algo = info->checksum;
68         struct ecdsa_public_key key;
69         int sig_node, key_node, ret;
70
71         if (!ops || !ops->verify)
72                 return -ENODEV;
73
74         if (info->required_keynode > 0) {
75                 ret = fdt_get_key(&key, info->fdt_blob, info->required_keynode);
76                 if (ret < 0)
77                         return ret;
78
79                 return ops->verify(dev, &key, hash, algo->checksum_len,
80                                    sig, sig_len);
81         }
82
83         sig_node = fdt_subnode_offset(info->fdt_blob, 0, FIT_SIG_NODENAME);
84         if (sig_node < 0)
85                 return -ENOENT;
86
87         /* Try all possible keys under the "/signature" node */
88         fdt_for_each_subnode(key_node, info->fdt_blob, sig_node) {
89                 ret = fdt_get_key(&key, info->fdt_blob, key_node);
90                 if (ret < 0)
91                         continue;
92
93                 ret = ops->verify(dev, &key, hash, algo->checksum_len,
94                                   sig, sig_len);
95
96                 /* On success, don't worry about remaining keys */
97                 if (!ret)
98                         return 0;
99         }
100
101         return -EPERM;
102 }
103
104 int ecdsa_verify(struct image_sign_info *info,
105                  const struct image_region region[], int region_count,
106                  uint8_t *sig, uint sig_len)
107 {
108         const struct checksum_algo *algo = info->checksum;
109         uint8_t hash[algo->checksum_len];
110         struct udevice *dev;
111         int ret;
112
113         ret = uclass_first_device_err(UCLASS_ECDSA, &dev);
114         if (ret) {
115                 debug("ECDSA: Could not find ECDSA implementation: %d\n", ret);
116                 return ret;
117         }
118
119         ret = algo->calculate(algo->name, region, region_count, hash);
120         if (ret < 0)
121                 return -EINVAL;
122
123         return ecdsa_verify_hash(dev, info, hash, sig, sig_len);
124 }
125
126 U_BOOT_CRYPTO_ALGO(ecdsa256) = {
127         .name = "ecdsa256",
128         .key_len = ECDSA256_BYTES,
129         .verify = ecdsa_verify,
130 };
131
132 U_BOOT_CRYPTO_ALGO(ecdsa384) = {
133         .name = "ecdsa384",
134         .key_len = ECDSA384_BYTES,
135         .verify = ecdsa_verify,
136 };
137
138 /*
139  * uclass definition for ECDSA API
140  *
141  * We don't implement any wrappers around ecdsa_ops->verify() because it's
142  * trivial to call ops->verify().
143  */
144 UCLASS_DRIVER(ecdsa) = {
145         .id             = UCLASS_ECDSA,
146         .name           = "ecdsa_verifier",
147 };
This page took 0.036801 seconds and 4 git commands to generate.