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