Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/lib/ecdsa/ecdsa-verify.c
Line
Count
Source
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 <mr.nuke.me@gmail.com>
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
0
{
23
0
  if (!strcmp(curve_name, "prime256v1"))
24
0
    return 256;
25
0
  else if (!strcmp(curve_name, "secp384r1"))
26
0
    return 384;
27
28
0
  return 0;
29
0
}
30
31
static int fdt_get_key(struct ecdsa_public_key *key, const void *fdt, int node)
32
0
{
33
0
  int x_len, y_len;
34
35
0
  key->curve_name = fdt_getprop(fdt, node, "ecdsa,curve", NULL);
36
0
  if (!key->curve_name) {
37
0
    debug("Error: ecdsa cannot get 'ecdsa,curve' property from key. Likely not an ecdsa key.\n");
38
0
    return -ENOMSG;
39
0
  }
40
41
0
  key->size_bits = ecdsa_key_size(key->curve_name);
42
0
  if (key->size_bits == 0) {
43
0
    debug("Unknown ECDSA curve '%s'", key->curve_name);
44
0
    return -EINVAL;
45
0
  }
46
47
0
  key->x = fdt_getprop(fdt, node, "ecdsa,x-point", &x_len);
48
0
  key->y = fdt_getprop(fdt, node, "ecdsa,y-point", &y_len);
49
50
0
  if (!key->x || !key->y)
51
0
    return -EINVAL;
52
53
0
  if (x_len != (key->size_bits / 8) || y_len != (key->size_bits / 8)) {
54
0
    printf("%s: node=%d, curve@%p x@%p+%i y@%p+%i\n", __func__,
55
0
           node, key->curve_name, key->x, x_len, key->y, y_len);
56
0
    return -EINVAL;
57
0
  }
58
59
0
  return 0;
60
0
}
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
0
{
66
0
  const struct ecdsa_ops *ops = device_get_ops(dev);
67
0
  const struct checksum_algo *algo = info->checksum;
68
0
  struct ecdsa_public_key key;
69
0
  int sig_node, key_node, ret;
70
71
0
  if (!ops || !ops->verify)
72
0
    return -ENODEV;
73
74
0
  if (info->required_keynode > 0) {
75
0
    ret = fdt_get_key(&key, info->fdt_blob, info->required_keynode);
76
0
    if (ret < 0)
77
0
      return ret;
78
79
0
    return ops->verify(dev, &key, hash, algo->checksum_len,
80
0
           sig, sig_len);
81
0
  }
82
83
0
  sig_node = fdt_subnode_offset(info->fdt_blob, 0, FIT_SIG_NODENAME);
84
0
  if (sig_node < 0)
85
0
    return -ENOENT;
86
87
  /* Try all possible keys under the "/signature" node */
88
0
  fdt_for_each_subnode(key_node, info->fdt_blob, sig_node) {
89
0
    ret = fdt_get_key(&key, info->fdt_blob, key_node);
90
0
    if (ret < 0)
91
0
      continue;
92
93
0
    ret = ops->verify(dev, &key, hash, algo->checksum_len,
94
0
          sig, sig_len);
95
96
    /* On success, don't worry about remaining keys */
97
0
    if (!ret)
98
0
      return 0;
99
0
  }
100
101
0
  return -EPERM;
102
0
}
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
0
{
108
0
  const struct checksum_algo *algo = info->checksum;
109
0
  uint8_t hash[algo->checksum_len];
110
0
  struct udevice *dev;
111
0
  int ret;
112
113
0
  ret = uclass_first_device_err(UCLASS_ECDSA, &dev);
114
0
  if (ret) {
115
0
    debug("ECDSA: Could not find ECDSA implementation: %d\n", ret);
116
0
    return ret;
117
0
  }
118
119
0
  ret = algo->calculate(algo->name, region, region_count, hash);
120
0
  if (ret < 0)
121
0
    return -EINVAL;
122
123
0
  return ecdsa_verify_hash(dev, info, hash, sig, sig_len);
124
0
}
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
};