1 /*
2 * Copyright (c) 2024, The TrustedFirmware-M Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8
9 #include "cc3xx_ecdsa.h"
10
11 #include "cc3xx_ec.h"
12 #include "cc3xx_config.h"
13
14 #include <stdint.h>
15 #include <stddef.h>
16
17 #include "fatal_error.h"
18
19 #ifdef CC3XX_CONFIG_ECDSA_KEYGEN_ENABLE
cc3xx_lowlevel_ecdsa_genkey(cc3xx_ec_curve_id_t curve_id,uint32_t * private_key,size_t private_key_len,size_t * private_key_size)20 cc3xx_err_t cc3xx_lowlevel_ecdsa_genkey(cc3xx_ec_curve_id_t curve_id,
21 uint32_t *private_key,
22 size_t private_key_len,
23 size_t *private_key_size)
24 {
25 cc3xx_ec_curve_t curve;
26 cc3xx_pka_reg_id_t private_key_reg;
27 cc3xx_err_t err;
28
29 /* This sets up various curve parameters into PKA registers */
30 err = cc3xx_lowlevel_ec_init(curve_id, &curve);
31 if (err != CC3XX_ERR_SUCCESS) {
32 goto out;
33 }
34
35 if (private_key_len < curve.modulus_size) {
36 FATAL_ERR(err = CC3XX_ERR_BUFFER_OVERFLOW);
37 goto out;
38 }
39
40 private_key_reg = cc3xx_lowlevel_pka_allocate_reg();
41
42 do {
43 err = cc3xx_lowlevel_pka_set_to_random_within_modulus(private_key_reg);
44 if (err != CC3XX_ERR_SUCCESS) {
45 goto out;
46 }
47 } while (!cc3xx_lowlevel_pka_greater_than_si(private_key_reg, 0));
48
49 cc3xx_lowlevel_pka_read_reg_swap_endian(private_key_reg, private_key, curve.modulus_size);
50
51 /* Destroy private key register */
52 cc3xx_lowlevel_pka_set_to_random(private_key_reg, curve.modulus_size * 8);
53
54 *private_key_size = curve.modulus_size;
55 out:
56 cc3xx_lowlevel_ec_uninit();
57
58 return err;
59 }
60
cc3xx_lowlevel_ecdsa_getpub(cc3xx_ec_curve_id_t curve_id,const uint32_t * private_key,size_t private_key_len,uint32_t * public_key_x,size_t public_key_x_len,size_t * public_key_x_size,uint32_t * public_key_y,size_t public_key_y_len,size_t * public_key_y_size)61 cc3xx_err_t cc3xx_lowlevel_ecdsa_getpub(cc3xx_ec_curve_id_t curve_id,
62 const uint32_t *private_key, size_t private_key_len,
63 uint32_t *public_key_x, size_t public_key_x_len,
64 size_t *public_key_x_size,
65 uint32_t *public_key_y, size_t public_key_y_len,
66 size_t *public_key_y_size)
67 {
68 cc3xx_ec_curve_t curve;
69 cc3xx_pka_reg_id_t private_key_reg;
70 cc3xx_ec_point_affine public_key_point;
71 cc3xx_err_t err;
72
73 /* This sets up various curve parameters into PKA registers */
74 err = cc3xx_lowlevel_ec_init(curve_id, &curve);
75 if (err != CC3XX_ERR_SUCCESS) {
76 goto out;
77 }
78
79 if (private_key_len > curve.modulus_size) {
80 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
81 goto out;
82 }
83
84 if (public_key_x_len < curve.modulus_size) {
85 FATAL_ERR(err = CC3XX_ERR_BUFFER_OVERFLOW);
86 goto out;
87 }
88
89 if (public_key_y_len < curve.modulus_size) {
90 FATAL_ERR(err = CC3XX_ERR_BUFFER_OVERFLOW);
91 goto out;
92 }
93
94 public_key_point = cc3xx_lowlevel_ec_allocate_point();
95 private_key_reg = cc3xx_lowlevel_pka_allocate_reg();
96
97 cc3xx_lowlevel_pka_write_reg_swap_endian(private_key_reg, private_key, private_key_len);
98
99 err = cc3xx_lowlevel_ec_multipy_point_by_scalar(&curve, &curve.generator, private_key_reg,
100 &public_key_point);
101
102 cc3xx_lowlevel_pka_read_reg_swap_endian(public_key_point.x, public_key_x, curve.modulus_size);
103 cc3xx_lowlevel_pka_read_reg_swap_endian(public_key_point.y, public_key_y, curve.modulus_size);
104
105 *public_key_x_size = curve.modulus_size;
106 *public_key_y_size = curve.modulus_size;
107
108 out:
109 cc3xx_lowlevel_ec_uninit();
110
111 return err;
112 }
113 #endif /* CC3XX_CONFIG_ECDSA_KEYGEN_ENABLE */
114
115 #ifdef CC3XX_CONFIG_ECDSA_VERIFY_ENABLE
116 /* As per NIST FIPS 186-5 section 6.4.2.
117 */
cc3xx_lowlevel_ecdsa_verify(cc3xx_ec_curve_id_t curve_id,const uint32_t * public_key_x,size_t public_key_x_len,const uint32_t * public_key_y,size_t public_key_y_len,const uint32_t * hash,size_t hash_len,const uint32_t * sig_r,size_t sig_r_len,const uint32_t * sig_s,size_t sig_s_len)118 cc3xx_err_t cc3xx_lowlevel_ecdsa_verify(cc3xx_ec_curve_id_t curve_id,
119 const uint32_t *public_key_x,
120 size_t public_key_x_len,
121 const uint32_t *public_key_y,
122 size_t public_key_y_len,
123 const uint32_t *hash, size_t hash_len,
124 const uint32_t *sig_r, size_t sig_r_len,
125 const uint32_t *sig_s, size_t sig_s_len)
126 {
127 cc3xx_ec_curve_t curve;
128 cc3xx_ec_point_affine public_key_point;
129 cc3xx_ec_point_affine calculated_r_point;
130 cc3xx_pka_reg_id_t sig_s_reg;
131 cc3xx_pka_reg_id_t sig_r_reg;
132 cc3xx_pka_reg_id_t u_reg;
133 cc3xx_pka_reg_id_t v_reg;
134 cc3xx_pka_reg_id_t hash_reg;
135 cc3xx_err_t err;
136 struct cc3xx_pka_state_t pka_state;
137
138 /* This sets up various curve parameters into PKA registers */
139 err = cc3xx_lowlevel_ec_init(curve_id, &curve);
140 if (err != CC3XX_ERR_SUCCESS) {
141 goto out;
142 }
143
144 if (public_key_x_len > curve.modulus_size) {
145 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
146 goto out;
147 }
148
149 if (public_key_y_len > curve.modulus_size) {
150 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
151 goto out;
152 }
153
154 if (sig_r_len > curve.modulus_size) {
155 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
156 goto out;
157 }
158
159 if (sig_s_len > curve.modulus_size) {
160 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
161 goto out;
162 }
163
164 /* The hash _can_ be larger than the modulus, but must still fit into the
165 * PKA reg.
166 */
167 cc3xx_lowlevel_pka_get_state(&pka_state, 0, NULL, NULL, NULL);
168 if (hash_len > pka_state.reg_size) {
169 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_HASH);
170 goto out;
171 }
172
173 /* Now that PKA is initialized, allocate the registers / points we'll use */
174 sig_r_reg = cc3xx_lowlevel_pka_allocate_reg();
175 sig_s_reg = cc3xx_lowlevel_pka_allocate_reg();
176 u_reg = cc3xx_lowlevel_pka_allocate_reg();
177 v_reg = cc3xx_lowlevel_pka_allocate_reg();
178 hash_reg = cc3xx_lowlevel_pka_allocate_reg();
179
180 calculated_r_point = cc3xx_lowlevel_ec_allocate_point();
181
182
183 /* This validates that the public key point lies on the curve, is not the
184 * identity element, and that it multiplied by the group order is infinity.
185 */
186 err = cc3xx_lowlevel_ec_allocate_point_from_data(&curve,
187 public_key_x, public_key_x_len,
188 public_key_y, public_key_y_len,
189 &public_key_point);
190 if (err != CC3XX_ERR_SUCCESS) {
191 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
192 goto out;
193 }
194
195 cc3xx_lowlevel_pka_write_reg_swap_endian(sig_s_reg, sig_s, sig_s_len);
196 /* Check that s is less than N */
197 if (!cc3xx_lowlevel_pka_less_than(sig_s_reg, CC3XX_PKA_REG_N)) {
198 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
199 goto out;
200 }
201 /* Check that s is not 0 */
202 if (cc3xx_lowlevel_pka_are_equal_si(sig_s_reg, 0)) {
203 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
204 goto out;
205 }
206
207 /* Check that r is less than N */
208 cc3xx_lowlevel_pka_write_reg_swap_endian(sig_r_reg, sig_r, sig_r_len);
209 if (!cc3xx_lowlevel_pka_less_than(sig_r_reg, CC3XX_PKA_REG_N)) {
210 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
211 goto out;
212 }
213 /* Check that r is not 0 */
214 if (cc3xx_lowlevel_pka_are_equal_si(sig_r_reg, 0)) {
215 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
216 goto out;
217 }
218
219 cc3xx_lowlevel_pka_write_reg_swap_endian(hash_reg, hash, hash_len);
220 /* Check that hash is not 0 */
221 if (cc3xx_lowlevel_pka_are_equal_si(hash_reg, 0)) {
222 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
223 goto out;
224 }
225 /* If the size of the hash is greater than the group order, reduce the amount of
226 * bits used by shifting.
227 */
228 if (hash_len > curve.modulus_size) {
229 cc3xx_lowlevel_pka_shift_right_fill_0_ui(hash_reg,
230 (hash_len - curve.modulus_size) * 8,
231 hash_reg);
232 }
233 /* Then finally a reduction so we can be sure the hash is below N */
234 cc3xx_lowlevel_pka_reduce(hash_reg);
235
236 /* u = hash * s^-1. Put s^-1 into v_reg so we can reuse it for calculating v
237 * later
238 */
239 cc3xx_lowlevel_pka_mod_inv(sig_s_reg, v_reg);
240 cc3xx_lowlevel_pka_mod_mul(v_reg, hash_reg, u_reg);
241
242 /* v = r * s^-1 */
243 cc3xx_lowlevel_pka_mod_mul(v_reg, sig_r_reg, v_reg);
244
245 /* R1 = [u]G + [v]Q */
246 err = cc3xx_lowlevel_ec_shamir_multiply_points_by_scalars_and_add(&curve,
247 &curve.generator, u_reg,
248 &public_key_point, v_reg,
249 &calculated_r_point);
250 if (err != CC3XX_ERR_SUCCESS) {
251 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
252 goto out;
253 }
254
255 /* Accept signature if r == r1 mod N */
256 cc3xx_lowlevel_pka_reduce(calculated_r_point.x);
257
258 if (cc3xx_lowlevel_pka_are_equal(sig_r_reg, calculated_r_point.x)) {
259 err = CC3XX_ERR_SUCCESS;
260 } else {
261 FATAL_ERR(err = CC3XX_ERR_ECDSA_SIGNATURE_INVALID);
262 }
263
264 out:
265 /* This frees all the PKA registers as it will deinit the PKA engine */
266 cc3xx_lowlevel_ec_uninit();
267
268 return err;
269 }
270 #endif /* CC3XX_CONFIG_ECDSA_VERIFY_ENABLE */
271
272 #ifdef CC3XX_CONFIG_ECDSA_SIGN_ENABLE
cc3xx_lowlevel_ecdsa_sign(cc3xx_ec_curve_id_t curve_id,const uint32_t * private_key,size_t private_key_len,const uint32_t * hash,size_t hash_len,uint32_t * sig_r,size_t sig_r_len,size_t * sig_r_size,uint32_t * sig_s,size_t sig_s_len,size_t * sig_s_size)273 cc3xx_err_t cc3xx_lowlevel_ecdsa_sign(cc3xx_ec_curve_id_t curve_id,
274 const uint32_t *private_key, size_t private_key_len,
275 const uint32_t *hash, size_t hash_len,
276 uint32_t *sig_r, size_t sig_r_len, size_t *sig_r_size,
277 uint32_t *sig_s, size_t sig_s_len, size_t *sig_s_size)
278 {
279 cc3xx_ec_curve_t curve;
280 cc3xx_ec_point_affine temp_point;
281 cc3xx_pka_reg_id_t sig_s_reg;
282 cc3xx_pka_reg_id_t sig_r_reg;
283 cc3xx_pka_reg_id_t k_reg;
284 cc3xx_pka_reg_id_t temp_reg;
285 cc3xx_pka_reg_id_t hash_reg;
286 cc3xx_pka_reg_id_t private_key_reg;
287 cc3xx_err_t err;
288
289 /* This sets up various curve parameters into PKA registers */
290 err = cc3xx_lowlevel_ec_init(curve_id, &curve);
291 if (err != CC3XX_ERR_SUCCESS) {
292 goto out;
293 }
294
295 if (private_key_len > curve.modulus_size) {
296 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
297 goto out;
298 }
299
300 if (sig_r_len < curve.modulus_size) {
301 FATAL_ERR(err = CC3XX_ERR_BUFFER_OVERFLOW);
302 goto out;
303 }
304
305 if (sig_s_len < curve.modulus_size) {
306 FATAL_ERR(err = CC3XX_ERR_BUFFER_OVERFLOW);
307 goto out;
308 }
309
310
311 /* Now that PKA is initialized, allocate the registers / points we'll use */
312 sig_r_reg = cc3xx_lowlevel_pka_allocate_reg();
313 sig_s_reg = cc3xx_lowlevel_pka_allocate_reg();
314 k_reg = cc3xx_lowlevel_pka_allocate_reg();
315 temp_reg = cc3xx_lowlevel_pka_allocate_reg();
316 hash_reg = cc3xx_lowlevel_pka_allocate_reg();
317 private_key_reg = cc3xx_lowlevel_pka_allocate_reg();
318
319 temp_point = cc3xx_lowlevel_ec_allocate_point();
320
321 cc3xx_lowlevel_pka_write_reg_swap_endian(private_key_reg, private_key, private_key_len);
322 /* Check that d is less than N */
323 if (!cc3xx_lowlevel_pka_less_than(private_key_reg, CC3XX_PKA_REG_N)) {
324 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
325 goto out;
326 }
327 /* Check that d is not 0 */
328 if (cc3xx_lowlevel_pka_are_equal_si(private_key_reg, 0)) {
329 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_KEY);
330 goto out;
331 }
332
333 cc3xx_lowlevel_pka_write_reg_swap_endian(hash_reg, hash, hash_len);
334 /* Check that hash is not 0 */
335 if (cc3xx_lowlevel_pka_are_equal_si(hash_reg, 0)) {
336 FATAL_ERR(err = CC3XX_ERR_ECDSA_INVALID_HASH);
337 goto out;
338 }
339 /* If the size of the hash is greater than the group order, reduce the amount of
340 * bits used by shifting.
341 */
342 if (hash_len > curve.modulus_size) {
343 cc3xx_lowlevel_pka_shift_right_fill_0_ui(hash_reg,
344 (hash_len - curve.modulus_size) * 8,
345 hash_reg);
346 }
347 /* Then finally a reduction so we can be sure the hash is below N */
348 cc3xx_lowlevel_pka_reduce(hash_reg);
349
350 do {
351 err = cc3xx_lowlevel_pka_set_to_random_within_modulus(k_reg);
352 if (err != CC3XX_ERR_SUCCESS) {
353 goto out;
354 }
355
356 cc3xx_lowlevel_ec_multipy_point_by_scalar(&curve, &curve.generator, k_reg,
357 &temp_point);
358 cc3xx_lowlevel_pka_copy(temp_point.x, sig_r_reg);
359 cc3xx_lowlevel_pka_reduce(sig_r_reg);
360
361 if (!cc3xx_lowlevel_pka_greater_than_si(sig_r_reg, 0)) {
362 continue;
363 }
364
365 cc3xx_lowlevel_pka_mod_mul(sig_r_reg, private_key_reg, temp_reg);
366 cc3xx_lowlevel_pka_mod_add(temp_reg, hash_reg, temp_reg);
367 cc3xx_lowlevel_pka_mod_inv(k_reg, k_reg);
368 cc3xx_lowlevel_pka_mod_mul(k_reg, temp_reg, sig_s_reg);
369
370 /* Destroy K */
371 cc3xx_lowlevel_pka_set_to_random(k_reg, curve.modulus_size * 8);
372 } while (!cc3xx_lowlevel_pka_greater_than_si(sig_s_reg, 0));
373
374 cc3xx_lowlevel_pka_read_reg_swap_endian(sig_s_reg, sig_s, curve.modulus_size);
375 cc3xx_lowlevel_pka_read_reg_swap_endian(sig_r_reg, sig_r, curve.modulus_size);
376
377 /* Destroy private key register */
378 cc3xx_lowlevel_pka_set_to_random(private_key_reg, curve.modulus_size * 8);
379
380 *sig_s_size = curve.modulus_size;
381 *sig_r_size = curve.modulus_size;
382
383 err = CC3XX_ERR_SUCCESS;
384 out:
385 /* This frees all the PKA registers as it will deinit the PKA engine */
386 cc3xx_lowlevel_ec_uninit();
387
388 return err;
389 }
390 #endif /* CC3XX_CONFIG_ECDSA_SIGN_ENABLE */
391