xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/crypto_ecc.c (revision a8a4d6c05a2e5f52e75e5096f9470aa3d36fd000)
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 
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 
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 */
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 
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  */
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 
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 
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 
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 
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 
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