1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2022-2024, HiSilicon Technologies Co., Ltd.
4 * Kunpeng hardware accelerator hpre dh algorithm implementation.
5 */
6
7 #include <drvcrypt.h>
8 #include <drvcrypt_acipher.h>
9 #include <initcall.h>
10 #include <malloc.h>
11 #include <rng_support.h>
12 #include <stdlib_ext.h>
13 #include <string.h>
14 #include <string_ext.h>
15 #include <trace.h>
16
17 #include "hpre_dh.h"
18 #include "hpre_main.h"
19
hpre_dh_alloc_keypair(struct dh_keypair * key,size_t size_bits)20 static TEE_Result hpre_dh_alloc_keypair(struct dh_keypair *key,
21 size_t size_bits)
22 {
23 if (!key || !size_bits) {
24 EMSG("Invalid input parameter");
25 return TEE_ERROR_BAD_PARAMETERS;
26 }
27
28 memset(key, 0, sizeof(*key));
29 key->g = crypto_bignum_allocate(size_bits);
30 if (!key->g)
31 goto g_err;
32
33 key->p = crypto_bignum_allocate(size_bits);
34 if (!key->p)
35 goto p_err;
36
37 key->x = crypto_bignum_allocate(size_bits);
38 if (!key->x)
39 goto x_err;
40
41 key->y = crypto_bignum_allocate(size_bits);
42 if (!key->y)
43 goto y_err;
44
45 /* Allocate subprime even if not used */
46 key->q = crypto_bignum_allocate(size_bits);
47 if (!key->q)
48 goto q_err;
49
50 return TEE_SUCCESS;
51 q_err:
52 crypto_bignum_free(&key->y);
53 y_err:
54 crypto_bignum_free(&key->x);
55 x_err:
56 crypto_bignum_free(&key->p);
57 p_err:
58 crypto_bignum_free(&key->g);
59 g_err:
60 EMSG("HPRE dh alloc key pair fail.");
61
62 return TEE_ERROR_OUT_OF_MEMORY;
63 }
64
hpre_dh_fill_sqe(void * bd,void * info)65 static enum hisi_drv_status hpre_dh_fill_sqe(void *bd, void *info)
66 {
67 struct hpre_dh_msg *msg = info;
68 struct hpre_sqe *sqe = bd;
69
70 sqe->w0 = msg->alg_type | SHIFT_U32(0x1, HPRE_DONE_SHIFT);
71 sqe->task_len1 = TASK_LENGTH(msg->key_bytes);
72 sqe->key = msg->x_p_dma;
73 sqe->in = msg->g_dma;
74 sqe->out = msg->out_dma;
75
76 return HISI_QM_DRVCRYPT_NO_ERR;
77 }
78
hpre_dh_parse_sqe(void * bd,void * info)79 static enum hisi_drv_status hpre_dh_parse_sqe(void *bd, void *info)
80 {
81 struct hpre_dh_msg *msg = info;
82 struct hpre_sqe *sqe = bd;
83 uint16_t err = 0;
84 uint16_t done = 0;
85
86 err = HPRE_TASK_ETYPE(sqe->w0);
87 done = HPRE_TASK_DONE(sqe->w0);
88 if (done != HPRE_HW_TASK_DONE || err) {
89 EMSG("HPRE do dh fail! done=0x%"PRIx16", etype=0x%"PRIx16,
90 done, err);
91 return HISI_QM_DRVCRYPT_IN_EPARA;
92 }
93
94 if (hpre_bin_to_crypto_bin(msg->out, msg->out, msg->key_bytes,
95 msg->out_bytes)) {
96 EMSG("Fail to transfer dh_y from hpre_bin to crypto_bin");
97 return HISI_QM_DRVCRYPT_EINVAL;
98 }
99
100 return HISI_QM_DRVCRYPT_NO_ERR;
101 }
102
hpre_dh_do_task(void * msg)103 static TEE_Result hpre_dh_do_task(void *msg)
104 {
105 enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
106 TEE_Result res = TEE_SUCCESS;
107 struct hisi_qp *qp = NULL;
108
109 qp = hpre_create_qp(HISI_QM_CHANNEL_TYPE0);
110 if (!qp) {
111 EMSG("Fail to create dh qp");
112 return TEE_ERROR_BUSY;
113 }
114
115 qp->fill_sqe = hpre_dh_fill_sqe;
116 qp->parse_sqe = hpre_dh_parse_sqe;
117 ret = hisi_qp_send(qp, msg);
118 if (ret) {
119 EMSG("Fail to send task, ret=%d", ret);
120 res = TEE_ERROR_BAD_STATE;
121 goto done_proc;
122 }
123
124 ret = hisi_qp_recv_sync(qp, msg);
125 if (ret) {
126 EMSG("Recv task error, ret=%d", ret);
127 res = TEE_ERROR_BAD_STATE;
128 goto done_proc;
129 }
130
131 done_proc:
132 hisi_qm_release_qp(qp);
133
134 return res;
135 }
136
round_key_size_to_hw_size(size_t key_bytes)137 static size_t round_key_size_to_hw_size(size_t key_bytes)
138 {
139 size_t size = 0;
140
141 if (key_bytes <= 96)
142 size = 96;
143 else if (key_bytes <= 128)
144 size = 128;
145 else if (key_bytes <= 192)
146 size = 192;
147 else if (key_bytes <= 256)
148 size = 256;
149 else if (key_bytes <= 384)
150 size = 384;
151 else if (key_bytes <= 512)
152 size = 512;
153 else
154 EMSG("Invalid key_bytes[%zu]", key_bytes);
155
156 return size;
157 }
158
hpre_dh_gen_privkey(struct bignum * x,size_t key_bits)159 static TEE_Result hpre_dh_gen_privkey(struct bignum *x, size_t key_bits)
160 {
161 size_t key_bytes = BITS_TO_BYTES(key_bits);
162 uint8_t buf[HPRE_DH_MAX_KEY_BYTES] = { };
163 TEE_Result ret = TEE_SUCCESS;
164
165 if (hw_get_random_bytes(buf, key_bytes)) {
166 EMSG("Fail to fill privkey");
167 return TEE_ERROR_NO_DATA;
168 }
169
170 ret = crypto_bignum_bin2bn(buf, key_bytes, x);
171 memzero_explicit(buf, key_bytes);
172
173 return ret;
174 }
175
hpre_dh_params_alloc(struct hpre_dh_msg * msg)176 static enum hisi_drv_status hpre_dh_params_alloc(struct hpre_dh_msg *msg)
177 {
178 uint32_t size = HPRE_DH_TOTAL_BUF_SIZE(msg->key_bytes);
179 uint8_t *data = NULL;
180
181 data = calloc(1, size);
182 if (!data) {
183 EMSG("Fail to alloc dh total buf");
184 return HISI_QM_DRVCRYPT_ENOMEM;
185 }
186
187 msg->x_p = data;
188 msg->x_p_dma = virt_to_phys(msg->x_p);
189
190 msg->g = msg->x_p + (msg->key_bytes << 1);
191 msg->g_dma = msg->x_p_dma + (msg->key_bytes << 1);
192 msg->out = msg->g + msg->key_bytes;
193 msg->out_dma = msg->g_dma + msg->key_bytes;
194
195 return HISI_QM_DRVCRYPT_NO_ERR;
196 }
197
hpre_dh_params_free(struct hpre_dh_msg * msg)198 static void hpre_dh_params_free(struct hpre_dh_msg *msg)
199 {
200 if (msg->x_p) {
201 free_wipe(msg->x_p);
202 msg->x_p = NULL;
203 }
204 }
205
hpre_dh_params_bn2bin(struct hpre_dh_msg * msg,struct dh_keypair * key,struct bignum * pubkey)206 static enum hisi_drv_status hpre_dh_params_bn2bin(struct hpre_dh_msg *msg,
207 struct dh_keypair *key,
208 struct bignum *pubkey)
209 {
210 uint8_t *p = msg->x_p + msg->key_bytes;
211 uint8_t *x = msg->x_p;
212 enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
213
214 msg->xbytes = BITS_TO_BYTES(key->xbits);
215 msg->out_bytes = msg->pbytes;
216 crypto_bignum_bn2bin(key->x, x);
217 crypto_bignum_bn2bin(key->p, p);
218
219 if (!pubkey) {
220 msg->gbytes = crypto_bignum_num_bytes(key->g);
221 crypto_bignum_bn2bin(key->g, msg->g);
222 } else {
223 msg->gbytes = crypto_bignum_num_bytes(pubkey);
224 if (msg->gbytes != msg->pbytes)
225 return HISI_QM_DRVCRYPT_EINVAL;
226 crypto_bignum_bn2bin(pubkey, msg->g);
227 }
228
229 ret = hpre_bin_from_crypto_bin(x, x, msg->key_bytes, msg->xbytes);
230 if (ret) {
231 EMSG("Fail to transfer dh_x from crypto_bin to hpre_bin");
232 return ret;
233 }
234
235 ret = hpre_bin_from_crypto_bin(p, p, msg->key_bytes, msg->pbytes);
236 if (ret) {
237 EMSG("Fail to transfer dh_p from crypto_bin to hpre_bin");
238 return ret;
239 }
240
241 ret = hpre_bin_from_crypto_bin(msg->g, msg->g, msg->key_bytes,
242 msg->gbytes);
243 if (ret)
244 EMSG("Fail to transfer dh_g from crypto_bin to hpre_bin");
245
246 return ret;
247 }
248
hpre_dh_request_init(struct hpre_dh_msg * msg,struct dh_keypair * key,struct bignum * pubkey)249 static TEE_Result hpre_dh_request_init(struct hpre_dh_msg *msg,
250 struct dh_keypair *key,
251 struct bignum *pubkey)
252 {
253 enum hisi_drv_status ret = HISI_QM_DRVCRYPT_NO_ERR;
254
255 msg->alg_type = HPRE_ALG_DH;
256 msg->key_bytes = round_key_size_to_hw_size(msg->pbytes);
257 if (!msg->key_bytes)
258 return TEE_ERROR_BAD_PARAMETERS;
259
260 ret = hpre_dh_params_alloc(msg);
261 if (ret)
262 return TEE_ERROR_OUT_OF_MEMORY;
263
264 ret = hpre_dh_params_bn2bin(msg, key, pubkey);
265 if (ret) {
266 hpre_dh_params_free(msg);
267 return TEE_ERROR_BAD_STATE;
268 }
269
270 return TEE_SUCCESS;
271 }
272
hpre_dh_request_deinit(struct hpre_dh_msg * msg)273 static void hpre_dh_request_deinit(struct hpre_dh_msg *msg)
274 {
275 hpre_dh_params_free(msg);
276 }
277
hpre_dh_gen_keypair(struct dh_keypair * key,struct bignum * q __unused,size_t key_size)278 static TEE_Result hpre_dh_gen_keypair(struct dh_keypair *key,
279 struct bignum *q __unused,
280 size_t key_size)
281 {
282 struct hpre_dh_msg msg = { };
283 TEE_Result ret = TEE_SUCCESS;
284 size_t p_bits = 0;
285
286 if (!key || !key->g || !key->p || !key->x || !key->y) {
287 EMSG("Invalid dh_gen_keypair input parameters");
288 return TEE_ERROR_BAD_PARAMETERS;
289 }
290
291 p_bits = crypto_bignum_num_bits(key->p);
292 if (!p_bits) {
293 EMSG("p_bits can not be zero");
294 return TEE_ERROR_BAD_PARAMETERS;
295 }
296 msg.pbytes = BITS_TO_BYTES(p_bits);
297
298 if (!key_size) {
299 /* xbits */
300 key->xbits = p_bits;
301 ret = hpre_dh_gen_privkey(key->x, key->xbits);
302 if (ret) {
303 EMSG("Fail to gen dh privkey");
304 return ret;
305 }
306 } else {
307 key->xbits = key_size;
308 }
309
310 ret = hpre_dh_request_init(&msg, key, NULL);
311 if (ret) {
312 EMSG("Fail to init dh msg");
313 return ret;
314 }
315
316 ret = hpre_dh_do_task(&msg);
317 if (ret)
318 goto req_deinit;
319
320 ret = crypto_bignum_bin2bn(msg.out, msg.out_bytes, key->y);
321 if (ret)
322 EMSG("Fail to bin2bn msg out");
323
324 req_deinit:
325 hpre_dh_request_deinit(&msg);
326
327 return ret;
328 }
329
hpre_dh_do_shared_secret(struct drvcrypt_secret_data * sdata)330 static TEE_Result hpre_dh_do_shared_secret(struct drvcrypt_secret_data *sdata)
331 {
332 struct hpre_dh_msg msg = { };
333 struct dh_keypair *key = NULL;
334 TEE_Result ret = TEE_SUCCESS;
335
336 if (!sdata || !sdata->key_priv || !sdata->key_pub) {
337 EMSG("Invalid dh_do_shared_secret input parameters");
338 return TEE_ERROR_BAD_PARAMETERS;
339 }
340
341 key = sdata->key_priv;
342 key->xbits = crypto_bignum_num_bits(key->x);
343 if (!key->xbits) {
344 EMSG("xbits can not be zero");
345 return TEE_ERROR_BAD_PARAMETERS;
346 }
347 msg.pbytes = crypto_bignum_num_bytes(key->p);
348
349 ret = hpre_dh_request_init(&msg, key, (struct bignum *)sdata->key_pub);
350 if (ret) {
351 EMSG("Fail to init dh msg");
352 return ret;
353 }
354
355 ret = hpre_dh_do_task(&msg);
356 if (ret)
357 goto req_deinit;
358
359 sdata->secret.length = msg.out_bytes;
360 memcpy(sdata->secret.data, msg.out, msg.out_bytes);
361 memzero_explicit(msg.out, msg.out_bytes);
362
363 req_deinit:
364 hpre_dh_request_deinit(&msg);
365
366 return ret;
367 }
368
369 static struct drvcrypt_dh driver_dh = {
370 .alloc_keypair = hpre_dh_alloc_keypair,
371 .gen_keypair = hpre_dh_gen_keypair,
372 .shared_secret = hpre_dh_do_shared_secret,
373 };
374
hpre_dh_init(void)375 TEE_Result hpre_dh_init(void)
376 {
377 TEE_Result ret = drvcrypt_register_dh(&driver_dh);
378
379 if (ret != TEE_SUCCESS)
380 EMSG("hpre dh register to crypto fail.");
381
382 return ret;
383 }
384
385 driver_init(hpre_dh_init);
386