1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2024 Rockchip Electronics Co., Ltd
4 */
5
6 #include <common.h>
7 #include <crypto.h>
8 #include <dm.h>
9 #include <linux/errno.h>
10 #include <rockchip/crypto_mpa.h>
11 #include <rockchip/crypto_v2.h>
12 #include <rockchip/crypto_ecc.h>
13
14 #define WORDS2BYTES(words) ((words) * 4)
15
16 #define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->d || b->size > RK_ECP_MAX_WORDS)
17 #define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID(p->x) && \
18 RK_ECP_IS_BIGNUM_INVALID(p->y))
19
20 /*************************************************************/
21 /* Macros for waiting EC machine ready states */
22 /*************************************************************/
23 #define RK_ECP_WRITE_REG(offset, val) crypto_write((val), (offset))
24 #define RK_ECP_READ_REG(offset) crypto_read((offset))
25
26 #define RK_ECP_RAM_FOR_ECC() \
27 RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC)
28
29 #define RK_ECP_RAM_FOR_CPU() \
30 RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU)
31
32 /* big endian to little endian */
33 #define RK_ECP_LOAD_DATA(dst, big_src) rk_ecp_load_data(dst, big_src)
34
35 /* little endian to littel endian */
36 #define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) \
37 do { \
38 util_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS);\
39 util_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \
40 } while (0)
41
42 #define RK_GET_GRPOUP_NBYTES(grp) ((grp)->p_len)
43
44 #define RK_LOAD_GROUP_A(G) do { \
45 grp->curve_name = #G; \
46 grp->wide = G ## _wide;\
47 grp->p = G ## _p; \
48 grp->p_len = sizeof(G ## _p); \
49 grp->a = G ## _a; \
50 grp->a_len = sizeof(G ## _a); \
51 grp->n = G ## _n; \
52 grp->n_len = sizeof(G ## _n); \
53 grp->gx = G ## _gx; \
54 grp->gx_len = sizeof(G ## _gx); \
55 grp->gy = G ## _gy; \
56 grp->gy_len = sizeof(G ## _gy); \
57 } while (0)
58
59 /* transform to big endian */
60 /*
61 * Domain parameters for secp192r1
62 */
63 static const uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192;
64
65 static const uint8_t secp192r1_p[] = {
66 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
67 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
68 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
69 };
70
71 static const uint8_t secp192r1_a[] = {
72 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
73 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
74 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
75 };
76
77 static const uint8_t secp192r1_gx[] = {
78 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4,
79 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C,
80 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18,
81 };
82
83 static const uint8_t secp192r1_gy[] = {
84 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73,
85 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63,
86 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07,
87 };
88
89 static const uint8_t secp192r1_n[] = {
90 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14,
91 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
93 };
94
95 /*
96 * Domain parameters for secp224r1
97 */
98 static const uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224;
99
100 static const uint8_t secp224r1_p[] = {
101 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
103 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
104 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
105 };
106
107 static const uint8_t secp224r1_a[] = {
108 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
109 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
110 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
111 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
112 };
113
114 static const uint8_t secp224r1_gx[] = {
115 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34,
116 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A,
117 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B,
118 0xBD, 0x0C, 0x0E, 0xB7,
119 };
120
121 static const uint8_t secp224r1_gy[] = {
122 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44,
123 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD,
124 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5,
125 0x88, 0x63, 0x37, 0xBD,
126 };
127
128 static const uint8_t secp224r1_n[] = {
129 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13,
130 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF,
131 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
132 0xFF, 0xFF, 0xFF, 0xFF,
133 };
134
135 /*
136 * Domain parameters for secp256r1
137 */
138 static const uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256;
139
140 static const uint8_t secp256r1_p[] = {
141 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
142 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
145 };
146
147 static const uint8_t secp256r1_a[] = {
148 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
149 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
152 };
153
154 static const uint8_t secp256r1_gx[] = {
155 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4,
156 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77,
157 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8,
158 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B,
159 };
160
161 static const uint8_t secp256r1_gy[] = {
162 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB,
163 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B,
164 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E,
165 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F,
166 };
167
168 static const uint8_t secp256r1_n[] = {
169 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3,
170 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC,
171 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
172 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
173 };
174
175 /*
176 * Domain parameters for sm2p256v1_p
177 */
178 static const uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256;
179
180 static const uint8_t sm2p256v1_p[] = {
181 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
182 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
183 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
184 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
185 };
186
187 static const uint8_t sm2p256v1_a[] = {
188 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
189 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
190 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
191 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
192 };
193
194 static const uint8_t sm2p256v1_gx[] = {
195 0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71,
196 0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F,
197 0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F,
198 0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32,
199 };
200
201 static const uint8_t sm2p256v1_gy[] = {
202 0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02,
203 0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0,
204 0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59,
205 0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC,
206 };
207
208 static const uint8_t sm2p256v1_n[] = {
209 0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53,
210 0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72,
211 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
212 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
213 };
214
word_reverse(u32 word)215 static inline u32 word_reverse(u32 word)
216 {
217 u32 i;
218 u32 new_word = 0;
219
220 for (i = 0; i < sizeof(u32); i++) {
221 new_word |= (word & 0xff) << (8 * (sizeof(u32) - i - 1));
222 word >>= 8;
223 }
224
225 return new_word;
226 }
227
is_ec_supported(void)228 static inline bool is_ec_supported(void)
229 {
230 return !!RK_ECP_READ_REG(RK_ECC_MAX_CURVE_WIDE);
231 }
232
233 /* reverse endian word copy */
rk_ecp_load_data(u32 * dst,struct mpa_num * src)234 static int rk_ecp_load_data(u32 *dst, struct mpa_num *src)
235 {
236 u32 i;
237 u32 dst_pos, src_pos;
238
239 util_word_memset(dst, 0, RK_ECP_MAX_WORDS);
240
241 dst_pos = src->size - 1;
242 src_pos = 0;
243
244 for (i = 0; i < src->size; i++)
245 dst[dst_pos--] = word_reverse(src->d[src_pos++]);
246
247 return 0;
248 }
249
rk_word_cmp_zero(uint32_t * buf1,uint32_t n_words)250 static int rk_word_cmp_zero(uint32_t *buf1, uint32_t n_words)
251 {
252 int ret = 0;
253 uint32_t i;
254
255 for (i = 0 ; i < n_words; i++) {
256 if (buf1[i] != 0)
257 ret = -EINVAL;
258 }
259
260 return ret;
261 }
262
263 /*
264 * Set a group using well-known domain parameters
265 */
rk_ecp_group_load(struct rk_ecp_group * grp,enum rk_ecp_group_id id)266 static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id)
267 {
268 memset(grp, 0x00, sizeof(*grp));
269
270 grp->id = id;
271
272 switch (id) {
273 case RK_ECP_DP_SECP192R1:
274 RK_LOAD_GROUP_A(secp192r1);
275 return 0;
276
277 case RK_ECP_DP_SECP224R1:
278 RK_LOAD_GROUP_A(secp224r1);
279 return 0;
280
281 case RK_ECP_DP_SECP256R1:
282 RK_LOAD_GROUP_A(secp256r1);
283 return 0;
284
285 case RK_ECP_DP_SM2P256V1:
286 RK_LOAD_GROUP_A(sm2p256v1);
287 return 0;
288
289 default:
290 return -EINVAL;
291 }
292 }
293
rockchip_ecc_request_set(uint32_t ecc_ctl,uint32_t wide)294 static int rockchip_ecc_request_set(uint32_t ecc_ctl, uint32_t wide)
295 {
296 RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide);
297
298 RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0);
299 RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST));
300 RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl);
301
302 return 0;
303 }
304
rockchip_ecc_request_wait_done(void)305 static int rockchip_ecc_request_wait_done(void)
306 {
307 int ret = 0;
308 u32 reg_val = 0;
309
310 do {
311 reg_val = crypto_read(RK_ECC_INT_ST);
312 } while ((reg_val & 0x01) != RK_ECC_INT_ST_DONE);
313
314 if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) {
315 ret = -EFAULT;
316 goto exit;
317 }
318
319 exit:
320 if (ret) {
321 printf("RK_ECC_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_CTL));
322 printf("RK_ECC_INT_EN = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_EN));
323 printf("RK_ECC_CURVE_WIDE = %08x\n", RK_ECP_READ_REG(RK_ECC_CURVE_WIDE));
324 printf("RK_ECC_RAM_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_RAM_CTL));
325 printf("RK_ECC_INT_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_ST));
326 printf("RK_ECC_ABN_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_ABN_ST));
327 }
328
329 RK_ECP_WRITE_REG(RK_ECC_CTL, 0);
330 RK_ECP_RAM_FOR_CPU();
331
332 return ret;
333 }
334
rockchip_ecc_request_trigger(void)335 static int rockchip_ecc_request_trigger(void)
336 {
337 uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL);
338
339 RK_ECP_RAM_FOR_ECC();
340
341 RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC);
342
343 return rockchip_ecc_request_wait_done();
344 }
345
rockchip_ecc_get_group_id(uint32_t crypto_algo)346 static uint32_t rockchip_ecc_get_group_id(uint32_t crypto_algo)
347 {
348 switch (crypto_algo) {
349 case CRYPTO_ECC_192R1:
350 return RK_ECP_DP_SECP192R1;
351 case CRYPTO_ECC_224R1:
352 return RK_ECP_DP_SECP224R1;
353 case CRYPTO_ECC_256R1:
354 return RK_ECP_DP_SECP256R1;
355 case CRYPTO_SM2:
356 return RK_ECP_DP_SM2P256V1;
357 default:
358 return RK_ECP_DP_NONE;
359 }
360 }
361
rockchip_ecc_verify(uint32_t crypto_algo,uint8_t * hash,uint32_t hash_len,struct rk_ecp_point * point_P,struct rk_ecp_point * point_sign)362 int rockchip_ecc_verify(uint32_t crypto_algo, uint8_t *hash, uint32_t hash_len,
363 struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign)
364 {
365 int ret;
366 uint32_t curve_sel = 0;
367 struct mpa_num *bn_hash = NULL;
368 uint32_t group_id = rockchip_ecc_get_group_id(crypto_algo);
369 struct rk_ecp_group grp;
370 struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)SM2_RAM_BASE;
371
372 if (!is_ec_supported())
373 return -ENOSYS;
374
375 if (!hash ||
376 hash_len == 0 ||
377 hash_len > RK_ECP_MAX_BYTES ||
378 RK_ECP_IS_POINT_INVALID(point_P) ||
379 RK_ECP_IS_POINT_INVALID(point_sign)) {
380 ret = -EINVAL;
381 goto exit;
382 }
383
384 ret = rk_ecp_group_load(&grp, group_id);
385 if (ret)
386 goto exit;
387
388 rk_mpa_alloc(&bn_hash, hash, BYTE2WORD(hash_len));
389 if (!bn_hash) {
390 ret = -ENOMEM;
391 goto exit;
392 }
393
394 RK_ECP_RAM_FOR_CPU();
395
396 curve_sel = group_id == RK_ECP_DP_SM2P256V1 ?
397 RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER;
398
399 RK_ECP_LOAD_DATA(ecc_st->e, bn_hash);
400 RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x);
401 RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y);
402 RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x);
403 RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y);
404
405 RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len);
406 RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len);
407 RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len);
408
409 RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len);
410 RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len);
411
412 rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide);
413
414 ret = rockchip_ecc_request_trigger();
415 if (ret ||
416 rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS) ||
417 rk_word_cmp_zero(ecc_st->r_, RK_ECP_MAX_WORDS) == 0) {
418 ret = -EKEYREJECTED;
419 }
420 exit:
421 rk_mpa_free(&bn_hash);
422
423 return ret;
424 }
425